I want to send mails and SMSs in a scheduled time. I would prefer not using a Windows Service.
Is there any options to schedule a task in a custom time in ASP.Net?
Please suggest which is best way.
Thanks in advance.
I want to send mails and SMSs in a scheduled time. I would prefer not using a Windows Service.
Is there any options to schedule a task in a custom time in ASP.Net?
Please suggest which is best way.
Thanks in advance.
I was facing a similar problem once when my website was hosted on a Godaddy shared hosting. I wanted to run scheduled tasks for sending emails without any windows service.
Finally, I resolved the issue by the use of cache.
A cache item expires on a given time or duration. In ASP.NET, you can add entries in the Cache and set an absolute expiry date time, or you can set a duration after which the item is removed from the cache. You can do this by utilizing the following method of the Cache class.
public void Insert ( System.String key , System.Object value ,
System.Web.Caching.CacheDependency dependencies ,
System.DateTime absoluteExpiration ,
System.TimeSpan slidingExpiration ,
System.Web.Caching.CacheItemPriority priority ,
System.Web.Caching.CacheItemRemovedCallback onRemoveCallback )
The onRemoveCallback is a delegate to a method which is called whenever a cache item expires. In that method, we can do anything we like. So, this is a good candidate for running code periodically, consistently without requiring any page visit.
This means, we can simulate a Windows Service utilizing Cache timeout.
You can find the entire details on the codeproject url http://www.codeproject.com/Articles/12117/Simulate-a-Windows-Service-using-ASP-NET-to-run-sc.
What about a timer callback, set it up in Application_Start:
protected void Application_Start(object sender, EventArgs e)
{
TimerCallback callback = (x) => { YourFunction(); };
int intervalInMS = 2 * 60 * 60 * 1000; // every 2 hours.
timer = new Timer(callback, state: null, dueTime: intervalInMS, period: intervalInMS);
}
Courtesy of Jeff Atwood..
At startup (global.asx), add an item to the HttpRuntime.Cache with a fixed expiration.
When cache item expires, do your work, such as WebRequest or what have you.
Re-add the item to the cache with a fixed expiration. The code is quite simple, really:
private static CacheItemRemovedCallback OnCacheRemove = null;
protected void Application_Start(object sender, EventArgs e)
{
AddTask("DoStuff", 60);
}
private void AddTask(string name, int seconds)
{
OnCacheRemove = new CacheItemRemovedCallback(CacheItemRemoved);
HttpRuntime.Cache.Insert(name, seconds, null,
DateTime.Now.AddSeconds(seconds), Cache.NoSlidingExpiration,
CacheItemPriority.NotRemovable, OnCacheRemove);
}
public void CacheItemRemoved(string k, object v, CacheItemRemovedReason r)
{
// do stuff here if it matches our taskname, like WebRequest
// re-add our task so it recurs
AddTask(k, Convert.ToInt32(v));
}
Your "DoStuff" is the method that triggers your real work required to run.
It's that easy!
Quartz.Net (http://www.mikesdotnetting.com/article/254/scheduled-tasks-in-asp-net-with-quartz-net) is a library that makes it easy to setup and manage jobs as a part of your application.
I created a class to encapsulate this behavior for tasks on my web server. It's inspired by the answers here and on Jeff Atwood's blog post, but I figured I'd share it in case it's useful to anyone else.
This is configured to work for my local timezone (CST), but could be adapted to another timezone pretty easily.
Application_Start
This example schedules the TaskUpdateUserRoles.Task
method to be called each day at 3:00AM CST. Place it in the Application_Start
method in your Global.asax.cs
file.
ServerTask.CreateDaily("Update User Roles",
TaskUpdateUserRoles.Task,
DateTime.Parse("3:00 AM").TimeOfDay); //This should be the local time. CST in this case.
using System;
using System.Diagnostics;
using System.IO;
using System.Web;
using System.Web.Caching;
namespace MySite.Admin.Tasks
{
/// <summary>
/// Manages recurring tasks to run on the server.
/// </summary>
public class ServerTask
{
private string TaskName { get; set; }
private TaskFrequency Frequency { get; set; }
private TimeSpan Offset { get; set; }
private Func<bool> TaskFunction { get; set; }
private CacheItemRemovedCallback OnCacheRemove = null;
private static readonly string TaskLogPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Admin/Logs/");
private ServerTask(string name, TaskFrequency freq, TimeSpan offset, Func<bool> taskFunction)
{
TaskName = name;
Frequency = freq;
Offset = offset;
TaskFunction = taskFunction;
}
/// <summary>
/// Creates a daily task that will run at the specified hour and minute.
/// </summary>
/// <param name="taskName">The task name.</param>
/// <param name="hourAndMinute">The hour and minute when the task should run (Central Standard Time).</param>
public static ServerTask CreateDaily(string taskName, Func<bool> taskFunction, TimeSpan hourAndMinute)
{
ServerTask thisTask = new ServerTask(taskName, TaskFrequency.Daily, hourAndMinute, taskFunction);
thisTask.QueueTask();
return thisTask;
}
/// <summary>
/// Creates a weekly task that will run on the specified weekday, hour, and minute.
/// </summary>
/// <param name="taskName">The task name.</param>
/// <param name="weekday">The day of the week when the task should run.</param>
/// <param name="hourAndMinute">The hour and minute when the task should run (Central Standard Time).</param>
public static ServerTask CreateWeekly(string taskName, Func<bool> taskFunction, DayOfWeek weekday, TimeSpan hourAndMinute)
{
TimeSpan ts = new TimeSpan((int)weekday, hourAndMinute.Hours, hourAndMinute.Minutes, 0);
ServerTask thisTask = new ServerTask(taskName, TaskFrequency.Weekly, ts, taskFunction);
thisTask.QueueTask();
return thisTask;
}
/// <summary>
/// Creates a monthly task that will run on the specified day of the month, hour, and minute.
/// </summary>
/// <param name="taskName">The task name.</param>
/// <param name="dayOfTheMonth">The day of the month when the task should run.</param>
/// <param name="hourAndMinute">The hour and minute when the task should run (Central Standard Time).</param>
public static ServerTask CreateMonthly(string taskName, Func<bool> taskFunction, int dayOfTheMonth, TimeSpan hourAndMinute)
{
TimeSpan ts = new TimeSpan(dayOfTheMonth, hourAndMinute.Hours, hourAndMinute.Minutes, 0);
ServerTask thisTask = new ServerTask(taskName, TaskFrequency.Monthly, ts, taskFunction);
thisTask.QueueTask();
return thisTask;
}
private enum TaskFrequency
{
Daily,
Weekly,
Monthly
}
private void QueueTask()
{
try
{
OnCacheRemove = new CacheItemRemovedCallback(RunTask);
HttpRuntime.Cache.Insert(TaskName, 1, null,
getNextTaskTime(), Cache.NoSlidingExpiration,
CacheItemPriority.NotRemovable, OnCacheRemove);
}
catch { }
}
private void RunTask(string taskName, object o, CacheItemRemovedReason r)
{
//First, verify that the cache entry has expired. It turns out the server often removes our Cache
//item even when it hasn't expired (generally about once per hour - there must be a server process
//that cleans out the cache regularly). If that happens, just re-queue the task again.
if (r == CacheItemRemovedReason.Expired)
{
try
{
Exception taskException = null;
bool taskResult = false;
Stopwatch taskTimer = Stopwatch.StartNew();
try
{
taskResult = TaskFunction();
}
catch (Exception e)
{
taskException = e;
}
taskTimer.Stop();
//Write a log file entry each time this task runs in a monthly log file
if (!Directory.Exists(Path.GetDirectoryName(TaskLogPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(TaskLogPath));
}
DateTime taskTime = Data.DataHelper.ConvertUTCtoCST(DateTime.UtcNow);
string logFileName = string.Format("Tasks.{0}.log", taskTime.ToString("MM.yyyy"));
using (StreamWriter sw = new StreamWriter(Path.Combine(TaskLogPath, logFileName), true))
{
if (taskException == null)
{
string taskResultString = taskResult ? "and reported success" : "but did not report successful completion.";
sw.WriteLine("The task \"{0}\" ran at {1} {2}. Task runtime was {3} milliseconds.",
taskName, taskTime.ToString(), taskResultString, taskTimer.ElapsedMilliseconds.ToString());
}
else
{
sw.WriteLine("Attempted to run the task \"{0}\" at {1}, but the task failed with the following error after {2} milliseconds: {3} [StackTrace: {4}]",
taskName, taskTime.ToString(), taskTimer.ElapsedMilliseconds.ToString(), taskException.Message, taskException.StackTrace);
}
}
}
catch { }
}
//queue this task to be called again
QueueTask();
}
private DateTime getNextTaskTime()
{
if (Frequency == TaskFrequency.Monthly)
{
return getNextMonthlyTime();
}
else if (Frequency == TaskFrequency.Weekly)
{
return getNextWeeklyTime();
}
return getNextDailyTime();
}
private DateTime getNextDailyTime()
{
DateTime now = Data.DataHelper.ConvertUTCtoCST(DateTime.UtcNow);
DateTime taskTime = new DateTime(now.Year, now.Month, now.Day, Offset.Hours, Offset.Minutes, 0);
taskTime = taskTime > now ? taskTime : taskTime.AddDays(1);
taskTime = Data.DataHelper.ConvertCSTtoUTC(taskTime);
return taskTime;
}
private DateTime getNextWeeklyTime()
{
DateTime now = Data.DataHelper.ConvertUTCtoCST(DateTime.UtcNow);
DateTime taskTime = new DateTime(now.Year, now.Month, now.Day, Offset.Hours, Offset.Minutes, 0);
while ((int)taskTime.DayOfWeek != Offset.Days)
{
taskTime = taskTime.AddDays(1);
}
taskTime = taskTime > now ? taskTime : taskTime.AddDays(7);
taskTime = Data.DataHelper.ConvertCSTtoUTC(taskTime);
return taskTime;
}
private DateTime getNextMonthlyTime()
{
DateTime now = Data.DataHelper.ConvertUTCtoCST(DateTime.UtcNow);
DateTime taskTime = new DateTime(now.Year, now.Month, Offset.Days, Offset.Hours, Offset.Minutes, 0);
if (taskTime.Day < now.Day)
{
taskTime = taskTime.AddMonths(1);
}
else if (taskTime.Day == now.Day)
{
taskTime = taskTime > now ? taskTime : taskTime.AddMonths(1);
}
taskTime = Data.DataHelper.ConvertCSTtoUTC(taskTime);
return taskTime;
}
private DateTime ConvertCSTtoUTC(DateTime cstTime)
{
try
{
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(cstTime, cstZone);
return utcTime;
}
catch { }
return cstTime; //fallback to unconverted time
}
private DateTime ConvertUTCtoCST(DateTime utcTime)
{
try
{
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, cstZone);
return cstTime;
}
catch { }
return utcTime; //fallback to unconverted time
}
}
}
public static class TaskUpdateUserRoles
{
public static bool Task()
{
//perform task here. Return true if successful.
}
}