我的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,所以我很确定这不是问题所在。
答案 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在某些情况下使用了默认构造函数,而在其他情况下使用了重载。任何人都可以对此有所了解吗?