Autofac在注册期间解决服务实施

时间:2016-06-20 16:37:42

标签: dependency-injection autofac service-locator

我正在尝试将代码放在一个地方,以便使用Autofac解析Keyed服务。

我有一个界面:

public interface IShipManagerService { }

两个实现:

public class InventoryShipManagerService : IShipManagerService
{

}

public class DemandShipManagerService : IShipManagerService
{

}

我还有一个UserProfileService,其中包含一些会话信息:

public interface IUserProfileService 
{
    OrderType OrderingMode {get;set;}
}

public enum OrderType {Inventory, Demand}

基本上,用户切换订购“模式”,并将其保留在会话中。

我要做的是使用Keyed注册解决IShipManagerService的正确实现 - 但我想把它放在一个位置。

我有这个:

builder.RegisterType<InventoryShipManagerService>()
   .As<IShipManagerService>().Keyed<OrderType>(OrderType.Inventory);

builder.RegisterType<InventoryShipManagerService>()
   .As<IShipManagerService>().Keyed<OrderType>(OrderType.Inventory);

解析将使用Autofac推荐的IIndex

private readonly IShipManagerService _shipManagerService;
private readlony IUserProfileService _profileService;

public class ShipToController
{

     public ShipToController(IUserProfileService profileService, IIndex<OrderType, IShipManagerService> shipManagerList)
     {
         _profileService = profileService;
         _shipManagerService = shipManagerList[_profileService.OrderType];
     }

这样可行 - 但我不想把它放在我使用IShipManagerService的任何地方(还有其他服务属于这个类别) - 我的控制器构造函数会很快变得混乱。

我希望做的是这样的事情(我有这个工作)

builder.Register(ctx =>
   {
       //so I can get the current "Ordering Mode"
       var profileService = ctx.Resolve<IUserProfileService>(); 

       //Default to Inventory
       IShipManagerService service = (Inventory)Activator.CreateInstance(typeof(InventoryShipManagerService),
          ctx.Resolve<IRepository>(),
          ctx.Resolve<IShoppingCartService>()) as IShipManagerService;

       switch (profileService.OrderingMode)
       {
            case OrderingMode.Demand:
               //if demand is "on"
               service = (DemandShipManagerService)Activator.CreateInstance(typeof(DemandShipManagerService),
                   ctx.Resolve<IRepository>(),
                   ctx.Resolve<IShoppingCartService>()) as IShipmanagerService;
       }

       return service;
    }

这里有两件事。

  1. 这有效,我知道这不是Autofac推荐的(使用服务定位器模式)。但是 - 我认为将服务解析代码放在我的应用程序的一个位置更清晰,更容易维护 - 而不是使用服务解析组件中的正确类型。

  2. 这 - 虽然它有效 - 看起来很难看。有没有办法可以使用Keyed服务解析?换句话说,注册两个服务并让autofac根据已解析的ProfileService.OrderingMode解析ResolveKeyed(OrderType)的正确服务实现?

  3. 我或多或少想在这里验证我的方法。如果有人拥有它,我会感激更好的方式。

    更新

    我正在尝试使用

    IIndex<T,V> 
    

    Autofac recommends

    我觉得我很亲密 - 但我得到的服务没有注册例外。

            _builder.RegisterType<TShelfShipToManagerService>().Keyed<IShipToManagerService>(OrderType.Shelf);
    
            _builder.RegisterType<TDemandShipToManagerService>().Keyed<IShipToManagerService>(OrderType.Demand);
    
            _builder.Register(ctx =>
            {
                var profileService = ctx.Resolve<IUserProfileService>();
    
                //The way Autofac recomends
                var services = ctx.Resolve<IIndex<OrderType, IShipToManagerService>>();
    
                //I get Component not Registered here??????
                return services[profileService.OrderingType];
    
    
                //this will go away if I can get the code above to work                
                IShipToManagerService service = Activator.CreateInstance(typeof(TShelfShipToManagerService),
                     ctx.Resolve<IRepository>(),
                     ctx.Resolve<IIntegrationService>(),
                     ctx.Resolve<IShoppingCartService>(),
                     ctx.Resolve<IUserProfileService>()
                     ) as IShipToManagerService;
    
                switch (profileService.OrderingType)
                {
                    case OrderType.Demand:
                        service = Activator.CreateInstance(typeof(TDemandShipToManagerService),
                            ctx.Resolve<IRepository>(),
                            ctx.Resolve<IIntegrationService>(),
                            ctx.Resolve<IShoppingCartService>(),
                            ctx.Resolve<IUserProfileService>()) as IShipToManagerService;
                        break;
                }
    
                return service;
            }).As<IShipToManagerService>();
    

    我不知道为什么这不起作用。

1 个答案:

答案 0 :(得分:0)

弄清楚了。

原来我错了两件事。

  1. 我从未使用要解决的接口注册服务。

        _builder.RegisterType<TShelfShipToManagerService>()
            .Keyed<IShipToManagerService>(OrderType.Shelf)
            .As<IShipToManagerService>();  //was missing that part
    
        _builder.RegisterType<TDemandShipToManagerService>()
            .Keyed<IShipToManagerService>(OrderType.Demand)
            .As<IShipToManagerService>();  //was missing that part
    
  2. 该方法假定订购模式可从UserProfile服务获得。我有足够的异常处理来确保它们是默认的UserProfile服务(对于启动和用户登录之前没有任何东西)。问题是我试图解决一个排序模式为0的键控服务(因为订购模式是一个枚举,它没有被用户会话设置,它被设置为零)。

  3. 从上面我只注册了两个键控服务OrderType.Shelf和OrderType.Demand - 所以当

           _builder.Register(ctx =>
            {
                var profileService = ctx.Resolve<IUserProfileService>();
    
    
                //The way Autofac recomends
                var services = ctx.Resolve<IIndex<OrderType, IShipToManagerService>>();
    
                //The first request ends up with an OrderingType == 0
                //Since I haven established the session 
                //I don't have service registered with a key 0
                return services[profileService.OrderingType];
            }).As<IShipToManagerService>();
    

    所以修复只是检查OrderingType == 0 - 如果是 - 然后使用默认设置。

    这里我有一个AppSettingService,它提供一个全局设置DefaultOrderingMode。

            _builder.Register(ctx =>
            { var profileService = ctx.Resolve<IUserProfileService>();
    
                //Check to see if their is a user profile (OrderType = 0) 
                //if not - then get the default setting
                if (profileService.OrderingType == 0)
                {
                    var appSettingService = ctx.Resolve<IApplicationSettingService>();
    
                    profileService.OrderingType = appSettingService.GetApplicationSetting(ApplicationSettings.DefaultOrderingMode).ToEnumTypeOf<OrderType>();
                }
                //The way Autofac recomends
                var services = ctx.Resolve<IIndex<OrderType, IShipToManagerService>>();
                return services[profileService.OrderingType];
    
            }).As<IShipToManagerService>();
    

    这是我想要实现的目标。

    我有大约10项服务将成为&#34; context&#34;依赖于用户正在做什么。这使得管理给予用户的服务的分辨率是清洁和可维护的。

    根据用户所处的模式,所有已解决的服务都是正确的,我不需要在控制器中检查它。

    我希望其他人可以使用这个。