Search code examples
.netautofac

Autofact initialize all registered services


Well I am using Autofact to make my (IoC). I have a list of registration of IServiceProvider on my variable Builder in my firt for each

I am using a "using scope ..." to initialize the service. IServiceProvider is an interface that has two methods "StartService" and "StopService" I currently need to initialize the services by executing "StartService".

The problem actually is that I have like 9 services registered, I tried to do a foreach to inizialize the 9 services but it doesn't work, what is the correct way to inizialize the other services? currently just I'm initalize one service with the using scope ..., I want initialice all services, I have these services store in the Builder.

Protected Property Services As List(Of IServiceProvider)

Public Sub StartServices(applicationDirectory As String) 'As List(Of IServiceProvider).
    Dim Builder = New ContainerBuilder
    Me.applicationDirectory = applicationDirectory

    Try
        Dim serviceProviderTypes = Directory.EnumerateFiles(applicationDirectory).Where(Function(filename) filename.EndsWith(".dll")).[Select](Function(filepath) Assembly.LoadFrom(filepath)).SelectMany(Function(assembly) assembly.GetTypes().Where(Function(type) GetType(IServiceProvider).IsAssignableFrom(type) AndAlso type.IsClass))
        For Each serviceProviderType In serviceProviderTypes
            Builder.RegisterType(serviceProviderType).[As](Of IServiceProvider)()
        Next

        Dim container = Builder.Build()

        Using scope = container.BeginLifetimeScope()
            Dim app = scope.Resolve(Of IServiceProvider)()
            app.StartService()
        End Using

    Catch ex As Reflection.ReflectionTypeLoadException
        Throw ex
    End Try

  

Solution

  • There are three problems with your code :

    • First you are only Resolving only one of your services.
    • Second, your components are only created within a custom scope, and will not be visible at container level.
    • Third you need to call StopService on shutdown

    (NOTE: I only use Autofac in c# so answer will be in that language, but it should be easy to translate to VB :)

    For the first Issue, in order to access all your services that implement IServiceProvider, you need to resolve as :

    IEnumerable<IServiceProvider> services;
    

    Then you can make a for each loop and call StartService for each of them.

    Another option is to use an activated event during registration :

     builder.RegisterType<MyService>().As<IServiceProvider>()
         .OnActivated(ctx => ctx.Instance.StartService());
    

    In that case it will only Start Service the first time IServiceProvider gets resolved, if you want them to be started immediately when container is built, you can use Auto activate, your registration becomes :

    builder.RegisterType<MyService>().As<IServiceProvider>()
        .OnActivated(ctx => ctx.Instance.StartService())
        .AutoActivate();
    

    Now in order to properly call StopService, you also have two options:

    First, simpler but more intrusive, your IServiceProvider interface can implement IDisposable instead of using StopService.

    So when container is released Dispose will be called automatically.

    Of course this is a breaking change, so the other option is to add another lifetime event during registration :

     builder.RegisterType<MyService>().As<IServiceProvider>()
         .OnActivated(ctx => ctx.Instance.StartService())
         .AutoActivate()
         .OnRelease(instance => instance.StopService());
    

    When your container will be disposed, the release event will be called, as well as stop service.

    For the last issue, you are creating a scope, resolve a service then release the scope, so if you try to resolve your services again at container level, they will not be visible.

    For that case, you should simply call :

    container.Resolve<IEnumerable<IServiceProvider>>();
    

    If you used the autoactivate event this is of course not needed anymore, Autofac wil have done it for you.