views:

294

answers:

3

I have a static class with serveral static methods. In these methods, I'm trying to access the current thread's context using HttpContext.Current. For example:

var userName = HttpContext.Current.User.Identity.Name;

However, when I do that, I receive a NullReferenceException, the infamous "Object reference not set to an instance of an object."

Any ideas?

A: 

Where exactly is the null exception being thrown? Have you debug and see what is null? Is the HttpContext.Current is null or the User?

azamsharp
It's difficult for me to debug this because it doesn't happen all the time. In fact, I'm having a difficult time trying to repro this on my dev box, in the test environment, or in the live environment.It seems to be happening at random with end users. I check for the null values and that's where it's being thrown (inside of the static method).
Jason N. Gaylord
I wonder if the forms authentication ticket is expiring thus making the User null.
azamsharp
+1  A: 

I've run into this a few times, especially with static methods in another library and not my main project. I've resorted to passing the HttpContext to the static method as a param when nothing else seems to work.

Keith Barrows
Good suggestion Keith. Thanks!
Jason N. Gaylord
+1  A: 

It isn't clear from the original post that the HttpContext is actually what's missing. The HttpContext.User property can also be null at certain stages of the lifecycle, which would give you the exact same exception. All other issues aside, you need to step through the source and see which part of the expression is actually null.

When you write code that references static methods/properties like HttpContext.Current, you have to write them knowing that your code isn't guaranteed to be run when the methods/properties are actually available. Normally you have something like this:

static string GetCurrentUserName()
{
    HttpContext context = HttpContext.Current;
    if (context == null)
        return null;
    IPrincipal user = context.User;
    if (user == null)
        return null;
    return user.Identity.Name;
}

Although I suspect that this wouldn't really solve your problem here, it would just get rid of the exception. The issue is more likely that you're calling this method at a time or place when the context is simply not available, such as on a background thread, static constructor or field initializer, or in the Application_BeginRequest method, or some similar place.

I might start by changing the static methods to instance methods of a class that depends on an HttpContext instance (i.e. taken in the constructor). It's easy to fool yourself into thinking that methods like GetCurrentUserName are simple "utility" methods, but they're really not, and it is generally invalid to be invoking a method that references HttpContext.Current through the static property from any place where you don't already have an instance reference to the same HttpContext (i.e. from the Page class). Odds are, if you start rewriting your classes like this:

public class UserResolver
{
    private HttpContext context;

    public UserResolver(HttpContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");
        this.context = context;
    }

    public string GetUserName()
    {
        return (context.User != null) ? context.User.Identity.Name : null;
    }
}

...then you will likely find out very quickly where the chain is being broken, which will be the point at which you need to reference HttpContext.Current because you can't get it from anywhere else.

In this specific case, obviously, you can solve the problem just by taking the stack trace of the NullReferenceException to find out where/when the chain begins, so you don't have to make the changes I've described above - I'm simply recommending a general approach that will help reduce these sorts of "missing singleton" errors in the future.

Aaronaught
It's not great to do this, but this is what I ended up doing. I also decided to strip a lot of the stuff I'd store in the object out and place it into the URL.
Jason N. Gaylord