DI в ServiceFabrice Service Remoting

У меня есть приложение Service Fabric с одной службой, доступной для Интернета (GatewayService) через веб-API ASP.NET, и парой внутренних служб, не подключенных к Интернету (назовем одну из них InternalService). Пока что InternalService также является веб-API ASP.NET, поэтому 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()))
    };
}

Класс Startup (в Startup.cs) для InternalService настраивает некоторые службы, такие как добавление SQL DbContext в систему внедрения зависимостей и, конечно же, настройка ASP.NET с AddMvc() и т. Д. У меня есть пара ApiController. которые предоставляют API.

Это работает, НО я не получаю никакой реальной безопасности типов с этим, и обычно это делает разработку немного громоздкой, так как необходимо вручную десериализовать результат в моем 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 на несколько классов точно так же, как ApiControllers разделяются на несколько классов? Я чувствую, что иметь все открытые методы в одном классе будет довольно неприятно.

person ShamPooSham    schedule 26.03.2020    source источник


Ответы (2)


Вы можете использовать Autofac, там есть целая страница, объясняющая, как установить это вверх:

  • Добавьте пакет Nuget Autofac.ServiceFabric
  • Настроить 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);
      }
    
  • ознакомьтесь с демонстрационным проектом.

person LoekD    schedule 26.03.2020
comment
Я решил использовать Autofac, как вы предложили. В основном это работает, но не решает проблему разделения API на несколько классов, а настройка EF Core была намного сложнее, чем использование класса Startup. Поскольку все вызовы в любом случае проходят через один и тот же класс, я не вижу особой выгоды в использовании DI, когда я мог бы просто инициировать необходимые классы в InternalService.cs. В любом случае спасибо - person ShamPooSham; 17.04.2020

Я знаю, что это уже принятый ответ, но я хочу добавить свои два цента.

Как вы уже поняли, удаленное взаимодействие имеет два основных отличия от WebApi:

  1. Учитывая интерфейс удаленного взаимодействия, у вас есть единственный класс реализации

  2. Класс реализации удаленного взаимодействия является одноэлементным, поэтому, даже если вы используете DI, как описано в принятом ответе, вы все равно не можете внедрить DbContext для каждого запроса.

Я могу предложить вам несколько решений этих проблем:

  1. Это просто: создайте больше интерфейсов. Вы можете добавить столько интерфейсов удаленного взаимодействия, сколько захотите, в одну службу Service Fabric. Итак, вам следует разделить ваш удаленный API на более мелкие интерфейсы с группами, которые имеют смысл (разделение интерфейсов). Но я не думаю, что у вас должно быть много, потому что это, вероятно, означало бы, что у вашего микросервиса слишком много обязанностей.

  2. Наивный подход к наличию зависимостей для каждого запроса состоит в том, чтобы внедрить фабрики в класс удаленного взаимодействия, чтобы вы могли разрешать и удалять зависимости в каждом методе вместо внедрения конструктора. Но я нашел гораздо лучший подход, используя Mediatr, который может показаться нетривиальным, но после настройки он очень легко использовать. Это работает так: вы создаете небольшой вспомогательный класс, который получает ILifetimeScope (как вы используете Autofac) в конструкторе и предоставляет метод Execute. Этот метод создаст дочерний объект LifetimeScope, разрешит Mediatr и отправит WrapperRequest<TRequest> (оболочка - это уловка, позволяющая удаленным объектам ввода и вывода не зависеть от Mediatr). Это позволит вам реализовать класс Handler для каждой операции удаленного взаимодействия, которая будет разрешаться для каждого запроса, чтобы вы могли внедрить зависимости в конструктор, как вы это делаете с контроллером WebApi.

Это может показаться странным, если вы не знакомы с Mediatr и Autofac. Если будет время, напишу об этом в блоге.

person Francesc Castells    schedule 28.04.2020
comment
Чем Вам за ответы! На данный момент я использую фабрики в своем классе удаленного взаимодействия, как вы написали. Я посмотрю на Mediatr. Спасибо! - person ShamPooSham; 29.04.2020
comment
В ПОРЯДКЕ. Мы сделали то же самое, сначала фабрики, но в конце концов мы перешли на Mediatr, и это было большим улучшением. Кстати, если вы используете Autofac для реализации своих фабрик, будьте осторожны с зависимостями, реализующими IDisposable (например, DbContext), так как если вы не используете Owned ‹T›, это вызовет утечку памяти. Мы усвоили это на собственном горьком опыте! - person Francesc Castells; 29.04.2020