0

I am pretty new to MVC and am having difficulties getting my application to run on my staging webserver. On my local machine and dev server it is running fine.

The issue is that in my Action the User is null (on staging, not on dev and local). I googled reasons why the User would be null, but everything seems covered. Strange thing is that it works perfectly on 2 servers.

Here is my code...

In Global.asax Using PostAcquireRequestState I override the principal using a custom principal holding an object stored in Session. Hence the SessionHelper which will get the object and add it to the principal. The principal is then set to the httpcontext and thread.

public class MvcApplication : HttpApplication
{
    public MvcApplication()
    {
        PostAcquireRequestState += new EventHandler(MvcApplication_PostAcquireRequestState);
    }

    void MvcApplication_PostAcquireRequestState(object sender, EventArgs e)
    {
        if (Context.User is ICSPrincipal)
            return;

        var principal = new ICSPrincipal(new GenericIdentity(User.Identity.Name), SessionHelper.UserClaims);
        HttpContext.Current.User = principal;
        Thread.CurrentPrincipal = principal;
    }

    ...
}

In my controller I will retrieve the value stored in the principal. But the problem is that User is null on my staging server. It works however on my local machine and my development server. Development server and staging server are running the same version of IIS and both have MVC3 installed.

public class HomeController : Controller
{
   public ActionResult Index()
   {
        //PROBLEM!!! User is NULL on staging server.
        var userClaims = ((ICSPrincipal)User).UserClaims;
        ...
   }
}

Does anyone have any experience with this problem and got it solved? I was under the impression I could safely call User from within my Action.

EDIT: Situation sketch on why I require SessionStorage in combination with a custom principal.

I use formsauthentication so the authentication is covered. However I used to store an object which held extra userdata (firstname, lastname; 6 properties in total) into the userdata from the authentication cookie. However investigating my requests I saw that each request (even for images; and I know I can optimize this using a cookieless domain, but that's a next step) was over 2.5KB. Therefor I switched back to just storing username in the cookie and on each request I want the data to be completed from session storage. That's why I thought a custom principal would be great. It starts with a generic principal and once we get to the Action there is a custom principal with all the data I require coming from wherever I want (in this case username from cookie added with data from session).

I hear you say: but hey, using Session is not safe, it expires after a while. And I am well aware of this, that's why SessionHelper has ofcourse some intelligence. If the Session object is null, it will get all data required based on the authenticated user's username. It than stores this data in Session so subsequent requests don't query my database.

I also use API communication (http or named pipes) and that's why I need this data in the custom principal. I can't access Session from that layer, but I can access the principal. Therefor if the principal is updated before getting to that communication everything works fine.

GETTING TO THE ACTUAL PROBLEM:

This setup described above actually works fine on multiple machines, but not on my staging server which is the same setup as my development server. Staging complaints that User is null in my action. And I don't know how that's even possible.

Guillaume Schuermans
  • 906
  • 2
  • 12
  • 28
  • Is your staging server in a different domain? – Hector Correa Apr 12 '12 at 19:13
  • yes it is, the entire staging environment is hosted on a different domain using their own servers (all in the same domain). – Guillaume Schuermans Apr 12 '12 at 22:02
  • I just published to a production environment and I have the same issue as on staging. So the score is 2-2. Local and dev are working (on the same domain), staging and production are not (also on the same domain, but a different one than dev and local). – Guillaume Schuermans Apr 13 '12 at 12:00
  • It would seem like the domain might have something to do with it. Also, you should probably check how the site is configured in both cases, particularly when it comes to pipeline mode, authentication, and other modules that may be enabled. – Erik Funkenbusch Apr 13 '12 at 14:53
  • http://support.microsoft.com/kb/980368/en seems to have fixed the issue. After this patch is applied, ASP.NET 4 applications can handle requests for extensionless URLs. Therefore, managed HttpModules that run prior to handler execution will run. In some cases, the HttpModules can return errors for extensionless URLs. For example, an HttpModule that was written to expect only .aspx requests may now return errors when it tries to access the HttpContext.Session property. – Guillaume Schuermans Apr 13 '12 at 16:09

2 Answers2

2

PostAcquireRequestState is an odd place to be doing this. You should be doing it in AuthenticateRequest. you should also set Context.User not HttpContext.Current.User.

Erik Funkenbusch
  • 92,674
  • 28
  • 195
  • 291
  • problem is User is not known yet in AuthenticateRequest. PostAuthenticateRequest could be used, but Session is not known until PostAcquireRequestState therefor I used this event. The idea is that I store userdata on the server using Session instead of storing it on the client and passing it along using a cookie on each request. – Guillaume Schuermans Apr 12 '12 at 22:00
  • @GuillaumeSchuermans - it's a bad idea to use session, because session can disappear at any time. IIS can recycle the session whenever it feels like it, so you need to be able to rebuild session from information stored in some other form (such as a cookie). Fact is, MVC wraps the Context in a testable wrapper, so setting HttpContext.* values after this wrapper is established can be tricky. – Erik Funkenbusch Apr 12 '12 at 23:02
  • @GuillaumeSchuermans - i'm confused. HOw do you not know who the user is in AuthenticateRequest? That's where you do the authentication if you're doing custom authentication. – Erik Funkenbusch Apr 13 '12 at 00:22
  • Valid remark. It made me realize my situation sketch was not complete. I will edit the original question since I don't have enough chars in this textbox. – Guillaume Schuermans Apr 13 '12 at 08:31
  • Ok, edited. I hope everything is clear since I could really use your help and am glad to hear your insights. – Guillaume Schuermans Apr 13 '12 at 08:44
0

http://support.microsoft.com/kb/980368/en

After this patch is applied, ASP.NET 4 applications can handle requests for extensionless URLs. Therefore, managed HttpModules that run prior to handler execution will run. In some cases, the HttpModules can return errors for extensionless URLs. For example, an HttpModule that was written to expect only .aspx requests may now return errors when it tries to access the HttpContext.Session property.

This has fixed the issue! Thanks all for making me experiment with multiple settings. This way I came up with this solution.

Guillaume Schuermans
  • 906
  • 2
  • 12
  • 28