0

REWRITTEN QUESTION

I have an ASP.NET MVC 4 site that uses forms auth. It also needs to retrieve custom user object from a service call and then set it to the HttpCurrent.User.Context.

this works fine but I realised that when it hits the post authenticate request that it will hit it several times per request - not good.

Global.asax.cs:

 protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
        {
            if (User.Identity.IsAuthenticated)
            {
               IIdentity ui = HttpContext.Current.User.Identity;
               MyMembershipUser myUser = new MyMembershipUser (ui.Name);
               MyCustomPrincipal myPrincipal = new MyCustomPrincipal (ui, myUser);
               HttpContext.Current.User = myPrincipal;
            }
        }

I cant entirely cache the user for a number of reasons so lets not go there.

so this gets executed a few times per request. This means for every hit, it calls the DB.

Some views on the site use the custom principal to display some user specific details only if they are authenticated. if they aren't, then it wont display it. But if they are authenticated, it gets the principal and casts it to "MyCustomPrincipal" so I can grab the properties I need to display.

How can I prevent these multiple hits?

I tried creating a custom Authorize attribute and doing the above code in there, it works but fails when it renders the view which can see the user is authenticated but fails to do the cast because at that point, the User Identity/principal is still set to the Generic principal.

typical code in the view:

@if (Helpers.UserContext.IsAuthenticated)
{
   @: tmpStatus = '@Helpers.UserContext.User.Status';
}

UserContext.IsAuthenticated just returns HttpContext.Current.User.Identity.IsAuthenticated

User in UserContext does the casting:

return HttpContext.Current.User as MyCustomPrincipal

I hope this clarifies the question more!

I want to avoid multiple hits happening on the PostAuthenticateRequest but not sure why those hits are happening. I am not even sure if it is the right place to place it. I want to make sure that the Context User is all setup for subsequent accesses/requests to it without having to call the service layer to get the details again.

thanks

Ahmed ilyas
  • 5,722
  • 8
  • 44
  • 72

1 Answers1

0

you minimise some action by check if authenticated

//assuming something like.... 
       public override void Init() {
        base.Init();

        // handlers managed by ASP.Net during Forms authentication

        PostAuthorizeRequest += new EventHandler(PostAuthHandler);

    }

// try screen out some calls that arent authenticated yet.
public void PostAuthHandler(object sender, EventArgs e) {
         if (Request.IsAuthenticated) {
         //.... try a break to see how often 
         }
    }

EDIT: But careful of multiple hits due to script and content bundling / loading.

Check the Request.Url value. Is it changing.
Also Note the thread Id. See Debug.Windows.Threads
The thread may also be changing.
Consider thread safety before you attempt any caching / global singletons etc.

You may wish consider moving some code to a controller Or Base Controller

phil soady
  • 11,043
  • 5
  • 50
  • 95
  • Where does this go in ASP.NET MVC? is this not the same as post authenticate request? will it not fire for every request? also remember, even if the user is authenticated, I still **NEED** to build the custom user context and set it to the http current user if they are authenticated. The post authenticate request does what I want except it fires for every request like css files, images, js etc... - I only want it for that action being executed and have the user context set before the action method begins to execute so everything is set in place beforehand – Ahmed ilyas Dec 17 '13 at 01:14
  • sorry i was assuming based on your comments, you had some central code in Global.asax. – phil soady Dec 17 '13 at 02:54
  • indeed I do. PostAuthenticateRequest is where the requests hit which then I check to see if the user is authenticated using User.Identity.IsAuthenticated. if so, I then create the custom principal and set it to the Current.User object. But it calls it multiple times. Don't want that. only want it for the current request/action being served and not for each file being requested (like images for that page, css, js, fonts etc...) – Ahmed ilyas Dec 17 '13 at 09:28
  • seems like your solution is what I am already using which is causing a problem :) – Ahmed ilyas Dec 17 '13 at 09:28
  • perhaps try a different question around mvc/asp.net pipeline and events – phil soady Dec 17 '13 at 09:59
  • not exactly sure what issue you are having. use this for inspiration http://stackoverflow.com/questions/5947278/when-postauthenticaterequest-gets-execute – phil soady Dec 17 '13 at 13:16
  • Thanks but i explained why it doesn't work in my scenario. Let me rewrite my question. – Ahmed ilyas Dec 17 '13 at 13:19
  • I have now re-written the question. Please take a look – Ahmed ilyas Dec 17 '13 at 14:07