Why cacheRolesinCookie does not work well with the Ajax Extensions 1.0 and RoleManager of .NET Framework 2.0?

One of my customers ran into this issue couple of months ago. I wanted to blog it earlier but I was waiting for the Fix to come out.

The typical scenario is - you are using the System.Web.RoleManager of .NET Framework 2.0 along with Ajax Extensions. When you do a callback you might run into exception as below (changed the names as required) -

Event Type: Warning

Event Source: ASP.NET 2.0.50727.0

Event Category: Web Event

Event ID: 1309

Date: 10/16/2007

Time: 11:24:13 PM

User: N/A

Computer: ABCD

Description:

Event code: 3005

Event message: An unhandled exception has occurred.

Event time: 10/16/2007 11:24:12 PM

Event time (UTC): 10/17/2007 5:24:12 AM

Event ID: 3984df620d5148d58cfddc59a2c64559

Event sequence: 17219

Event occurrence: 95

Event detail code: 0

Application information:

    Application domain: /LM/W3SVC/12345/Root/Client-11-128370461828028786

    Trust level: Full

    Application Virtual Path: /Client

    Application Path: C:\Inetpub\wwwroot\Test\

    Machine name: ABCD

Process information:

    Process ID: 4448

    Process name: w3wp.exe

    Account name: ABCD\ABCD

Exception information:

    Exception type: HttpException

    Exception message: Server cannot modify cookies after HTTP headers have been sent.

Request information:

    Request URL: <https://Test/App_Themes/Default/Styles/Base.css>

    Request path: /App_Themes/Default/Styles/Base.css

   User host address: 71.123.134.143

    User: ABCD@ABCD.com

    Is authenticated: True

    Authentication Type: Forms

    Thread account name: ABCD\ABCD

Thread information:

    Thread ID: 18

    Thread account name: ABCD\ABCD

    Is impersonating: False

    Stack trace: at System.Web.HttpCookieCollection.Add(HttpCookie cookie)

   at System.Web.Security.RoleManagerModule.OnLeave(Object source, EventArgs eventArgs)

   at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()

   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

 Custom event details:

For more information, see Help and Support Center at <https://go.microsoft.com/fwlink/events.asp>.  

This comes up because you can’t send a set-cookie header after anything has been sent to the client.

Now the OnLeave event of RoleManager is set to be executed on App.EndRequest (Code taken from Reflector) –

public void Init(HttpApplication app)

{

    if (Roles.Enabled)

    {

        app.PostAuthenticateRequest += new EventHandler(this.OnEnter);

        app.EndRequest += new EventHandler(this.OnLeave);

    }

}

And when you use Ajax, HTTP Headers are sent back to client before Application_End and this OnLeave event will try to modify the cookie if CacheRolesInCookie is true –

private void OnLeave(object source, EventArgs eventArgs)

{

    if (Roles.Enabled && Roles.CacheRolesInCookie)

    {

                .......

                .......

    }

}

Since the content is flushed by the time that code runs and the code does not check if something is sent to client already, the exception comes up.

This issue has been fixed in the .NET Framework 3.5 release. It still doesn’t send the cookie, but you won’t throw an exception. The code looks like below -

private void OnLeave(object source, EventArgs eventArgs)

{

    HttpApplication application = (HttpApplication) source;

    HttpContext context = application.Context;

    if (((Roles.Enabled && Roles.CacheRolesInCookie) && !context.Response.HeadersWritten) && (((context.User != null) && (context.User is RolePrincipal)) && context.User.Identity.IsAuthenticated))

    {

       .....

                .....

    }

}

 

There is no workaround for this issue in .NET Framework other than not using CacheRolesInCookie itself by setting it to false.

 

I hope this help!