Hello to all.
Recently, I finally decided to read the entire series of articles about Data acquisition. And starting from the
first part I found for myself a lot of interesting things about windows service.
Just hung the task to write a simple service, which will be scheduled to pull our corporate site. I think, here it is a chance to consolidate fresh knowledge. Honestly, I started to fasten all the chips that were written in the article regarding windows service, but I started to run across the jambs. But it is not about the doorposts.
Another thought occurred to me that surely someone had already done such smart services, and for sure there are ready-made beautiful solutions. A couple of minutes of searching and what a surprise it was when I found the
NCron project, which gives not only an easy way to create a service, but also:
- It knows how to install itself and uninstall as windows service.
- It can perform tasks on a flexible schedule (from simple, every day at 6 am, to more complex, every third day of the quarterly month at 18 hours and 40 minutes)
- Allows you to configure an unlimited number of tasks to perform.
- It allows you to easily tie the logging of common frameworks and already has its own simple built-in logging mechanism in the Event Log.
- It has enough flexibility to use your favorite IoC containers.
And something else useful and convenient. So it’s not hard to see that this was exactly what I needed. Does everything with almost no gestures on my part. Moreover, I will say that services are very often written for just such simple tasks, which this project covers with its head.
So how to fasten this miracle.
')
Create a project
First, create a project
Console application . Everything is standard and simple.

Add Reference to NCron

Slightly change the main method
using NCron.Service;
using NCron.Fluent.Crontab;
using NCron.Fluent.Generics;
namespace ScheduledService
{
class Program
{
static void Main( string [] args)
{
Bootstrap.Init(args, ServiceSetup);
}
static void ServiceSetup(SchedulingService service)
{
}
}
}
There may be a question why the command line arguments are passed, they are needed so that later the service can install itself (you just need to run it with the
install
parameter). The
ServiceSetup
method
ServiceSetup
be needed later to configure our tasks on a schedule.
Create a simple task
This is done simply. Inheriting your class from the
CronJob
class and overriding the
Execute
abstract method. I immediately added a simplified implementation of the query for some link that comes into the constructor of our task.
using NCron;
namespace ScheduledService
{
public class RequestParameters
{
public String Uri { get ; set ; }
public int Timeout { get ; set ; }
}
public class RequestSenderJob : CronJob
{
private RequestParameters RequestParameters { get ; set ; }
public RequestSenderJob(RequestParameters requestParameters)
{
RequestParameters = requestParameters;
}
public override void Execute()
{
WebRequest request = WebRequest.Create(RequestParameters. Uri );
request.UseDefaultCredentials = true ;
request.Timeout = RequestParameters.Timeout > 0 ? RequestParameters.Timeout * 1000 : 60*1000; //default 1 min <br/>
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
response.Close();
}
}
}
I must say that in case of an error, its description will already be logged in the Event Log, and if necessary, you can connect your favorite library for logging.
Now the task has been created and you just need to configure its launch.
Configure task launch
This is where the previously created
ServiceSetup
method
ServiceSetup
in
ServiceSetup
, in which we will enter the logic for queuing calls
using NCron.Fluent.Crontab;
using NCron.Service;
namespace ScheduledService
{
class Program
{
static void Main( string [] args)
{
Bootstrap.Init(args, ServiceSetup);
}
static void ServiceSetup(SchedulingService service)
{
XDocument document = XDocument .Load( "Config.xml" );
var requestTasks = from task in document.Root.Elements( "RequestTask" ) select task;
foreach ( XElement requestTask in requestTasks)
{
RequestParameters requestParameters = new RequestParameters
{
Uri = requestTask. Attribute ( "RequestUri" ).Value,
Timeout = int .Parse(requestTask. Attribute ( "Timeout" ).Value)
};
String shedule = requestTask. Attribute ( "Shedule" ).Value;
service.At(shedule).Run(() => new RequestSenderJob(requestParameters));
}
}
}
}
For xml file of the form
<?xml version= "1.0" encoding= "utf-8" ?>
<Config>
<RequestTask RequestUri= "http://habrahabr.ru/" Shedule= "0 1 * * *" Timeout= "180" />
</Config>
Yes, here you can kick me for not having checked a single variable for
null
(I did it solely for clarity and simplicity of the example). But you should be interested in the variable
shedule
. It will contain a string describing the schedule by which the task is launched.
Schedule setting
The schedule for which the task is started is set using the
MINUTES HOURS DAYS MONTHS DAYS-OF-WEEK
format string.
Here are a couple of examples from the site itself:
// 9 . <br/>
service.At( "0 9 * * 0" ).Run<EatBaconAndEggs>();
// 8 , . <br/>
service.At( "0 8 1 1,4,7,10 *" ).Run<SubmitVatDeclaration>();
// , 8 17, . <br/>
service.At( "*/30 8-17 * * 1-5" ).Run<LookAtStackoverflow>();
As you can see from the example, you can set instead of numbers: '*' - select all, 'nm' - interval from m to n, '* / n' - every nth value, well, for dessert, you can list the values separated by commas and group others types of samples, and indeed you can programmatically set your own rules for the schedule.
Installation
And lastly on how to start our service, in which, by the way, we have not seen a single class related to the service. For this, I wrote 2 elementary batch file.
install.bat
ScheduledService install
pause
uninstall.bat
ScheduledService uninstall
pause
There is a truth and a more advanced version with parameters so that the service is immediately created with the necessary settings. You can read about it
here .
That's basically it.