2

我有一个 Service Fabric 应用程序,其中一个服务通过 ASP.NET Web API向 Internet ( GatewayService ) 公开,另外还有几个未向 Internet 公开的内部服务(我们称其中一个为InternalService)。到目前为止,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 类 (in Startup.cs)配置了一些服务,例如将 SQL DbContext 添加到依赖注入系统,当然还有设置 ASP.NET等。我有几个公开 API 的 ApiController。AddMvc()

这行得通,但是我没有得到任何真正的类型安全性,而且它通常使开发有点麻烦,需要在操作之前在我的 GatewayService 中手动反序列化结果。所以我决定改用SF 的 Service Remoting,得到的CreateServiceInstanceListeners()方法如下所示:

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

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

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

2 回答 2

1

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

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

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

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

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

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

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

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

于 2020-04-28T21:04:41.683 回答
0

您可以使用 Autofac,有一整解释了如何设置它:

  • 添加Autofac.ServiceFabric nuget 包
  • 配置 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);
      }
    
  • 查看演示项目。

于 2020-03-26T10:57:58.443 回答