我正在使用 ASP.NET MVC WebApi 2 ,并使用 Unity 3 将具体类型注入控制器,这Unity MVC bootstrapper。
这里的问题是注册类型为每个解决方案初始化实体框架6 DbContext
:
public sealed class EntityFrameworkUnitOfWork : IUnitOfWork
{
internal DbContext Context { get; private set; }
public EntityFrameworkUnitOfWork()
{
Context = new SomeContext();
}
public void Commit()
{
Context.SaveChanges();
}
public void Dispose(bool disposing)
{
if (disposing)
{
if (Context != null)
{
Context.Dispose();
Context = null;
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
例如,EntityFrameworkUnitOfWork
将构造函数注入到控制器中,如下所示:
public class UserController : ApiController
{
public UsersController(IUserRepository userRepository, IUnitOfWork unitOfWork)
{
// unitOfWork is a EntityFrameworkUnitOfWork
}
// ...
}
当相关的 MVC 控制器处理完毕后,我需要在上面的Dispose()
类型中调用EntityFrameworkUnitOfWork
方法,处置基础DbContext
。
使用Unity注册此类型:
Container.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>(
new DisposingTransientLifetimeManager()
);
我正在使用DisposingTransientLifetimeManager
生命周期管理器,正如this article中所建议的那样,认为它会自动处理我的IDisposable
类型。我似乎还需要拨打Container.Teardown(someInstance)
。我无法做到这一点,因为 MVC Bootstrapper 正在处理所有DI解析。
我在哪里以及如何执行这些初始化类型的拆解?
当相关的MVC控制器破坏时执行此拆解是理想的,但也许这也可能在HTTP请求结束时发生?
修改
注入的IDisposable不一定可以从控制器访问。例如,我还可以将IUserService
注入控制器,控制器本身(IUserService
类)注入了IUserRepository
和IUnitOfWork
。我可以从IUserService
链接Dispose方法来处理它们,但这需要更改数百个控制器和服务。理想情况下,我应该可以在某个地方调用container.Dispose()
让Unity处理所有注入的一次性用品。
编辑2:
RaraituL带来了别的东西。 IUnitOfwork
未实现IDisposable
,只有EntityFrameworkUnitOfWork
。这实质上意味着MVC控制器无法调用dispose方法,因为它只知道IUnitOfWork
。这是Unity应该这样做的另一个原因 - 它创建了IDisposable,因此它也应该处理它们。
答案 0 :(得分:2)
听起来你想要一个PerRequestTransientLifetimeManager。这将是你必须要建立的东西。这并不难,因为你使用Unity 3,大部分工作已经完成了。
public class PerRequestTransientLifetimeManager : ILifetimePolicy
{
public object GetValue()
{
// will always create a new object (Transient)
return null;
}
public void SetValue(object newValue)
{
// No point in saving to http context if not disposable
if (newValue is IDisposable)
{
var perRequestLifetimeManager = new PerRequestLifetimeManager();
perRequestLifetimeManager.SetValue(newValue);
}
}
public void RemoveValue()
{
// can't remove since transient didn't keep a reference
}
}
如果缺少PerRequestLifetimeManager类,您将需要Unity.Mvc nuget包。您还需要使用Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule
注册UnityPerRequestHttpModule。我应该从MS site
指出虽然PerRequestLifetimeManager生命周期管理器可以正常工作 正确,可以帮助处理有状态或线程不安全 在HTTP请求范围内的依赖关系,通常不是 这是一个好主意,可以避免使用它,因为它可以经常导致 糟糕的做法或很难找到最终用户的应用程序代码中的错误 使用不当时。建议依赖你 寄存器是无状态的,如果需要共享共同状态 然后,在HTTP请求的生命周期中,在几个对象之间 您可以拥有明确存储和检索的无状态服务 此状态使用Current对象的Items集合。
答案 1 :(得分:1)
您可以在已经引用的相同NuGet包中使用UnityHierarchicalDependencyResolver
(Unity.AspNet.WebApi)。然后使用HierarchicalLifetimeManager
注册您要处理的服务。此依赖项解析程序在每个Web Api请求上创建并处置新的子容器。放置Unity容器时,该容器中的所有构建对象也将被丢弃。
IUnityContainer rootContainer = new UnityContainer();
GlobalConfiguration.Configuration.DependencyResolver =
new UnityHierarchicalDependencyResolver(rootContainer);
rootContainer.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>
(new HierarchicalLifetimeManager());