I have the following registration code:
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;
}
I use also a Microsoft's CommonServiceLocator for one edge case. Inside "OnActionExecuting" function I set up one of the properties in IUserSettings:
public override void OnActionExecuting(HttpActionContext actionContext)
{
...
var userSettings = actionContext.Request.GetDependencyScope().GetService(typeof(IUserSettings)) as IUserSettings;
**userSettings.Test = 123;**
}
In the whole MVC app and inside some libraries, which are MVC app dependencies I can resolve the same object of IUserSettings - if I use a classic DI via constructor.But when I try to resolve it via global service locator:
var settings = ServiceLocator.Current.GetInstance<IUserSettings>();
I get a new instance of IUserSettings, not the initial one which come with the request. Singleton instances works fine, but not those registered as "InstancePerLifetimeScope".
Does anybody know what I did wrong? Is there a way to resolve the same instance of IUserSettings using global "ServiceLocator"?
The short version is: You can't [easily] do what you're trying to do.
If you recall from your lifetime scope knowledge, lifetime scopes in a request-based application are hierarchical.
ServiceLocator
is usually stuck here.
If you register something as InstancePerLifetimeScope
, it's going to create one in each of those "buckets."
ServiceLocator
does), you'll get an instance there.But there's no "tie" between the ServiceLocator
and a request lifetime scope.
Now, the AutofacDependencyResolver
does have a Current
property to let you get the request lifetime scope, but be aware that's only going to work in the context of a web request - if you do something async and the request ends before your work is done, that resolver will disappear out from under you.
DI is largely "viral." If you switch from DI to service location, you're sort of breaking the pattern and it's going to require some workarounds and hackery. I know sometimes that's required, just, you're not going to get as much "free out of the box" and "just working" when you switch from one to the other, which is, apparently, what's happening. You'd be better off if you can stick with DI and allow request services to be injected as needed and not go through service location if possible.