C# 基于路由参数的子容器注册
我们有一个multi-tennant ASP.NET MVC应用程序,为多个客户端托管一个预订引擎。每个客户端都有多个包,这些包可能会影响Unity容器配置。我们正在为每个请求创建一个子容器,并根据通过路由传递的客户端和包参数注册不同的接口实现 目前,我们正在通过以下方式实现这一目标: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,该属性访问控制器
公共接口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获取RemoteRateServiceurl:/ClientB/Package2/Rate-RateController获取LocalRateServiceAbatishchev通过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));