1

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.

Nuri Tasdemir
  • 9,720
  • 3
  • 42
  • 67

1 Answers1

1

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>(); 
Cyril Durand
  • 15,834
  • 5
  • 54
  • 62
  • You have some good points. IStartable seems a good solution, however I do not want to add anything related to a specific container (like IStartable) to dll containing the services. Some can use Autofac, some use something else. Also in case I build another service for initialisation purposes and register it as singleton, its instance also will not be released. It is more by the book, I agree. However in practice nothing is changed. Am I right? – Nuri Tasdemir Jun 29 '16 at 10:48
  • If you register the initializer as singleton, the instance will be disposed when the application stop. But I don't think it is a real problem because you won't need to dispose it, as I understand, you only need to dispose `SomeService` – Cyril Durand Jun 29 '16 at 12:21