basquang™ on clouds

May 11, 2017

Xap packaging failed. Cannot access a closed Stream

Filed under: Windows Phone — basquang @ 5:53 PM

Problem:

  • When you try to build Windows Phone 8.0 Silverlight project

18448072_10208528682447253_61194586_n

Solution:

  • Reinstall Windows Phone SDK 8.0 for Visual Studio

Hope this help!

April 27, 2017

Calling Untrusted SSL HTTPS request using HttpClient give “Message=The remote certificate is invalid according to the validation procedure”

Filed under: JSON,Microsoft Technology,MVC,WebAPI — basquang @ 3:36 PM

Scenario:

+You want to deploy web application server (for example ASP.NET Web API) which require SSL certificate and HTTPS

+You want to make a call to that server using HttpClient

Problem:

+You may see the following errors message when make a call to https required url using HttpClient
HResult=-2146233079
Message=The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

HResult=-2146233087
Message=The remote certificate is invalid according to the validation procedure.

HResult=-2146233088
Message=An error occurred while sending the request.

Solution:

Using this lines of code to accept all server certificates from client. This line of code is using for testing purpose only with you are using self-signed or untrusted certificates

//Accept all server certificate
ServicePointManager.ServerCertificateValidationCallback =
    delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
                {
                    return true;
                };

For example you want to make a https POST to Web API method in this post Hello ASP.NET Web API

static async Task PostSampleAsync()
        {
            //Accept all server certificate
            ServicePointManager.ServerCertificateValidationCallback =
                delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
                {
                    return true;
                };
            client.BaseAddress = new Uri("https://10.1.16.193/WebAPISample/");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            HttpResponseMessage response = await client.PostAsJsonAsync("api/values", "hello!");
            response.EnsureSuccessStatusCode();
            var result = response.Content.ReadAsAsync<string>().Result;
            Console.WriteLine(result);
        }

Happy coding!

Hello ASP.NET Web API

Filed under: JSON,Microsoft Technology,MVC,WebAPI — basquang @ 3:13 PM

1. Create a simple ASP.NET Web API project with HTTP GET and POST method

Create a simple Web API Controller like this:

    public class ValuesController : ApiController
    {
        string[] list = new string[] { "value1", "value2" };
        // GET api/values
        public IEnumerable<string> Get() { return list; }

        // GET api/values/1
        public string Get(int id) { return list[id]; }

        // POST api/values
        public string Post([FromBody]string value) { return value; }
    }

2. Test the Web API using web browser or POSTMAN

Navigate GET method by web browser

http://localhost:3649/api/values

webapi1

in POSTMAN http://localhost:3649/api/values/1

webapi2

in POSTMAN test HTTP POST method

webapi3

3. Call the Web API using HttpClient

+ Create a console application

+ Install Nuget package

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net452" />
  <package id="Newtonsoft.Json" version="6.0.4" targetFramework="net452" />
</packages>

+ Create a method to consume Web API method GET like this

static HttpClient client = new HttpClient();
        static void Main(string[] args)
        {
            RunAsync().Wait();
        }

        static async Task RunAsync()
        {
            //await PostSampleAsync();
            await GetSampleAsync();

            Console.ReadLine();
        }
static async Task GetSampleAsync()
        {
            // this is where we will send it
            string uri = "http://localhost:3649/api/values";

            // create a request
            HttpWebRequest request = (HttpWebRequest)
            WebRequest.Create(uri); request.KeepAlive = false;
            request.ProtocolVersion = HttpVersion.Version10;
            request.Method = "GET";

            /*====HTTP POST====*/
            //request.Method = "POST";
            //// turn our request string into a byte stream
            //byte[] postBytes = Encoding.ASCII.GetBytes("hello"); //param

            //// this is important - make sure you specify type this way
            //request.ContentType = "application/x-www-form-urlencoded";
            //request.ContentLength = postBytes.Length;
            //Stream requestStream = request.GetRequestStream();

            //// now send it
            //requestStream.Write(postBytes, 0, postBytes.Length);
            //requestStream.Close();

            // grab te response and print it out to the console along with the status code
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Console.WriteLine(new StreamReader(response.GetResponseStream()).ReadToEnd());
            Console.WriteLine(response.StatusCode);
        }

+ Run debug application you will see the result as below

webapi4

+ Create a method to consume Web API method POST like this

static async Task PostSampleAsync()
        {
            client.BaseAddress = new Uri("http://localhost:3649/");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            HttpResponseMessage response = await client.PostAsJsonAsync("api/values", "hello!");
            response.EnsureSuccessStatusCode();
            var result = response.Content.ReadAsAsync<string>().Result;
            Console.WriteLine(result);
        }

+ Run debug application for this method you will see the result as below

webapi5.PNG

Happy coding!

November 25, 2015

Transfer large data with WCF

Filed under: Uncategorized,WCF — basquang @ 3:16 PM
Tags:

[MSDN]: Introduction to Building Windows Communication Foundation Services

[MSDN]: Large Data and Streaming

[MSDN] Transferring large blobs of data with WCF

[MSDN]: Streaming Message Transfer

Transferring large files using WCF

File Transfer with WCF

WCF Streaming: Upload files over HTTP

Transferring large data over the wire using WCF

Passing Large Files in Windows Communication Foundation (WCF) using Streaming and TCP

MTOM vs. Streaming vs. Compression – Large attachments over WCF

Streaming Files (for Upload/Download) in WCF (Message Contracts)

 

November 10, 2015

Secure your WCF Web Services resource references

Filed under: Digital Signature,WCF — basquang @ 3:52 PM
Tags:

You want to secure your WCF web services, you want to sign digital signature on your web service here are some good references

[MSDN]: Using Message Contracts

[MSDN]How to: Set the ProtectionLevel Property

[VS Magazine] Security Considerations and Best Practices for WCF 4 Apps

[MSDN] Message Security with a Certificate Client

[MSDN] Message Security Certificate

[CodeProject] WCF Service Method Level Security using Message Contract

October 26, 2015

TFS 2015: Fail to create Team Project

Filed under: TFS — basquang @ 2:03 PM
Tags:

You may receive following error when try to create TFS Team Project from Visual Studio

Problem: Fail to create team project

Error
The Project Creation Wizard encountered an error while creating reports to the SQL Server Reporting Services on http://win-i20evd01dob/ReportServer/ReportService2005.asmx.
Explanation
The Project Creation Wizard encountered a problem while creating reports on the SQL Server Reporting Services on http://win-i20evd01dob/ReportServer/ReportService2005.asmx. The reason for the failure cannot be determined at this time. Because the operation failed, the wizard was not able to finish creating the SQL Server Reporting Services site.
User Action
Contact the administrator for the SQL Server Reporting Services on http://win-i20evd01dob/ReportServer/ReportService2005.asmx to confirm that the SQL Server Reporting Services server is running and you have sufficient privileges to create a project. Your user account on SQL Server Reporting Services must have Content Manager permission to create a new project. Also, you might find additional helpful information in the project creation log. The log shows each action taken by the wizard at the time of the failure and may include additional details about the error.
Open the log file you may see:
Event Description: TF30162: Task “Populate Reports” from Group “Reporting” failed
Exception Type: Microsoft.TeamFoundation.Client.PcwException
Exception Message: The Project Creation Wizard encountered an error while creating reports to the SQL Server Reporting Services
Exception Message: TF30225: Error uploading report ‘Backlog Overview’: The current action cannot be completed. The user data source credentials do not meet the requirements to run this report or shared dataset. Either the user data source credentials are not stored in the report server database, or the user data source is configured not to require credentials but the unattended execution account is not specified. —> Microsoft.ReportingServices.Diagnostics.Utilities.InvalidDataSourceCredentialSettingException: The current action cannot be completed. The user data source credentials do not meet the requirements to run this report or shared dataset. Either the user data source credentials are not stored in the report server database, or the user data source is configured not to require credentials but the unattended execution account is not specified. (type ReportingUploaderException)
Assumption:
1. The SQL Server Reporting Services is running
2. You are logged in as [DOMAIN]\AccountName to Team Foundation Server to create Team Project
Solution:
You have following items to check:
1. Open Team Foundation Administration Console
a. In Application Tier | Reporting Services Summary has valid Reader Account for example [DOMAIN]\AccountName. If not enter that account
b. In Reporting tab, Edit the Reporting configuration and in Reports tab enter valid account for “Account for accessing datasource” for example [DOMAIN]\AccountName
2. Open Reporting Services Configuration Manager
a. In Encryption Keys tab, try to delete Encrypted Content
b. In Execution Account tab, enter valid account for example [DOMAIN]\AccountName
c. In Database tab, enter try to enter valid account for “Current Report Server Database Credential” for example [DOMAIN]\AccountName
3. Open Report Manager URL at http:/……/Reports
Open security setting for your TFS Reports Database and make sure that your account [DOMAIN]\AccountName. has Content Manager and Team Foundation Content Manager Role Assigment
Hop this help!

September 28, 2015

UWP: Open Store Rating to request user review and rate from your Windows 10 app

Filed under: UWP,windows 10 — basquang @ 4:32 PM
Tags: , , ,

In Windows Phone 8.x, you can use the Marketplace review task to launch the Store or Marketplace and then display the review page for the current app. The code is simple as below

MarketplaceReviewTask marketplaceReviewTask = new MarketplaceReviewTask();
marketplaceReviewTask.Show();

Unfortunately, UWP Windows 10 app does not support this kind of Marketplace review task. So the question is “How to open review page for current app to request user to rate your app on Windows 10?” Solution is, you can use Windows.System.Launcher to launch the ms-windows-store: URI scheme. The URI schema to launches the write a review experience for a product for example are:

Product ID: ms-windows-store://review/?ProductId=9WZDNCRFHVJL
Package Family Name (PFN): ms-windows-store://review/?PFN= Microsoft.Office.OneNote_8wekyb3d8bbwe

And then, in your code, using one of the uriString above

await Windows.System.Launcher.LaunchUriAsync(new Uri(uriString));

For Windows app, using the second schema uri is my recommendation, because you can get PFN dynamically from your code by using Windows.ApplicationModel.PackageId.FamilyName
but Windows.ApplicationModel.PackageId.ProductID is only available for Windows Phone app.

Hope this help!

September 9, 2015

Best Practices: Upgrade to Windows 10 UWP Universal apps

Filed under: Microsoft Technology,UWP — basquang @ 11:29 AM
Tags: ,
Scenario:
– You have Windows Phone 8.x and Windows 8.x apps and want to upgrade the app to UWP Universal for Windows 10 to take advantage of new API platform?
– You just only want to update the Windows app to UWP but leave the phone app version in 8.x for some reason ex: AdMob SDK has not yet supported for Windows Phone 8.1 or later. Here are some best practices for you:
1. To target your UWP app only for Windows 10 devices without phone version
Open the Package.appxmanifest file then edit the Dependencies as below
<Dependencies>
    <!--<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />-->
    <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.10240.0" MaxVersionTested="10.0.10240.0" />
  </Dependencies>
For this setting, you cannot deploy your app to Emulator or phone devices. And then when you upload the package to store, you will see the instruction below “Device families: Windows.Destop minverion 10.0.10240.0”
11638797_10204463343656324_1794777682_o
For more detail please visit msdn link here
https://msdn.microsoft.com/en-us/library/windows/apps/dn986903.aspx
2. Your UWP app using some extra features as access user appointments, contacts…but you do not see that capabilities in Package.appxmanifest to declare.
The solution is open Package.appxmanifest file then edit the node Capabilities as below:
<Capabilities>
    <Capability Name="internetClient" />
    <uap:Capability Name="appointments" />
  </Capabilities>
For more detail please visit msdn link here
https://msdn.microsoft.com/en-us/library/windows/apps/mt270968.aspx
https://msdn.microsoft.com/en-us/library/windows/apps/dn934741.aspx
3. You want to create settings page for your UWP looks like Microsoft Mail Universal app, which display the page flyout on the right. With Windows 8.x this will be completed by using SettingFlyout template, but the template is not supported for Windows 10 UWP.
Solution is create a new page or usercontrol then change the page/usercontrol class to inherit to Windows.UI.Xaml.Controls.SettingsFlyout. In UWP app the SettingsFlyout control is not visible in template selection but it still there in code.
public sealed partial class SettingsFlyoutControl : SettingsFlyout
<SettingsFlyout
    x:Class="LichViet.UserControls.SettingsFlyoutControl"...>
....
</SettingsFlyout>

Hope this help!

August 7, 2014

[Quartz.NET]: Configure AdoJobStore JobStore

Filed under: Quartz,Quartz.NET — basquang @ 4:05 PM
Tags: ,

JobStore‘s are responsible for keeping track of all the “work data” that you give to the scheduler: jobs, triggers, calendars, etc.

RAMJobStore

RAMJobStore is the simplest JobStore to use, it is also the most performant (in terms of CPU time). RAMJobStore gets its name in the obvious way: it keeps all of its data in RAM. This is why it’s lightning-fast, and also why it’s so simple to configure. The drawback is that when your application ends (or crashes) all of the scheduling information is lost – this means RAMJobStore cannot honor the setting of “non-volatility” on jobs and triggers. For some applications this is acceptable – or even the desired behavior, but for other applications, this may be disasterous.

Configuring Quartz to use RAMJobStore

quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz

To use RAMJobStore (and assuming you’re using StdSchedulerFactory) you don’t need to do anything special. Default configuration of Quartz.NET uses RAMJobStore as job store implementation.

ADO.NET Job Store (AdoJobStore)

AdoJobStore is also aptly named – it keeps all of its data in a database via ADO.NET. Because of this it is a bit more complicated to configure than RAMJobStore, and it also is not as fast. However, the performance draw-back is not terribly bad, especially if you build the database tables with indexes on the primary keys.

To use AdoJobStore, you must first create a set of database tables for Quartz.NET to use. You can find table-creation SQL scripts in the “database/dbtables” directory of the Quartz.NET distribution. If there is not already a script for your database type, just look at one of the existing ones, and modify it in any way necessary for your DB. One thing to note is that in these scripts, all the the tables start with the prefix “QRTZ_” such as the tables “QRTZ_TRIGGERS”, and “QRTZ_JOB_DETAIL”). This prefix can actually be anything you’d like, as long as you inform AdoJobStore what the prefix is (in your Quartz.NET properties). Using different prefixes may be useful for creating multiple sets of tables, for multiple scheduler instances, within the same database.

This article describe simple steps to configure ADO.NET Job Store

  1. Download Quartz.NET package from here http://sourceforge.net/projects/quartznet/files/quartznet/
  2. Run the SQL file tables_sqlServer.sql to create ADO.NET Quartz Job Store tables. After complete you will see list of tables as picture below

     

  3. Create Console Application
  4. Install Quartz.NET NuGet package
  5. Configure logging in App.config as code below

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    
      <configSections>
        <!--<section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />-->
        <sectionGroup name="common">
          <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
        </sectionGroup>
      </configSections>
    
      <common>
        <logging>
          <factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging">
            <arg key="showLogName" value="true"/>
            <arg key="showDataTime" value="true"/>
            <arg key="level" value="INFO"/>
            <arg key="dateTimeFormat" value="HH:mm:ss:fff"/>
          </factoryAdapter>
        </logging>
      </common>
    
      <connectionStrings>
        <add name="QuartzStore" connectionString="Data Source=QUANGNB;Initial Catalog=QuartzNETStore;User ID=sa;Password=********" providerName="System.Data.SqlClient" />
      </connectionStrings>
    
      <!-- 
        We use quartz.config for this server, you can always use configuration section if you want to.
        Configuration section has precedence here.  
      -->
      <!--
      <quartz >
      </quartz>
      -->
    
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
      </startup>
    </configuration>
    

  6. Create quartz.config file and set Build Action = None, Copy to Output Directory = Copy Always. Then add following code to configure Quartz.NET to use ADO Job Store

    # You can configure your scheduler in either <quartz> configuration section
    # or in quartz properties file
    # Configuration section has precedence
    
    quartz.scheduler.instanceName = MyScheduler
    quartz.scheduler.instanceId = AUTO
    quartz.threadPool.type = Quartz.Simpl.SimpleThreadPool, Quartz 
    
    # this section configures the scheduler to use sqlite as the jobstore
    # to use the RAM store just comment all of this out
    # to use the sqlite store, uncomment all of this 
    quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz 
    quartz.jobStore.dataSource = default 
    quartz.jobStore.tablePrefix = QRTZ_ 
    quartz.jobStore.clustered = false
    quartz.jobStore.lockHandler.type = Quartz.Impl.AdoJobStore.SimpleSemaphore, Quartz 
    quartz.jobStore.driverDelegateType = Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz 
    quartz.dataSource.default.provider = SqlServer-20
    quartz.jobStore.useProperties = true
    quartz.jobStore.selectWithLockSQL = SELECT * FROM {0} LOCKS UPDLOCK WHERE LOCK_NAME = @ lockName
    quartz.dataSource.default.connectionStringName = QuartzStore
    quartz.dataSource.default.connectionString = Data Source=QUANGNB;Initial Catalog=QuartzNETStore;User ID=sa;Password=******
    
    # this section configures the scheduler to use sql server ce as the jobstore
    #quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz 
    #quartz.jobStore.dataSource = default 
    #quartz.dataSource.default.connectionString = Data Source=quartz.sdf;Persist Security Info=False;
    #quartz.jobStore.tablePrefix = QRTZ_ 
    #quartz.jobStore.clustered = false
    #quartz.jobStore.lockHandler.type = Quartz.Impl.AdoJobStore.UpdateLockRowSemaphore, Quartz 
    #quartz.jobStore.driverDelegateType = Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz 
    #quartz.dataSource.default.provider = SqlServerCe-351
    #quartz.jobStore.useProperties = true
    

  7. Create Simple Job like this

    public class SimpleJob : IJob
        {
            private static ILog logging = LogManager.GetLogger(typeof(SimpleJob));
    
            public void Execute(IJobExecutionContext context)
            {
                logging.InfoFormat("Hello from job");
            }
        }
    

  8. Using the Job in Program like this

    ILog log = LogManager.GetLogger(typeof(Program));           
    
    // First we must get a reference to a scheduler
    ISchedulerFactory sf = new StdSchedulerFactory();
    IScheduler sched = sf.GetScheduler();
    
    try
    {
    	var startTime = DateTimeOffset.Now.AddSeconds(5);
    
    	var job = JobBuilder.Create<SimpleJob>()
    						.WithIdentity("job1", "group1")
    						.Build();
    
    	var trigger = TriggerBuilder.Create()
    		.WithIdentity("trigger1", "group1")
    		.StartAt(startTime)
    		.WithSimpleSchedule(x => x.WithIntervalInSeconds(10).RepeatForever())
    		.Build();
    
    	sched.ScheduleJob(job, trigger);       
    
    	sched.Start();
    	Thread.Sleep(TimeSpan.FromMinutes(2));
    }
    finally
    {
    	sched.Shutdown(true);
    }         
    

  9. Now run for testing ADO Job Store. The Output like this

    15:56:31:280 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz.NET properties loa
    ded from configuration file 'C:\Users\Quang\Documents\Visual Studio 2013\Project
    s\QuartzNETSolution\Lesson6\bin\Debug\quartz.config'
    15:56:31:372 [INFO]  Quartz.Util.DBConnectionManager - Registering datasource 'd
    efault' with db provider: 'Quartz.Impl.AdoJobStore.Common.DbProvider'
    15:56:31:372 [INFO]  Quartz.Impl.StdSchedulerFactory - Using default implementat
    ion for object serializer
    15:56:31:383 [INFO]  Quartz.Impl.StdSchedulerFactory - Using custom data access
    locking (synchronization): Quartz.Impl.AdoJobStore.SimpleSemaphore
    15:56:31:384 [INFO]  Quartz.Impl.StdSchedulerFactory - Using default implementat
    ion for ThreadExecutor
    15:56:31:460 [INFO]  Quartz.Core.SchedulerSignalerImpl - Initialized Scheduler S
    ignaller of type: Quartz.Core.SchedulerSignalerImpl
    15:56:31:461 [INFO]  Quartz.Core.QuartzScheduler - Quartz Scheduler v.2.2.4.400
    created.
    15:56:31:491 [WARN]  Quartz.Impl.AdoJobStore.JobStoreTX - Detected usage of SQL
    Server provider without SqlServerDelegate, SqlServerDelegate would provide bette
    r performance
    15:56:31:491 [INFO]  Quartz.Impl.AdoJobStore.JobStoreTX - JobStoreTX initialized
    .
    15:56:31:498 [INFO]  Quartz.Core.QuartzScheduler - Scheduler meta-data: Quartz S
    cheduler (v2.2.4.400) 'MyScheduler' with instanceId 'NON_CLUSTERED'
      Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.
      NOT STARTED.
      Currently in standby mode.
      Number of jobs executed: 0
      Using thread pool 'Quartz.Simpl.SimpleThreadPool' - with 10 threads.
      Using job-store 'Quartz.Impl.AdoJobStore.JobStoreTX' - which supports persiste
    nce. and is not clustered.
    
    15:56:31:500 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz scheduler 'MySched
    uler' initialized
    15:56:31:501 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz scheduler version:
     2.2.4.400
    15:56:31:800 [INFO]  Quartz.Impl.AdoJobStore.JobStoreTX - Freed 0 triggers from
    'acquired' / 'blocked' state.
    15:56:31:844 [INFO]  Quartz.Impl.AdoJobStore.JobStoreTX - Recovering 0 jobs that
     were in-progress at the time of the last shut-down.
    15:56:31:844 [INFO]  Quartz.Impl.AdoJobStore.JobStoreTX - Recovery complete.
    15:56:31:861 [INFO]  Quartz.Impl.AdoJobStore.JobStoreTX - Removed 0 'complete' t
    riggers.
    15:56:31:876 [INFO]  Quartz.Impl.AdoJobStore.JobStoreTX - Removed 0 stale fired
    job entries.
    15:56:31:888 [INFO]  Quartz.Core.QuartzScheduler - Scheduler MyScheduler_$_NON_C
    LUSTERED started.
    15:56:36:787 [INFO]  Lesson6.SimpleJob - Hello from job
    15:56:46:619 [INFO]  Lesson6.SimpleJob - Hello from job
    ...
    

     

    While program running Open QRTZ_FIRED_TRIGGERS table

     

    While program running Open QRTZ_JOB_DETAILS table

     

    While program running Open QRTZ_TRIGGERS table

     

    Hope this help!

August 6, 2014

[Quartz.NET]: Configure Job in XML using Quartz plug-in XMLSchedulingDataProcessorPlugin

Filed under: Quartz,Quartz.NET — basquang @ 2:57 PM
Tags: ,

You can initialize the scheduler with predefined jobs and triggers using the XMLSchedulingDataProcessorPlugin. This plugin loads XML file(s) to add jobs and schedule them with triggers as the scheduler is initialized, and can optionally periodically scan the file for changes.The XML schema definition can be found here: http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd

Here are simple steps to use Quartz.NET plugin

  1. Create Console Application
  2. Install Quartz.NET from NuGet
  3. Add logging configuration in App.config as below

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    
      <configSections>
        <sectionGroup name="common">
          <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
        </sectionGroup>
      </configSections>
    
      <common>
        <logging>
          <factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging">
            <arg key="showLogName" value="true"/>
            <arg key="showDataTime" value="true"/>
            <arg key="level" value="INFO"/>
            <arg key="dateTimeFormat" value="HH:mm:ss:fff"/>
          </factoryAdapter>
        </logging>
      </common>
      
        <startup> 
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
        </startup>
    </configuration>
    

  4. Create a simple job as code below

    namespace Lesson5
    {
        public class SimpleJob : IJob
        {
            private static readonly ILog log = LogManager.GetLogger(typeof(SimpleJob));
    
            /// <summary>
            /// Called by the <see cref="IScheduler" /> when a
            /// <see cref="ITrigger" /> fires that is associated with
            /// the <see cref="IJob" />.
            /// </summary>
            public virtual void Execute(IJobExecutionContext context)
            {
                // This job simply prints out its job name and the
                // date and time that it is running
                JobKey jobKey = context.JobDetail.Key;
                log.InfoFormat("Executing job: {0} executing at {1}", jobKey, DateTime.Now.ToString("r"));
    
    
                if (context.MergedJobDataMap.Count > 0)
                {
                    ICollection<string> keys = context.MergedJobDataMap.Keys;
                    foreach (string key in keys)
                    {
                        String val = context.MergedJobDataMap.GetString(key);
                        log.InfoFormat(" - jobDataMap entry: {0} = {1}", key, val);
                    }
                }
    
                context.Result = "hello";
            }
        }
    }
    

  5. Create a xml file named as quartz_jobs.xml and set Build Action=Content and Copy to Output Directory=Copy always as below

    <?xml version="1.0" encoding="utf-8" ?>
    <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     				version="2.0">
    
      <processing-directives>
        <overwrite-existing-data>true</overwrite-existing-data>
      </processing-directives>
    
      <schedule>
    
        <job>
          <name>jobName1</name>
          <group>jobGroup1</group>
          <description>jobDesciption1</description>
          <job-type>Lesson5.SimpleJob, Lesson5</job-type>
          <durable>true</durable>
          <recover>false</recover>
          <job-data-map>
            <entry>
              <key>key0</key>
              <value>value0</value>
            </entry>
            <entry>
              <key>key1</key>
              <value>value1</value>
            </entry>
            <entry>
              <key>key2</key>
              <value>value2</value>
            </entry>
          </job-data-map>
        </job>
    
        <trigger>
          <simple>
            <name>simpleName</name>
            <group>simpleGroup</group>
            <description>SimpleTriggerDescription</description>
            <job-name>jobName1</job-name>
            <job-group>jobGroup1</job-group>
            <start-time>1982-06-28T18:15:00.0Z</start-time>
            <end-time>2020-05-04T18:13:51.0Z</end-time>
            <misfire-instruction>SmartPolicy</misfire-instruction>
            <repeat-count>100</repeat-count>
            <repeat-interval>3000</repeat-interval>
          </simple>
        </trigger>
    
      </schedule>
    
    </job-scheduling-data>
    

  6. Loading the job in XML plugin in Program console as code below

    ILog log = LogManager.GetLogger(typeof(Program));
    
    // our properties that enable XML configuration plugin
    // and makes it watch for changes every two minutes (120 seconds)
    var properties = new NameValueCollection();
    properties["quartz.plugin.triggHistory.type"] = "Quartz.Plugin.History.LoggingJobHistoryPlugin";
    
    properties["quartz.plugin.jobInitializer.type"] = "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin";
    properties["quartz.plugin.jobInitializer.fileNames"] = "quartz_jobs.xml";
    properties["quartz.plugin.jobInitializer.failOnFileNotFound"] = "true";
    properties["quartz.plugin.jobInitializer.scanInterval"] = "120";
    
    // First we must get a reference to a scheduler
    ISchedulerFactory sf = new StdSchedulerFactory(properties);
    IScheduler sched = sf.GetScheduler();
    
    // start the schedule 
    sched.Start();
    
    // wait five minutes to give our jobs a chance to run
    try
    {
    	Thread.Sleep(TimeSpan.FromMinutes(5));
    }
    catch (ThreadInterruptedException)
    {
    }
    
    // shut down the scheduler
    sched.Shutdown(true);      
    

Hope this help!

Next Page »

Blog at WordPress.com.