Поделиться через


ASP.NET Core в Microsoft Azure Service Fabric Reliable Services

ASP.NET Core — это кроссплатформенная среда с открытым исходным кодом. Она предназначена для создания облачных приложений с подключением к Интернету, таких как веб-приложения, приложения для Интернета вещей и серверные части мобильных приложений.

Эта статья представляет собой подробное руководство по размещению служб ASP.NET Core в надежных службах Service Fabric Reliable Services с использованием набора пакетов NuGet Microsoft.ServiceFabric.AspNetCore.

Вводное руководство по ASP.NET Core в Microsoft Azure Service Fabric и инструкции по настройке среды разработки см. в разделе Руководство по созданию и развертыванию приложения с интерфейсной службой веб-API ASP.NET Core и серверной службой с отслеживанием состояния.

В оставшейся части этой статьи предполагается, что вы знакомы с ASP.NET Core. В противном случае ознакомьтесь с основными сведениями об ASP.NET Core.

ASP.NET Core в среде Service Fabric

Приложения ASP.NET Core и Microsoft Azure Service Fabric можно запускать в .NET Core или в полной версии .NET Framework. Вы можете использовать ASP.NET Core в Microsoft Azure Service Fabric двумя различными способами:

  • Разместить в виде гостевого исполняемого файла. В основном этот способ используется для запуска существующих приложений ASP.NET Core в Microsoft Azure Service Fabric без изменения кода.
  • Выполнить в службе Reliable Service. Этот способ обеспечивает более эффективную интеграцию со средой выполнения Microsoft Azure Service Fabric и позволяет использовать службы ASP.NET Core с отслеживанием состояния.

Далее в этой статье объясняется, как использовать ASP.NET Core внутри надежной службы с помощью компонентов интеграции ASP.NET, поставляемых с пакетом средств разработки программного обеспечения для Microsoft Azure Service Fabric.

Размещение службы Service Fabric

В Microsoft Azure Service Fabric один или несколько экземпляров и (или) реплик службы выполняются в хост-процессе службы — исполняемом файле, который выполняет код службы. Создателю службы принадлежит хост-процесс службы, который Microsoft Azure Service Fabric активирует и отслеживает.

Обычно ASP.NET (до MVC 5) тесно связан с IIS через System.Web.dll. ASP.NET Core разделяет веб-сервер и веб-приложение. Такое разделение обеспечивает возможность переноса веб-приложений с одного веб-сервера на другой. Это также позволяет размещать веб-серверы локально. Это означает, что вы можете запустить веб-сервер в собственном процессе, а не в процессе, принадлежащем программному обеспечению выделенного веб-сервера, например IIS.

Чтобы объединить службу Microsoft Azure Service Fabric и ASP.NET в качестве гостевого исполняемого приложения или в надежной службе, необходимо запустить ASP.NET в хост-процессе службы. Автономное размещение ASP.NET Core позволяет это сделать.

Размещение ASP.NET Core в надежной службе

Как правило, автономно размещаемые приложения ASP.NET Core создают WebHost в точке входа приложения, например метод static void Main() в Program.cs. В таком случае жизненный цикл WebHost привязан к жизненному циклу процесса.

Размещение ASP.NET Core в процессе

Но точка входа приложения не является подходящим местом для создания WebHost в надежной службе. Это связано с тем, что точка входа приложения используется только для регистрации типа службы в среде выполнения Microsoft Azure Service Fabric, чтобы она могла создавать экземпляры этого типа службы. WebHost должен создаваться в самой надежной службе. В хост-процессе службы экземпляры службы и (или) реплики могут проходить несколько жизненных циклов.

Экземпляр Reliable Service представлен с помощью класса службы, производного от StatelessService или StatefulService. Стек связи для службы содержится в реализации ICommunicationListener класса службы. Пакеты NuGet Microsoft.ServiceFabric.AspNetCore.* содержат реализации ICommunicationListener, которые запускают и администрируют ASP.NET Core WebHost для Kestrel или HTTP.sys в надежной службе.

Схема размещения ASP.NET Core в надежной службе

Объекты ICommunicationListener в ASP.NET Core

Реализации ICommunicationListener для Kestrel и HTTP.sys в пакетах NuGet Microsoft.ServiceFabric.AspNetCore.* имеют одинаковые шаблоны использования. Но они выполняют немного различные действия, характерные для каждого веб-сервера.

Оба прослушивателя связи предоставляют конструктор, который принимает следующие аргументы:

  • ServiceContext serviceContext . Это объект ServiceContext, содержащий сведения о выполняемой службе.
  • string endpointName . Это имя конфигурации Endpoint в файле ServiceManifest.xml. Это основное отличие прослушивателей связи: для HTTP.sys требуется конфигурация Endpoint, а для Kestrel — нет.
  • Func<string, AspNetCoreCommunicationListener, IWebHost> build . Это реализуемое лямбда-выражение, в котором создается и возвращается IWebHost. Это позволяет настроить IWebHost так же, как в приложении ASP.NET Core. Лямбда-выражение содержит URL-адрес, который создается в зависимости от используемых параметров интеграции Microsoft Azure Service Fabric и предоставляемой конфигурации Endpoint. Затем вы можете изменить этот URL-адрес или использовать для запуска веб-сервера.

ПО промежуточного уровня для интеграции Service Fabric

Пакет NuGet Microsoft.ServiceFabric.AspNetCore содержит метод расширения UseServiceFabricIntegration в IWebHostBuilder, который добавляет ПО промежуточного слоя, поддерживающее Microsoft Azure Service Fabric. Это ПО промежуточного слоя настраивает Kestrel или HTTP.sys ICommunicationListener для регистрации уникального URL-адреса службы в Службе именования Microsoft Azure Service Fabric. Затем он проверяет клиентские запросы, чтобы обеспечить подключение клиентов к соответствующей службе.

Этот шаг необходим для предотвращения ошибочного подключения клиентов к неправильной службе. Это связано с тем, что в среде совместного размещения, такой как Microsoft Azure Service Fabric, несколько веб-приложений могут выполняться на одном физическом компьютере или виртуальной машине, но не использовать уникальные имена узлов. Данный сценарий описан более подробно в следующем разделе.

Причина ошибочный идентификации

Реплики службы, независимо от протокола, прослушивают уникальное сочетание "IP-адрес:порт". Начав прослушивать сочетание "IP-адрес:порт" конечной точки, реплика службы сообщает адрес этой конечной точки Службе именования Microsoft Azure Service Fabric. Там его могут обнаружить клиенты или другие службы. Если службы используют динамически назначаемые порты приложения, реплика службы может случайно использовать ту же конечную точку "IP-адрес:порт" другой службы, которая ранее находилась на том же физическом компьютере или виртуальной машине. Это может привести к ошибочному подключению клиента к неверной службе, что может произойти, если возникает следующая последовательность событий:

  1. Служба А прослушивает 10.0.0.1:30000 по протоколу HTTP.
  2. Клиент разрешает службу А и получает адрес 10.0.0.1:30000.
  3. Служба А перемещается на другой узел.
  4. Служба Б помещается в 10.0.0.1 и случайно использует тот же порт 30000.
  5. Клиент пытается подключиться к службе А с помощью кэшированного адреса 10.0.0.1:30000.
  6. Теперь клиент подключен к службе Б, не зная, что подключен к неверной службе.

Это может периодически вызывать ошибки, которые трудно диагностировать.

Использование уникальных URL-адресов службы

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

В доверенной среде ПО промежуточного слоя, которое добавляется с помощью метода UseServiceFabricIntegration, автоматически добавляет уникальный идентификатор к адресу, размещенному в Службе именования. Оно проверяет этот идентификатор в каждом запросе. Если идентификатор не совпадает, ПО промежуточного слоя немедленно возвращает ответ HTTP 410 Gone (HTTP 410 — потеряно).

Службы, использующие динамически назначаемый порт, должны использовать это ПО промежуточного слоя.

Службы, использующие постоянный уникальный порт, не имеют такой проблемы в совместной среде. Постоянный уникальный порт обычно используется для внешних служб, которым необходим известный порт для подключения клиентских приложений. Например, большинство веб-приложений с доступом к Интернету используют порт 80 или 443 для соединений веб-браузера. В этом случае не следует включать уникальный идентификатор.

На схеме ниже показан поток запроса с включенным ПО промежуточного слоя.

Интеграция Service Fabric ASP.NET Core

Реализации ICommunicationListener Kestrel и HTTP.sys используют этот механизм совершенно одинаковым образом. Несмотря на то что HTTP.sys может внутренне различать запросы на основе уникальных URL-адресов с помощью базовой функции совместного использования портов HTTP.sys, эта функция не используется реализацией ICommunicationListener HTTP.sys. Иначе могут возникать ошибки с кодами состояния HTTP 503 и HTTP 404 в сценарии, описанном выше. В свою очередь для клиентов это усложняет определение причины ошибки, так как HTTP 503 и HTTP 404 часто используются для указания других ошибок.

Поэтому реализации ICommunicationListener Kestrel и HTTP.sys стандартизируются в ПО промежуточного слоя, предоставляемом методом расширения UseServiceFabricIntegration. Таким образом, клиентам необходимо выполнить только действие повторного разрешения конечной точки службы для ответов HTTP 410.

HTTP.sys в Reliable Services

HTTP.sys можно использовать в Reliable Services, импортировав пакет NuGet Microsoft.ServiceFabric.AspNetCore.HttpSys. Этот пакет содержит HttpSysCommunicationListener (реализацию ICommunicationListener). HttpSysCommunicationListener позволяет создать WebHost ASP.NET Core в надежной службе, используя HTTP.sys в качестве веб-сервера.

HTTP.sys основан на API сервера HTTP Windows. Этот API использует драйвер ядра HTTP.sys для обработки HTTP-запросов и их перенаправления в процессы, выполняющие веб-приложения. Это позволяет нескольким процессам на одном физическом компьютере или виртуальной машине размещать на одном порту веб-приложения, которые отличаются уникальным URL-адресом или именем узла. Эти функции в Service Fabric полезны для размещения нескольких веб-сайтов в одном кластере.

Примечание

Реализация HTTP.sys работает только на платформе Windows.

На следующей схеме показано, как HTTP.sys использует драйвер ядра HTTP.sys в Windows для совместного использования портов:

Схема HTTP.sys

HTTP.sys в службе без отслеживания состояния

Для использования HttpSys в службе без отслеживания состояния переопределите метод CreateServiceInstanceListeners и верните экземпляр HttpSysCommunicationListener:

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 в службе с отслеживанием состояния

HttpSysCommunicationListener в настоящее время не предназначен для использования в службах с отслеживанием состояния из-за сложности с базовой функцией совместного использования портов HTTP.sys. Дополнительные сведения о динамическом назначении портов HTTP.sys см. в следующем разделе. Для служб с отслеживанием состояния рекомендуется в качестве веб-сервера использовать Kestrel.

Конфигурация конечной точки

Для веб-серверов, использующих API сервера HTTP Windows (включая HTTP.sys), требуется конфигурация Endpoint. Для веб-серверов, использующих API сервера HTTP Windows, сначала необходимо зарезервировать URL-адрес в HTTP.sys (обычно это осуществляется с помощью инструмента netsh).

Для этого действия требуется более высокий уровень привилегий, которого по умолчанию нет у служб. Параметры "http" или "https" для свойства Protocol конфигурации Endpoint в файле ServiceManifest.xml используются специально для того, чтобы сообщить среде выполнения Microsoft Azure Service Fabric о необходимости регистрации URL-адреса в HTTP.sys от вашего имени. Для этого используется префикс URL-адреса со строгими подстановочными знаками.

Например, чтобы зарезервировать http://+:80 для службы, в файле ServiceManifest.xml используйте следующую конфигурацию:

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

</ServiceManifest>

Также необходимо передать имя конечной точки в конструктор HttpSysCommunicationListener.

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

Использование HTTP.sys со статическим портом

Чтобы использовать статический порт с HTTP.sys, укажите номер порта в конфигурации Endpoint:

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

Использование HTTP.sys с динамическим портом

Чтобы использовать динамически назначаемый порт с HTTP.sys, опустите свойство Port в конфигурации Endpoint:

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

Динамический порт, выделенный с помощью конфигурации Endpoint, предоставляет только один порт каждому хост-процессу. Текущая модель размещения Microsoft Azure Service Fabric позволяет размещать несколько экземпляров службы и (или) реплик в одном процессе. То есть все они будут совместно использовать один и тот же порт при выделении через конфигурацию Endpoint. Несколько экземпляров HTTP.sys могут совместно использовать порт с помощью базовой функции совместного использования портов HTTP.sys. Но это не поддерживается HttpSysCommunicationListener из-за сложности, которая создается для клиентских запросов. Для использования динамических портов рекомендуемым веб-сервером является Kestrel.

Kestrel в Reliable Services

Kestrel можно использовать в Reliable Services, импортировав пакет NuGet Microsoft.ServiceFabric.AspNetCore.Kestrel. Этот пакет содержит KestrelCommunicationListener (реализацию ICommunicationListener). KestrelCommunicationListener позволяет создать WebHost ASP.NET Core в надежной службе, используя Kestrel в качестве веб-сервера.

Kestrel — это кроссплатформенный веб-сервер для ASP.NET Core. В отличие от HTTP.sys, Kestrel не использует централизованный диспетчер конечных точек и не поддерживает совместное использование порта несколькими процессами. Каждый экземпляр Kestrel должен использовать уникальный порт. Дополнительные сведения о Kestrel см. в разделе Сведения о реализации.

Схема Kestrel

Kestrel в службе без отслеживания состояния

Для использования Kestrel в службе без отслеживания состояния переопределите метод CreateServiceInstanceListeners и верните экземпляр KestrelCommunicationListener:

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 в службе с отслеживанием состояния

Для использования Kestrel в службе с отслеживанием состояния переопределите метод CreateServiceReplicaListeners и верните экземпляр KestrelCommunicationListener:

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

В этом примере одноэлементный экземпляр IReliableStateManager предоставляется контейнеру внедрения зависимостей WebHost. Это не является обязательным, но позволяет использовать IReliableStateManager и надежные коллекции в методах действий контроллера MVC.

Имя конфигурации Endpointне предоставляется KestrelCommunicationListener в службе с отслеживанием состояния. Это объясняется более подробно в следующем разделе.

Настройка Kestrel для использования HTTPS

При включении HTTPS с использованием Kestrel в службе вам потребуется задать несколько параметров для ожидания передачи данных. Обновите ServiceInstanceListener, чтобы использовать конечную точку EndpointHttps и ожидать передачи данных на определенном порту (например, на порту 443). При настройке веб-узла для использования веб-сервера Kestrel нужно настроить на сервере Kestrel ожидание передачи данных на IPv6-адреса для всех сетевых интерфейсов:

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

Полный пример, используемый в руководстве, см. в разделе Настройка Kestrel для использования HTTPS.

Конфигурация конечной точки

Для использования Kestrel конфигурация Endpoint не требуется.

Kestrel является простым изолированным веб-сервером. В отличие от HTTP.sys (или HttpListener), для него не требуется конфигурация Endpoint в ServiceManifest.xml, так как для запуска не нужна регистрация URL-адреса.

Использование Kestrel и статического порта

Можно настроить статический порт в конфигурации Endpoint файла ServiceManifest.xml для использования с Kestrel. Хотя это не является обязательным, это обеспечивает два потенциальных преимущества:

  • Если порт не попадает в диапазон портов для приложений, он открывается в брандмауэре ОС с помощью Microsoft Azure Service Fabric.
  • URL-адрес, предоставленный с помощью KestrelCommunicationListener, будет использовать этот порт.
  <Resources>
    <Endpoints>
      <Endpoint Protocol="http" Name="ServiceEndpoint" Port="80" />
    </Endpoints>
  </Resources>

Если Endpoint настроена, ее имя необходимо передать в конструктор KestrelCommunicationListener.

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

Если в ServiceManifest.xml не используется конфигурация Endpoint, не указывайте имя в конструкторе KestrelCommunicationListener. В этом случае будет использоваться динамический порт. Этот процесс подробнее описан в следующем разделе.

Использование Kestrel и динамического порта

Kestrel не может использовать автоматическое назначение портов из конфигурации Endpoint в файле ServiceManifest.xml. Это связано с тем, что автоматическое назначение портов из конфигурации Endpoint присваивает уникальный порт каждому хост-процессу, а один хост-процесс может содержать несколько экземпляров Kestrel. В случае с Kestrel это не работает, так как Kestrel не поддерживает совместное использование портов. Поэтому каждый экземпляр Kestrel должен быть открыт на уникальном порту.

Чтобы использовать динамическое назначение портов в Kestrel, полностью опустите конфигурацию Endpoint в файле ServiceManifest.xml и не передавайте имя конечной точки в конструктор KestrelCommunicationListener:

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

В этой конфигурации KestrelCommunicationListener автоматически выберет неиспользуемый порт из диапазона портов приложения.

Для HTTPS должна быть настроена конечная точка с протоколом HTTPS без порта, указанного в файле ServiceManifest.xml, и имя конечной точки должно передаваться в конструктор KestrelCommunicationListener.

Интеграция IHost и минимального размещения

Кроме IWebHost/IWebHostBuilder, KestrelCommunicationListener и HttpSysCommunicationListener поддерживают создание служб ASP.NET Coree с помощью IHost/IHostBuilder. Эта возможность доступна начиная с версии 5.2.1363 пакетов Microsoft.ServiceFabric.AspNetCore.Kestrel и Microsoft.ServiceFabric.AspNetCore.HttpSys.

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

Примечание

Поскольку KestrelCommunicationListener и HttpSysCommunicationListener предназначены для веб-служб, необходимо зарегистрировать или настроить веб-сервер (с помощью метода ConfigureWebHostDefaults или ConfigureWebHost ) через IHost

В ASP.NET 6 появилась модель минимального размещения, которая является более простым и быстрым способом создания веб-приложений. Модель минимального размещения также можно использовать с KestrelCommunicationListener и 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;
            }))
    };
}

Поставщик конфигурации Microsoft Azure Service Fabric

Конфигурация приложения в ASP.NET Core основана на парах "ключ — значение", установленных поставщиком конфигурации. Прочитайте раздел Конфигурация в ASP.NET Core, чтобы подробнее узнать о поддержке общей конфигурации ASP.NET Core.

В этом разделе описано, как поставщик конфигурации Microsoft Azure Service Fabric интегрируется с конфигурацией ASP.NET Core путем импорта пакета NuGet Microsoft.ServiceFabric.AspNetCore.Configuration.

Расширения запуска AddServiceFabricConfiguration

После импорта пакета NuGet Microsoft.ServiceFabric.AspNetCore.Configuration необходимо зарегистрировать источник конфигурации Microsoft Azure Service Fabric с помощью API конфигурации ASP.NET Core. Для этого нужно проверить сравнить расширения AddServiceFabricConfiguration в пространстве имен Microsoft.ServiceFabric.AspNetCore.Configuration с IConfigurationBuilder.

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

Теперь служба ASP.NET Core может получить доступ к параметрам конфигурации Microsoft Azure Service Fabric, как и к любым другим параметрам приложения. Например, можно использовать шаблон параметров для загрузки параметров в строго типизированные объекты.

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

Сопоставление ключей по умолчанию

По умолчанию поставщик конфигурации Microsoft Azure Service Fabric содержит имя пакета, имя раздела и имя свойства. Вместе они формируют ключ конфигурации ASP.NET Core следующим образом:

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

Например, если есть пакет конфигурации MyConfigPackage со следующим содержимым, то значение конфигурации будет доступно в ASP.NET Core IConfiguration в 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>

Опции конфигурации Microsoft Azure Service Fabric

Поставщик конфигурации Microsoft Azure Service Fabric также поддерживает ServiceFabricConfigurationOptions для изменение сопоставления ключей по умолчанию.

Зашифрованные параметры

Microsoft Azure Service Fabric поддерживает зашифрованные параметры, как и поставщик конфигурации Microsoft Azure Service Fabric. Зашифрованные параметры не расшифровываются в ASP.NET Core IConfiguration по умолчанию. Вместо этого хранятся зашифрованные значения. Но если вы хотите расшифровать значение, которое будет храниться в ASP.NET Core IConfiguration, в расширении AddServiceFabricConfiguration можно установить для флага DecryptValue значение false следующим образом:

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

Несколько пакетов конфигурации

Microsoft Azure Service Fabric поддерживает несколько пакетов конфигурации. По умолчанию имя пакета включается в ключ конфигурации. Но можно установить для флага IncludePackageName значение false следующим образом:

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

Пользовательское сопоставление ключей, извлечение значений и заполнение данных

Поставщик конфигурации Microsoft Azure Service Fabric также поддерживает более сложные сценарии для настройки сопоставления ключей с ExtractKeyFunc и настраиваемого извлечения значений с помощью ExtractValueFunc. Можно даже изменить весь процесс заполнения данных из конфигурации Microsoft Azure Service Fabric в конфигурацию ASP.NET Core с помощью ConfigAction.

В следующих примерах показано, как использовать ConfigAction для настройки заполнения данных.

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

Обновления конфигурации

Поставщик конфигурации Microsoft Azure Service Fabric также поддерживает обновления конфигурации. Вы можете использовать ASP.NET Core IOptionsMonitor для получения уведомлений об изменениях, а затем использовать IOptionsSnapshot для повторной загрузки данных конфигурации. Подробные сведения см. в статье Параметры ASP.NET Core.

Эти параметры поддерживаются по умолчанию. Для включения обновлений конфигурации написание дополнительного кода не требуется.

Сценарии и конфигурации

В этом разделе представлено сочетание параметров веб-сервера, конфигурации портов, интеграции Microsoft Azure Service Fabric и прочих параметров, которые мы рекомендуем использовать для устранения неполадок в следующих сценариях.

  • Доступные извне службы ASP.NET Core без отслеживания состояния
  • Службы ASP.NET Core без отслеживания состояния только для внутреннего использования
  • Службы ASP.NET Core с отслеживанием состояния только для внутреннего использования

Доступная извне служба предоставляет конечную точку, вызываемую снаружи кластера, обычно через подсистему балансировки нагрузки.

Служба только для внутреннего использования — это служба, конечная точка которой вызывается только в пределах кластера.

Примечание

Конечные точки службы с отслеживанием состояния не следует делать доступными в Интернете. Кластеры, находящиеся за подсистемами балансировки нагрузки, которые не знают о разрешении службы Microsoft Azure Service Fabric, например Azure Load Balancer, не смогут предоставлять службы с отслеживанием состояния. Это обусловлено тем, что подсистема балансировки нагрузки не сможет найти и направить трафик в соответствующую реплику службы с отслеживанием состояния.

Доступные извне службы ASP.NET Core без отслеживания состояния

Kestrel является рекомендуемым веб-сервером для внешних служб, которые предоставляют внешние конечные точки HTTP с доступом в Интернет. В Windows HTTP.sys может предоставлять возможность совместного использования портов, что позволяет размещать несколько веб-служб в одном наборе узлов, используя один и тот же порт. В этом сценарии веб-службы отличаются по имени узла или пути, не полагаясь на интерфейсный прокси-сервер или шлюз для предоставления маршрутизации по протоколу HTTP.

Доступная через Интернет служба без отслеживания состояния должна использовать хорошо известную и стабильную конечную точку, доступную через подсистему балансировки нагрузки. Этот URL-адрес вы будете предоставлять пользователям приложения. Используйте следующие конфигурации:

Тип Рекомендация Примечания
Веб-сервер Kestrel Kestrel является предпочтительным веб-сервером, так как он поддерживается в Windows и Linux.
Конфигурация порта static Хорошо известный статический порт необходимо настроить в конфигурации Endpoints файла ServiceManifest.xml, например 80 для HTTP и 443 для HTTPS.
ServiceFabricIntegrationOptions Нет Используйте параметр ServiceFabricIntegrationOptions.None при настройке ПО промежуточного слоя интеграции Microsoft Azure Service Fabric, чтобы служба не пыталась проверять входящие запросы на наличие уникального идентификатора. Внешние пользователи приложения не будут знать уникальную идентифицирующую информацию, используемую ПО промежуточного слоя.
Число экземпляров -1 В типичных вариантах использования для параметра числа экземпляров должно быть задано значение -1. Это необходимо для того, чтобы экземпляр был доступен на всех узлах, которые получают трафик от системы балансировки нагрузки.

Если несколько служб, доступных извне, совместно используют один и тот же набор узлов, HTTP.sys следует использовать с уникальным, но стабильным URL-адресом. Для этого можно изменить URL-адрес, указанный при настройке IWebHost. Обратите внимание, что это относится только к HTTP.sys.

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

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

Служба ASP.NET Core без отслеживания состояния только для внутреннего использования

Службы без отслеживания состояния, которые вызываются только из кластера, должны использовать уникальные URL-адреса и динамически назначаемые порты для обеспечения взаимодействия между несколькими службами. Используйте следующие конфигурации:

Тип Рекомендация Примечания
Веб-сервер Kestrel Несмотря на то что HTTP.sys может использоваться для внутренних служб без отслеживания состояния, Kestrel лучше всего подходит в качестве сервера, на котором несколько экземплярам службы могут совместно использовать один узел.
Конфигурация порта динамическое назначение Множество реплик службы с отслеживанием состояния могут совместно использовать хост-процесс или операционную систему, и поэтому для них требуются уникальные порты.
ServiceFabricIntegrationOptions UseUniqueServiceUrl При динамическом назначении порта этот параметр предотвращает ошибочную идентификацию, описанную ранее.
InstanceCount any Для параметра количества экземпляров может быть присвоено любое значение, необходимое для работы службы.

Служба ASP.NET Core с отслеживанием состояния только для внутреннего использования

Службы с отслеживанием состояния, которые вызываются только из кластера, должны использовать динамически назначаемые порты для обеспечения взаимодействия между несколькими службами. Используйте следующие конфигурации:

Тип Рекомендация Примечания
Веб-сервер Kestrel HttpSysCommunicationListener не предназначен для служб с отслеживанием состояния, в которых реплики совместно используют хост-процесс.
Конфигурация порта динамическое назначение Множество реплик службы с отслеживанием состояния могут совместно использовать хост-процесс или операционную систему, и поэтому для них требуются уникальные порты.
ServiceFabricIntegrationOptions UseUniqueServiceUrl При динамическом назначении порта этот параметр предотвращает ошибочную идентификацию, описанную ранее.

Дальнейшие действия

Отладка приложения Service Fabric с помощью Visual Studio