0

How can we utilize HTTP Context while running the Background Worker Thread? Getting exception while using MVC mailer to send email by a background thread. Exception: Parameter cannot be NULL, HTTP Context.

tereško
  • 58,060
  • 25
  • 98
  • 150
user792373
  • 21
  • 1
  • 2

2 Answers2

2

When using async/await and HTTPContext together, always use ConfigureAwait(true) to allow to continue on the original context. For example, see below. You can call ConfigureAwait on await calls as well.

var task = new Task(() => book.Bindbook()).ConfigureAwait(true); 

task.Start();
HarryPotter
  • 119
  • 7
1

I suppose your method needs an HttpContext but is not executed withing an WebRequest.

HttpContext is not easy to mock but not impossible. Try assigning HttpContext current with this code

        HttpContext.Current = HttpContextHelper.CreateHttpContext(
            new HttpRequest("SomePage.asmx", "http://localhost/SomePage.asmx", ""),
            new HttpResponse(new StringWriter())
        );

HttpContext helper is a helper class based on this blog post http://www.necronet.org/archive/2010/07/28/unit-testing-code-that-uses-httpcontext-current-session.aspx

public class HttpContextHelper
{
    public static HttpContext CreateHttpContext(HttpRequest httpRequest, HttpResponse httpResponse)
    {

        var httpContext = new HttpContext(httpRequest, httpResponse);

        var sessionContainer = new HttpSessionStateContainer("id", new SessionStateItemCollection(),
                                                new HttpStaticObjectsCollection(), 10, true,
                                                HttpCookieMode.AutoDetect,
                                                SessionStateMode.InProc, false);

        httpContext.Items["AspSession"] = typeof(HttpSessionState).GetConstructor(
                                    BindingFlags.NonPublic | BindingFlags.Instance,
                                    null, CallingConventions.Standard,
                                    new[] { typeof(HttpSessionStateContainer) },
                                    null)
                            .Invoke(new object[] { sessionContainer });

        return httpContext;
    }

}

However (and that's important): You're propably doing it wrong. BackgroundWorker is not intended to use within MVC but with Windows Forms. Try using the TPL instead.

public ActionResult SendMail()
{
    Task.Factory.StartNew(() => MailSender.SendMail(...));
    return View(...);
}

Or even better, with async:

[AsyncTimeout(150)]
[HandleError(ExceptionType = typeof(TimeoutException),
                                    View = "TimeoutError")]
public async Task<ActionResult> SendMailAsync(CancellationToken cancellationToken )
{
    ViewBag.SyncOrAsync = "Asynchronous";
    return View("SendMail", await MailSender.SendMailAsync(cancellationToken));
}

Explaination here http://www.asp.net/mvc/overview/performance/using-asynchronous-methods-in-aspnet-mvc-4

Jürgen Steinblock
  • 30,746
  • 24
  • 119
  • 189