gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 17:21:55 25 4
gpt4 key购买 nike

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

目前,我们正在通过执行以下操作来实现此目的:

  • Controller 有一个属性 ServiceLocator,它使用一个统一容器来解决依赖关系。
  • Controller 将 IUnityContainer 注入(inject)并分配给一个属性。
  • Controller 有一个自定义的 ActionFilterAttribute 访问 Controller 的统一容器,创建一个子容器,根据客户端和包路由参数有条件地注册依赖实现,然后将此子容器分配给 Controller 的 serviceLocator。
  • Controller 按需使用 serviceLocator 来解决各个依赖项。

  • 这行得通,但真的很笨拙,我觉得最终它将是不可持续的。我正在寻找更好的解决方案。

    我们目前停留在 .NET 4.0 上,直到我们整理了一些遗留的东西,所以我专门针对 Unity 2。

    我尝试创建一个自定义 IDependencyResolver 来创建子容器并根据将容器存储在 Session 或 HttpContext 项中的路由参数注册依赖项,但遇到了 null HttpContext 问题。有没有其他方法可以在路由上进行注册并将依赖项注入(inject)到 Controller 构造函数中?

    最终我也需要一个 Web API 的解决方案。

    编辑:示例
    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;
    }
    ...
    }

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

    最佳答案

    Abatishchev 在评论中回答了我的问题,用 IControllerFactory 为我指明了正确的方向。对于到此结束的随机谷歌搜索,这是我通过继承 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。将来,一旦我能够解决我们项目对 session 的使用,我将把它换成 HttpContext.Items。

    为了启用自定义 Controller 工厂,我将此行添加到 Bootstrapper.Initialise() 方法
    ControllerBuilder.Current
    .SetControllerFactory(new UnitySessionControllerFactory(container));

    关于c# - 基于路由参数的子容器注册,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21820521/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com