我正在尝试将代码放在一个地方,以便使用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;
}
这里有两件事。
这有效,我知道这不是Autofac推荐的(使用服务定位器模式)。但是 - 我认为将服务解析代码放在我的应用程序的一个位置更清晰,更容易维护 - 而不是使用服务解析组件中的正确类型。
这 - 虽然它有效 - 看起来很难看。有没有办法可以使用Keyed服务解析?换句话说,注册两个服务并让autofac根据已解析的ProfileService.OrderingMode解析ResolveKeyed(OrderType)的正确服务实现?
我或多或少想在这里验证我的方法。如果有人拥有它,我会感激更好的方式。
更新
我正在尝试使用
IIndex<T,V>
我觉得我很亲密 - 但我得到的服务没有注册例外。
_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>();
我不知道为什么这不起作用。
答案 0 :(得分:0)
弄清楚了。
原来我错了两件事。
我从未使用要解决的接口注册服务。
_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
该方法假定订购模式可从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项服务将成为&#34; context&#34;依赖于用户正在做什么。这使得管理给予用户的服务的分辨率是清洁和可维护的。
根据用户所处的模式,所有已解决的服务都是正确的,我不需要在控制器中检查它。
我希望其他人可以使用这个。