首页 文章

ASP.NET MVC中每个请求一个DbContext(没有IOC容器)

提问于
浏览
49

如果这已经得到回答,请道歉,但如果您不使用IOC容器,如何保证每个请求有一个Entity Framework DbContext? (到目前为止,我遇到的答案涉及IOC容器解决方案 . )

似乎大多数解决方案都挂钩到 HttpContext.Current.Items 字典中,但是如何在请求完成时保证处理DbContext? (或者,对于EF DbContext ,处理不是绝对必要的吗?)

Edit

我目前正在我的控制器中实例化和处理我的DbContext,但我在ActionFilters和我的MembershipProvider中也有几个单独的DbContext实例(我刚注意到,也有几个验证器) . 因此,我认为集中我的DbContext的实例化和存储以减少开销可能是个好主意 .

6 回答

  • 70

    我会使用BeginRequest / EndRequest方法,这有助于确保在请求结束时正确处理您的上下文 .

    protected virtual void Application_BeginRequest()
    {
        HttpContext.Current.Items["_EntityContext"] = new EntityContext();
    }
    
    protected virtual void Application_EndRequest()
    {
        var entityContext = HttpContext.Current.Items["_EntityContext"] as EntityContext;
        if (entityContext != null)
            entityContext.Dispose();
    }
    

    在你的EntityContext类中......

    public class EntityContext
    {
        public static EntityContext Current
        {
            get { return HttpContext.Current.Items["_EntityContext"] as EntityContext; }
        }
    }
    
  • 0

    我知道这不是最近的一个问题,但无论如何我都会发布我的答案,因为我相信有人会觉得它很有用 .

    可能很多其他人,我按照接受的答案中提到的步骤 . 是的,它有效 . HOWEVER ,有一个问题:

    方法BeginRequest()和EndRequest() fire each time a request is made ,但不仅适用于aspx页面,还适用于所有静态内容!也就是说,如果您使用上面提到的代码并且在页面上有,请让's say 30 images, you'重新实例化dbcontext 30次!

    解决方案是使用包装类来检索上下文,如下所示:

    internal static class ContextPerRequest
    {
          internal static DB1Entities Current
          {
              get
              {
                  if (!HttpContext.Current.Items.Contains("myContext"))
                  {
                      HttpContext.Current.Items.Add("myContext", new DB1Entities());
                  }
                  return HttpContext.Current.Items["myContext"] as DB1Entities;
              }
          }
     }
    

    然后进行处置

    protected void Application_EndRequest(object sender, EventArgs e)
    {
       var entityContext = HttpContext.Current.Items["myContext"] as DB1Entities;
       if (entityContext != null) 
          entityContext.Dispose();
    }
    

    此修改可确保您仅在每个请求时仅在需要时实例化和处置上下文一次 . 选定的答案每次都会实例化上下文 .

    Note: DB1Entities派生自DbContext(由VS生成) . 你可能想用你的上下文名称改变它;)

    Note 2: 在这个例子中我认为这是世界问题的最终解决方案,因为它肯定不是最终产品 . 它只是为了提示,如何以一种非常简单的方式实现它 .

    Note 3: 也可以在不同情况下使用相同的方法,例如,当您对DbContext对象或者Entity框架不作为时 .

  • 58

    一种方法是订阅 Application_BeginRequest 事件,将DbContext注入当前的HttpContext和HttpContext的 Application_EndRequest 提取并处理 . 介于两者之间的任何东西(几乎所有东西:-))都可以从当前的HttpContext中获取DbContext并使用它 . 而且,是的,你应该处理它 . 顺便说一下,你有没有理由不使用已经为你做过的DI框架以及其他有用的东西?

  • 10

    Chad Moran的小补充回答 . 它受到沃尔特笔记的启发 . 为了避免静态内容的上下文初始化,我们应该检查当前的路由处理程序(这个例子仅适用于MVC):

    protected virtual void Application_BeginRequest()
    {
      var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(this.Context));
      if (routeData != null && routeData.RouteHandler is MvcRouteHandler)
      {
        HttpContext.Current.Items["_EntityContext"] = new EntityContext();
      }
    }
    
  • 1

    如果在控制器中实现IDisposable,并在disposing方法中配置上下文,并在控制器构造函数中实例化新上下文,那么在为每个请求实例化控制器时应该是安全的 . 但是,我没有看到你为什么要那样做? ...您应该使用DI,或者使用一个静态的上下文实例创建一个上下文工厂 . 如果你不使用一个实例(你为每个请求创建一个实例),那么在某些时候你会遇到问题 . 不受干扰的上下文的问题是EF在上下文中缓存数据,并且如果某个其他上下文实例在DB中已经在另一个上下文中缓存了某些内容 - 那么您将拥有不一致的状态 . 在DI变得如此受欢迎之前,我曾经在应用程序中的某个地方有一个静态的上下文实例,这比让每个请求创建自己的上下文要快得多,也更安全,但是你需要实现状态检查代码来确保上下文与数据库的连接是正确的...这个问题有很多更好的解决方案,最好是使用一些DI框架 . 我建议将Ninject与MVCTurbine结合使用,它很容易设置,你可以通过NuGet添加它 .

  • 7

    这里的滑坡是不一致的状态 . 如果您的应用程序将拥有多个用户,并且他们有可能同时更改数据,那么如果您保留一个数据完整性,则可能会遇到数据完整性问题单一背景 .

相关问题