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


ASP.NET Core в службах Azure Service Fabric, рассчитанных на надежность

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

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

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

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

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

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

  • Размещен в качестве гостевого исполняемого файла. Этот способ в основном используется для запуска существующих приложений ASP.NET Core в Service Fabric без изменений кода.
  • Запуск внутри надежной службы. Таким образом можно улучшить взаимодействие со средой выполнения Service Fabric и обеспечить поддержку stateful служб ASP.NET Core.

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

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

В Service Fabric один или несколько экземпляров и (или) реплик службы выполняются в процессе узла службы: исполняемый файл, который запускает код службы. Вы, как автор службы, владеете процессом размещения службы, и Service Fabric активирует и отслеживает его для вас.

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

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

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

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

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

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

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

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

ASP.NET Core ICommunicationListeners

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

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

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

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

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

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

Случай ошибочной идентификации

Реплики служб, независимо от протокола, прослушивают уникальное сочетание IP:port. После того как реплика службы начала прослушивать конечную точку IP:port, она сообщает, что адрес конечной точки в службе именования Service Fabric. Там клиенты или другие службы могут обнаружить его. Если службы используют динамически назначенные порты приложений, реплика службы может случайно использовать ту же конечную точку IP:port другой службы ранее на той же физической или виртуальной машине. Это может привести к ошибке подключения клиента к неправильной службе. Этот сценарий может привести к возникновению следующей последовательности событий:

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

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

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

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

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

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

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

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

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

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

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

HTTP.sys в Надежных службах

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

HTTP.sys основан на API HTTP Server Для 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 является предлагаемым веб-сервером.

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

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

Для этого действия требуются повышенные привилегии, которые у ваших служб нет по умолчанию. Параметры "http" или "https" для Protocol свойства Endpoint конфигурации в ServiceManifest.xml используются специально для указания среде выполнения 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 конфигурацией, предоставляет только один порт для каждого процесса узла. Текущая модель размещения Service Fabric позволяет размещать несколько экземпляров служб и (или) реплик в одном процессе. Это означает, что каждый из них будет использовать один и тот же порт при выделении через Endpoint конфигурацию. Несколько экземпляров HTTP.sys могут совместно использовать порт с помощью базовой функции совместного использования портов HTTP.sys . Но это не поддерживается HttpSysCommunicationListener из-за осложнений, которые он вводит для клиентских запросов. Для динамического использования портов Kestrel — это предлагаемый веб-сервер.

Kestrel в надёжных службах

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

Kestrel — это кроссплатформенный веб-сервер для ASP.NET Core. В отличие от HTTP.sys, Kestrel не использует централизованный диспетчер конечных точек. Кроме того, в отличие от 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.

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

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

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

Используйте Kestrel со статическим портом

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

  • Если порт не попадает в диапазон портов приложения, он открывается через брандмауэр ОС 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, исключите Endpoint конфигурацию в ServiceManifest.xml полностью и не передавайте имя конечной точки в конструктор KestrelCommunicationListener, как показано ниже:

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

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

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

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

В дополнение к IWebHost/IWebHostBuilder, KestrelCommunicationListener и HttpSysCommunicationListener поддерживают создание служб ASP.NET Core с помощью 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;
            }))
    };
}

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

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

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

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

После импорта Microsoft.ServiceFabric.AspNetCore.Configuration пакета NuGet необходимо зарегистрировать источник конфигурации 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 может получить доступ к параметрам конфигурации Service Fabric, как и к любым другим параметрам приложения. Например, можно использовать шаблон параметров для загрузки параметров в строго типизированные объекты.

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

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

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

$"{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>

Параметры конфигурации Service Fabric

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

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

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

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

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

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

Настраиваемое сопоставление ключей, извлечение значений и заполнение данных

Поставщик конфигурации Service Fabric также поддерживает более сложные сценарии для настройки сопоставления ключей с помощью ExtractKeyFunc и пользовательского извлечения значений с помощью ExtractValueFunc. Вы даже можете изменить весь процесс заполнения данных из конфигурации 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();
}

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

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

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

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

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

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

Внешняя служба — это служба, которая предоставляет конечную точку, вызов к которой осуществляется извне кластера, обычно через балансировщик нагрузки.

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

Примечание.

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

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

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

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

Тип Рекомендация Примечания.
Веб-сервер Пустельга Kestrel является предпочтительным веб-сервером, так как он поддерживается в Windows и Linux.
Конфигурация порта статичный Известный статический порт должен быть настроен в Endpoints конфигурации ServiceManifest.xml, например 80 для HTTP или 443 для HTTPS.
ServiceFabricIntegrationOptions Отсутствует Используйте параметр ServiceFabricIntegrationOptions.None при настройке промежуточного программного обеспечения интеграции 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-адреса и динамически назначаемые порты, чтобы обеспечить сотрудничество между несколькими службами. Рекомендуется использовать следующую конфигурацию:

Тип Рекомендация Примечания.
Веб-сервер Пустельга Хотя для внутренних служб без отслеживания состояния можно использовать HTTP.sys, Kestrel — лучший сервер, позволяющий нескольким экземплярам служб совместно использовать узел.
Конфигурация порта динамически назначается Несколько реплик службы с отслеживанием состояния могут совместно использовать процесс узла или операционную систему узла, поэтому потребуются уникальные порты.
Опции интеграции Service Fabric ИспользоватьУникальныйURLСервиса При динамическом назначении портов этот параметр предотвращает проблему путаницы в идентификации, описанную ранее.
КоличествоЭкземпляров любой Параметр счетчика экземпляров можно задать для любого значения, необходимого для работы службы.

Внутренняя служба с отслеживанием состояния ASP.NET Core

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

Тип Рекомендация Примечания.
Веб-сервер Пустельга Он HttpSysCommunicationListener не предназначен для использования службами с отслеживанием состояния, в которых реплики совместно используют процесс узла.
Конфигурация порта динамически назначается Несколько реплик службы с отслеживанием состояния могут совместно использовать процесс узла или операционную систему узла, поэтому потребуются уникальные порты.
ServiceFabricIntegrationOptions ИспользоватьУникальныйURLСервиса При динамическом назначении портов этот параметр предотвращает проблему путаницы в идентификации, описанную ранее.

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

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