Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 基于路由参数的子容器注册_C#_Asp.net Mvc_Dependency Injection_Unity Container - Fatal编程技术网

C# 基于路由参数的子容器注册

C# 基于路由参数的子容器注册,c#,asp.net-mvc,dependency-injection,unity-container,C#,Asp.net Mvc,Dependency Injection,Unity Container,我们有一个multi-tennant ASP.NET MVC应用程序,为多个客户端托管一个预订引擎。每个客户端都有多个包,这些包可能会影响Unity容器配置。我们正在为每个请求创建一个子容器,并根据通过路由传递的客户端和包参数注册不同的接口实现 目前,我们正在通过以下方式实现这一目标: 控制器有一个属性ServiceLocator,它使用unity容器来解析依赖项 控制器将IUnityContainer注入并分配给属性 控制器具有自定义ActionFilterAttribute,该属性访问控制器

我们有一个multi-tennant ASP.NET MVC应用程序,为多个客户端托管一个预订引擎。每个客户端都有多个包,这些包可能会影响Unity容器配置。我们正在为每个请求创建一个子容器,并根据通过路由传递的客户端和包参数注册不同的接口实现

目前,我们正在通过以下方式实现这一目标:

  • 控制器有一个属性ServiceLocator,它使用unity容器来解析依赖项
  • 控制器将IUnityContainer注入并分配给属性
  • 控制器具有自定义ActionFilterAttribute,该属性访问控制器unity容器,创建子容器,根据客户端和包路由参数有条件地注册依赖项实现,然后将该子容器分配给控制器的serviceLocator
  • 控制器按需使用serviceLocator来解析各个依赖项
  • 这是可行的,但真的很笨拙,我觉得最终它将是不可持续的。我在寻找更好的解决办法

    目前,我们仍停留在.NET4.0上,直到我们总结了一些遗留的东西,所以我特别针对Unity2

    我尝试创建一个定制的IDependencyResolver来创建子容器,并根据将容器存储在会话或HttpContext项中的路由参数注册依赖项,但遇到了空HttpContext问题。是否有其他方法可以基于路由注册,并将依赖项注入控制器构造函数

    最后,我还需要一个Web API解决方案

    编辑:示例

    公共接口IRateService{…}
    公共类RemoteRateService:IRateService{…}
    公共类LocalRateService:IRateService{…}
    公共类CustomDependencyResolver:IDependencyResolver
    {
    公共对象GetService(类型serviceType)
    {
    if(ChildContainer==null)
    {
    ChildContainer=_container.CreateChildContainer();
    
    var routeData=HttpContext.Current.Request.RequestContext.routeData.Values; 如果(路由数据[“客户端”]=“客户端”) RegisterType(); 其他的 RegisterType(); } 返回ChildContainer.Resolve(服务类型); } } 公共类速率控制器:控制器 { 私人伊拉克服务(rateService);; 公共费率控制员(IRateService费率服务) { _rateService=rateService; } ... }
    url:/ClientA/Package1/Rate-RateController获取RemoteRateService

    url:/ClientB/Package2/Rate-RateController获取LocalRateService

    Abatishchev通过IControllerFactory为我指出了正确的方向,回答了我在评论中提出的问题。对于此处结束的随机google搜索,以下是我从DefaultControllerFactory继承使用的基本设置:


    实现
    IDependencyResolver
    还有什么问题?这是正确的方法。您是否也尝试过
    IControllerFactory
    ?向控制器构造函数注入不同的实现是我试图实现的。我在我的帖子中加入了一个例子。当我尝试在CustomDependencyResolver.IControllerFactory中访问RouteData时,它为空。我将进一步研究它。HttpContext.Current.Request.RequestContext.RouteData.Values(“MS_DirectRouteMatches”)?(0)?。Values?(“clientName”)很高兴您找到了解决方案!顺便问一下,为什么要动态创建一个容器,而不是?作为
    IDependencyResolver
    的参考实现,可以对您有所帮助。另请参阅并感谢您的签入,我不确定使用命名类型解析是什么意思。您的意思是在应用程序启动时为每个客户端创建子容器吗?我们有400多个不同的客户端,每个客户端的配置可能不同。这是为了避免预先预测每一种不同的排列方式,并且让我们的新开发人员添加特性,而不必过多地处理依赖项注册。Unity3和MVC5有一些我们期待的功能,但在我们完成一些遗留代码之前,我们目前只能停留在.NET4.0上。哦,我明白了。那么我的解决方案在这里就行不通了。感谢您的澄清,您的案例和解决方案令我非常感兴趣。
    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;
        }
        ...
    }
    
    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);
        }
    }
    
    ControllerBuilder.Current
        .SetControllerFactory(new UnitySessionControllerFactory(container));