如何基于web应用程序URL为Unity容器动态注册类型(例如,不同的实现)
本文关键字:例如 类型 实现 注册 动态 应用程序 web 何基于 URL Unity | 更新日期: 2023-09-27 18:26:28
目前我陷入了一个我认为是简单架构问题的困境。
我有一个控制器(这些只是例子,因为我不能分享我的真实代码,但原理成立):
public class StackOverflowController : Controller
{
private readonly IStackOverflowService stackOverflowService;
public StackOverflowService (IStackOverflowService stackOverflowService)
{
this.stackOverflowService = stackOverflowService;
}
// GET: StackOverflow
public ActionResult Index()
{
var foo = stackOverflowService.Get(bar);
return View(foo);
}
}
我正在使用Unity MVC4引导程序来管理注射:
public static class Bootstrapper
{
public static IUnityContainer Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
container.RegisterType<IStackOverflowService, StackOverflowService>("DefaultStackOverflowService");
return container;
}
}
到目前为止,注射效果很好。我现在陷入困境的是,基于配置或一些变量,我希望能够更改StackOverflowService
的实现。
因此,例如,如果url="somethingelse.com",我希望能够自动注入从IStackOverflow Service继承的CustomStackOverflow服务。但这就是我迷路的地方。我尝试过使用命名注册,但似乎不知道如何根据一些替代标准手动解析要实现的正确服务。
如果有人能帮忙,那将是史诗般的:)
编辑:理想情况下,实现更改的标准将实时计算出来,比如说,基于当前访问的实际url。这是一个多租户环境,因此可能类似于domain.com/stackoverflow
和domain2.com/stackoverflow.
。每个站点的实现需要有所不同。我甚至不知道这是否可能是诚实的,也不知道如何做到这一点。我对IoC这门学科还相当陌生。
EDIT2:我对此做了进一步的了解,并设法手动调用了一个特定的实现。我现在正在考虑使用自定义控制器工厂来解决要使用的实现,但我不确定这是否是正确的方法,或者是否有更简单的方法。
我需要记住,随着越来越多的客户加入,我需要能够为每个新客户快速添加更多的实现。因此,理想情况下,我会有一些简单的方法来管理特定客户端的方法。
EDIT 3:进一步更新,我已经重写了我的控制器,允许注入构造函数来确定依赖关系。然而,我最初的问题仍然有效,因为这是在构建控制器时触发的,我没有访问请求的权限,因此无法确定URL来解决依赖关系。任何想法都将不胜感激。
使用IControllerFactory和子容器应该可以工作,但会将MVC依赖解析程序紧密耦合到Unity。
首先更改引导程序,为每个域创建一个子容器,并为每个子容器配置该域所需的特殊注册。另外,我们需要告诉MVC,我们有一个IControllerFactory,我们想使用
public class Bootstrapper
{
public static IUnityContainer Initialize()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// Register unity controller factory to resolve controllers
container.RegisterType<IControllerFactory, UnityControllerFactory>();
// default registrations
container.RegisterType<IStackOverFlowService, StackOverflowService>();
// Do special registration per domain
LocalHostRegistrations(container);
SomeThingElseRegistrations(container);
return container;
}
private static void LocalHostRegistrations(IUnityContainer container)
{
// you can create a child container per domain
var localHostContainer = container.CreateChildContainer();
// all special registrations for localhost go in this container
// any registrations that are the same as the default we can leave off and unity will
// auto find them from the parent
localHostContainer.RegisterType<IStackOverFlowService, LocalHostStackOverflowService>();
// register the child container in the parent container with a registration name
container.RegisterInstance(typeof(IUnityContainer), "localhost", localHostContainer);
}
private static void SomeThingElseRegistrations(IUnityContainer container)
{
var localHostContainer = container.CreateChildContainer();
localHostContainer.RegisterType<IStackOverFlowService, CustomStackOverflowService>();
container.RegisterInstance(typeof(IUnityContainer), "somethingelse", localHostContainer);
}
}
现在我们创建控制器工厂
public class UnityControllerFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
IController controller = null;
var type = GetControllerType(requestContext, controllerName);
if (type != null)
{
// read host from incoming url
var domain = requestContext.HttpContext.Request.Url.Host.ToLower();
// get parent unity container
var container = DependencyResolver.Current.GetService<IUnityContainer>();
// check if there is a child container for this domain
if (container.IsRegistered<IUnityContainer>(domain))
{
container = container.Resolve<IUnityContainer>(domain);
}
controller = container.Resolve(type) as IController;
}
// if didn't find type or not right type just pass into base to handle errors
if (controller == null)
{
return base.CreateController(requestContext, controllerName);
}
return controller;
}
}
该工厂将从MVC依赖解析程序中检索父统一容器,并查看是否注册了任何子容器。如果是这样,它将使用子容器来解析控制器,并注入子容器特有的任何注册。这确实将统一容器与MVC的依赖解析程序紧密耦合,并且是通过传递依赖解析程序并直接使用统一来实现的,但应该会为您提供所需的内容。