Periodically run an event on Server side itself - asp.net

I want to run an event periodically on the server side that is to be initiated by the server in ASP.NET scenario. There will be no request from client.
Your help will be much appreciated.

Assuming you have access to the server and can install external applications, you could create a stand-alone Windows Service or even a console application that is triggered by the built in Windows Task Scheduler.
For something that runs in Asp.Net you could use Quartz.net. This SO question explains how to use it with Asp.Net

You need to spawn a process using the Process class. The process will sleep until the recurrence time comes.
Process p = new Process();
p.StartInfo.FileName = "foo";
p.Start();
Another alternative is to spool a thread using the Thread class.

For a similar situation in some of the applications, I use a separate service (windows service/web service) and use System.Threading.Timer (see http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx) and implement a scheduler of my own. Or otherwise, you can use any server based standard scheduler to invoke some executable that in turn hits your service.

I would just create a standard command line executable and have it run with the Windows Scheduling Tool.
A windows service is fine if it runs in very short intervals, but for example for once a day task, I think its the wrong approach.

Have a look at the Windows Workflow Foundation
That framework is built for this kind of things, like state persistance etc. It also runs separate, so the process will not go down when your app(pool) goes down (by default due to IIS).
Integrates fully with asp.net and you'll probably end up (in a positive way) with a Delay Activity.

Related

Windows scheduler API with console application Vs .net scheduler tools with asp.net mvc to execute long running processes inside my asp.net MVC

I am working on an asp.net mvc-5 web application, deployed under windows 2012 & iis-8. my asp.net mvc have many CRUD operations which are implemented as action methods inside my asp.net mvc.
But my asp.net mvc web application will be doing scheduled long running network scan process, the network scan will mainly do the following steps:-
Get the list of our servers and vms from our database.
Get the scanning username and password for each server and vm from a third party tool, using Rest API.
Call some powershell scripts to retrieve the servers & vms info such as network info, memory, name, etc.
Update our ERP system with the scan info using Rest API.
Now I did a pilot project using the following approach:-
I define a Model method inside my asp.net mvc to do the above 4 steps.
Then I install hangfire tool which will be calling the scan method on predefined scheduler.
Also I create a View inside my asp.net mvc which allow users to set the hangfire schedule settings (this require to do an IIS reset on the host server for hangfire to get the new settings).
Now I run a test scan for a round 150 servers which took around 40 minutes to complete , and it worked well. The only thing I noted is that if I set the schedule to run on non-business hours (where no activity is made on IIS) then hangfire will not be able to call the job, and once the first request is made the missed jobs will run. I overcome this limitation by defining a windows task which calls IIS each 15 minutes, to keep application pool live, and it worked well...
Now the other approach I am reading about is doing my above is as follow:-
Instead of defining Model method inside asp.net mvc to do the scan, I can create a separate console application to do the scan.
Then inside my asp.net mvc to create a view which allow users to create and schdule a task inside the windows tasks scheduler. I can do so by integrating with the windows task scheduler API.
Where this windows task will be calling the console application.
Now I am not sure which approach is better and why ? now generally speaking long running/background jobs should not run under iis.. But at the same time defining these long running processes as console app and calling these apps inside windows task scheduler will create extra dependencies on my web application. And will add extra effort when moving the application from move server to another (for example from test to live)..
Beside this I read that tools such as hangfire, quartz and other are designed to allow running long running tasks inside IIS and they eliminate the need to create console applications and scheduling these console applications using task scheduler ..
So can anyone advice on this?
In my opinion, if it is possible to solve the scheduling problem on the web application side, there is no need to create a scheduler task or a new console application for triggering purposes. The problem you will probably face when using scheduling task in a web application is generally common as you might see is that: The scheduler works like a charm during debugging of the web application, but not being able to trigger after publishing it to IIS. At this point the problem is generally related to IIS rather than the schedulers Quartz.NET, Hangfire, etc. Although there are lots of articles or solution methods posted on the web, unfortunately only some of them is working properly. In addition to this, most of them require lots of configuration settings on the web and machine configuration.
However, there are also some kind of solutions for such a kind of scheduling problem and I believe in that it is worthy to give a try Keep Alive Service For IIS 6.0/7.5. Just install it on the server to which you publish your application and enjoy. Then your published application will be alive after application pool recycling, IIS/Application restarting, etc. That is also used in our MVC application in order to send notification mails weekly and has been worked for months without any problem. Here are the sample code that I use in our MVC application. For more information please visit Scheduled Tasks In ASP.NET With Quartz.Net and Quartz.NET CronTrigger.
*Global.asax:*
protected void Application_Start()
{
JobScheduler.Start();
}
*EmailJob.cs:*
using Quartz;
public class EmailJob : IJob
{
public void Execute(IJobExecutionContext context)
{
SendEmail();
}
}
*JobScheduler.cs:*
using Quartz;
using Quartz.Impl;
public class JobScheduler
{
public static void Start()
{
IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
scheduler.Start();
IJobDetail job = JobBuilder.Create<EmailJob>().Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSchedule(CronScheduleBuilder
.WeeklyOnDayAndHourAndMinute(DayOfWeek.Monday, 10, 00)
//.WithMisfireHandlingInstructionDoNothing() //Do not fire if the firing is missed
.WithMisfireHandlingInstructionFireAndProceed() //MISFIRE_INSTRUCTION_FIRE_NOW
.InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("GTB Standard Time")) //(GMT+02:00)
)
.Build();
scheduler.ScheduleJob(job, trigger);
}
}
Also I create a View inside my asp.net mvc which allow users to set the hangfire schedule settings (this require to do an IIS reset on the host server for hangfire to get the new settings).
You're resetting your webserver to update a task's schedule? That doesn't sound healthy. What you might do is keep track of what the scheduled time should be, and on execution, check if the current time is within a certain range of the scheduled time (or has already been executed), otherwise abort the job.
The only thing I noted is that if I set the schedule to run on non-business hours (where no activity is made on IIS) then hangfire will not be able to call the job, and once the first request is made the missed jobs will run. I overcome this limitation by defining a windows task which calls IIS each 15 minutes, to keep application pool live, and it worked well...
Hangfire's documentation has a page about running delayed tasks that mentions what you need to change to accomodate this.
Using Windows' Task Scheduler doesn't seem like a good idea; it's not meant for the execution of ad-hoc, short-lived tasks. You probably need elevation to create tasks, and you'd probably need to define another scheduled task to clean up the mountain of tasks that would exist after a few dozen background jobs have been executed.
You're also correct that using Windows' Task Scheduler would make it more difficult to move your application around.

Is it safe to use a long running data processing function in ASP.NET

I have a function that takes about 2-3 minutes to do all of the processing it needs
It only needs to do the calculations once daily. The processing is done inside of a background thread that is started inside Application_Start in Global.asax.cs.
I am worried that the application will kill the method while it is running.
You are doing the process in in Application_Start, are you restarting your application daily ?. A better approach would be to create a separate executable for the task, and schedule it on your server using Windows Scheduler.
For the above scenario, either you can use windows service or console application and schedule it when you want it to run.
But doing it at the start of application is never recommended in this scenario.

Hosting WF as Windows Service

I am trying to construct a simple windows workflow to monitor a directory for inbound files and do some DB updates using Windows WF 4.0. Currently I am planning to build a 'WCF Workflow Service' and host it as a 'Windows service' running 24/7 (with a daily service shutdown and startup).
Further in the future I am planning to consume this service using an ASP.NET/WPF application to create a basic dashboard kind of stuff.
Considering the idea of directory polling for files with WF hosted on windows service, does it seems to be a good idea? What can be the cons of this?
Please advice if there are any drawbacks on this or can this achieved by better means?
I'm actually doing this, but it is a bit more complex than you think, and should be avoided if possible.
You should not be blocking from within an Activity; if it is expected to be a long running Activity that is waiting from input from the outside (FileSystemWatcher event, for instance), the workflow should idle itself and wait to be woken from the outside.
How I did this was I created a workflow extension that hosted the FileSystemWatcher. Once the Activity was ready to watch for a file, it created a bookmark and passed it to the extension.
The extension then started the FSW, holding onto the bookmark.
When a FSW event was fired, the extension resumed the bookmark, passing in an object that contained details about the event. The Activity did what was needed with the event, then re-scheduled itself.
Normally I wouldn't have done this, but I had some requirements that forced me to use WF4 to accomplish this goal. If I didn't have to use WF4, I would have just spun up the FSW within the service and consumed the events.
Unless you expect to have to be very flexible with your configuration detailing what you do with the FSW event, and expect this to change relatively often during deployment of the service, I'd skip WF4.

schedule method in asp.net

How can i send emails automatically every day by asp.net application and c#?
Your best bet is to use a Scheduler like Quartz.NET. It will give you the most precise, flexible, and predictable results.
ASP.NET application cannot run scheduled code. It works on simple request response pattern so it can run the code only if HTTP request arrives. To do the scheduling you have to write another application. Ugly way is to use console application and schedule it by Windows scheduler. Better approach is to use windows service.

Get host name without using HttpRequest

I want to run a "background job" in my ASP.NET application (periodically, as separate thread). And I need host name (DNS name or IP) to do my tasks. The problem is that the HttpContext.Current may be not available here (it's NULL).
Is there any way to get a host name in not using HttpContext.Current.Request.Url.Host.
When the host name is available in HttpContext.Request.Url.Host, it is a result of the host name being part of the request sent by the client. As an example, take a request to this page:
GET /questions/2164261/get-host-name-without-using-httprequest HTTP/1.1
Host: stackoverflow.com
...
When running in a background thread, no request context is available, and there really is no concept of a host name at all. Your only alternative is to store the hostname within the code or in configuration.
Slightly off topic: Running scheduled tasks within a web application is asking for trouble, and spawning threads only deals with a few of them. If at all possible, consider running your scheduled jobs from a Windows service, possibly built using a framework like NCron.
probably you can add a class variable in your thread class, and set this variable with request.url.host before you run the thread class.
this method can also apply to the session object.
Keep in mind that it's a bad idea to initiate that "background job" from a web application if you need that background process to run 24/7 independently. Even if you start it in a new thread. Your web app may have no requests for some time. In this case the run time will shut down the process and all its "child" threads. For continuous running you need to run it as a Windows service. Otherwise, the Darren is right, use the System.Net.Dns.GetHostName().
I'm using the same approach as you for scheduling regular tasks and the way I worked around this is to store the machine name for later use when the application gets any kind of web request.
It's a rather dirty hack, but the only way to do this unless you want to hard-code it or retrieve it from an external configuration file, which was too dangerous (unreliable) for my purposes.

Resources