Autofac разрешить внедрение сервиса при регистрации

Я пытаюсь поместить код в одном месте для разрешения служб Keyed с помощью Autofac.

У меня есть интерфейс:

public interface IShipManagerService { }

Две реализации:

public class InventoryShipManagerService : IShipManagerService
{

}

public class DemandShipManagerService : IShipManagerService
{

}

У меня также есть UserProfileService, в котором содержится некоторая информация о сеансе:

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

public enum OrderType {Inventory, Demand}

Обычно пользователь переключает "режимы" упорядочивания, и я сохраняю это в сессии.

То, что я пытаюсь сделать, это решить правильную реализацию 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 (используя шаблон Service Locator). Однако - я считаю, что проще и проще поддерживать код разрешения службы в одном месте моего приложения, а не определять правильный тип в компонентах, использующих службы.

  2. Это - пока это работает - кажется уродливым. Есть ли способ использовать разрешение службы Keyed? Другими словами, зарегистрируйте обе службы и разрешите автофаку разрешить правильную реализацию службы ResolveKeyed(OrderType) на основе разрешенного ProfileService.OrderingMode?

Я более или менее пытаюсь подтвердить свой подход здесь. Буду признателен за лучший способ, если у кого-то есть.

ОБНОВИТЬ

Я пытаюсь использовать

IIndex<T,V> 

который рекомендует Autofac.

Я чувствую себя так близко - но я получаю услугу незарегистрированным исключением.

        _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 ответ

Решение

Понял.

Оказывается, у меня было две вещи неправильно.

  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 (так как режим упорядочения является перечислением, и он не был установлен сеансом пользователя, он устанавливается в ноль).

Сверху я зарегистрировал только два ключевых сервиса 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 сервисов, которые станут зависимыми от контекста в зависимости от того, что делает пользователь. Это делает управление разрешением того, какой сервис предоставляется пользователю, чистым и обслуживаемым.

Все разрешенные службы будут корректными в зависимости от того, в каком режиме находится пользователь, и мне не нужно проверять его в контроллерах.

Я надеюсь, что кто-то еще может найти применение этому.

Другие вопросы по тегам