I am using a scheduler that will send out reminders through a library called actionMailer. I however need the httpcontext to work as well actionMailer uses mvc.
So I came up with this:
// global aspx.
protected void Application_Start()
{
// Hook our DI stuff when application starts
IKernel kernel = SetupDependencyInjection();
// get the reminder service
IScheduledRemindersService scheduledRemindersService = kernel.Get<IScheduledRemindersService>();
RemindersController.iScheduledReminedrService = scheduledRemindersService;
RemindersController.StartScheduler();
}
// Reminder Controller
private static HttpContext httpContext;
public static void StartScheduler()
{
// needed for action mailer
httpContext = System.Web.HttpContext.Current;
iScheduledReminedrService.StartAppointmentRemindersSchedule();
}
// Scheduler Service
public void StartAppointmentRemindersSchedule()
{
// get a scheduler and start it.
IScheduler scheduler = GetScheduler();
scheduler.Start();
// setup a job
JobDetail jobDetail = SetupJob("AppointmentRemindersJob", typeof(AppointmentRemindersJob));
//setup a trigger
SimpleTrigger trigger = SetupSimpleTrigger("AppointmentRemindersTrigger");
// schedule the job
scheduler.ScheduleJob(jobDetail, trigger);
}
//Appointment Job
public void Execute(JobExecutionContext context)
{
// code above to get CalendarAppointments
RemindersController.CalendarAppointmentsReminders(calendarAppointments);
}
//Reminder Controller
[NonAction]
public static void CalendarAppointmentsReminders(List<CalendarAppointment> appointments)
{
// set it to have a http context so we can send out emails through mvc mailer.
System.Web.HttpContext.Current = httpContext;
List<CalendarAppointmentReminderVM> vm = Mapper.Map<List<CalendarAppointment>, List<CalendarAppointmentReminderVM>>(appointments);
foreach (var v in vm)
{
new EmailController().SendCalendarAppointmentNotifiation(v).DeliverAsync();
}
}
// email controller
public EmailResult SendCalendarAppointmentNotifiation(CalendarAppointmentReminderVM vm)
{
To.Add(vm.To);
Subject = String.Format("Hi");
return Email("SendCalendarAppointmentEmail", vm);
}
Works perfectly the first time I start up the application and run it. After that it crashes on the 2nd time around
System.NullReferenceException was
unhandled by user code
Message=Object reference not set to an
instance of an object.
Source=WebDev.WebHost40 StackTrace:
at Microsoft.VisualStudio.WebHost.Connection.get_RemoteIP()
at Microsoft.VisualStudio.WebHost.Connection.get_RemoteIP()
at Microsoft.VisualStudio.WebHost.Request.GetRemoteAddress()
at System.Web.HttpRequest.get_IsLocal()
at System.Web.HttpRequestWrapper.get_IsLocal()
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext
pageContext, TextWriter writer,
WebPageRenderingBase startPage)
at System.Web.Mvc.RazorView.RenderView(ViewContext
viewContext, TextWriter writer, Object
instance)
at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext
viewContext, TextWriter writer)
at ActionMailer.Net.EmailResult.RenderViewAsString(ControllerContext
context, IView view)
at ActionMailer.Net.EmailResult.AddMessageViews(ControllerContext
context)
at ActionMailer.Net.EmailResult.ExecuteResult(ControllerContext
context)
at ActionMailer.Net.MailerBase.Email(String
viewName, Object model, String
masterName)
at EmailController.SendCalendarAppointmentNotifiation(CalendarAppointmentReminderVM
vm) in EmailController.cs:line 80
at RemindersController.CalendarAppointmentsReminders(List`1
appointments) in
RemindersController.cs:line 61
at AppointmentRemindersJob.Execute(JobExecutionContext
context) in
AppointmentRemindersJob.cs:line 40
at Quartz.Core.JobRunShell.Run()
InnerException:
The HttpContext is not going to be reliably available out side of an actual http request made into IIS. Even if you set it to a static field. You could maybe try mocking a local request made to the site to kick off the email. I don’t know anything about ActionMailer, but perhaps their is a way to use their framework outside of the controller?
To mock a request you’ll need to know the URL of the action you are targeting first, something like this should be a setting configured by the developer, or by the site automatically if possible.
This is not a recommended approach as their may be issues with permissions opening sockets and such. By far the best way to send an email is using framework that already exists such as System.Net.Mail.SmtpClient