Autofact 初始化所有注册的服务

时间:2021-06-28 22:38:53

标签: .net autofac

好吧,我正在使用 Autofact 来制作我的 (IoC)。我在我的第一个 Builder

变量 for each 上有一个 IServiceProvider 的注册列表

我正在使用“使用范围...”来初始化服务。 IServiceProvider 是一个接口,有两个方法“StartService”和“StopService”,我目前需要通过执行“StartService”来初始化服务。

问题实际上是我注册了 9 个服务,我尝试执行 foreach 来初始化 9 个服务但它不起作用,初始化其他服务的正确方法是什么?目前我只是用 using scope ... 初始化一项服务,我想初始化所有服务,我在 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

  

1 个答案:

答案 0 :(得分:0)

您的代码存在三个问题:

  • 首先,您只是在解析您的一项服务。
  • 其次,您的组件仅在自定义范围内创建,在容器级别不可见。
  • 第三,您需要在关机时调用 StopService

(注意:我只在 c# 中使用 Autofac,所以答案将使用该语言,但应该很容易翻译成 VB :)

对于第一个问题,为了访问你所有实现 IServiceProvider 的服务,你需要解析为:

IEnumerable<IServiceProvider> services;

然后您可以为每个循环创建一个并为每个循环调用 StartService。

另一种选择是在注册期间使用激活的事件:

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

这样的话它只会在第一次 IServiceProvider 得到解析时启动服务,如果你希望它们在容器构建时立即启动,你可以使用自动激活,你的注册变成:

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

现在为了正确调用StopService,你还有两个选择:

首先,更简单但更具侵入性的是,您的 IServiceProvider 接口可以实现 IDisposable 而不是使用 StopService。

所以当容器被释放时,Dispose 会被自动调用。

当然这是一个突破性的变化,所以另一个选择是在注册期间添加另一个生命周期事件:

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

当您的容器被释放时,将调用 release 事件,并停止服务。

对于最后一个问题,您正在创建范围、解析服务然后释放范围,因此如果您尝试在容器级别再次解析您的服务,它们将不可见。

对于这种情况,您应该简单地调用:

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

如果您使用了 autoactivate 事件,这当然不再需要了,Autofac 将为您完成。