1

我的 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 上的 Logout 操作:

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

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

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

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

4

2 回答 2

1

要跟进我的评论,请查看此链接,更具体地说是此处的 Microsoft 文档链接,其中说明:

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

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

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

无论如何,如果处理 n 层架构,请不要使用全局 DataContext,也不要持久化 DataContext。

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

于 2009-06-09T23:27:42.790 回答
0

由于我不太明白的原因,当为 Logout 操作创建新的 AccountController 时,ASP.NET MVC 正在使用带有 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 在某些情况下使用了默认构造函数,而在其他情况下使用了重载。任何人都可以对此有所了解吗?

于 2009-06-09T23:45:11.303 回答