I have created a C# Windows Service to poll(each one hour) and email with some attachments.
Everything is working fine.
Now, I want to convert the polling mechanism to a scheduler( like the program to be executed on 8.00, 12.00, 16.00 etc.)
Can I use the Services calss and Thread to do this? Or should I use timer and check the schedule time?
I am using the following logic now,
do
{
PollingPass();
// Next PollingPass() will execute after one hour.
TimeSpan s = new TimeSpan(1, 0, 0);
Thread.Sleep(s);
}
while(1 == 1);
Related
Basically what I have to do is create a thread that executes in a given number of days, which can change. The point is that an email should be sent periodically, and I'm looking for the best approach eventhough I know this is definitely not one of the best solutions but I must continue with this per requirements, hence I cannot use Windows Services, Windows Scheduler or anything similar. So the starting day for this email to be sent is when app starts, and then the next time should be after X days as specified in web.config. The problem is that I don't know how to keep track of that if the application stops (I can save the date of application start in database) but the number of days for the next execution may change. This is what I've done so far:
private async Task<int> EmailScheduler()
{
var day = DateTime.Now.Day; //day when app starts
while (true)
{
var currentTime = DateTime.Now;
if (currentTime.Day == day)
{
SendEmail("mailto", "", "", "subject", EmailMessage());
day += Int32.Parse(ConfigurationManager.AppSettings["NumberOfDays"]); //next schedule
}
await Task.Delay((int)TimeSpan.FromDays(1).TotalMilliseconds);
}
}
Thanks in advance.
You have no control over when your application pool restarts, and it will most certainly not be running for extended periods of time.
You could save the last execution date in a database, and periodically poll it to see if it has been longer than your given number of days.
The polling frequency would depend on your requirements.
This would somewhat approach sending a mail "every few days", but it would probably not be as accurate as a scheduled task.
I've searched a way to run a Background Task daily at a specific time, e.x. at at 12:00.
I've registered the BackgroundTask with a TimeTrigger, which unfortunately starts immediately after registering.
builder.SetTrigger(new TimeTrigger(24 * 60, false));
Is there a easier way, then checking every hour, if this is the right time of day?
Microsoft seems to avoid apps from triggering at a precise time, but you might be able to get close by calculating the number of minutes from the time the user registers the task to 12:00, then resubscribe another task from there set for 24*60 as you have. I'm unsure if Microsoft allows this within a Background task, but it's worth a shot.
Example of calculating the minutes to midnight for the task
var tommorowMidnight = DateTime.Today.AddDays(1);
var timeTilMidnight = tommorowMidnight - DateTime.Now;
var minutesTilMidnight = (uint)timeTilMidnight.TotalMinutes;
builder.SetTrigger(new TimeTrigger(minutesTilMidnight, true));
I've used this task wrapper to create something like this before and it fired everyday. Maybe this is what you are looking for.
http://taskscheduler.codeplex.com/
I have a MVC5 application that has a function to send e-mail to user after subscribing the newsletter. Now i have a requirement to send e-mail to all those users whose are running 1 month ahead of expiry date of their subscription. In this case i need to implement a background process that will run every day at a specific time on the web server. How can i do that?
Thanks
You can create a Windows Service to make that work for you.
You should follow this tutorial.
You can store the date/time on the project web.config/app.config which when you want your service to be executed. When the service executes, you validate the time and call a generic function that will do what you want. Follow this example:
public partial class Service1 : ServiceBase
{
YourServiceClass service;
private Timer serviceTimer;
public Service1()
{
InitializeComponent();
service = new YourServiceClass();
}
protected override void OnStart(string[] args)
{
TimerCallback timerDelegate = new TimerCallback(service.GetData); // You should add this function to your class. You have an example below
string time = System.Configuration.ConfigurationSettings.AppSettings["SceduleTime"]; // Gets time from app.config like 12:50
string[] timeS = time.Split(':');
DateTime DateIni = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, Convert.ToInt32(timeS[0]), Convert.ToInt32(timeS[1]), 0);
TimeSpan diff = DateTime.Now - DateIni;
if (diff.TotalSeconds < 0)
diff = DateIni - DateTime.Now;
else
diff = DateIni.AddDays(1) - DateTime.Now;
// create timer and attach our method delegate to it
serviceTimer = new Timer(timerDelegate, service, diff, new TimeSpan(1, 0, 0, 0));
}
protected override void OnStop()
{
serviceTimer.Dispose();
}
}
And on your YourServiceClass class, you add this function:
public void GetData(object state){
// Do something...
}
Hope it helps!
Personally, I'd create a separate dedicated Windows Service to periodically check for expiry, and then call the code to send the emails.
An alternative is to create a simple console application to run the task, and call it using the Windows Task Scheduler.
A less secure method is to use a ping service, to periodically hit a page with an obfuscated URL which processes the emails.
A slightly old, but relevant blog post, detailing the issues with recurrent background tasks in .net sites can be read here.
I recommend you to use Quartz library. Your process should be independent from your web application since the web app will recycle from time to time based on the user traffic which will trigger Application_End event and will start once a new request is sent which will trigger Application_Start so you wont be able to manage correctly your schedule start and end.
It really depends on your requirements, and whether you want this update to be truly independent on the server, in a web application or bundled with your app.
I recently found a great third party library for ASP.NET called Hang Fire.
It looks like it can be as simple as:
RecurringJob.AddOrUpdate(
() => Console.WriteLine("Transparent!"),
Cron.Daily);
It supports:
Delayed Jobs
Recurring Tasks
Automatic Retries
And it has a nicely themed Management/Reporting interface
I'm planning to use it for some scheduled batch tasks I need to run on a CRM system. No experience with it yet, but it does seem to have some great features and I think I've seen it recommended a few times around Stack Overflow!
There are a ton of different ways to approach what you want (Scheduled Task on the server is another off the top of my head). This is a nice little package that lets me bundle it with my web applications.
I am working on an assignment in asp.net to send notification email to users at specific intervals.
But the problem is that since the server is not privately owned i cannot implement a windows service on it.
Any ideas?
There's no reliable way to achieve that. If you cannot install a Windows Service on the host you could write a endpoint (.aspx or .ashx) that will send the email and then purchase on some other site a service which will ping this endpoint at regular intervals by sending it HTTP request. Obviously you should configure this endpoint to be accessible only from the IP address of the provider you purchase the service from, otherwise anyone could send an HTTP request to the endpoint and trigger the process which is probably undesirable.
Further reading: The Dangers of Implementing Recurring Background Tasks In ASP.NET.
There are several ways to get code executing on an interval that don't require a windows service.
One option is to use the Cache class - use one of the Insert overloads that takes a CacheItemRemovedCallback - this will be called when the cache item is removed. You can re-add the cache item with this callback again and again...
Though, the first thing you need to do is contact the hosting company and find out if they already have some sort of solution for you.
You could set up a scheduled task on the server to invoke a program with the desired action.
You can always use a System.Timer and create a call at specific intervals. What you need to be careful is that this must be run one time, eg on application start, but if you have more than one pools, then it may run more times, and you also need to access some database to read the data of your actions.
using System.Timers;
var oTimer = new Timer();
oTimer.Interval = 30000; // 30 second
oTimer.Elapsed += new ElapsedEventHandler(MyThreadFun);
oTimer.Start();
private static void MyThreadFun(object sender, ElapsedEventArgs e)
{
// inside here you read your query from the database
// get the next email that must be send,
// you send them, and mark them as send, log the errors and done.
}
why I select system timer:
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx
more words
I use this in a more complex class and its work fine. What are the points that I have also made.
Signaling the application stop, to wait for the timer to end.
Use mutex and database for synchronize the works.
Easiest solution is to exploit global.asax application events
On application startup event, create a thread (or task) into a static singleton variable in the global class.
The thread/task/workitem will have an endless loop while(true) {...} with your "service like" code inside.
You'll also want to put a Thread.Sleep(60000) in the loop so it doesn't eat unnecessary CPU cycles.
static void FakeService(object obj) {
while(true) {
try {
// - get a list of users to send emails to
// - check the current time and compare it to the interval to send a new email
// - send emails
// - update the last_email_sent time for the users
} catch (Exception ex) {
// - log any exceptions
// - choose to keep the loop (fake service) running or end it (return)
}
Thread.Sleep(60000); //run the code in this loop every ~60 seconds
}
}
EDIT Because your task is more or less a simple timer job any of the ACID type concerns from an app pool reset or other error don't really apply, because it can just start up again and keep trucking along with any data corruption. But you could also use the thread to simply execute a request to an aspx or ashx that would hold your logic.
new WebClient().DownloadString("http://localhost/EmailJob.aspx");
Here I below pasted code I'm using in current window service solution, this will run job every day 10 AM regularly, I will pass the parameters using App.configuaration file
APP.CONFIG
<add key ="FIREHOST_TIME" value ="10" ></add>
<add key ="SETDAYS" value ="1" ></add>
CODE BEHIND PAGE
protected override void OnStart(string[] args)
{
DateTime tenAM = DateTime.Today.AddHours(FIREHOST_TIME);
if (DateTime.Now > tenAM)
tenAM = tenAM.AddDays(SETDAYS);
// calculate milliseconds until the next 10:00 AM.
int timeToFirstExecution = (int)tenAM.Subtract(DateTime.Now).TotalMilliseconds;
// calculate the number of milliseconds in 24 hours.
int timeBetweenCalls = (int)new TimeSpan(24, 0, 0).TotalMilliseconds;
TimerCallback methodToExecute = kickstart;
// start the timer. The timer will execute "ProcessFile" when the number of seconds between now and
// the next 10:00 AM elapse. After that, it will execute every 24 hours.
System.Threading.Timer timer = new System.Threading.Timer(methodToExecute, null, timeToFirstExecution, timeBetweenCalls);
}
Now I am trying to run my service, based up on the below Mentioned conditions:
I want to start my service but it should job perform the job based on the this new tag which I will add newly in app.config
BY based on above four tags
if RUN_NOW == 1
has to perform service based on FIREHOST_TIME and SETDAYS normal thing
else
service have to perform the Job doing by after 5 days(because WAIT_DAYS = 5)
then it have to use the FIREHOST_TIME and SETDAYS value
Note: service should not get stopped, it should be in started condition only
How can I achieve this?
I don't know exactly how you want implement the whole program logic, the portion I can try to help you is about reacting to a config file modification without restarting the service, this can be done with:
ConfigurationManager.RefreshSection("thesectiontorefresh");
for a better work, you can call this with a FileSystemWatcher listening for someone modifying the app.config file and react properly after calling the refresh as show above. You can obtain the configuration file path with this:
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
As a general information, consider to redesign the way you are solving the problem by using system scheduled task instead of writing your own service.