Search code examples
c#asp.netazure-service-fabricservice-fabric-statelessservice-fabric-remoting

DI in Service Fabric Service Remoting


I have a Service Fabric application with one service which is exposed to Internet (GatewayService) through an ASP.NET Web API and a couple of internal services not exposed to the Internet (let's call one of them InternalService). So far, InternalService is also an ASP.NET Web APIs, so InternalService.cs has a CreateServiceInstanceListeners() method which looks like this:

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()))
    };
}

The Startup class (in Startup.cs) for InternalService configures some services, such as adding a SQL DbContext to the Dependency Injection system, and of course setting up ASP.NET with AddMvc() etc. I have a couple of ApiControllers which expose the API.

This works, BUT I don't get any real type safety with this, and it generally makes development a bit cumbersome, needing to deserialize the result manually in my GatewayService before manipulating it. So I decided to go with SF's Service Remoting instead, resulting in a CreateServiceInstanceListeners() method which looks like this:

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

Then I copied all the logic from the controllers into InternalService.cs too, but this lead to an issue: I don't have access to my DbContext anymore, because it was injected into the constructor of the ApiController, instantiated by ASP.NET according to the rules set in the Startup class, which isn't used anymore.

  1. Is there a way for me to use Startup in the same way when using Service Remoting?
  2. Can I separate the API into multiple classes, in the same way as ApiControllers are separated into multiple classes? I feel like having all exposed methods in the same class will be quite a hazzle.

Solution

  • You can use Autofac, there's an entire page that explains how to set it up:

    • Add the Autofac.ServiceFabric nuget package
    • Configure 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);
        }
      
    • check out the demo project.