在多个MVC区域中使用多个Unity IOC容器

时间:2015-05-29 08:50:53

标签: asp.net-mvc asp.net-mvc-5 inversion-of-control unity-container asp.net-mvc-areas

情况:我有多个MVC区域,我想在每个应该独立工作的区域设置统一IOC(UnityConfig.cs)。

问题:IOC容器会覆盖自己。

问题:如何使每个区域的容器独一无二? 或者如何从区域中将RegisterType项添加到现有容器(例如在根网站中)?

提前致谢,

Mogica

区域1

public static void RegisterTypes(IUnityContainer container)
{
    container.RegisterType<DbContext, CmsContext>(new HierarchicalLifetimeManager());
    container.RegisterType<IUnitOfWork, UnitOfWork>();
    container.RegisterType<ISiteRepository, SiteRepository>();
    container.RegisterType<IPageRepository, PageRepository>();
    container.RegisterType<IViewRepository, ViewRepository>();
}

区域2

public static void RegisterTypes(IUnityContainer container)
{
    container.RegisterType<IPostRepository, PostRepository>();
}

Area3中

public static void RegisterTypes(IUnityContainer container)
{
    container.RegisterType<IJobRepository, JobRepository>();
}

1 个答案:

答案 0 :(得分:2)

如果您希望通过为每个隔离的部件提供不同的容器实例(通过有效地使每个区域成为模块)来隔离应用程序的部分,则必须拦截控制器的创建并将其分派到正确区域的容器中。

通过实施自定义IControllerFactory来拦截控制器的创建。这样的实现可能如下所示:

public class PerAreaControllerFactoryComposite : IControllerFactory {
    private IDictionary<string, IControllerFactory> areaControllerFactories;

    public PerAreaControllerFactoryComposite(
        IDictionary<string, IControllerFactory> areaControllerFactories) {
        this.areaControllerFactories = areaControllerFactories;
    }

    public IController CreateController(RequestContext requestContext,
        string controllerName) {
        var factory = this.FindFactory(requestContext);
        var controller = factory.CreateController(requestContext, controllerName);
        HttpContext.Current.Items["Factory_" + controller.GetType().Name] = factory;

        return controller;
    }

    public void ReleaseController(IController controller) {
        var factory = HttpContext.Current.Items["Factory_" + controller.GetType().Name]
            as IControllerFactory;

        factory.ReleaseController(controller);
    }

    public SessionStateBehavior GetControllerSessionBehavior(
        RequestContext requestContext, string controllerName) {
        var factory = this.FindFactory(requestContext);
        return factory.GetControllerSessionBehavior(requestContext, controllerName);
    }

    private IControllerFactory FindFactory(RequestContext context) {
        string area = context.RouteData.DataTokens["area"].ToString();
        return this.areaControllerFactories[area];
    }
}

IControllerFactory实现接受带有IControllerFactory实现集合的字典,其中字典的键是区域的名称。调用CreateController时,它将确定当前区域并将调用转发给该区域的IControllerFactory实施。

您可以按如下方式创建此实现:

var factory = new PerAreaControllerFactoryComposite(new Dictionary
{
    { "Area1", new UnityControllerFactory(area1Container) },
    { "Area2", new UnityControllerFactory(area2Container) },
    { "Area3", new UnityControllerFactory(area3Container) },
});

ControllerBuilder.Current.SetControllerFactory(factory);

Unity集成包可能缺少UnityControllerFactory,但创建一个将是微不足道的(您可以简单地从DefaultControllerFactory派生。)

请注意,在一个应用程序中运行隔离的模块会带来额外的开发开销,因此应用程序的大小必须证明其合理性。有多个容器实例使您的注册变得复杂,因此通常最好不要这样做。