Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FormsAuthentication.SetAuthCookie throwing NullReferenceException in async action

I am finding that FormsAuthentication.SetAuthCookie is throwing a NullReferenceException - Object reference not set to an instance of an object inside an async action on an azure website.

I found the following:

http://connect.microsoft.com/VisualStudio/feedback/details/743350/formsauthentication-setauthcookie-throws-nullreferenceexception-if-called-in-an-async-action-in-mvc4

However I already have

 <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />

set and my code works fine locally I only experience the problem when I deploy to azure. I am using Azure Websites (https://www.windowsazure.com/en-us/home/scenarios/web-sites/), it was my understanding that this uses the web.config normally? I have also tried adding the appsetting through the Azure control panel

enter image description here

And adding .ConfigureAwait(false); to my awaited method but have had no luck.

The following code will throw the exception

public class TestController : Controller
    {
        public async Task<ActionResult> Index()
        {
            var httpResponse = await new HttpClient().GetAsync("http://www.google.com");
            FormsAuthentication.SetAuthCookie("test", true);
            return View();
        }
    }

Anyone know how I can get this to work?

UPDATE:

Stack Trace:

[NullReferenceException: Object reference not set to an instance of an object.]
   System.Threading.Tasks.<>c__DisplayClass1c.<GetRethrowWithNoStackLossDelegate>b__1b(Task task) +91
   System.Threading.Tasks.TaskHelpersExtensions.ThrowIfFaulted(Task task) +15
   System.Web.Mvc.Async.TaskAsyncActionDescriptor.EndExecute(IAsyncResult asyncResult) +77
   System.Web.Mvc.Async.<>c__DisplayClass3f.<BeginInvokeAsynchronousActionMethod>b__3e(IAsyncResult asyncResult) +16
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +50
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +29
   System.Web.Mvc.Async.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33() +59
   System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +240
   System.Web.Mvc.Async.<>c__DisplayClass37.<BeginInvokeActionMethodWithFilters>b__36(IAsyncResult asyncResult) +12
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +50
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +31
   System.Web.Mvc.Async.<>c__DisplayClass2a.<BeginInvokeAction>b__20() +23
   System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +128
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +50
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +26
   System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +14
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +25
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +55
   System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +41
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +25
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +55
   System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +28
   System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10
   System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__4(IAsyncResult asyncResult) +28
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +25
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +55
   System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +31
   System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7
   System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +23
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +59
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
   System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +96

UPDATE

I found it works if setting the Cookie manually

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, "test", DateTime.Now, DateTime.Now.AddMinutes(30), true, null, FormsAuthentication.FormsCookiePath);
            string encTicket = FormsAuthentication.Encrypt(ticket);
            Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));

I'm not going to answer the question though as would like to know why FormsAuthentication.SetAuthCookie is throwing the exception and why it is behaving differently on Azure Websites

like image 452
Tom Avatar asked Aug 09 '12 11:08

Tom


1 Answers

This issue is not specific to Azure - the method FormsAuthentication.SetAuthCookie will throw a null reference exception in an async action when an await statement is called before FormsAuthentication.SetAuthCookie is called.

The easiest solution is to use the following:

        Response.Cookies.Add(FormsAuthentication.GetAuthCookie("user-1", true));

An alternative would be to specify the ticket creation yourself:

        var ticket = new FormsAuthenticationTicket(
            2,
            "user-1",
            DateTime.Now,
            DateTime.Now.AddDays(2),
            true,
            String.Empty,
            "/");

        var encTicket = FormsAuthentication.Encrypt(ticket);

        Response.Cookies.Add(new HttpCookie(".AUTH", encTicket));
like image 120
Glenn Morton Avatar answered Sep 20 '22 06:09

Glenn Morton