Service Fabric с несколькими конечными точками и внедрением зависимостей - PullRequest
0 голосов
/ 11 июня 2018

В настоящее время я работаю над проектом POC и пытаюсь выяснить, как я могу разделить зависимость службы между различными конечными точками, чтобы контролировать состояние приложения и обрабатывать все запросы на обслуживание (давайте назовем его ControlService) - особенно когда один изэти конечные точки являются KestrelCommunicationListener / HttpSysCommunicationListener и объединяются с FabricTransportServiceRemotingListener (или любым другим типом настраиваемого прослушивателя)

Autofac выглядел многообещающе, но примеры не показывают, как заставить работать прослушиватель HTTPкогда контейнер встроен в автозагрузку, а не в основную точку входа - нужно ли передавать контейнер в MyFabricService, чтобы его можно было передавать и добавлять при регистрации запуска?

Я видел ссылки на использованиеcontainer.Update () или добавление регистраций на лету с помощью container.BeginLifetimeScope (), но все они используют контейнер, встроенный в main, и тогда я не уверен, как добавить API-интерфейсы, созданные слушателем HTTP.r к исходному контейнеру.

Возможно, я не очень хорошо это объясняю, поэтому в заключение я хотел бы найти что-то похожее на приведенный ниже сервис, который может принимать сообщения через nразные конечные точки - обработать сообщение и затем отправить сообщения через n.клиенты (или другие конечные точки обслуживания)

Control Service Endpoints

enter image description here

С удовольствием уточню, если что-то неясно- возможно, даже используя другую креативную диаграмму:)

Обновлено:

Из Program.Main ()

   ServiceRuntime.RegisterServiceAsync("ManagementServiceType",
                                context => new ManagementService(context)).GetAwaiter().GetResult();

Вот мой сервис Fabric

public ManagementService(StatefulServiceContext context)
        : base(context)
    {
        //this does not work but is pretty much what I'm after
        _managementService = ServiceProviderFactory.ServiceProvider.GetService(typeof(IManagementService)) as IManagementService;
    }

    protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners() =>
       new ServiceReplicaListener[]
       {
           //create external http listener
            ServiceReplicaListenerFactory.CreateExternalListener(typeof(Startup), StateManager, (serviceContext, message) => ServiceEventSource.Current.ServiceMessage(serviceContext, message), "ServiceEndpoint"),

            //create remoting listener with injected dependency
            ServiceReplicaListenerFactory.CreateServiceReplicaListenerFor(() => new RemotingListenerService(_managementService), "ManagmentServiceRemotingEndpoint", "ManagementServiceListener")

       };

ServiceReplicaListener

public static ServiceReplicaListener CreateExternalListener(Type startupType, IReliableStateManager stateManager, Action<StatefulServiceContext, string> loggingCallback, string endpointname)
    {
        return new ServiceReplicaListener(serviceContext =>
        {
            return new KestrelCommunicationListener(serviceContext, endpointname, (url, listener) =>
            {
                loggingCallback(serviceContext, $"Starting Kestrel on {url}");

                return new WebHostBuilder().UseKestrel()
                            .ConfigureServices((hostingContext, services) =>
                            {
                                services.AddSingleton(serviceContext);
                                services.AddSingleton(stateManager);

                                services.AddApplicationInsightsTelemetry(hostingContext.Configuration);
                                services.AddSingleton<ITelemetryInitializer>((serviceProvider) => new FabricTelemetryInitializer(serviceContext));
                            })
                            .ConfigureAppConfiguration((hostingContext, config) =>
                            {
                                config.AddServiceFabricConfiguration(serviceContext);
                            })
                            .ConfigureLogging((hostingContext, logging) =>
                            {
                                logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                                logging.AddDebug();
                            })
                            .UseContentRoot(Directory.GetCurrentDirectory())
                            .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                            .UseStartup(startupType)
                            .UseUrls(url)
                            .Build();
            });
        });
    }

Запуск

public class Startup
{
    private const string apiTitle = "Management Service API";
    private const string apiVersion = "v1";

    private readonly IConfiguration configuration;

    public Startup(IConfiguration configuration)
    {
        this.configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        var modules = new List<ICompositionModule>
                      {
                          new Composition.CompositionModule(),
                          new BusinessCompositionModule()
                      };

        foreach (var module in modules)
        {
            module.AddServices(services, configuration);
        }

        services.AddSwashbuckle(configuration, apiTitle, apiVersion, "ManagementService.xml");
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddApplicationInsights(app.ApplicationServices);

        // app.UseAuthentication();
        //  app.UseSecurityContext();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
          //  app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();

        app.UseCors("CorsPolicy");

        app.UseMvc();

        app.UseSwagger(apiTitle, apiVersion);

        //app.UseMvc(routes =>
        //{
        //    routes.MapRoute(
        //        name: "default",
        //        template: "{controller=Home}/{action=Index}/{id?}");
        //});

    }
}

Все сервисные зависимости добавляются в модули CompositionModules с использованием Microsoft.Extensions.DependencyInjection (не autofac) в startup.cs

Это прекрасно работает и создает мой HTTP-прослушиватель - теперь мне просто нужен способ получить доступ к моим службам, которые были добавлены в контейнер во время запуска моего http listener / webhost.

Ответы [ 2 ]

0 голосов
/ 14 июня 2018

@ Тим

Извините за поздний ответ.В настоящее время я работаю над библиотечным пакетом, который мы используем в нашей компании для внутренних проектов.Эта библиотека упрощает настройку надежных сервисов.Я думаю, что наши последние улучшения могут сделать то, что вам нужно (надеюсь, я правильно понял вариант использования).

Всю информацию о библиотеке можно найти на странице проекта в GitHub и NuGet.пакет можно найти здесь (обратите внимание, что это предварительная версия, но мы планируем вскоре перейти к полной версии).

Если у вас есть какие-либо вопросы или вам нужна дополнительная информацияНе стесняйтесь связаться со мной.

ОБНОВЛЕНИЕ

Я создал образец приложения .Пожалуйста, не стесняйтесь попробовать.

Вот пример кода.

public interface IManagementService
{
    string GetImportantValue();
}

public interface IMessageProvider
{
    string GetMessage();
}

public class MessageProvider : IMessageProvider
{
    public string GetMessage()
    {
        return "Value";
    }
}

public class ManagementService : IManagementService
{
    private readonly IMessageProvider provider;

    public ManagementService(
        IMessageProvider provider)
    {
        this.provider = provider;
    }

    public string GetImportantValue()
    {
        // Same instances should have the same hash
        return this.provider.GetMessage() + $"Hash: {this.GetHashCode()}";
    }
}

public interface IRemotingImplementation : IService
{
    Task<string> RemotingGetImportantValue();
}

public class RemotingImplementation : IRemotingImplementation
{
    private readonly IManagementService managementService;

    public RemotingImplementation(
        IManagementService managementService)
    {
        this.managementService = managementService;
    }

    public Task<string> RemotingGetImportantValue()
    {
        return Task.FromResult(this.managementService.GetImportantValue());
    }
}

public class WebApiImplementationController : ControllerBase
{
    private readonly IManagementService managementService;

    public WebApiImplementationController(
        IManagementService managementService)
    {
        this.managementService = managementService;
    }

    [HttpGet]
    public Task<string> WebApiGetImportantValue()
    {
        return Task.FromResult(this.managementService.GetImportantValue());
    }
}

public class WebApiStartup
{
    private readonly IConfiguration configuration;

    public WebApiStartup(
        IConfiguration configuration)
    {
        this.configuration = configuration;
    }

    public void ConfigureServices(
        IServiceCollection services)
    {
        services.AddMvc();
    }

    public void Configure(
        IApplicationBuilder app,
        IHostingEnvironment env,
        ILoggerFactory loggerFactory)
    {
        app.UseMvcWithDefaultRoute();
    }
}

internal static class Program
{
    /// <summary>
    ///     This is the entry point of the service host process.
    /// </summary>
    private static void Main()
    {
        var host = new HostBuilder()
           .ConfigureServices(
                services =>
                {
                    services.AddTransient<IMessageProvider, MessageProvider>();
                    services.AddSingleton<IManagementService, ManagementService>();
                })
           .ConfigureStatefulService(
                serviceBuilder =>
                {
                    serviceBuilder
                       .UseServiceType("StatefulServiceType")
                       .DefineAspNetCoreListener(
                            listenerBuilder =>
                            {
                                listenerBuilder
                                   .UseEndpointName("ServiceEndpoint")
                                   .UseKestrel()
                                   .UseUniqueServiceUrlIntegration()
                                   .ConfigureWebHost(
                                        webHostBuilder =>
                                        {
                                            webHostBuilder.UseStartup<WebApiStartup>();
                                        });
                            })
                       .DefineRemotingListener(
                            listenerBuilder =>
                            {
                                listenerBuilder
                                   .UseEndpointName("ServiceEndpoint2")
                                   .UseImplementation<RemotingImplementation>();
                            });
                })
           .Build()
           .Run();
    }
}
0 голосов
/ 11 июня 2018

Вы можете использовать Autofac.Integration.ServiceFabriс, расширение Autofac для поддержки Service Fabric.Вам нужно создать контейнер в Program.cs

var builder = new ContainerBuilder();

builder.RegisterServiceFabricSupport();
builder.RegisterType<SomeService>().As<IManagementService>();

builder.RegisterStatelessService<ManagementService>("ManagementServiceType");
using (builder.Build())
{
   // Prevents this host process from terminating so services keep running.
   Thread.Sleep(Timeout.Infinite);
}

Затем вы можете внедрить его в конструктор вашей службы фабрики.Вы можете найти больше информации по этой теме на https://alexmg.com/posts/introducing-the-autofac-integration-for-service-fabric

...