ASP.NET Core no Azure Service Fabric Reliable Services

ASP.NET Core é uma arquitetura open source e multiplataformas. Esta arquitetura foi concebida para criar aplicações com base na cloud e ligadas à Internet, como aplicações Web, aplicações IoT e back-ends móveis.

Este artigo é um guia aprofundado para alojar ASP.NET Core serviços no Service Fabric Reliable Services através do conjunto de pacotes NuGet Microsoft.ServiceFabric.AspNetCore.

Para obter um tutorial introdutório sobre ASP.NET Core no Service Fabric e instruções sobre como configurar o seu ambiente de desenvolvimento, consulte Tutorial: Criar e implementar uma aplicação com um serviço de front-end da API Web ASP.NET Core e um serviço de back-end com estado.

O resto deste artigo pressupõe que já está familiarizado com ASP.NET Core. Caso contrário, leia as ASP.NET Core noções básicas.

ASP.NET Core no ambiente do Service Fabric

As aplicações ASP.NET Core e do Service Fabric podem ser executadas no .NET Core ou em .NET Framework completos. Pode utilizar ASP.NET Core de duas formas diferentes no Service Fabric:

  • Alojado como executável convidado. Desta forma, é utilizado principalmente para executar aplicações ASP.NET Core existentes no Service Fabric sem alterações de código.
  • Execute dentro de um serviço fiável. Desta forma, permite uma melhor integração com o runtime do Service Fabric e permite serviços de ASP.NET Core com monitorização de estado.

O resto deste artigo explica como utilizar ASP.NET Core dentro de um serviço fiável, através dos componentes de integração ASP.NET Core que são enviados com o SDK do Service Fabric.

Alojamento do serviço Service Fabric

No Service Fabric, uma ou mais instâncias e/ou réplicas do seu serviço são executadas num processo de anfitrião de serviço: um ficheiro executável que executa o código de serviço. O Utilizador, enquanto autor de serviço, é o proprietário do processo de anfitrião de serviços e o Service Fabric ativa e monitoriza-o automaticamente.

As ASP.NET tradicionais (até MVC 5) são fortemente associadas ao IIS através de System.Web.dll. ASP.NET Core fornece uma separação entre o servidor Web e a sua aplicação Web. Esta separação permite que as aplicações Web sejam portáteis entre diferentes servidores Web. Também permite que os servidores Web sejam autoalojados. Isto significa que pode iniciar um servidor Web no seu próprio processo, ao contrário de um processo que pertence a software de servidor Web dedicado, como o IIS.

Para combinar um serviço do Service Fabric e ASP.NET, como executável convidado ou num serviço fiável, tem de ser capaz de iniciar ASP.NET dentro do seu processo de anfitrião de serviço. ASP.NET Core autoalojação permite-lhe fazê-lo.

Alojar ASP.NET Core num serviço fiável

Normalmente, as aplicações ASP.NET Core autoalojadas criam um WebHost no ponto de entrada de uma aplicação, como o static void Main() método em Program.cs. Neste caso, o ciclo de vida do WebHost está vinculado ao ciclo de vida do processo.

Alojar ASP.NET Core num processo

No entanto, o ponto de entrada da aplicação não é o local certo para criar um WebHost num serviço fiável. Isto deve-se ao facto de o ponto de entrada da aplicação ser utilizado apenas para registar um tipo de serviço com o runtime do Service Fabric, para que possa criar instâncias desse tipo de serviço. O WebHost deve ser criado num serviço fiável. No processo de anfitrião de serviço, as instâncias de serviço e/ou réplicas podem passar por vários ciclos de vida.

Uma instância do Reliable Service é representada pela sua classe de serviço derivada de StatelessService ou StatefulService. A pilha de comunicação de um serviço está contida numa implementação ICommunicationListener na sua classe de serviço. Os Microsoft.ServiceFabric.AspNetCore.* pacotes NuGet contêm implementações desse ICommunicationListener início e gerem o ASP.NET Core WebHost para kestrel ou HTTP.sys num serviço fiável.

Diagrama para alojar ASP.NET Core num serviço fiável

ASP.NET Core ICommunicationListeners

As ICommunicationListener implementações de Kestrel e HTTP.sys nos Microsoft.ServiceFabric.AspNetCore.* pacotes NuGet têm padrões de utilização semelhantes. Contudo, executam ações ligeiramente diferentes específicas de cada servidor Web.

Ambos os serviços de escuta de comunicação fornecem um construtor que utiliza os seguintes argumentos:

  • ServiceContext serviceContext: este é o ServiceContext objeto que contém informações sobre o serviço em execução.
  • string endpointName: este é o nome de uma Endpoint configuração no ServiceManifest.xml. É principalmente onde os dois ouvintes de comunicação diferem. HTTP.sys requer uma configuração Endpoint , enquanto o Kestrel não.
  • Func<string, AspNetCoreCommunicationListener, IWebHost> build: este é um lambda que implementa, no qual cria e devolve um IWebHost. Permite-lhe configurar IWebHost como faria normalmente numa aplicação ASP.NET Core. O lambda fornece um URL que é gerado automaticamente, dependendo das opções de integração do Service Fabric que utiliza e da Endpoint configuração que fornecer. Em seguida, pode modificar ou utilizar esse URL para iniciar o servidor Web.

Middleware de integração do Service Fabric

O Microsoft.ServiceFabric.AspNetCore pacote NuGet inclui o UseServiceFabricIntegration método de extensão que IWebHostBuilder adiciona middleware com suporte para o Service Fabric. Este middleware configura o Kestrel ou HTTP.sys ICommunicationListener para registar um URL de serviço exclusivo no Serviço de Nomenclatura do Service Fabric. Em seguida, valida os pedidos de cliente para garantir que os clientes estão a ligar-se ao serviço certo.

Este passo é necessário para impedir que os clientes se liguem erradamente ao serviço errado. Isto porque, num ambiente de anfitrião partilhado, como o Service Fabric, várias aplicações Web podem ser executadas na mesma máquina física ou virtual, mas não utilizam nomes de anfitrião exclusivos. Este cenário é descrito mais detalhadamente na secção seguinte.

Um caso de identidade errada

As réplicas de serviço, independentemente do protocolo, escutam numa combinação ip:porta exclusiva. Assim que uma réplica de serviço começar a escutar num ponto final IP:port, comunica esse endereço de ponto final ao Serviço de Nomenclatura do Service Fabric. Aí, os clientes ou outros serviços podem detetá-lo. Se os serviços utilizarem portas de aplicação atribuídas dinamicamente, uma réplica de serviço poderá, por coincidência, utilizar o mesmo ponto final IP:porta de outro serviço anteriormente na mesma máquina física ou virtual. Isto pode fazer com que um cliente se ligue erradamente ao serviço errado. Este cenário pode resultar se ocorrer a seguinte sequência de eventos:

  1. O Serviço A escuta em 10.0.0.1:30000 através de HTTP.
  2. O cliente resolve o Serviço A e obtém o endereço 10.0.0.1:30000.
  3. O Serviço A muda para um nó diferente.
  4. O Serviço B é colocado em 10.0.0.1 e, por coincidência, utiliza a mesma porta 30000.
  5. O cliente tenta ligar ao serviço A com o endereço em cache 10.0.0.1:30000.
  6. O cliente está agora ligado com êxito ao serviço B, não percebendo que está ligado ao serviço errado.

Isto pode causar erros aleatórios que podem ser difíceis de diagnosticar.

Utilizar URLs de serviço exclusivos

Para evitar estes erros, os serviços podem publicar um ponto final no Serviço de Nomenclatura com um identificador exclusivo e, em seguida, validar esse identificador exclusivo durante os pedidos de cliente. Trata-se de uma ação de cooperação entre serviços num ambiente fidedigno de inquilino não hostil. Não fornece autenticação de serviço segura num ambiente de inquilino hostil.

Num ambiente fidedigno, o middleware adicionado pelo UseServiceFabricIntegration método acrescenta automaticamente um identificador exclusivo ao endereço publicado no Serviço de Nomenclatura. Valida esse identificador em cada pedido. Se o identificador não corresponder, o middleware devolve imediatamente uma resposta HTTP 410 Ausente.

Os serviços que utilizam uma porta atribuída dinamicamente devem utilizar este middleware.

Os serviços que utilizam uma porta única fixa não têm este problema num ambiente cooperativo. Normalmente, é utilizada uma porta exclusiva fixa para serviços externos que precisam de uma porta conhecida para as aplicações cliente se ligarem. Por exemplo, a maioria das aplicações Web com acesso à Internet utilizará a porta 80 ou 443 para ligações de browser. Neste caso, o identificador exclusivo não deve ser ativado.

O diagrama seguinte mostra o fluxo do pedido com o middleware ativado:

Integração de ASP.NET Core do Service Fabric

Tanto as implementações de Kestrel como HTTP.sys ICommunicationListener utilizam este mecanismo exatamente da mesma forma. Embora HTTP.sys possam diferenciar internamente os pedidos com base em caminhos de URL exclusivos através da funcionalidade de partilha de portasHTTP.sys subjacente, essa funcionalidade não é utilizada pela implementação HTTP.sys ICommunicationListener . Isto porque resulta em códigos de estado de erro HTTP 503 e HTTP 404 no cenário descrito anteriormente. Isto, por sua vez, dificulta que os clientes determinem a intenção do erro, uma vez que HTTP 503 e HTTP 404 são normalmente utilizados para indicar outros erros.

Assim, as implementações Kestrel e HTTP.sys ICommunicationListener uniformizam o middleware fornecido pelo UseServiceFabricIntegration método de extensão. Por conseguinte, os clientes só precisam de executar uma ação de resolução de pontos finais de serviço em respostas HTTP 410.

HTTP.sys no Reliable Services

Pode utilizar HTTP.sys no Reliable Services ao importar o pacote NuGet Microsoft.ServiceFabric.AspNetCore.HttpSys . Este pacote contém HttpSysCommunicationListener, uma implementação de ICommunicationListener. HttpSysCommunicationListenerpermite-lhe criar um WebHost ASP.NET Core dentro de um serviço fiável com HTTP.sys como servidor Web.

HTTP.sys é criada na API do Windows HTTP Server. Esta API utiliza o HTTP.sys controlador kernel para processar pedidos HTTP e encaminhá-los para processos que executam aplicações Web. Isto permite que vários processos na mesma máquina física ou virtual alojem aplicações Web na mesma porta, desambiguadas por um caminho de URL exclusivo ou nome de anfitrião. Estas funcionalidades são úteis no Service Fabric para alojar vários sites no mesmo cluster.

Nota

HTTP.sys implementação funciona apenas na plataforma Windows.

O diagrama seguinte ilustra como HTTP.sys utiliza o controlador kernel HTTP.sys no Windows para partilha de portas:

HTTP.sys diagrama

HTTP.sys num serviço sem estado

Para utilizar HttpSys num serviço sem estado, substitua o CreateServiceInstanceListeners método e devolva uma HttpSysCommunicationListener instância:

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return new ServiceInstanceListener[]
    {
        new ServiceInstanceListener(serviceContext =>
            new HttpSysCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
                new WebHostBuilder()
                    .UseHttpSys()
                    .ConfigureServices(
                        services => services
                            .AddSingleton<StatelessServiceContext>(serviceContext))
                    .UseContentRoot(Directory.GetCurrentDirectory())
                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                    .UseStartup<Startup>()
                    .UseUrls(url)
                    .Build()))
    };
}

HTTP.sys num serviço com estado

HttpSysCommunicationListener Atualmente, não foi concebido para ser utilizado em serviços com monitorização de estado devido a complicações com a funcionalidade de partilha de portasHTTP.sys subjacente. Para obter mais informações, veja a secção seguinte sobre a alocação de portas dinâmicas com HTTP.sys. Para serviços com monitorização de estado, o Kestrel é o servidor Web sugerido.

Configuração do ponto final

Endpoint É necessária uma configuração para servidores Web que utilizam a API do Windows HTTP Server, incluindo HTTP.sys. Os servidores Web que utilizam a API do Windows HTTP Server têm primeiro de reservar o URL com HTTP.sys (isto é normalmente conseguido com a ferramenta netsh ).

Esta ação requer privilégios elevados que os seus serviços não têm por predefinição. As opções "http" ou "https" para a Protocol propriedade da Endpoint configuração no ServiceManifest.xml são utilizadas especificamente para instruir o runtime do Service Fabric a registar um URL com HTTP.sys em seu nome. Efetua esta ação com o prefixo de URL de caráter universal forte .

Por exemplo, para reservar http://+:80 para um serviço, utilize a seguinte configuração no ServiceManifest.xml:

<ServiceManifest ... >
    ...
    <Resources>
        <Endpoints>
            <Endpoint Name="ServiceEndpoint" Protocol="http" Port="80" />
        </Endpoints>
    </Resources>

</ServiceManifest>

E o nome do ponto final tem de ser transmitido para o HttpSysCommunicationListener construtor:

 new HttpSysCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
 {
     return new WebHostBuilder()
         .UseHttpSys()
         .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
         .UseUrls(url)
         .Build();
 })

Utilizar HTTP.sys com uma porta estática

Para utilizar uma porta estática com HTTP.sys, forneça o número da porta na Endpoint configuração:

  <Resources>
    <Endpoints>
      <Endpoint Protocol="http" Name="ServiceEndpoint" Port="80" />
    </Endpoints>
  </Resources>

Utilizar HTTP.sys com uma porta dinâmica

Para utilizar uma porta atribuída dinamicamente com HTTP.sys, omita a Port propriedade na Endpoint configuração:

  <Resources>
    <Endpoints>
      <Endpoint Protocol="http" Name="ServiceEndpoint" />
    </Endpoints>
  </Resources>

Uma porta dinâmica alocada por uma Endpoint configuração fornece apenas uma porta por processo anfitrião. O modelo de alojamento atual do Service Fabric permite que várias instâncias de serviço e/ou réplicas sejam alojadas no mesmo processo. Isto significa que cada uma partilhará a mesma porta quando alocada através da Endpoint configuração. Várias instâncias deHTTP.sys podem partilhar uma porta com a funcionalidade de partilha de portasHTTP.sys subjacente. No entanto, não é suportado pelo HttpSysCommunicationListener devido às complicações que introduz para pedidos de cliente. Para a utilização de portas dinâmicas, o Kestrel é o servidor Web sugerido.

Kestrel no Reliable Services

Pode utilizar o Kestrel no Reliable Services ao importar o pacote NuGet Microsoft.ServiceFabric.AspNetCore.Kestrel . Este pacote contém KestrelCommunicationListener, uma implementação do ICommunicationListener. KestrelCommunicationListenerpermite-lhe criar um ASP.NET Core WebHost dentro de um serviço fiável através do Kestrel como servidor Web.

O Kestrel é um servidor Web multiplataforma para ASP.NET Core. Ao contrário HTTP.sys, o Kestrel não utiliza um gestor de pontos finais centralizado. Ao contrário do HTTP.sys, o Kestrel não suporta a partilha de portas entre vários processos. Cada instância do Kestrel tem de utilizar uma porta exclusiva. Para obter mais informações sobre o Kestrel, veja Detalhes da Implementação.

Diagrama de Kestrel

Kestrel num serviço sem estado

Para utilizar Kestrel num serviço sem estado, substitua o CreateServiceInstanceListeners método e devolva uma KestrelCommunicationListener instância:

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return new ServiceInstanceListener[]
    {
        new ServiceInstanceListener(serviceContext =>
            new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
                new WebHostBuilder()
                    .UseKestrel()
                    .ConfigureServices(
                        services => services
                            .AddSingleton<StatelessServiceContext>(serviceContext))
                    .UseContentRoot(Directory.GetCurrentDirectory())
                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl)
                    .UseStartup<Startup>()
                    .UseUrls(url)
                    .Build();
            ))
    };
}

Kestrel num serviço com estado

Para utilizar Kestrel num serviço com monitorização de estado, substitua o CreateServiceReplicaListeners método e devolva uma KestrelCommunicationListener instância:

protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
    return new ServiceReplicaListener[]
    {
        new ServiceReplicaListener(serviceContext =>
            new KestrelCommunicationListener(serviceContext, (url, listener) =>
                new WebHostBuilder()
                    .UseKestrel()
                    .ConfigureServices(
                         services => services
                             .AddSingleton<StatefulServiceContext>(serviceContext)
                             .AddSingleton<IReliableStateManager>(this.StateManager))
                    .UseContentRoot(Directory.GetCurrentDirectory())
                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl)
                    .UseStartup<Startup>()
                    .UseUrls(url)
                    .Build();
            ))
    };
}

Neste exemplo, é fornecida uma instância singleton de ao contentor de IReliableStateManager injeção de dependência do WebHost. Isto não é estritamente necessário, mas permite-lhe utilizar IReliableStateManager e Reliable Collections nos métodos de ação do controlador MVC.

Um Endpoint nome de configuração não é fornecido a KestrelCommunicationListener num serviço com monitorização de estado. Isto é explicado mais detalhadamente na secção seguinte.

Configurar o Kestrel para utilizar HTTPS

Ao ativar o HTTPS com o Kestrel no seu serviço, terá de definir várias opções de escuta. Atualize o ServiceInstanceListener para utilizar um ponto final EndpointHttps e ouça numa porta específica (como a porta 443). Ao configurar o anfitrião Web para utilizar o servidor Web Kestrel, tem de configurar o Kestrel para escutar endereços IPv6 em todas as interfaces de rede:

new ServiceInstanceListener(
serviceContext =>
    new KestrelCommunicationListener(
        serviceContext,
        "EndpointHttps",
        (url, listener) =>
        {
            ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");

            return new WebHostBuilder()
                .UseKestrel(opt =>
                {
                    int port = serviceContext.CodePackageActivationContext.GetEndpoint("EndpointHttps").Port;
                    opt.Listen(IPAddress.IPv6Any, port, listenOptions =>
                    {
                        listenOptions.UseHttps(GetCertificateFromStore());
                        listenOptions.NoDelay = true;
                    });
                })
                .ConfigureAppConfiguration((builderContext, config) =>
                {
                    config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
                })

                .ConfigureServices(
                    services => services
                        .AddSingleton<HttpClient>(new HttpClient())
                        .AddSingleton<FabricClient>(new FabricClient())
                        .AddSingleton<StatelessServiceContext>(serviceContext))
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseStartup<Startup>()
                .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                .UseUrls(url)
                .Build();
        }))

Para obter um exemplo completo num tutorial, veja Configurar o Kestrel para utilizar HTTPS.

Configuração do ponto final

Não Endpoint é necessária uma configuração para utilizar o Kestrel.

O Kestrel é um servidor Web autónomo simples. Ao contrário HTTP.sys (ou HttpListener), não precisa de uma configuração Endpoint no ServiceManifest.xml porque não requer o registo de URL antes de iniciar.

Utilizar o Kestrel com uma porta estática

Pode configurar uma porta estática na Endpoint configuração do ServiceManifest.xml para utilização com o Kestrel. Embora tal não seja estritamente necessário, oferece dois potenciais benefícios:

  • Se a porta não cair no intervalo de portas da aplicação, será aberta através da firewall do SO pelo Service Fabric.
  • O URL que lhe foi fornecido irá KestrelCommunicationListener utilizar esta porta.
  <Resources>
    <Endpoints>
      <Endpoint Protocol="http" Name="ServiceEndpoint" Port="80" />
    </Endpoints>
  </Resources>

Se um Endpoint estiver configurado, o respetivo nome tem de ser transmitido para o KestrelCommunicationListener construtor:

new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) => ...

Se ServiceManifest.xml não utilizar uma configuração Endpoint , omita o nome no KestrelCommunicationListener construtor. Neste caso, irá utilizar uma porta dinâmica. Consulte a secção seguinte para obter mais informações sobre isto.

Utilizar o Kestrel com uma porta dinâmica

O Kestrel não consegue utilizar a atribuição automática de portas a Endpoint partir da configuração no ServiceManifest.xml. Isto acontece porque a atribuição automática de portas a partir de uma Endpoint configuração atribui uma porta exclusiva por processo anfitrião e um único processo de anfitrião pode conter várias instâncias do Kestrel. Isto não funciona com o Kestrel porque não suporta a partilha de portas. Por conseguinte, cada instância do Kestrel tem de ser aberta numa porta exclusiva.

Para utilizar a atribuição de portas dinâmicas com o Kestrel, omita totalmente a Endpoint configuração no ServiceManifest.xml e não transmita um nome de ponto final ao KestrelCommunicationListener construtor, da seguinte forma:

new KestrelCommunicationListener(serviceContext, (url, listener) => ...

Nesta configuração, KestrelCommunicationListener irá selecionar automaticamente uma porta não utilizada no intervalo de portas da aplicação.

Para HTTPS, deve ter o Ponto Final configurado com o protocolo HTTPS sem uma porta especificada no ServiceManifest.xml e passar o nome do ponto final para o construtor KestrelCommunicationListener.

Integração de IHost e Alojamento Mínimo

Além do IWebHost/IWebHostBuilder, KestrelCommunicationListener e HttpSysCommunicationListener suporta a criação de serviços ASP.NET Core com o IHost/IHostBuilder. Está disponível a partir da v5.2.1363 de Microsoft.ServiceFabric.AspNetCore.Kestrel e Microsoft.ServiceFabric.AspNetCore.HttpSys pacotes.

// Stateless Service
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return new ServiceInstanceListener[]
    {
        new ServiceInstanceListener(serviceContext =>
            new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
            {
                return Host.CreateDefaultBuilder()
                        .ConfigureWebHostDefaults(webBuilder =>
                        {
                            webBuilder.UseKestrel()
                                .UseStartup<Startup>()
                                .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                                .UseContentRoot(Directory.GetCurrentDirectory())
                                .UseUrls(url);
                        })
                        .ConfigureServices(services => services.AddSingleton<StatelessServiceContext>(serviceContext))
                        .Build();
            }))
    };
}

// Stateful Service
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
    return new ServiceReplicaListener[]
    {
        new ServiceReplicaListener(serviceContext =>
            new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
            {
                return Host.CreateDefaultBuilder()
                        .ConfigureWebHostDefaults(webBuilder =>
                        {
                            webBuilder.UseKestrel()
                                .UseStartup<Startup>()
                                .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl)
                                .UseContentRoot(Directory.GetCurrentDirectory())
                                .UseUrls(url);
                        })
                        .ConfigureServices(services =>
                        {
                            services.AddSingleton<StatefulServiceContext>(serviceContext);
                            services.AddSingleton<IReliableStateManager>(this.StateManager);
                        })
                        .Build();
            }))
    };
}

Nota

Uma vez que KestrelCommunicationListener e HttpSysCommunicationListener se destinam a serviços Web, é necessário registar/configurar um servidor Web (através do método ConfigureWebHostDefaults ou ConfigureWebHost ) através do IHost

ASP.NET 6 introduziu o modelo de Alojamento Mínimo, que é uma forma mais simplificada e simplificada de criar aplicações Web. O modelo de alojamento mínimo também pode ser utilizado com KestrelCommunicationListener e HttpSysCommunicationListener.

// Stateless Service
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return new ServiceInstanceListener[]
    {
        new ServiceInstanceListener(serviceContext =>
            new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
            {
                var builder = WebApplication.CreateBuilder();

                builder.Services.AddSingleton<StatelessServiceContext>(serviceContext);
                builder.WebHost
                            .UseKestrel()
                            .UseContentRoot(Directory.GetCurrentDirectory())
                            .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                            .UseUrls(url);

                builder.Services.AddControllersWithViews();

                var app = builder.Build();

                if (!app.Environment.IsDevelopment())
                {
                    app.UseExceptionHandler("/Home/Error");
                }

                app.UseHttpsRedirection();
                app.UseStaticFiles();
                app.UseRouting();
                app.UseAuthorization();
                app.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");

                return app;
            }))
    };
}
// Stateful Service
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
    return new ServiceReplicaListener[]
    {
        new ServiceReplicaListener(serviceContext =>
            new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
            {
                var builder = WebApplication.CreateBuilder();

                builder.Services
                            .AddSingleton<StatefulServiceContext>(serviceContext)
                            .AddSingleton<IReliableStateManager>(this.StateManager);
                builder.WebHost
                            .UseKestrel()
                            .UseContentRoot(Directory.GetCurrentDirectory())
                            .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl)
                            .UseUrls(url);

                builder.Services.AddControllersWithViews();

                var app = builder.Build();

                if (!app.Environment.IsDevelopment())
                {
                    app.UseExceptionHandler("/Home/Error");
                }
                app.UseStaticFiles();
                app.UseRouting();
                app.UseAuthorization();
                app.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");

                return app;
            }))
    };
}

Fornecedor de configuração do Service Fabric

A configuração da aplicação no ASP.NET Core baseia-se em pares chave-valor estabelecidos pelo fornecedor de configuração. Leia Configuração no ASP.NET Core para saber mais sobre o suporte geral de configuração de ASP.NET Core.

Esta secção descreve como o fornecedor de configuração do Service Fabric se integra com ASP.NET Core configuração ao importar o Microsoft.ServiceFabric.AspNetCore.Configuration pacote NuGet.

AddServiceFabricConfiguration startup extensions (Extensões de arranque addServiceFabricConfiguration)

Depois de importar o Microsoft.ServiceFabric.AspNetCore.Configuration pacote NuGet, tem de registar a origem de Configuração do Service Fabric com ASP.NET Core API de configuração. Para tal, verifique as extensões AddServiceFabricConfiguration no espaço de nomes em relação IConfigurationBuildera Microsoft.ServiceFabric.AspNetCore.Configuration .

using Microsoft.ServiceFabric.AspNetCore.Configuration;

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddServiceFabricConfiguration() // Add Service Fabric configuration settings.
        .AddEnvironmentVariables();
    Configuration = builder.Build();
}

public IConfigurationRoot Configuration { get; }

Agora, o serviço ASP.NET Core pode aceder às definições de configuração do Service Fabric, tal como qualquer outra definição da aplicação. Por exemplo, pode utilizar o padrão de opções para carregar definições em objetos com tipos fortes.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration);  // Strongly typed configuration object.
    services.AddMvc();
}

Mapeamento de chaves predefinido

Por predefinição, o fornecedor de configuração do Service Fabric inclui o nome do pacote, o nome da secção e o nome da propriedade. Em conjunto, estes formulários formam a chave de configuração ASP.NET Core, da seguinte forma:

$"{this.PackageName}{ConfigurationPath.KeyDelimiter}{section.Name}{ConfigurationPath.KeyDelimiter}{property.Name}"

Por exemplo, se tiver um pacote de configuração com MyConfigPackage o nome com o seguinte conteúdo, o valor de configuração estará disponível no ASP.NET Core IConfiguration através de MyConfigPackage:MyConfigSection:MyParameter.

<?xml version="1.0" encoding="utf-8" ?>
<Settings xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2011/01/fabric">  
  <Section Name="MyConfigSection">
    <Parameter Name="MyParameter" Value="Value1" />
  </Section>  
</Settings>

Opções de configuração do Service Fabric

O fornecedor de configuração do Service Fabric também suporta ServiceFabricConfigurationOptions a alteração do comportamento predefinido do mapeamento de chaves.

Definições encriptadas

O Service Fabric suporta definições encriptadas, tal como o fornecedor de configuração do Service Fabric. As definições encriptadas não são desencriptadas para ASP.NET Core IConfiguration por predefinição. Em vez disso, os valores encriptados são armazenados aí. No entanto, se quiser desencriptar o valor a armazenar no ASP.NET Core IConfiguration, pode definir o sinalizador DecryptValue como falso na AddServiceFabricConfiguration extensão, da seguinte forma:

public Startup()
{
    ICodePackageActivationContext activationContext = FabricRuntime.GetActivationContext();
    var builder = new ConfigurationBuilder()        
        .AddServiceFabricConfiguration(activationContext, (options) => options.DecryptValue = false); // set flag to decrypt the value
    Configuration = builder.Build();
}

Vários pacotes de configuração

O Service Fabric suporta vários pacotes de configuração. Por predefinição, o nome do pacote está incluído na chave de configuração. Mas pode definir o IncludePackageName sinalizador como falso, da seguinte forma:

public Startup()
{
    ICodePackageActivationContext activationContext = FabricRuntime.GetActivationContext();
    var builder = new ConfigurationBuilder()        
        // exclude package name from key.
        .AddServiceFabricConfiguration(activationContext, (options) => options.IncludePackageName = false); 
    Configuration = builder.Build();
}

Mapeamento de chaves personalizada, extração de valores e população de dados

O fornecedor de configuração do Service Fabric também suporta cenários mais avançados para personalizar o mapeamento de chaves com ExtractKeyFunc e extrair os valores com ExtractValueFunc. Pode até alterar todo o processo de povoamento de dados da configuração do Service Fabric para ASP.NET Core configuração com ConfigAction.

Os exemplos seguintes ilustram como utilizar ConfigAction para personalizar a população de dados:

public Startup()
{
    ICodePackageActivationContext activationContext = FabricRuntime.GetActivationContext();
    
    this.valueCount = 0;
    this.sectionCount = 0;
    var builder = new ConfigurationBuilder();
    builder.AddServiceFabricConfiguration(activationContext, (options) =>
        {
            options.ConfigAction = (package, configData) =>
            {
                ILogger logger = new ConsoleLogger("Test", null, false);
                logger.LogInformation($"Config Update for package {package.Path} started");

                foreach (var section in package.Settings.Sections)
                {
                    this.sectionCount++;

                    foreach (var param in section.Parameters)
                    {
                        configData[options.ExtractKeyFunc(section, param)] = options.ExtractValueFunc(section, param);
                        this.valueCount++;
                    }
                }

                logger.LogInformation($"Config Update for package {package.Path} finished");
            };
        });
  Configuration = builder.Build();
}

Atualizações de configuração

O fornecedor de configuração do Service Fabric também suporta atualizações de configuração. Pode utilizar ASP.NET Core IOptionsMonitor para receber notificações de alteração e, em seguida, utilizar IOptionsSnapshot para recarregar dados de configuração. Para obter mais informações, veja ASP.NET Core opções.

Estas opções são suportadas por predefinição. Não é necessária mais codificação para ativar as atualizações de configuração.

Cenários e configurações

Esta secção fornece a combinação de servidor Web, configuração de portas, opções de integração do Service Fabric e definições diversas que recomendamos para resolver os seguintes cenários:

  • Serviços sem estado ASP.NET Core expostos externamente
  • Serviços só internos ASP.NET Core sem estado
  • Serviços com estado apenas internos ASP.NET Core

Um serviço exposto externamente é aquele que expõe um ponto final chamado de fora do cluster, normalmente através de um balanceador de carga.

Um serviço apenas interno é aquele cujo ponto final só é chamado a partir do cluster.

Nota

Geralmente, os pontos finais de serviço com estado não devem ser expostos à Internet. Os clusters por trás de balanceadores de carga que desconhecem a resolução do serviço Service Fabric, como Balanceador de Carga do Azure, não poderão expor serviços com estado. Tal deve-se ao facto de o balanceador de carga não conseguir localizar e encaminhar o tráfego para a réplica de serviço com estado adequado.

Serviços sem estado ASP.NET Core expostos externamente

O Kestrel é o servidor Web sugerido para serviços de front-end que expõem pontos finais HTTP externos e com acesso à Internet. No Windows, HTTP.sys pode fornecer capacidade de partilha de portas, o que lhe permite alojar vários serviços Web no mesmo conjunto de nós com a mesma porta. Neste cenário, os serviços Web são diferenciados pelo nome ou caminho do anfitrião, sem depender de um proxy de front-end ou gateway para fornecer o encaminhamento HTTP.

Quando exposto à Internet, um serviço sem estado deve utilizar um ponto final bem conhecido e estável que seja acessível através de um balanceador de carga. Irá fornecer este URL aos utilizadores da sua aplicação. Recomendamos a seguinte configuração:

Tipo Recomendação Notas
Servidor Web Kestrel O Kestrel é o servidor Web preferido, uma vez que é suportado no Windows e linux.
Configuração de portas static Uma porta estática bem conhecida deve ser configurada na Endpoints configuração de ServiceManifest.xml, como 80 para HTTP ou 443 para HTTPS.
ServiceFabricIntegrationOptions Nenhuma Utilize a opção ao configurar o ServiceFabricIntegrationOptions.None middleware de integração do Service Fabric, para que o serviço não tente validar os pedidos recebidos de um identificador exclusivo. Os utilizadores externos da sua aplicação não conhecerão as informações de identificação exclusivas que o middleware utiliza.
Contagem de Instâncias -1 Em casos de utilização típicos, a definição de contagem de instâncias deve ser definida como -1. Isto é feito para que uma instância esteja disponível em todos os nós que recebem tráfego de um balanceador de carga.

Se vários serviços expostos externamente partilharem o mesmo conjunto de nós, pode utilizar HTTP.sys com um caminho de URL exclusivo, mas estável. Pode fazê-lo ao modificar o URL fornecido ao configurar o IWebHost. Tenha em atenção que isto se aplica apenas a HTTP.sys.

new HttpSysCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
{
    url += "/MyUniqueServicePath";

    return new WebHostBuilder()
        .UseHttpSys()
        ...
        .UseUrls(url)
        .Build();
})

Serviço de ASP.NET Core sem estado interno

Os serviços sem estado que são chamados apenas a partir do cluster devem utilizar URLs exclusivos e portas atribuídas dinamicamente para garantir a cooperação entre vários serviços. Recomendamos a seguinte configuração:

Tipo Recomendação Notas
Servidor Web Kestrel Embora possa utilizar HTTP.sys para serviços internos sem estado, o Kestrel é o melhor servidor para permitir que várias instâncias de serviço partilhem um anfitrião.
Configuração de portas atribuído dinamicamente Várias réplicas de um serviço com estado podem partilhar um processo de anfitrião ou sistema operativo anfitrião e, assim, precisarão de portas exclusivas.
ServiceFabricIntegrationOptions UseUniqueServiceUrl Com a atribuição de porta dinâmica, esta definição impede o problema de identidade errado descrito anteriormente.
InstanceCount qualquer A definição de contagem de instâncias pode ser definida como qualquer valor necessário para operar o serviço.

Serviço de ASP.NET Core com estado interno

Os serviços com estado que são chamados apenas a partir do cluster devem utilizar portas atribuídas dinamicamente para garantir a cooperação entre vários serviços. Recomendamos a seguinte configuração:

Tipo Recomendação Notas
Servidor Web Kestrel O HttpSysCommunicationListener não foi concebido para ser utilizado por serviços com estado em que as réplicas partilham um processo de anfitrião.
Configuração de portas atribuído dinamicamente Várias réplicas de um serviço com estado podem partilhar um processo de anfitrião ou sistema operativo anfitrião e, assim, precisarão de portas exclusivas.
ServiceFabricIntegrationOptions UseUniqueServiceUrl Com a atribuição de porta dinâmica, esta definição impede o problema de identidade errado descrito anteriormente.

Passos seguintes

Depurar a sua aplicação do Service Fabric com o Visual Studio