Asp.net mvc 基于运行时会话值从Autofac解析服务实现

Asp.net mvc 基于运行时会话值从Autofac解析服务实现,asp.net-mvc,runtime,autofac,dependency-resolution,Asp.net Mvc,Runtime,Autofac,Dependency Resolution,需要一些帮助来解决问题,在运行时基于参数解决服务的实现。换句话说,使用带有DI的工厂模式 我们已将Autofac连接到MVC应用程序。我试图弄清楚如何使用用户会话变量(称之为排序类型)用于依赖项解析器来解析服务的正确实现 我们正在尝试做的一个例子 该应用程序有两种“类型”的订购-真正的电子商务类型的订购(将物品添加到购物车、结帐等) 另一种称为预测排序。用户创建订单,但他们不会立即得到满足。他们通过审批流程,然后完成 底线是数据模式和后端系统,应用程序根据订单类型进行更改 我想做的是: 我有管理

需要一些帮助来解决问题,在运行时基于参数解决服务的实现。换句话说,使用带有DI的工厂模式

我们已将Autofac连接到MVC应用程序。我试图弄清楚如何使用用户会话变量(称之为排序类型)用于依赖项解析器来解析服务的正确实现

我们正在尝试做的一个例子

该应用程序有两种“类型”的订购-真正的电子商务类型的订购(将物品添加到购物车、结帐等)

另一种称为预测排序。用户创建订单,但他们不会立即得到满足。他们通过审批流程,然后完成

底线是数据模式和后端系统,应用程序根据订单类型进行更改

我想做的是:

  • 我有管理服务

    public interface IOrderManagerService
    {
          Order GetOrder(int orderNumber);
          int CreateOrder(Order order);
    }
    
  • 因为我们有两种排序“类型”——我有两种IOrderManagerService的实现:

    public class ShelfOrderManager : IOrderManagerService
    {
        public Order GetOrder(int orderMumber)
        {
             ...code
        }
    
        public int CreateOrder(Order order)
        {
            ...code
        }
    }
    
  • 我的第一个问题是——在我的MVC应用程序中——我是否将这些实现注册为

    builder.RegisterType<ShelfOrderManager>().As<IOrderManagerService>();
    builder.RegisterType<ForecastOrderManager>().As<IOrderManagerService>();
    
  • 我已经准备好了,并且很好地解释了这个概念

    问题是运行时参数用于构造服务并在运行时解析。i、 e

         var service = resolvedServiceClass.Factory("runtime parameter")
    
    所有这些都将为我提供在构造函数中使用“运行时参数”的“服务”

    我也看过决议

    起初我认为我可以将这两种技术结合起来,但是控制器依赖于接口,而不是具体的实现。(应该如此)


    任何关于如何避开这一问题的想法都将非常感谢

    我不会为此依赖Autofac。IOC用于解决依赖关系并为其提供实现,您需要的是基于决策标志调用同一接口的不同实现

    我基本上会使用一个简单的工厂,比如一个有两个静态方法的类,当你知道决定是什么时,调用你需要的任何实现。这将为您提供所需的运行时解析器。我想说,保持简单


    尽管如此,似乎还有另一种选择。看看“按上下文选择”选项,也许你可以重新设计你的类来利用这一点:

    ,因为事实证明我们很接近@安德烈对我们所做的一切很满意。我将为下一个遇到这个问题的人解释下面的答案

    为了重述这个问题,我需要在运行时使用Autofac解决接口的具体实现。这通常由工厂模式解决,但我们已经实现了DI

    解决方案是两者兼用。使用Autofac支持,我创建了一个简单的factory类

    我选择私下解决组件上下文

       DependencyResolver.Current.GetService<IComponentContext>();
    
    在构造函数中使用-我将用ServiceFactory.Factory替换它。我不想在需要工厂的地方也包括IComponentContext

    enum OrderType 
    {
        Shelf,
        Forecast
     }
    
    public class ServiceFactory : IServiceFactory
    {
        private readonly IComponentContext _componentContext;
        private readonly OrderType _orderType;
        public ServiceFactory(OrderType orderingType)
        {
            _componentContext = DependencyResolver.Current.GetService<IComponentContext>();
            _orderType = orderingType;
        }
    
        public delegate ServiceFactory Factory(OrderType orderingType);
    
        public T Resolve<T>()
        {
            if(!_componentContext.IsRegistered<T>())
                return _componentContext.ResolveNamed<T>(_orderType.ToString());
    
            return _componentContext.Resolve<T>();
        }
    }
    
    密钥服务的注册:

            //register the shelf implementation
            builder.RegisterType<ShelfOrderManager>()
                .Keyed(OrderType.Shelf)
                .As<IOrderManager>();
    
            //register the forecast implementation
            builder.RegisterType<ForecastOrderManager>()
                .Keyed(OrderType.Shelf)
                .As<IOrderManager>();
    
    //注册工具架实现
    builder.RegisterType()
    .Keyed(OrderType.Shelf)
    .As();
    //注册预测实现
    builder.RegisterType()
    .Keyed(OrderType.Shelf)
    .As();
    
    注册工厂:

     builder.RegisterType<IMS.POS.Services.Factory.ServiceFactory>()
                .AsSelf()
                .SingleInstance();
    
    builder.RegisterType()
    .AsSelf()
    .SingleInstance();
    
    最后,在控制器(或任何其他类)中使用它:

    公共类HomeController:BaseController
    {
    私有只读IContentManagerService_contentManagerService;
    私有只读IViewModelService_viewModelService;
    私有只读IApplicationSettingService\u applicationSettingService;
    专用只读IOrderManagerService(U orderManagerService);
    私有只读设备工厂;
    公共家庭控制器(ServiceFactory.Factory,
    IViewModelService viewModelService,
    IContentManagerService内容管理器服务,
    IAApplicationSettingService应用程序设置服务)
    {
    //首先分配工厂
    //我们在会话中保留用户排序类型-如果未设置该值-默认为Shelf Ordering
    _工厂=工厂(UIUserSession?.OrderingMode?OrderType.Shelf);
    //现在我有了一个工厂来实现我所需要的
    _orderManagerService=_factory.Resolve();
    //其余问题由Autofac解决
    _contentManagerService=contentManagerService;
    _viewModelService=viewModelService;
    _applicationSettingService=applicationSettingService;
    }
    }
    

    我想对Resolve方法进行更多的处理—但对于第一次测试,这是可行的。一点工厂模式(在我们需要的地方),但仍然使用Autofac来完成大部分工作

    有趣的是,我的一位开发人员在我们完成了这个概念后发现了这一点。不完全一样,但非常接近。我们的控制器构造器可以处理很多依赖的服务——我想我会坚持使用ServiceFactory.Factory和func Factory来处理每个需要一次性解决的服务。
    enum OrderType 
    {
        Shelf,
        Forecast
     }
    
    public class ServiceFactory : IServiceFactory
    {
        private readonly IComponentContext _componentContext;
        private readonly OrderType _orderType;
        public ServiceFactory(OrderType orderingType)
        {
            _componentContext = DependencyResolver.Current.GetService<IComponentContext>();
            _orderType = orderingType;
        }
    
        public delegate ServiceFactory Factory(OrderType orderingType);
    
        public T Resolve<T>()
        {
            if(!_componentContext.IsRegistered<T>())
                return _componentContext.ResolveNamed<T>(_orderType.ToString());
    
            return _componentContext.Resolve<T>();
        }
    }
    
    public interface IOrderManagerService
    {
        Order GetOrder(int orderNumber);
    
        int CreateOrder(Order order);
    }
    
    public class ShelfOrderManager : IOrderManagerService
    {
        public Order GetOrder(int orderNumber)
        {
            ...
        }
    
        public int CreateOrder(Order order)
        {
            ...
        }
    }
    
    public class ForecastOrderManager : IOrderManagerService
    {
        public Order GetOrder(int orderNumber)
        {
            ...
        }
    
        public int CreateOrder(Order order)
        {
           ...
        }
    }
    
            //register the shelf implementation
            builder.RegisterType<ShelfOrderManager>()
                .Keyed(OrderType.Shelf)
                .As<IOrderManager>();
    
            //register the forecast implementation
            builder.RegisterType<ForecastOrderManager>()
                .Keyed(OrderType.Shelf)
                .As<IOrderManager>();
    
     builder.RegisterType<IMS.POS.Services.Factory.ServiceFactory>()
                .AsSelf()
                .SingleInstance();
    
    public class HomeController : BaseController
    {
        private readonly IContentManagerService _contentManagerService;
        private readonly IViewModelService _viewModelService;
        private readonly IApplicationSettingService _applicationSettingService;
        private readonly IOrderManagerService _orderManagerService;
        private readonly IServiceFactory _factory;
    
        public HomeController(ServiceFactory.Factory factory,
                                        IViewModelService viewModelService, 
                                        IContentManagerService contentManagerService, 
                                        IApplicationSettingService applicationSettingService)
        {
            //first assign the factory
            //We keep the users Ordering Type in session - if the value is not set - default to Shelf ordering
            _factory = factory(UIUserSession?.OrderingMode ?? OrderType.Shelf);
    
            //now that I have a factory to get the implementation I need
            _orderManagerService = _factory.Resolve<IOrderManagerService>();
    
            //The rest of these are resolved by Autofac
            _contentManagerService = contentManagerService;
            _viewModelService = viewModelService;
            _applicationSettingService = applicationSettingService;
    
        }
    }