【问题标题】:DI in Service Fabric Service RemotingServiceFabrice 服务远程处理中的 DI
【发布时间】:2020-07-06 22:42:17
【问题描述】:

我有一个 Service Fabric 应用程序,其中一个服务通过 ASP.NET Web API 暴露给 Internet (GatewayService),还有几个内部服务不暴露给 Internet(我们称之为他们内部服务)。到目前为止,InternalService 也是一个 ASP.NET Web API,所以 InternalService.cs 有一个 CreateServiceInstanceListeners() 方法,如下所示:

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return new[] {
        new ServiceInstanceListener(serviceContext =>
            new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
                WebHost.CreateDefaultBuilder()
                    .UseStartup<Startup>()
                    .ConfigureServices((context, services) => { services.AddSingleton(serviceContext); })
                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                    .UseUrls(url)
                    .Build()))
    };
}

InternalService 的 Startup 类(在 Startup.cs 中)配置一些服务,例如向依赖注入系统添加 SQL DbContext,当然还有使用 AddMvc() 设置 ASP.NET 等. 我有几个暴露 API 的 ApiControllers。

这行得通,但是我没有得到任何真正的类型安全,而且它通常使开发有点麻烦,需要在我的 GatewayService 中手动反序列化结果,然后再操作它。所以我决定改用SF's Service Remoting,导致CreateServiceInstanceListeners() 方法看起来像这样:

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return this.CreateServiceRemotingInstanceListeners();
}

然后我将控制器中的所有逻辑也复制到InternalService.cs,但这导致了一个问题:我无法再访问我的 DbContext,因为它被注入到 ApiController 的构造函数中,由 ASP 实例化.NET 根据Startup 类中设置的规则,不再使用。

  1. 在使用 Service Remoting 时,有没有办法让我以同样的方式使用 Startup
  2. 我可以将 API 分成多个类,就像将 ApiController 分成多个类一样吗?我觉得将所有公开的方法都放在同一个类中会很麻烦。

【问题讨论】:

    标签: c# asp.net azure-service-fabric service-fabric-stateless service-fabric-remoting


    【解决方案1】:

    你可以使用 Autofac,有一个完整的 page 解释了如何设置它:

    • 添加Autofac.ServiceFabric nuget package
    • 配置 DI:

        // Start with the trusty old container builder.
        var builder = new ContainerBuilder();
      
        // Register any regular dependencies.
        builder.RegisterModule(new LoggerModule(ServiceEventSource.Current.Message));
      
        // Register the Autofac magic for Service Fabric support.
        builder.RegisterServiceFabricSupport();
      
        // Register a stateless service...
        builder.RegisterStatelessService<DemoStatelessService>("DemoStatelessServiceType");
      
        // ...and/or register a stateful service.
        // builder.RegisterStatefulService<DemoStatefulService>("DemoStatefulServiceType");
      
        using (builder.Build())
        {
          ServiceEventSource.Current.ServiceTypeRegistered(
            Process.GetCurrentProcess().Id,
            typeof(DemoStatelessService).Name);
      
          // Prevents this host process from terminating so services keep running.
          Thread.Sleep(Timeout.Infinite);
        }
      
    • 查看demo 项目。

    【讨论】:

    • 我决定按照您的建议使用 Autofac。它大部分都可以工作,但它并没有解决将 API 分成多个类的问题,而且设置 EF Core 比使用 Startup 类要尴尬得多。既然所有调用都通过同一个类,我看不出使用 DI 有什么好处,因为我可以在 InternalService.cs 中启动所需的类。还是谢谢
    【解决方案2】:

    我知道这已经是一个公认的答案,但我想加两分钱。

    如您所见,远程处理与 WebApi 相比有两个主要区别:

    1. 给定一个远程接口,你有一个实现类

    2. 远程实现类是一个单例,因此,即使您按照接受的答案中的说明使用 DI,您仍然无法为每个请求注入 DbContext。

    我可以给你一些解决这些问题的方法:

    1. 这个很简单:创建更多接口。您可以在单个服务结构服务中添加任意数量的远程处理接口。因此,您应该将您的远程 API 拆分为更小的接口,其中包含有意义的组(接口隔离)。但是,我认为你不应该有很多,因为这可能意味着你的微服务有太多的责任。

    2. 为每个请求建立依赖关系的一种简单方法是将工厂注入到远程处理类中,因此您可以在每个方法中解析和处理依赖关系,而不是通过构造函数注入。但是我发现使用Mediatr 的方法要好得多,这可能看起来并不简单,但是一旦设置它就非常容易使用。它的工作方式是创建一个小助手类,在构造函数中获取ILifetimeScope(当您使用 Autofac)并公开一个 Execute 方法。此方法将创建一个子 LifetimeScope,解析 Mediatr 并发送一个WrapperRequest&lt;TRequest&gt;(包装器是一个技巧,因此远程输入和输出对象不必依赖于 Mediatr)。这将允许您为每个远程操作实现一个 Handler 类,该类将根据请求进行解析,以便您可以像使用 WebApi 控制器一样在构造函数中注入依赖项。

    如果您不熟悉 Mediatr 和 Autofac,这可能听起来令人困惑。如果我有时间,我会写一篇关于它的博客文章。

    【讨论】:

    • 感谢您的回答!至于现在,就像你写的那样,我在我的远程课程中使用工厂。我会看看 Mediatr。谢谢!
    • 好的。我们做了同样的事情,第一家工厂,但最终,我们搬到了 Mediatr,这是一个很大的进步。顺便说一句,如果您使用 Autofac 来实现您的工厂,请小心实现 IDisposable(如 DbContext)的依赖项,就好像您不使用 Owned 一样,它会导致内存泄漏。我们很难学到这一点!
    猜你喜欢
    • 2017-09-17
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多