3 votes

Service Fabric avec plusieurs points d'accès et injection de dépendances

Je travaille actuellement sur un projet POC et j'essaie de comprendre comment je peux partager une dépendance de service entre différents points d'extrémité pour contrôler l'état de l'application et gérer toutes les demandes de service (appelons-le ControlService) - spécifiquement lorsque l'un de ces points d'extrémité est un KestrelCommunicationListener / HttpSysCommunicationListener et combiné avec un FabricTransportServiceRemotingListener (ou tout autre type d'écouteur personnalisé).

Autofac semble prometteur mais les exemples ne montrent pas comment faire fonctionner un écouteur HTTP lorsque le conteneur est construit au démarrage plutôt qu'au point d'entrée principal. Devrais-je passer le conteneur à MyFabricService pour qu'il puisse être passé et ajouté par les enregistrements de démarrage ?

J'ai vu des références à l'utilisation de container.Update() ou à l'ajout d'enregistrements à la volée à l'aide de container.BeginLifetimeScope() mais elles utilisent toutes un conteneur construit en main et je ne sais pas comment ajouter les API créées par l'écouteur HTTP au conteneur original.

Je ne l'explique peut-être pas très bien, donc en résumé je cherche à avoir quelque chose comme le service ci-dessous qui peut recevoir des communications via n. points d'extrémité différents - traiter le message et ensuite envoyer des messages via n. clients (aka d'autres points d'extrémité du service)

Control Service Endpoints

enter image description here

Heureux de clarifier si quelque chose n'est pas clair - peut-être même en utilisant un autre diagramme créatif :)

Mis à jour :

De Programme.Main()

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

Voici mon service de tissus

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

Démarrage

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?}");
        //});

    }
}

Toutes les dépendances du service sont ajoutées dans les CompositionModules en utilisant Microsoft.Extensions.DependencyInjection (pas autofac) dans startup.cs.

Cela fonctionne très bien et crée mon écouteur HTTP - j'ai maintenant besoin d'un moyen d'accéder à mes services qui ont été ajoutés au conteneur pendant le démarrage de mon écouteur http / webhost.

0voto

Alex Riabov Points 4207

Vous pouvez utiliser Autofac.Integration.ServiceFabriс, une extension Autofac pour supporter Service Fabric. Vous devez créer un conteneur dans 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);
}

Vous pouvez ensuite l'injecter dans le constructeur de votre service de fabrication. Vous pouvez trouver plus d'informations à ce sujet sur https://alexmg.com/posts/introducing-the-autofac-integration-for-service-fabric

0voto

Oleg Karasik Points 770

@Tim

Désolé pour la réponse tardive. Je travaille actuellement sur un ensemble de bibliothèques que nous utilisons dans notre entreprise pour des projets internes. Cette bibliothèque simplifie la configuration des services fiables. Je pense que nos récentes améliorations peuvent faire ce dont vous avez besoin (j'espère avoir bien compris le cas d'utilisation).

Toutes les informations concernant la bibliothèque sont disponibles sur page du projet sur GitHub et le paquet NuGet peut être trouvé aquí (veuillez noter qu'il s'agit d'une version préliminaire mais que nous prévoyons de la transformer en version complète prochainement).

Si vous avez des questions ou besoin de plus d'informations, n'hésitez pas à me contacter.

UPDATE

J'ai créé un application type . N'hésitez pas à l'essayer.

Voici un exemple de code.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X