为什么我的 DataContext 仅在一项操作中为 null?

发布于 2024-07-24 09:10:40 字数 1233 浏览 7 评论 0原文

我的 BaseController 上有一个名为 DataContext 的属性,它保存我的 LINQ to SQL 数据上下文(或用于测试的假上下文)。 使用无参数构造函数时(换句话说,当向 ASP.NET MVC 发出请求时),会将 LINQ to SQL 数据上下文的新实例分配给该属性:

public class BaseController : Controller {
    public IDataContextWrapper DataContext { get; set; }

    public BaseController() : this(new DataContextWrapper<MyDataContext>()) { }

    public BaseController(IDataContextWrapper context) {
        DataContext = context;
    }
}

还在我的 BaseController 中,我设置了一些全局 ViewData 项:

protected override void OnActionExecuting(ActionExecutingContext filterContext) {
    ViewData["Example"] = DataContext.Table<Example>().Count();
    base.OnActionExecuting(filterContext);
}

这几乎适用于每个动作。 唯一不起作用的是我的 AccountController 上的注销操作:

public ActionResult Logout() {
    FormsAuth.SignOut();
    return RedirectToResult("Login");
}

这会在 BaseController.OnActionExecuting 期间引发 NullReferenceException。 执行该特定操作时,DataContext 属性为 null。

为什么这只会发生在一个动作上?

注意: IDataContextWrapper 和 DataContextWrapper 只是包装了 LINQ to SQL DataContext 对象的现有功能,以便可以在单元测试中用假上下文替换它。 它本身不会进行任何处理,而是将其留给底层 DataContext,所以我非常确定这不是问题。

I have a property on my BaseController called DataContext that holds my LINQ to SQL data context (or fake context for testing). When using a parameterless constructor (in other words, when a request to ASP.NET MVC is made), a new instance of my LINQ to SQL data context is assigned to the property:

public class BaseController : Controller {
    public IDataContextWrapper DataContext { get; set; }

    public BaseController() : this(new DataContextWrapper<MyDataContext>()) { }

    public BaseController(IDataContextWrapper context) {
        DataContext = context;
    }
}

Also in my BaseController, I set some global ViewData items:

protected override void OnActionExecuting(ActionExecutingContext filterContext) {
    ViewData["Example"] = DataContext.Table<Example>().Count();
    base.OnActionExecuting(filterContext);
}

This is working fine for almost every action. The only one that doesn't work is the Logout action on my AccountController:

public ActionResult Logout() {
    FormsAuth.SignOut();
    return RedirectToResult("Login");
}

This raises a NullReferenceException during BaseController.OnActionExecuting. When executing that particular action, the DataContext property is null.

Why would this only occur on one action?

Note: IDataContextWrapper and DataContextWrapper simply wraps the existing functionality of the LINQ to SQL DataContext object so that it can be replaced with a fake context in unit tests. It doesn't do any disposing on its own, but leaves it up to the underlying DataContext, so I'm pretty certain that's not the problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

软糖 2024-07-31 09:10:41

要跟进我的评论,查看此链接,更具体地说是链接 Microsoft 文档 这里其中指出:

一般来说,DataContext 实例被设计为持续一个“工作单元”,但您的应用程序定义了该术语。 DataContext 是轻量级的并且创建起来并不昂贵。 典型的 LINQ to SQL 应用程序在方法范围内创建 DataContext 实例,或者作为表示相关数据库操作的逻辑集的短期类的成员。

Microsoft 在解释这一点上做得很糟糕,并且首先坦率地解释了在 n 层环境中使用 Linq。 在我的特定情况下,我有一个通过单例模式实现的(静态)数据上下文,我猜这也是您所做的。 (恕我直言,因为这是最合乎逻辑的设计)。 然而,这绝对不是做事的方式。 就我而言,修复实际上非常简单,只需更改 GetDataContext() 调用以每次返回一个新的 DataContext,而不是返回静态实例。 然而,您会发现,这会产生一系列新的问题。 一旦你弄清楚它们,它们都不是不可克服的,但绝对是一种痛苦。

如果您有这样的设置(DataContext 的单例访问器),请更改它以查看是否可以解决您的问题。

无论如何,不​​要使用全局 DataContext,如果处理 n 层架构,也不要保留 DataContext。

即使这不能解决您的特定问题,我也强烈建议您重新构建您的解决方案,使 DataContext 具有一个工作单元的生命周期,如果它还没有困扰您,它会的。

To follow up my comment, check out this link and more specifically the link Microsoft documentation here which state:

In general, a DataContext instance is designed to last for one "unit of work" however your application defines that term. A DataContext is lightweight and is not expensive to create. A typical LINQ to SQL application creates DataContext instances at method scope or as a member of short-lived classes that represent a logical set of related database operations.

Microsoft did a terrible job explaining this and frankly explaining using Linq in an n-tier environment in the first place. In my particular case, I had one (static) datacontext implemented via Singleton pattern, which I am guessing is what you have done as well. ( As it is the most logical design, IMHO ). This however, is extremely NOT the way to do things. In my case, the fix was actually pretty easy, changing my GetDataContext() call to return a new DataContext every time, instead of returning the static instance. This however, you will find, creates a whole new crop of problems. None of them are insurmountable once you figure them out, but definitely a pain.

If you have such a setup ( Singleton accessors for your DataContext), change it to see if it fixes your problem.

Regardless, do not use a global DataContext, nor persist a DataContext if dealing with an n-tier architecture.

Even if this doesn't solve your particular problem, I highly suggest you re-architect your solution to make DataContexts have a unit of work lifespan, if it hasn't bitten you already, it will.

虐人心 2024-07-31 09:10:41

由于我不太明白的原因,当为注销操作创建新的 AccountController 时,ASP.NET MVC 使用带有 null 参数的第二个构造函数(可能是一个错误?)。 当参数为 null 时,我更改了该类以创建新的默认 DataContext:

public class BaseController : Controller {
    public IDataContextWrapper DataContext { get; set; }

    public BaseController() : this(null) { }

    public BaseController(IDataContextWrapper context) {
        DataContext = dataContext ?? new DataContextWrapper<MyDataContext>();
    }
}

现在它可以工作了。

让我感到奇怪的是,ASP.NET MVC 在某些情况下使用默认构造函数,而在其他情况下使用重载。 有人能解释一下吗?

For reasons that I don't quite understand, when a new AccountController is created for the Logout action, ASP.NET MVC is using the second constructor with a null parameter (could be a bug?). I changed the class to create a new default DataContext when the parameter is null:

public class BaseController : Controller {
    public IDataContextWrapper DataContext { get; set; }

    public BaseController() : this(null) { }

    public BaseController(IDataContextWrapper context) {
        DataContext = dataContext ?? new DataContextWrapper<MyDataContext>();
    }
}

Now it works.

It strikes me as strange that ASP.NET MVC used the default constructor in some cases, and an overload in others, though. Can anyone shed some light on this?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文