asp.net-mvc ASP.NET MVC 中的每个请求一个 DbContext(没有 IOC 容器)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6334592/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
One DbContext per request in ASP.NET MVC (without IOC container)
提问by devuxer
Apologies if this has already been answered, but how do you guarantee one Entity Framework DbContext per request if you are not using an IOC container? (The answers I've come across so far deal with IOC container solutions.)
抱歉,如果已经回答了这个问题,但是如果您不使用 IOC 容器,您如何保证每个请求有一个实体框架 DbContext?(到目前为止,我遇到的答案涉及 IOC 容器解决方案。)
It seems like most solutions hook into the HttpContext.Current.Items
dictionary, but how do you guarantee disposal of the DbContext when the request is finished? (Or is disposal not absolutely necessary with an EF DbContext
?)
似乎大多数解决方案都与HttpContext.Current.Items
字典挂钩,但是您如何保证在请求完成后处理 DbContext?(或者使用 EF 处理不是绝对必要的DbContext
?)
Edit
编辑
I'm currently instantiating and disposing my DbContext in my controllers, but I also have several separate instantiations of my DbContext in ActionFilters and my MembershipProvider (and I just noticed, also a couple validators). So, I thought it might be a good idea to centralize instantiation and storage of my DbContext to reduce overhead.
我目前正在我的控制器中实例化和处理我的 DbContext,但我在 ActionFilters 和我的 MembershipProvider 中也有几个单独的 DbContext 实例(我刚刚注意到,还有几个验证器)。所以,我认为集中我的 DbContext 的实例化和存储以减少开销可能是一个好主意。
回答by walther
I know this is not a recent question, but I'll post my answer anyway, because I believe someone may find it useful.
我知道这不是最近的问题,但无论如何我都会发布我的答案,因为我相信有人可能会觉得它很有用。
As probably many others, I followed the steps mentioned in the accepted answer. Yay, it works. HOWEVER, there's one catch:
与其他许多人一样,我按照已接受的答案中提到的步骤进行了操作。是的,它有效。但是,有一个问题:
Methods BeginRequest() and EndRequest() fire each time a request is made, but not only for aspx pages, but for ALL STATIC CONTENT! That said, if you use the code mentioned above and you have on your page let's say 30 images, you're re-instantiating your dbcontext 30 times!
每次发出请求时,方法 BeginRequest() 和 EndRequest() 都会触发,但不仅针对 aspx 页面,还针对所有静态内容!也就是说,如果您使用上面提到的代码并且您的页面上有 30 张图像,那么您将重新实例化 dbcontext 30 次!
The solution for this is to use a wrapping class for retrieving the context, something like this:
解决方案是使用包装类来检索上下文,如下所示:
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;
}
}
}
And then for disposing
然后用于处置
protected void Application_EndRequest(object sender, EventArgs e)
{
var entityContext = HttpContext.Current.Items["myContext"] as DB1Entities;
if (entityContext != null)
entityContext.Dispose();
}
This modification ensures that you instantiate and dispose your context only once per request and only when needed. Selected answer instantiates context every single time.
此修改可确保每个请求仅在需要时实例化和处理上下文一次。选定的答案每次都会实例化上下文。
Note:DB1Entities is derived from DbContext (generated by VS). You would probably want to alter it with your context name ;)
注意:DB1Entities 派生自 DbContext(由 VS 生成)。你可能想用你的上下文名称来改变它;)
Note 2:in this example I'm working with just one dbcontext. If you need to work with multiple, you would need to modify this code according to your needs. Don't take this as some ultimate solution to world problems, because it certainly isn't a final product. It is meant just to give a hint, how it may be achieved in a very easy way.
注意 2:在这个例子中,我只使用了一个 dbcontext。如果您需要使用多个,则需要根据需要修改此代码。不要把它当作世界问题的最终解决方案,因为它肯定不是最终产品。这只是为了提供一个提示,即如何以非常简单的方式实现它。
Note 3:Same approach can be used in different situations as well, for instance when you'd like to share an instance of SqlConnection or any other... This solution isn't exclusive to DbContext object, nor to Entity framework.
注意 3:相同的方法也可以用于不同的情况,例如,当您想要共享 SqlConnection 或任何其他实例时...此解决方案不仅适用于 DbContext 对象,也不适用于实体框架。
回答by Chad Moran
I would use the BeginRequest/EndRequest method, this helps ensure that your context is disposed of properly when the request is over with.
我将使用 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();
}
And in your EntityContext class...
在您的 EntityContext 类中...
public class EntityContext
{
public static EntityContext Current
{
get { return HttpContext.Current.Items["_EntityContext"] as EntityContext; }
}
}
回答by Darin Dimitrov
One way would be to subscribe for the Application_BeginRequest
event, inject the DbContext into the current HttpContext and in the Application_EndRequest
fetch from the HttpContext and dispose. Anything in between (which is pretty much everything :-)) could fetch the DbContext from the current HttpContext and use it. And, yes, you should dispose it. And by the way is there any reason you don't use a DI framework which already does this for you among other useful things?
一种方法是订阅Application_BeginRequest
事件,将 DbContext 注入当前 HttpContext 并Application_EndRequest
从 HttpContext 获取并处理。介于两者之间的任何东西(几乎就是一切:-))都可以从当前的 HttpContext 中获取 DbContext 并使用它。而且,是的,你应该处理它。顺便说一句,您是否有任何理由不使用已经为您执行此操作的 DI 框架以及其他有用的东西?
回答by DrunkCoder
Small addition for Chad Moran answer. It is inspired by walther notes. To avoid context initialization for static content we should check current route handler (this example only for MVC):
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();
}
}
回答by Goran Obradovic
If you implement IDisposable in your controller, and dispose context in disposing method, and instantiate new context in controller constructor, you should be safe as controller is instantiated for each request. I don't see, however, why would you want to do that? ... You should use DI, or make a context factory with one static instance of context. If you don't use one instance (you make one for each request) you are to have problems at some point. The problem with undisposed context is that EF caches data in context, and if some other instance of context changes something in DB that is already cached in another context - you have unconsistent state. Before DI became so popular, I used to have one static instance of context somewhere in application, and that is a lot faster and safer than having each request make its own context, but you need to implement state-checking code which makes sure that context connection to db is ok... There are a lot better solutions to this problem, and the best is to use some DI framework. I would recommend Ninject in combination with MVCTurbine, it is easy to set up and you can add it through NuGet.
如果您在控制器中实现 IDisposable,并在处理方法中处理上下文,并在控制器构造函数中实例化新的上下文,那么您应该是安全的,因为控制器是为每个请求实例化的。但是,我不明白您为什么要这样做?...您应该使用 DI,或者使用上下文的一个静态实例创建一个上下文工厂。如果您不使用一个实例(您为每个请求创建一个),您将在某个时候遇到问题。未处理上下文的问题在于 EF 在上下文中缓存数据,如果其他上下文实例更改了已缓存在另一个上下文中的数据库中的某些内容 - 您的状态不一致。在 DI 变得如此流行之前,我曾经在应用程序的某个地方有一个上下文的静态实例,这比让每个请求创建自己的上下文要快得多,也更安全,但是您需要实现状态检查代码,以确保与 db 的上下文连接正常......这个问题有很多更好的解决方案,最好是使用一些 DI 框架。我建议将 Ninject 与 MVCTurbine 结合使用,它易于设置,您可以通过 NuGet 添加。
回答by mymex1
The slippery slope here is having inconsistent state. If you're app is going to have multiple users on it, and they have the potential to change data concurrently then you might start running into problems with data integrity if you keep a single context.
这里的滑坡状态不一致。如果您的应用程序将有多个用户,并且他们有可能同时更改数据,那么如果您保留单个上下文,您可能会开始遇到数据完整性问题。