在 Web Api 2.0 中通过 Microsoft Unity 为每个请求实例化 Entity Framework 上下文
Instanciate Entity Framework context per request via Microsoft Unity in WebApi 2.0
我有一个 N 层解决方案,可以在我的开发环境中正常工作。显然它也适用于生产环境,但有时执行失败。我不懂为什么。我只知道数据库没有任何变化,没有可见的有用错误,也没有写入日志。
我的假设是并发问题。我认为当 entity framework 上下文初始化后,当我尝试执行多个 select 时会失败。
这里是我的解决方案的结构
在外观中,我注入了 entity framework 上下文。这里是我的服务接口web.config上的配置:
<containers>
<container>
<types>
<register type="it.MC.IContext.IDataContext, IContext"
mapTo="it.MC.EntityFrameworkContext.PublicAreaContext, EntityFrameworkContext">
<lifetime type="singleton" />
</register>
<register type="it.MC.IFacade.IPublicAreaFacade, IFacade"
mapTo="it.MC.Facade.PublicAreaFacade, Facade">
<interceptor type="TransparentProxyInterceptor" />
<lifetime type="singleton" />
<constructor>
<param name="context" type="it.MC.IContext.IDataContext, IContext"/>
</constructor>
</register>
</types>
</container>
</containers>
如您所见,我的上下文和外观是单例的。我认为两者都是错误的。我认为实体 Framewrk 上下文的 Facade 都应该根据请求实例化。我认为这也将解决并发问题。
有人可以帮我更正我的代码吗?
谢谢
我知道你的问题是:
Can anyone help me to correct my code please?
我是这样读的:
Can anyone help me change this code so that IContext
and IFacade
will be re-initialized per request.
话虽如此...是的,我也怀疑你是否想将 IContext
保持为单身。
Why you shouldn't use singleton DataContexts in Entity Framework
以下是将生命周期管理器更改为 PerRequestLifetimeManager
, if that's what you want. Note that you probably need the Unity.Mvc NuGet 包的方法。
<containers>
<container>
<types>
<register type="it.MC.IContext.IDataContext, IContext"
mapTo="it.MC.EntityFrameworkContext.PublicAreaContext, EntityFrameworkContext">
<lifetime type="Microsoft.Practices.Unity.PerRequestLifetimeManager, Microsoft.Practices.Unity.Mvc" />
</register>
<register type="it.MC.IFacade.IPublicAreaFacade, IFacade"
mapTo="it.MC.Facade.PublicAreaFacade, Facade">
<interceptor type="TransparentProxyInterceptor" />
<lifetime type="Microsoft.Practices.Unity.PerRequestLifetimeManager, Microsoft.Practices.Unity.Mvc" />
<constructor>
<param name="context" type="it.MC.IContext.IDataContext, IContext"/>
</constructor>
</register>
</types>
</container>
</containers>
在投入生产之前,我建议您阅读 关于 PerRequestLifetimeManager
。
Its purpose would be to only instantiate one instance per request,
which could (for example) prevent redundant operations and lookups
during the course of a single request.
The danger is if someone assumes that the object created is a good
place to store state during the request. The idea of dependency
injection is that a class receives a dependency (commonly an
interface) and doesn't "know" anything about it at all except that it
implements that interface.
另外,考虑一下您得到的 Facade
,如果每个请求都重新启动它,它将如何工作。它在初始化时是否执行任何繁重的操作?您可能需要考虑那个的 lifetimemanager。
更新
由于您使用的是 WebAPI,因此您应该可以改用 HierarchicalLifetimeManager
。
http://www.asp.net/web-api/overview/advanced/dependency-injection
The dependency resolver attached to the HttpConfiguration object has
global scope. When Web API creates a controller, it calls BeginScope.
This method returns an IDependencyScope that represents a child scope.
Web API then calls GetService on the child scope to create the
controller. When request is complete, Web API calls Dispose on the
child scope. Use the Dispose method to dispose of the controller’s
dependencies.
http://www.devtrends.co.uk/blog/introducing-the-unity.webapi-nuget-package
If you are registering any components that implement IDisposable such
as Entity Framework's DbContext, you will want to make sure that these
components get disposed of at the end of the request. This is achieved
by registering these components with a HierarchicalLifetimeManager.
我有一个 N 层解决方案,可以在我的开发环境中正常工作。显然它也适用于生产环境,但有时执行失败。我不懂为什么。我只知道数据库没有任何变化,没有可见的有用错误,也没有写入日志。 我的假设是并发问题。我认为当 entity framework 上下文初始化后,当我尝试执行多个 select 时会失败。
这里是我的解决方案的结构
在外观中,我注入了 entity framework 上下文。这里是我的服务接口web.config上的配置:
<containers>
<container>
<types>
<register type="it.MC.IContext.IDataContext, IContext"
mapTo="it.MC.EntityFrameworkContext.PublicAreaContext, EntityFrameworkContext">
<lifetime type="singleton" />
</register>
<register type="it.MC.IFacade.IPublicAreaFacade, IFacade"
mapTo="it.MC.Facade.PublicAreaFacade, Facade">
<interceptor type="TransparentProxyInterceptor" />
<lifetime type="singleton" />
<constructor>
<param name="context" type="it.MC.IContext.IDataContext, IContext"/>
</constructor>
</register>
</types>
</container>
</containers>
如您所见,我的上下文和外观是单例的。我认为两者都是错误的。我认为实体 Framewrk 上下文的 Facade 都应该根据请求实例化。我认为这也将解决并发问题。
有人可以帮我更正我的代码吗?
谢谢
我知道你的问题是:
Can anyone help me to correct my code please?
我是这样读的:
Can anyone help me change this code so that
IContext
andIFacade
will be re-initialized per request.
话虽如此...是的,我也怀疑你是否想将 IContext
保持为单身。
Why you shouldn't use singleton DataContexts in Entity Framework
以下是将生命周期管理器更改为 PerRequestLifetimeManager
, if that's what you want. Note that you probably need the Unity.Mvc NuGet 包的方法。
<containers>
<container>
<types>
<register type="it.MC.IContext.IDataContext, IContext"
mapTo="it.MC.EntityFrameworkContext.PublicAreaContext, EntityFrameworkContext">
<lifetime type="Microsoft.Practices.Unity.PerRequestLifetimeManager, Microsoft.Practices.Unity.Mvc" />
</register>
<register type="it.MC.IFacade.IPublicAreaFacade, IFacade"
mapTo="it.MC.Facade.PublicAreaFacade, Facade">
<interceptor type="TransparentProxyInterceptor" />
<lifetime type="Microsoft.Practices.Unity.PerRequestLifetimeManager, Microsoft.Practices.Unity.Mvc" />
<constructor>
<param name="context" type="it.MC.IContext.IDataContext, IContext"/>
</constructor>
</register>
</types>
</container>
</containers>
在投入生产之前,我建议您阅读 PerRequestLifetimeManager
。
Its purpose would be to only instantiate one instance per request, which could (for example) prevent redundant operations and lookups during the course of a single request.
The danger is if someone assumes that the object created is a good place to store state during the request. The idea of dependency injection is that a class receives a dependency (commonly an interface) and doesn't "know" anything about it at all except that it implements that interface.
另外,考虑一下您得到的 Facade
,如果每个请求都重新启动它,它将如何工作。它在初始化时是否执行任何繁重的操作?您可能需要考虑那个的 lifetimemanager。
更新
由于您使用的是 WebAPI,因此您应该可以改用 HierarchicalLifetimeManager
。
http://www.asp.net/web-api/overview/advanced/dependency-injection
The dependency resolver attached to the HttpConfiguration object has global scope. When Web API creates a controller, it calls BeginScope. This method returns an IDependencyScope that represents a child scope.
Web API then calls GetService on the child scope to create the controller. When request is complete, Web API calls Dispose on the child scope. Use the Dispose method to dispose of the controller’s dependencies.
http://www.devtrends.co.uk/blog/introducing-the-unity.webapi-nuget-package
If you are registering any components that implement IDisposable such as Entity Framework's DbContext, you will want to make sure that these components get disposed of at the end of the request. This is achieved by registering these components with a HierarchicalLifetimeManager.