如何基于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/stackoverflowdomain2.com/stackoverflow.。每个站点的实现需要有所不同。我甚至不知道这是否可能是诚实的,也不知道如何做到这一点。我对IoC这门学科还相当陌生。

EDIT2:我对此做了进一步的了解,并设法手动调用了一个特定的实现。我现在正在考虑使用自定义控制器工厂来解决要使用的实现,但我不确定这是否是正确的方法,或者是否有更简单的方法。

我需要记住,随着越来越多的客户加入,我需要能够为每个新客户快速添加更多的实现。因此,理想情况下,我会有一些简单的方法来管理特定客户端的方法。

EDIT 3:进一步更新,我已经重写了我的控制器,允许注入构造函数来确定依赖关系。然而,我最初的问题仍然有效,因为这是在构建控制器时触发的,我没有访问请求的权限,因此无法确定URL来解决依赖关系。任何想法都将不胜感激。

如何基于web应用程序URL为Unity容器动态注册类型(例如,不同的实现)

使用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的依赖解析程序紧密耦合,并且是通过传递依赖解析程序并直接使用统一来实现的,但应该会为您提供所需的内容。

相关文章: