Reputation: 9842
In an API controller project in .NET, there is a service I am using, say SomeService
, requires one time only initialisation (not per request or per SomeService instance) (Although I do not think it is relevant, here the explanation for this init part: It does some setup in Azure storage for once the api is created. Doing this for every instance of SomeService
is unnecessarely costly. Therefore there was the following line in Global.asax
new SomeService().Init();
Now, I am using Autofac
for dependency injection. I register SomeService
as ISomeService
and as InstancePerRequest
(because SomeService
is not thread-safe). Therefore now I want to initialise SomeService in Global.asax via an instance from container. However If I try to get an instance from container as in
container.Resolve<ISomeService>().Init();
it gives this error
An exception of type 'Autofac.Core.DependencyResolutionException' occurred in Autofac.dll but was not handled in user code
Additional information: No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
Therefore in Global.asax I get an instance as suggested in the error explanation.
DependencyResolver.Current.GetService<ISomeService>().Init();
What I want to know is that the SomeService
instance I get from Current
is released or not? Since there is no real request, I am not sure. At worst I can get the instance from concrete with new
.
Upvotes: 1
Views: 1377
Reputation: 16192
You are trying to merge 2 responsibilities into 1 components which breaks the Single Responsibility Principle.
In order to solve it, you can split the component with a component that will initialize the azure storage (IStorageProvider
for example) and another component that will do the job. The IStorageProvider
will be declared as SingleInstance
(and implement IStartable
if needed) and the other component will use this component.
public class AzureStorageProvider : IStorageProvider, IStartable
{
public void Start()
{
// initialize storage
this._storage = new ...
}
}
public class SomeService : ISomeService
{
public SomeService(IStorageProvider storageProvider)
{
this._storageProvider = storageProvider;
}
private readonly IStorageProvider _storageProvider;
public void Do()
{
// do things with storage
this._storageProvider.Storage.ExecuteX();
}
}
and the registration :
builder.RegisterType<AzureStorageProvider>().As<IStorageProvider>().SingleInstance();
builder.RegisterType<SomeService>().As<ISomeService>().InstancePerRequest();
you can also register a IStorage
and let SomeService depends directly on IStorage
and use the IStorageProvider
as a factory.
builder.Register(c => c.Resolve<IStorageProvider>().Storage).As<IStorage>();
Upvotes: 1