我有以下注册码:
private static IContainer BuildContainer()
{
var builder = new ContainerBuilder();
// current assembly
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
...
builder.Register(c => new UserSettings(_connectionString)).As<IUserSettings>().**InstancePerLifetimeScope**();
...
var container = builder.Build();
**CommonServiceLocator.ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container));**
return container;
}
我还使用 Microsoft 的 CommonServiceLocator 来处理一种边缘情况。在“OnActionExecuting”函数中,我设置了 IUserSettings 中的属性之一:
public override void OnActionExecuting(HttpActionContext actionContext)
{
...
var userSettings = actionContext.Request.GetDependencyScope().GetService(typeof(IUserSettings)) as IUserSettings;
**userSettings.Test = 123;**
}
在整个 MVC 应用程序和一些库(它们是 MVC 应用程序依赖项)中,我可以解析 IUserSettings 的相同对象 - 如果我通过构造函数使用经典 DI。但是当我尝试通过全局服务定位器解析它时:
var settings = ServiceLocator.Current.GetInstance<IUserSettings>();
我得到了 IUserSettings 的一个新实例,而不是请求附带的初始实例。单例实例工作正常,但注册为“InstancePerLifetimeScope”的实例则不行。
有人知道我做错了什么吗?有没有办法使用全局“ServiceLocator”解析 IUserSettings 的同一实例?
简短的版本是:你无法[轻易]做你想做的事。
如果您还记得您的生命周期范围知识,基于请求的应用程序中的生命周期范围是分层的。
ServiceLocator
通常卡在这里。
如果您将某些内容注册为
InstancePerLifetimeScope
,它将在每个“存储桶”中创建一个。
ServiceLocator
所做的那样),您将在那里获得一个实例。但是
ServiceLocator
和请求生命周期范围之间没有“联系”。
AutofacDependencyResolver
确实有一个Current
属性,可以让您获取请求生命周期范围,但请注意,这仅在网络请求的上下文中起作用 - 如果您执行异步操作并且请求在你的工作完成之前结束,该解析器将从你的身下消失。
DI 在很大程度上是“病毒式”的。如果您从 DI 切换到服务位置,您就打破了模式,并且需要一些变通方法和黑客技术。我知道有时这是必需的,只是,当您从一种切换到另一种时,您不会获得尽可能多的“开箱即用”和“正常工作”,显然,这就是正在发生的情况。如果您能坚持使用 DI 并允许根据需要注入请求服务,并且尽可能不通过服务位置,您的情况会更好。