Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dealing with null HttpContext.Current when starting an application given the user already has a cookie

I'm developing a web project which contains the authorisation system which uses cookies. I'm using Identity 2.0 Sample Project so I got that feature built-in. I also use Git as my version control system.

I have merged two branches. Both of them work with authorisation and cookies easily. When you log in and then stop the application via Visual Studio, I can start the application again and I will remain logged in.

After I have merged two branches I got some strange behavior. The code I have merged doesn't affect the authorisation system.

When you log in the cookie file is created, so when I manually stop the application via Visual Studio and then start it again, I'm supposed to be logged in. Howether the application crashes with the following exception:

An exception of type 'System.NullReferenceException' occurred in Microsoft.Owin.Host.SystemWeb.dll but was not handled in user code

And the Visual Studio points at the following line:

 var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();

The code was included in Identity Sample and it had been working fine before the merge. As I have found out, if I delete following piece of code, the app works fine; I can stop it and run it again having zero exceptions:

 @{
        var manager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
        var currentUser = manager.FindById(User.Identity.GetUserId());
 }
 @Html.ActionLink("Hello " + currentUser.UserNickName + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })

This code is a part of _LoggingPartial View which was genereated by Visual Studio and modified in branch I merged with.

So now I'm totally lost because I have no idea what that exception was caused by.

Perhaps someone could help me, give an advice on how I can solve it.

UPDATE:

As I've figrued out, the problem isn't with the nickname. Actually, the app crashes after stop-start even if I add the following code to the old vesrion:

 @{
        var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
        var currentUser = userManager.FindById(User.Identity.GetUserId());
 }
 @Html.ActionLink("Hello " + currentUser.Email.ToString() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })

As you see, this code doesn't use any methods but native Identity's.

Also, I've tested different methods to get the user and got the following results:

The app crashes if I use ' var currentUser = userManager.FindById(User.Identity.GetUserId());'

The app crashes if I use ' var currentUser = userManager.FindByIdAsync(User.Identity.GetUserId());' (Of course, I've modified the rest of the code to work with async result)

The app crashes if I use ' var currentUser = userManager.FindByName(User.Identity.GetUserName());'

The app does not crash if I use ' var currentUser = userManager.FindByNameAsync(User.Identity.GetUserName());'

So, neither does it work with FindById nor with FindByIdAsync. If I use FindByName, it works with FindByNameAsync but crashes with simple FindByName

like image 924

1 Answers

Found out the reason of the bug. When we first log in, our user information is saved in cookies. Since we use the string Id (by default in Identity), userId = someRandomHash(). Perhaps not random, but it's not constant anyway. So, we have randomString1 in our cookies. When we stop the server and start it again, the database is generated again because we have our database initialisation defined as 'DropCreateAlways'. Therefore, there's randomString2 in our database but randomString1 in cookies. When we try to get the saved Id from cookies, we get it successfully but we can't find it in the database with the userManager since the Id is now different.

Also, it explains why the bug isn't reproducible with GetName() method - we always have the same userName. And it works only with async Find() because it's run when we still have a database. However, the simple not async method's run when the db is already dropped and we don't have any name there. Still don't know why Visual Studio pointed on the 'var userManager' line but I guess 'tis not very important.

like image 99