HttpContext.Current在静态方法中出现NullReferenceException异常

4

我有一个静态类,其中包含几个静态方法。在这些方法中,我试图使用HttpContext.Current访问当前线程的上下文。例如:

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

然而,当我这样做时,我收到了一个NullReferenceException,也就是臭名昭著的“对象引用未设置为对象的实例”错误。

有什么想法吗?


1
什么是静态方法?它们在哪里被调用? - SLaks
3个回答

6
原帖并没有明确指出缺少的是HttpContext。在生命周期的某些阶段,HttpContext.User属性也可能为空,这将导致相同的异常。除了其他问题之外,您需要逐步查看源代码,并确定表达式中哪一部分实际上是null。
当您编写引用静态方法/属性(如HttpContext.Current)的代码时,必须知道您的代码不能保证在方法/属性实际可用时运行。通常情况下,您需要像这样编写代码:
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;
}

尽管我怀疑这并不能真正解决你的问题,只是摆脱了异常。问题更可能是你在一个没有上下文的时间或地点调用了这个方法,比如在后台线程、静态构造函数或字段初始化器中,或者在Application_BeginRequest方法中,或类似的地方。
我建议将静态方法改为依赖于HttpContext实例的类的实例方法(即在构造函数中传入)。很容易让自己认为像GetCurrentUserName这样的方法是简单的“实用”方法,但它们实际上不是,通常无效的是从任何你还没有相同HttpContext实例引用的地方(即从Page类)通过静态属性引用HttpContext.Current的方法。如果你开始像这样重写你的类:
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;
    }
}

如果你遇到了链路中断的问题,很可能会很快找到具体的问题点。这个问题点是需要引用HttpContext.Current的地方,因为你无法从其他地方获取它。
在这种情况下,显然,你可以通过获取NullReferenceException的堆栈跟踪来找出链路开始的地方和时间,所以你不必进行上述更改 - 我只是推荐一个通用方法,以帮助减少这类“缺失单例”错误。

这样做并不是很好,但这就是我最终做的决定。我还决定剥离对象中存储的许多内容,并将其放入URL中。 - Jason N. Gaylord

2

我遇到过这种情况,尤其是在另一个库中使用静态方法而不是我的主项目。当没有其他方法可行时,我会将HttpContext作为参数传递给静态方法。


0

空引用异常具体是在哪里抛出的?您是否进行了调试并查看了哪个对象为空?HttpContext.Current是空还是User是空?


这很难调试,因为它并不总是发生。事实上,我很难在我的开发环境、测试环境或生产环境中尝试重现它。它似乎是在最终用户那里随机发生的。我检查了空值,这就是它被抛出的位置(在静态方法内部)。 - Jason N. Gaylord
我想知道表单身份验证票证是否过期,从而使用户为空。 - azamsharp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接