Планирование заданий в ASP.NET (автоматическая отправка электронной почты)
Я занимаюсь разработкой приложения ASP.NET (с сервером sql). Мое требование - отправлять электронные письма с хост-сервера (в моем случае это Shared Hosting от Godaddy) через определенные промежутки времени - это может быть ежедневно, еженедельно или ежемесячно. Вкладка Cron не может использоваться, потому что это команда Linux, которая работает на хостинге Linux. Общий хостинг Godaddy не имеет инструмента планировщика заданий. Я пробовал много раз, но не смог добиться успеха. Я уже использовал эти три кода.
Первая попытка:
<%@ Application Language="C#" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Threading" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.Timers" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
Thread timerThread = new Thread(TimerForNotification);
timerThread.IsBackground = true;
timerThread.Priority = ThreadPriority.Highest;
timerThread.Start();
}
void TimerForNotification()
{
//Code that runs on application startup
System.Timers.Timer timScheduledTask = new System.Timers.Timer();
timScheduledTask.Interval = 1000 * 60 * 60; //TimeSpan.FromMinutes(30).Minutes * 1000 * 60;
timScheduledTask.Enabled = true;
timScheduledTask.Elapsed += new System.Timers.ElapsedEventHandler(timScheduledTas_Elapsed);
}
void timScheduledTas_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
ConnectionStringSettings conn = ConfigurationManager.ConnectionStrings["myshop_con"];
SqlConnection con = new SqlConnection(conn.ConnectionString);
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "insert into dbo.tblUserDetail(UName)VALUES('" + DateTime.Now.ToString() + "')";
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
</script>
Вторая попытка:
<%@ Application Language="C#" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Threading" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script runat="server">
public class TimerStarter
{
private static System.Threading.Timer threadingTimer;
public static void StartTimer()
{
if (null == threadingTimer)
{
threadingTimer = new System.Threading.Timer(new TimerCallback(DoActions), HttpContext.Current, 0, 3600000);
}
}
private static void DoActions(object sender)
{
ConnectionStringSettings conn = ConfigurationManager.ConnectionStrings["myshop_con"];
SqlConnection con = new SqlConnection(conn.ConnectionString);
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "insert into dbo.tblUserDetail(UName)VALUES('" + DateTime.Now.ToString() + "')";
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
}
void Application_Start(object sender, EventArgs e)
{
TimerStarter.StartTimer();
}
</script>
Третья попытка:
<%@ Application Language="C#" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Threading" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script runat="server">
private void NightlyProcess(object o)
{
ConnectionStringSettings conn = ConfigurationManager.ConnectionStrings["myshop_con"];
SqlConnection con = new SqlConnection(conn.ConnectionString);
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "insert into dbo.tblUserDetail(UName)VALUES('" + DateTime.Now.ToString() + "')";
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
void Application_Start(object sender, EventArgs e)
{
System.Threading.TimerCallback tcb = new System.Threading.TimerCallback(NightlyProcess);
System.Threading.Timer theTimer = new System.Threading.Timer(tcb, null, GetTimerInitialDelay(20, 40), GetTimerRepeatDelay(24));
}
private long GetTimerInitialDelay(int hours, int minutes)
{
long startMS, repeatMS, currentMS;
startMS = (1000 * 60 * 60 * hours) + (1000 * 60 * minutes);
repeatMS = GetTimerRepeatDelay(24);
DateTime now = DateTime.Now;
long currentHours = 1000 * 60 * 60 * now.Hour;
long currentMinutes = 1000 * 60 * now.Minute;
long currentSeconds = 1000 * now.Second;
long currentMilliSeconds = now.Millisecond;
currentMS = currentHours + currentMinutes + currentSeconds + currentMilliSeconds;
long delay = startMS - currentMS;
if (delay < 0)
{
return repeatMS + delay;
}
else
{
return delay;
}
}
private long GetTimerRepeatDelay(int hours)
{
long repeatMS;
repeatMS = 1000 * 60 * 60 * hours;
return repeatMS;
}
</script>
Как я могу получать эти письма с такими интервалами?
2 ответа
То, чего вы пытаетесь достичь, невозможно без какого-либо планировщика задач или службы Windows, работающей в фоновом режиме.
То, что вы можете попытаться сделать, - это создать веб-страницу, которая при запросе будет отправлять определенное количество электронных писем, а затем вызывать эту страницу, используя какой-либо сторонний ping-сервис или какой-нибудь очень простой скрипт, работающий на вашем локальном ПК.
Обратите внимание, что это только обходной путь, и для надежного решения требуется больший доступ на сервере с VPS или выделенным сервером.
Еще одна вещь, которую вы можете попробовать - это какая-то сторонняя служба, которая будет отправлять вам электронные письма. Вы можете попробовать почтовый шимпанзе - у них есть бесплатная версия с ограниченным количеством писем в месяц, а также есть API, который вы можете использовать.
Очень старый вопрос, но может помочь некоторым новым читателям. В ASP.NET мы можем моделировать Windows Service для запуска запланированных заданий.
Это очень странно, но элементы кэша очень полезны для этой цели.
Логика очень проста и отличается.
Создать объект кеша
private const string DummyCacheItemKey = "GagaGuguGigi"; protected void Application_Start(Object sender, EventArgs e) { RegisterCacheEntry(); } private bool RegisterCacheEntry() { if( null != HttpContext.Current.Cache[ DummyCacheItemKey ] ) return false; HttpContext.Current.Cache.Add( DummyCacheItemKey, "Test", null, DateTime.MaxValue, TimeSpan.FromMinutes(1), CacheItemPriority.Normal, new CacheItemRemovedCallback( CacheItemRemovedCallback ) ); return true; }
Когда объект кэша удален, вызовите функцию обратного вызова для запуска запланированных заданий.
public void CacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason) { Debug.WriteLine("Cache item callback: " + DateTime.Now.ToString() ); HitPage() // Do the service works DoWork(); }
При использовании функции обратного вызова вы должны снова установить кэш. Для этого создайте фиктивную страницу и зайдите через веб-клиент.
private const string DummyPageUrl = "http://localhost/TestCacheTimeout/WebForm1.aspx"; private void HitPage() { WebClient client = new WebClient(); client.DownloadData(DummyPageUrl); }
На Application_BeginRequest проверьте, является ли это фиктивной страницей или нет.
protected void Application_BeginRequest(Object sender, EventArgs e) { // If the dummy page is hit, then it means we want to add another item // in cache if( HttpContext.Current.Request.Url.ToString() == DummyPageUrl ) { // Add the item in cache and when succesful, do the work. RegisterCacheEntry(); } }
Вот подробности, как вы можете планировать свои действия с чистым ASP.NET