lunes, 19 de marzo de 2012

WinHost - MVC3 web application users are logged out / sessions lost.

I wrote this small tutorial on the WinHost forums because many people seem to face random logout and session wipes when hosting on a shared environment. This for an MVC3 web application, but should work across the board.

Here’s how I fixed this issue by switching over to SQL Session saving.

Basically the issue boils down to this:

WinHost recycles your web application whenever your web app reaches it’s memory pool limit. It also recycles it when there has been no HTTP activity for over 20 minutes.

When this happens, all information in session in lost. Since MVC3 uses InProc as the default for saving session information, this means logged in users are now logged out, every time your app pool recycles.

The fix is very simple, although I did have to hunt down some old forums posts and StackOverflow questions. Hopefully this saves some people some headaches.

Although not necessary, I recommend you give this article a read to get an overview of what it is we’re going to do to our web application.

1. Create a support ticket to request an installation of the SQL Server Session database.

While WinHost recommends you use a separate database for this, it works perfectly fine if you use only one. The downside is you’ll have three extra tables that aren’t related to the business end of the application. Not a problem though.

"Hello, please install the sql server session schema on my database: "foobarbaz".

2. Add the relevant sessionState node to your web.config file.

   1: <system.web>
   2:     <sessionState mode="SQLServer"
   3:                   allowCustomSqlDatabase="true"                  
   4:                   cookieless="false"
   5:                   timeout="2880"
   6:                   sqlConnectionString="data Source='tcp:s027.winhost.com';database='DB_3347_mydb';user id='DB_23_my_user'; password='mypassword';" />

This is essentially changing the way MVC3 is saving our session information. From InProc to SQLServer.


3. Generate a machine key.


Generate a machine key using this online tool and copy it somewhere.


4. Paste the machine key inside your root web.config file.



   1: <machineKey validationKey="D87832412312312312332EB48DC12091C2A671F2B6BFB733E5C50179A875EE03902E0127A46D38" 
   2:             decryptionKey="0769851231231231231239F7" 
   3:             validation="SHA1" 
   4:             decryption="AES" />    
   5: <trust level="Full"/>

Notice that we’re also setting trust level to Full.


 


That’s all you need to fix this problem.


Now if your app pool is recycled, your users will no longer be logged out. As an example I’ll post two small code snippet below. One shows you how I log users into my web application. The other shows you how I check if a user is logged in.


Login example:



   1: [HttpPost]
   2: public ActionResult Login(LogOnModel model)
   3: {
   4:     using (EfAccountRepository accountRepository = new EfAccountRepository())
   5:     {
   6:         if (accountRepository.ValidateCredentials(model.Email, model.Password))
   7:         {
   8:             //THE IMPORTANT BIT IS THIS.
   9:             FormsAuthentication.SetAuthCookie(model.Email, true);
  10:             return RedirectToAction("Index", "Home");
  11:         }
  12:         ModelState.AddModelError("", "Your email or password is incorrect.");
  13:         return View(model);
  14:     }
  15: }

Logged in status verification:



   1: public static bool UserIsPartOfCompany(HttpContext context)
   2: {
   3:     if (!context.Request.IsAuthenticated)
   4:         return false;
   5:  
   6:     using (EfAccountRepository accountRepository = new EfAccountRepository())
   7:     {
   8:         var loggedInUser = accountRepository.FindByEmail(context.User.Identity.Name);
   9:         string[] userRoles = accountRepository.GetRolesForUser(loggedInUser.AccountId);
  10:  
  11:         return userRoles.Contains("Editor") || userRoles.Contains("Finance") || userRoles.Contains("Administrator");
  12:     }
  13: }
  14:  

 


That’s all there is to it! If you have any questions, please let me know.