为什么我的DataContext只在一个动作中为空?

时间:2009-06-09 22:19:55

标签: asp.net-mvc linq-to-sql datacontext

我的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属性为null。

为什么这只会在一次行动中发生?

注意: IDataContextWrapper和DataContextWrapper简单地将LINQ的现有功能包装到SQL DataContext对象中,以便在单元测试中将其替换为伪上下文。它本身不进行任何处理,但将其留给底层的DataContext,所以我很确定这不是问题所在。

2 个答案:

答案 0 :(得分:1)

要跟进我的评论check out this link,更具体地说是微软文档here的链接,其中说明:

  

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

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

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

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

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

答案 1 :(得分:0)

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