【问题标题】:Why is my DataContext null in only one action?为什么我的 DataContext 仅在一个操作中为空?
【发布时间】:2010-11-01 15:33:36
【问题描述】:

我的 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,所以我很确定这不是问题。

【问题讨论】:

  • 只是为了验证,您没有重用或持久化 DataContext 是吗? DataContext 应该在一个工作单元内创建并过期。当我做错这件事时,我因奇怪的行为而感到很痛苦。
  • 我有一个用于整个控制器的 DataContext 实例,它只分配一次(在创建控制器时),如果这就是你的意思。我可以在其他操作中多次成功访问它(在 OnActionExecuting 和操作方法本身中),但在 Logout 方法的情况下,DataContext 只使用一次(在 OnActionExecuting 中)。
  • 好的,这很糟糕,如果它是您问题的原因,我不会感到震惊。不应保留数据上下文。在我的特殊情况下,问题表现为不同的用户看到彼此的数据(真的......有点碍事)。我不能肯定这是你的问题,但我可以向你保证,这是有问题的。
  • 你在使用任何类型的 DI 吗?

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


【解决方案1】:

要跟进我的评论,check out this link,更具体地说,链接 Microsoft 文档 here 声明:

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

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

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

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

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

【讨论】:

  • 我的系统工作方式与 CodePlex 上的 Nerd Dinner 示例相同。每次创建控制器时,它都会获得一个新的 DataContext。它不是静态单例(如您在我的代码中所见)。如果 DataContext 在我访问它之前被释放,我会不会收到 ObjectDisposedException 而不是 NullReferenceException? NullReferenceException 让我认为 DataContext 属性甚至没有被初始化,这似乎是不可能的。
【解决方案2】:

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

【讨论】:

  • MVC 应该始终使用默认的无参数构造函数,除非 DI 框架和/或使用 SetControllerFactory 在 global.asax 中注册的控制器工厂另有说明 - 你在做这些吗?
猜你喜欢
  • 2016-02-07
  • 2011-12-20
  • 1970-01-01
  • 2019-09-07
  • 1970-01-01
  • 2016-03-03
  • 1970-01-01
  • 1970-01-01
  • 2012-05-29
相关资源
最近更新 更多