基于路由参数的子容器注册 [英] Child container registration based on route parameters

查看:123
本文介绍了基于路由参数的子容器注册的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们必须承载多个客户端预订引擎多坦ASP.NET MVC应用程序。每个客户端具有能够影响统一容器配置多个包。我们正在创建每个请求的子容器,并根据通过路由通过客户端和封装参数注册不同的接口实现

We have a multi-tennant ASP.NET MVC application that hosts a booking engine for multiple clients. Each of these clients has multiple packages that can influence Unity Container configuration. We are creating a child container per request and registering different interface implementations based on the client and package parameters passed through the route.

目前,我们正在通过以下操作完成的:

Currently we are accomplishing this by doing the following:


  1. 控制器具有使用一个统一的容器,以解决依赖属性的ServiceLocator。

  2. 控制器获取IUnityContainer注入并分配到一个属性。

  3. 控制器具有访问控制器统一容器,创建一个子容器定制ActionFilterAttribute,有条件注册基于客户端和包路由参数依赖实现,那么分配此子容器到控制器的服务定位。

  4. 控制器采用按需服务定位,以解决个人的依赖关系。

  1. Controller has a property ServiceLocator that uses a unity container to resolve dependencies.
  2. Controller gets IUnityContainer injected and assigned to a property.
  3. Controller has a custom ActionFilterAttribute that accesses the controllers unity container, creates a child container, conditionally registers dependency implementations based on client and package route parameters, then assigns this child container to the controller's serviceLocator.
  4. Controller uses serviceLocator on demand to resolve individual dependencies.

这工作,但实在是笨拙的,我觉得它最终将难以为继。我正在寻找一个更好的解决方案。

This works but is really clumsy and I feel eventually it will be unsustainable. I'm looking for a better solution.

我们正被困在.NET 4.0的那一刻,直到我们结束一些旧的东西,所以我针对统一专2

We're stuck on .NET 4.0 at the moment until we wrap up some legacy stuff so I'm targeting Unity 2 specifically.

我试图创建一个自定义的IDependencyResolver基于路由参数存储容器在任何会议或在HttpContext的项目创建子容器并注册的依赖,但跑进空HttpContext的问题。是否有任何其他方式的路线基地注册并依赖注入到控制器构造函数?

I've tried creating a custom IDependencyResolver to create the child container and register dependencies based on route parameters storing the container in either Session or in HttpContext items but ran into the null HttpContext problems. Is there any other way to base registrations on the route and have the dependencies injected to the controller constructor?

最后,我需要的Web API以及一个解决方案。

Eventually I will need a solution for Web API as well.

编辑:示例
结果

public interface IRateService { ... }
public class RemoteRateService : IRateService { ... }
public class LocalRateService : IRateService { ... }

public class CustomDependencyResolver : IDependencyResolver
{
    public object GetService(Type serviceType)
    {
        if(ChildContainer == null)
        {
            ChildContainer = _container.CreateChildContainer();
            var routeData = HttpContext.Current.Request.RequestContext.RouteData.Values;
            if(routeData["client"] == "ClientA")
                ChildContainer.RegisterType<IRateService, RemoteRateService>();
            else
                ChildContainer.RegisterType<IRateService, LocalRateService>();
        }
        return ChildContainer.Resolve(serviceType);
    }
}

public class RateController : Controller
{
    private IRateService _rateService;
    public RateController(IRateService rateService)
    {
        _rateService = rateService;
    }
    ...
}



网址:/客户端A /包1 /速率 - RateController得到RemoteRateService结果
网址:/ ClientB /包2 /速率 - RateController得到LocalRateService

url: /ClientA/Package1/Rate - RateController gets RemoteRateService
url: /ClientB/Package2/Rate - RateController gets LocalRateService

推荐答案

Abatishchev通过指着我与IControllerFactory正确的方向回答在评论我的问题。对于这里就结束了随机谷歌搜索,这里是我以前从DefaultControllerFactory继承基本设置:
搜索结果

Abatishchev answered my question in the comments by pointing me in the right direction with IControllerFactory. For the random google searches that end here, here is the basic setup I used by inheriting from DefaultControllerFactory:

public class UnitySessionControllerFactory : DefaultControllerFactory
{
    private const string HttpContextKey = "Container";
    private readonly IUnityContainer _container;

    public UnitySessionControllerFactory (IUnityContainer container)
    {
        _container = container;
    }

    protected IUnityContainer GetChildContainer(RequestContext requestContext)
    {
        var routeData = requestContext.RouteData.Values
        ?? new RouteValueDictionary();
        var clientName = routeData["clientName"] as string;
        var packageId = routeData["packageID"] as int?;

        if (clientName == null)
            throw new ArgumentException("ClientName not included in route parameters");

        var childContainer = requestContext.HttpContext.Session[clientName + HttpContextKey] as IUnityContainer;

        if (childContainer != null)
            return childContainer;

        requestContext.HttpContext.Session[clientName + HttpContextKey] = childContainer = _container.CreateChildContainer();

        var moduleLoader = childContainer.Resolve<ModuleLoader>();

        moduleLoader.LoadModules(clientName, packageId);

        return childContainer;
    }

    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
        var controllerType = GetControllerType(requestContext, controllerName);
        var container = GetChildContainer(requestContext);
        return container.Resolve(controllerType) as IController;
    }

    public override void ReleaseController(IController controller) 
    {
        _container.Teardown(controller);
    }
}

下面请原谅使用session。今后,我将换取HttpContext.Items一次我能够在我们的项目的使用session的缠斗。
搜索结果
要启用自定义控制器工厂添加此行到Bootstrapper.Initialise()方法
搜索结果

Forgive the use of session here. In the future I will exchange it for HttpContext.Items once I am able to wrangle in our project's use of session.

To enable the custom controller factory I added this line to the Bootstrapper.Initialise() method

ControllerBuilder.Current
    .SetControllerFactory(new UnitySessionControllerFactory(container));

这篇关于基于路由参数的子容器注册的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆