I have complete code for send daily mail to expiration mail to user. my description of code is below:
Global.asax :
void Application_Start(object sender, EventArgs e)
{
System.Timers.Timer myTimer = new System.Timers.Timer();
double inter = (double)GetNextInterval();
myTimer.Interval = inter;
myTimer.AutoReset = true;
myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed);
myTimer.Enabled = true;
}
private double GetNextInterval(){
string timeString;
timeString = "12:00 AM";
DateTime t = DateTime.Parse(timeString);
TimeSpan ts = new TimeSpan();
int x;
ts = t - System.DateTime.Now;
if (ts.TotalMilliseconds < 0)
{
ts = t.AddDays(1) - System.DateTime.Now;
}
return ts.TotalMilliseconds;
}
public void myTimer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
// My Mail Code
}
This code is work for first time mail but i want to daily basis send mail.
How it possible?
Create a console application that sends an E-Mail and schedule a task to run your console application every day using task scheduler.
You can create Scheduled Tasks for .aspx Files also. It will open a browser and send mail , than u have to create another Scheduled Tasks to close it.
Here is Example :
https://mohammednv.wordpress.com/2008/01/08/how-to-create-scheduled-tasks-for-aspx-files/
You can schedule any procedure on the code side using Quartz.NET
But there is a problem. If an asp.net application stays inactive ( Not receiving any requests) it is put to sleep from IIS.
So you have 2 options.
Change IIS Settings to keep your app pool always awake
or poke your application with dummy requests to any method to prevent it from sleeping
My suggestion and implementation is the following which i think is the most professional way of doing it.
Expose your timely tasks as wcf services.
Develop a Windows Service which runs Quartz and invokes those wcf services in a timely manner.
The pros are you get to keep your business logic code in one place and it works also in server farm scenarios
Related
I have a thread that shoots events to run programs at certain times.
I do want the website to have full control over the process so that is why I built it into the site as a long term thread that loops.
The issue is I scheduled a task to happen at a particular time and it happens almost randomly (maybe when I load the page). It seems as if the web app sleeps all threads until its used or something.
Here is the code:
public void run()
{
Task.Factory.StartNew(() =>
{
while (true)
{
var lastDate = InternalEventLogger.GetLastDateTime();
if (DateTime.Now >= lastDate.AddDays(1))
{
System.Diagnostics.Debug.WriteLine(DateTime.Now);
System.Diagnostics.Debug.WriteLine(lastDate.AddDays(1));
InternalEventLogger.RefreshLog();
}
bool needUpdate = false;
System.Diagnostics.Debug.WriteLine("this");
List<Event> tempList = new List<Event>(this.evtList.getList());
foreach (Event evt in this.evtList.getList())
{
if (!evt.status.Equals("success"))
continue;
if (evt.nextRun <= DateTime.Now)
{
var tempEvt = evt;
System.Diagnostics.Debug.WriteLine("time to run: "+evt.name);
tempList.Remove(evt);
tempEvt.nextRun = evt.nextRun.AddMinutes(evt.interval);
tempEvt.lastRan = DateTime.Now;
tempList.Add(tempEvt);
needUpdate = true;
if (tempEvt.runLocation != null)
Task.Factory.StartNew(() =>
{
Process p = new Process();
p.StartInfo.FileName = tempEvt.runLocation;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.Start();
string output = p.StandardOutput.ReadToEnd();
string err = p.StandardError.ReadToEnd();
InternalEventLogger.WriteLog(output);
InternalEventLogger.WriteLog("// ------------- ERROR -------------- \n" + err);
p.WaitForExit();
});
}
}
if (needUpdate)
{
this.evtList.setList(tempList);
this.evtList.serialize(ConfigurationManager.AppSettings["xmlEventLocation"]);
}
Thread.Sleep(10000);
}
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
Ran from:
private static void RegisterServices(IKernel kernel)
{
evtManager = new EventManager(ConfigurationManager.AppSettings["xmlEventLocation"]);
evtManager.run();
// Initalize Event Logger
new InternalEventLogger();
}
Here is a pic that shows the problem in timing:
IIS Settings below
Only at visit does it start the tasks.
Open that settings dialog in your IIS Manager.
Make sure you have:
Start Mode = AlwaysRunning
Idle Time-out (minutes) = 0
for the application pool you are using - test the settings so that you are sure you are editing the correct pool.
If you have this, your application should be running all the time, but there is one more thing - Recycling - at the bottom of that setting dialog, set up your Recycling as you need it. It might be the case that you are OK with the defaults, but if you are not aware of Recycling, it might surprise you, so make sure you understand it and configure the settings as you need it.
Yes, you are right, the IIS hosting do not stores the threads, as all the Web Application has to do is handle the request and provide the response. If you want to run the task on schedule, you really shouldn't use the web application, as it cancels all the background threads after the response is sent.
I suggest you to change your architecture, and create a Windows service (like daemon) which will start automatically after system boot, and which can much more easily control the event firing.
If for somewhat reason you want a web interface for such method, you can use a WCF binding between your web application and windows service (over TCP/IP or named pipes or whatever), but your approach wouldn't work for Web Application.
I want also to point out that this code:
while (true)
is a bad idea - you should use a CancellationToken for your task in this case.
I developed a http server via console application in C# and decided to turn it into a Windows service to be able to initialize it without the need to login the machine.
I followed all the steps in How to create Windows Service and chose the account as "Local System", but when I install in my server machine and push the start button it takes a while and gives the following error:
Erro 1053: The service did not respond to the start or control request in timely fashion.
After that, the service status stays stuck in "starting" and the application don't work and I can't even stop the service anymore.
Trying to work around this problem, I changed it to "Network Service", so it started normally, but the application was not listening in the port I set when I checked in the prompt with the command "netstat -an". But the application listens normally if i run it as a console application.
So I am looking for an answer to one of these two questions:
What should I do to make the service starts properly with a Local System account?
If I decide to use Network service account, what should I care about to guarantee that my service works properly as a server?
When I converted my console application to windows service I simply put my code directly in the OnStart method. However, I realized the OnStart method should start the service, but needs to end some time to the service indeed start. So I created a thread that runs my service and let the OnStart method finish. I tested and the service worked just fine. Here is how it was the code:
protected override void OnStart(string[] args)
{
Listener(); // this method never returns
}
Here is how it worked:
protected override void OnStart(string[] args)
{
Thread t = new Thread(new ThreadStart(Listener));
t.Start();
}
But I still don't understand why the service ran (passed the "starting" status, but didn't work) when I used network service account. If anyone knows, I'll be glad to know the reason.
If you have a service that is not responding or showing pending in Windows services that you are unable to stop, use the following directions to force the service to stop.
Start -> Run or Start -> type services.msc and press Enter
Look for the service and check the Properties and identify its service name
Once found, open a command prompt. Type sc queryex [servicename]
Identify the PID (process ID)
In the same command prompt type taskkill /pid [pid number] /f
Find PID of Service
sc queryex <SERVICE_NAME>
Give result's below
SERVICE_NAME: Foo.Services.Bar TYPE : 10 WIN32_OWN_PROCESS STATE : 2 0 START_PENDING (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0 PID : 3976 FLAGS :
Now Kill the Service:
taskkill /f /pid 3976
SUCESS: The process with PID 3976 has been terminated.
Check the Windows Application event log, it could contain some entries from your service's auto generated event source (which should have the same name of the service).
For me it was a while loop that looked at an external queue. The while-loop continued running until the queue was empty. Solved it by calling a timer event directly only when Environment.UserInteractive. Therefore the service could be debugged easily but when running as a service it would wait for the timers ElapsedEventHandler event.
Service:
partial class IntegrationService : ServiceBase
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private System.Timers.Timer timer;
public IntegrationService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
// Add code here to start your service.
logger.Info($"Starting IntegrationService");
var updateIntervalString = ConfigurationManager.AppSettings["UpdateInterval"];
var updateInterval = 60000;
Int32.TryParse(updateIntervalString, out updateInterval);
var projectHost = ConfigurationManager.AppSettings["ProjectIntegrationServiceHost"];
var projectIntegrationApiService = new ProjectIntegrationApiService(new Uri(projectHost));
var projectDbContext = new ProjectDbContext();
var projectIntegrationService = new ProjectIntegrationService(projectIntegrationApiService, projectDbContext);
timer = new System.Timers.Timer();
timer.AutoReset = true;
var integrationProcessor = new IntegrationProcessor(updateInterval, projectIntegrationService, timer);
timer.Start();
}
catch (Exception e)
{
logger.Fatal(e);
}
}
protected override void OnStop()
{
try
{
// Add code here to perform any tear-down necessary to stop your service.
timer.Enabled = false;
timer.Dispose();
timer = null;
}
catch (Exception e)
{
logger.Fatal(e);
}
}
}
Processor:
public class IntegrationProcessor
{
private static Logger _logger = LogManager.GetCurrentClassLogger();
private static volatile bool _workerIsRunning;
private int _updateInterval;
private ProjectIntegrationService _projectIntegrationService;
public IntegrationProcessor(int updateInterval, ProjectIntegrationService projectIntegrationService, Timer timer)
{
_updateInterval = updateInterval;
_projectIntegrationService = projectIntegrationService;
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Interval = _updateInterval;
//Don't wait for first elapsed time - Should not be used when running as a service due to that Starting will hang up until the queue is empty
if (Environment.UserInteractive)
{
OnTimedEvent(null, null);
}
_workerIsRunning = false;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
try
{
if (_workerIsRunning == false)
{
_workerIsRunning = true;
ProjectInformationToGet infoToGet = null;
_logger.Info($"Started looking for information to get");
//Run until queue is empty
while ((infoToGet = _projectIntegrationService.GetInformationToGet()) != null)
{
//Set debugger on logger below to control how many cycles the service should run while debugging.
var watch = System.Diagnostics.Stopwatch.StartNew();
_logger.Info($"Started Stopwatch");
_logger.Info($"Found new information, updating values");
_projectIntegrationService.AddOrUpdateNewInformation(infoToGet);
_logger.Info($"Completed updating values");
watch.Stop();
_logger.Info($"Stopwatch stopped. Elapsed seconds: {watch.ElapsedMilliseconds / 1000}. " +
$"Name queue items: {infoToGet.NameQueueItems.Count} " +
$"Case queue items: {infoToGet.CaseQueueItems.Count} " +
$"Fee calculation queue items: {infoToGet.FeeCalculationQueueItems.Count} " +
$"Updated foreign keys: {infoToGet.ShouldUpdateKeys}");
}
_logger.Info($"Nothing more to get from integration service right now");
_workerIsRunning = false;
}
else
{
_logger.Info($"Worker is already running! Will check back again after {_updateInterval / 1000} seconds");
}
}
catch (DbEntityValidationException exception)
{
var newException = new FormattedDbEntityValidationException(exception);
HandelException(newException);
throw newException;
}
catch (Exception exception)
{
HandelException(exception);
//If an exception occurs when running as a service, the service will restart and run again
if (Environment.UserInteractive)
{
throw;
}
}
}
private void HandelException(Exception exception)
{
_logger.Fatal(exception);
_workerIsRunning = false;
}
}
You can try to increase the windows service timeout with a key in the registry
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
"ServicesPipeTimeout"=dword:300000 (300 seconds or 5 minutes)
If it doesn't exists it has to be created.
I am working on a window services application and my window service will call one of the web services in certain intervals (for example 3 min). From the web service I will get data from a database and using that data I will send an email.
If I am having huge sets of rows in my db table it will take some time to send the mail. Here I have the problem: The window services send the first request and it will handle some set of records. So, while processing it by the web service, the window service sends another request to the web service before it has completed the first request.
Due to this, the web service gets the same records from db again and again whenever it receives a new request from the windows service.
Can any one suggest me how to lock the previous request until it completes its work or some other way to handle this situation?
Web Service call:
protected override void OnStart(string[] args)
{
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 180000;
timer.AutoReset = false;
timer.Enabled = true;
}
Inside Method
using (MailWebService call = new MailWebService())
{
try
{
call.ServiceUrl = GetWebServiceUrl();
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
call.CheckMailQueue();
}
catch (Exception ex)
{
LogHelper.LogWriter(ex);
}
finally
{
}
}
The Monitor class works great for this scenario. Here is an example of how to use it:
// This is the object that we lock to control access
private static object _intervalSync = new object();
private void OnElapsedTime(object sender, ElapsedEventArgs e)
{
if (System.Threading.Monitor.TryEnter(_intervalSync))
{
try
{
// Your code here
}
finally
{
// Make sure Exit is always called
System.Threading.Monitor.Exit(_intervalSync);
}
}
else
{
//Previous interval is still in progress.
}
}
There is also an overload for TryEnter that allows you to specify timeout for entering the section.
I am developing an application in which Lets says 50-60 Modbus supporting devices (Slaves) are connected to a Com Port which are communicating with my application in request response mechanism.
I want after every 15 min. request should be sent to every meter and response to be received from meter one by one.
communicating with multiple slave (Modbus protocol based)
For this i am making the use of System.Timers.timer to call the method lets say ReadAllSlave() after every 15 min.
In ReadAllSlave() i have used For loop to send the request and to receive response and using thread.sleep to maintain the delay..! but it seems that its not working and loop is executing in damn wired way.
private void StartPoll()
{
double txtSampleRate = 15 * 60 * 1000;
timer.Interval = txtSampleRate;
timer.AutoReset = true;
timer.Start();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
for(int index = 0; index<meterCount; Index++)
{
//Sending request to connected meter..
mb.SendFc3(m_slaveID[0], m_startRegAdd[0], m_noOfReg[0], ref value_meter);
if (mb.modbusStatus == "Read successful")
{
//Some code for writing the values in SQL Express database
}
//Wait for some time so that will not get timeout error for the next
//request..
Thread.Sleep(10000);
}
}
Can any one please suggest me the best approach to implement the same.
Thanks in advance.
It looks like your problem is a trivial one... You're always interrogating the same slave !
"index" is never used in your code...
What about something like this :
mb.SendFc3(m_slaveID[index], m_startRegAdd[index], m_noOfReg[index], ref value_meter);
I have a newsletter tool that I am trying to setup to run as a background process to send out the emails. The code below works without any issues but the problem I have is that it is slow.
If there are 50 emails to send it can be very slow for the end user as they have to stare at the screen for up to 1min 30secs. This becomes a bigger problem for me if they client is sending an email to a larger group of people.
The reason I send each mail individually as apposed to sending 1 and bcc'ing the email list is that each email contains certain specific content for each user - like unsubscribe link codes, personal name at the start of the mail, etc.
I am looking for a solution where I can let the user click on a button and have .net run the sending email part in the background while the front end user is brought to a page saying that their email is being sent. Ideally, it should take no longer than a regular postback for all that to occur - not the current few minutes.
Any thoughts on how best to achieve this?
Thanks for your help,
Rich
if (Page.IsPostBack)
{
if (JustMeButton.Checked)
{
SendMail("emailme#address", EmailTemplate);
}
if (EveryoneButton.Checked)
{
//setup background process
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = false;
bw.WorkerSupportsCancellation = false;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
//bring user to next screen and display message
Response.Redirect("emailSendingMessageScreen.aspx");
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
DataTable emailTable = (DataTable)Session["emailTable"];
foreach (DataRow row in emailTable.Rows)
{
SendMail(row["email"], row["name"], EmailTemplate);
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!(e.Error == null))
{
SendMail("admin#address", "Error sending <br><br>" + e.Error.Message);
}
else
{
SendMail("admin#address", "emails sent successfully.");
}
//clear out the sessions created for sending this email
Session.Remove("emailTable");
}
private void SendMail(string email, string emailMessage)
{
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress("from#address");
mailMessage.To.Add(new MailAddress(email));
mailMessage.Subject = Server.HtmlEncode(EmailSubject.Text.Trim());
mailMessage.Body = emailMessage;
mailMessage.IsBodyHtml = true;
SmtpClient smtpClient = new SmtpClient();
Object userState = mailMessage;
smtpClient.SendCompleted += new SendCompletedEventHandler(smtpClient_SendCompleted);
smtpClient.Timeout = 10000;
try
{
smtpClient.SendAsync(mailMessage, userState);
}
catch (SmtpException smtpExc)
{
MailMessageTxt.Text += "Error Code: " + smtpExc.StatusCode;
MailMessageTxt.Visible = true;
}
catch (Exception ex)
{
MailMessageTxt.Text += "Error is: " + ex;
MailMessageTxt.Visible = true;
}
}
void smtpClient_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
MailMessage mailMessage = e.UserState as MailMessage;
if (e.Error != null)
{
MailMessageTxt.Text = "Error occured, info=" + e.Error.Message;
MailMessageTxt.Visible = true;
}
}
I did this very thing sending a newsletter with the BeerHouse in the new version. You can get the book now and the source code is on CodePlex, http://thebeerhouse.codeplex.com/
http://professionalaspnet.com/archive/2009/10/07/ASP.NET-3.5-Problem-1320-Design-2D00-Solution.aspx
alt text http://Professionalaspnet.com/images/187586-fg0705.jpg
The Solution uses AJAX to send the e-mails and allows the user to keep browsing around the site without being concerned about the newsletter being sent out. When it is done it just takes care of itself and the user can check on as they want. Its chapter 7 in the book, enjoy.
A thread created within an ASP page will get killed if the ASP worker process is recycled for whatever reason. A Windows service that performs the task via a message queue is ideal for long running jobs. Another "trick" solution is using cache expiry, explained here: http://www.codeproject.com/KB/aspnet/ASPNETService.aspx
Move all the work of sending the email to separate class and run it using ThreadPool
MailSender sender = new MailSender(parameters. ....);
ThreadPool.EnqueueUserItem(sender.sendAllEmails)
Using background worker won't work. It will be disposed when it goes out of context, meaning on Response.End
I have found trying to do tasks like this within the ASP.NET process is problematic as you cannot guarantee the process will complete or be successful. If the process gets cut off you have no recovery. I would have all your emails saved to a DB first and then have a service that polls for new entries in this database or table that handles the actual sending of the emails.
The advantage to this is that if your email provider or ASP.NET process goes down you don't lose any emails and you have a history of all emails sent with their details of when, who, etc... You can also rip out or change the emailer to do more, like send to Twitter or a phone text message etc. This effectively decouples your notifications from your application.
All applications I have made recently use this type of model and it has stopped emails from being lost due to service failures and other reasons. It has also made it possible to lookup all emails that have gone through the system and get metrics that allows me to optimize the need to send emails by storing extra information in the email record like reason sent, if it's to report an error, etc... Adding on additions such as routing notifications (eg go to text message instead if email) based on time of day or user has been possible with no changes to the primary applicaton.
Simply use ajax to execute the process.let the user continue their activity while the server bares the burden.