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: <http://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 <http://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!

Skip to main content