使用Unity MVC引导程序拆分注入的类型

时间:2014-05-15 09:53:41

标签: c# asp.net-mvc asp.net-mvc-4 asp.net-mvc-5 unity-container

我正在使用 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类)注入了IUserRepositoryIUnitOfWork。我可以从IUserService链接Dispose方法来处理它们,但这需要更改数百个控制器和服务。理想情况下,我应该可以在某个地方调用container.Dispose()让Unity处理所有注入的一次性用品。

编辑2:

RaraituL带来了别的东西。 IUnitOfwork未实现IDisposable,只有EntityFrameworkUnitOfWork。这实质上意味着MVC控制器无法调用dispose方法,因为它只知道IUnitOfWork。这是Unity应该这样做的另一个原因 - 它创建了IDisposable,因此它也应该处理它们。

2 个答案:

答案 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());