Azure Service Fabric 中的 ASP.NET Core Reliable ServicesASP.NET Core in Azure Service Fabric Reliable Services

ASP.NET Core 是一種開放原始碼和跨平臺架構。ASP.NET Core is an open-source and cross-platform framework. 此架構是專為建立雲端式、網際網路連線的應用程式(例如 web apps、IoT 應用程式和行動後端)所設計。This framework is designed for building cloud-based, internet-connected applications, such as web apps, IoT apps, and mobile back ends.

本文是使用ServiceFabric AspNetCore在 Service Fabric Reliable Services 中裝載 ASP.NET Core 服務的深入指南。This article is an in-depth guide to hosting ASP.NET Core services in Service Fabric Reliable Services by using the Microsoft.ServiceFabric.AspNetCore. 一組 NuGet 套件。set of NuGet packages.

如需 Service Fabric 的 ASP.NET Core 簡介教學課程,以及如何設定開發環境的指示,請參閱教學課程:使用 ASP.NET Core WEB API 前端服務和具狀態後端服務建立和部署應用程式For an introductory tutorial on ASP.NET Core in Service Fabric and instructions on getting your development environment set up, see Tutorial: Create and deploy an application with an ASP.NET Core Web API front-end service and a stateful back-end service.

本文的其餘部分假設您已熟悉 ASP.NET Core。The rest of this article assumes you're already familiar with ASP.NET Core. 如果沒有,請閱讀 ASP.NET Core 的基本概念。If not, please read through the ASP.NET Core fundamentals.

Service Fabric 環境中的 ASP.NET CoreASP.NET Core in the Service Fabric environment

ASP.NET Core 和 Service Fabric 應用程式都可以在 .NET Core 或完整 .NET Framework 上執行。Both ASP.NET Core and Service Fabric apps can run on .NET Core or full .NET Framework. 您可以透過兩種不同的方式在 Service Fabric 中使用 ASP.NET Core:You can use ASP.NET Core in two different ways in Service Fabric:

  • 裝載作為客體可執行檔Hosted as a guest executable. 這種方式主要是用來在 Service Fabric 上執行現有的 ASP.NET Core 應用程式,而不需要變更程式碼。This way is primarily used to run existing ASP.NET Core applications on Service Fabric with no code changes.
  • 在可靠的服務內執行Run inside a reliable service. 如此一來,就能更有效地與 Service Fabric 執行時間整合,並允許具狀態的 ASP.NET Core 服務。This way allows better integration with the Service Fabric runtime and allows stateful ASP.NET Core services.

本文的其餘部分將說明如何透過 Service Fabric SDK 隨附的 ASP.NET Core 整合元件,在可靠的服務內使用 ASP.NET Core。The rest of this article explains how to use ASP.NET Core inside a reliable service, through the ASP.NET Core integration components that ship with the Service Fabric SDK.

Service Fabric 服務裝載Service Fabric service hosting

在 Service Fabric 中,服務的一個或多個實例及/或複本會在服務主機進程中執行:執行您的服務程式代碼的可執行檔。In Service Fabric, one or more instances and/or replicas of your service run in a service host process: an executable file that runs your service code. 身為服務作者,您可以擁有服務主機進程,並 Service Fabric 為您啟用和監視。You, as a service author, own the service host process, and Service Fabric activates and monitors it for you.

傳統 ASP.NET (直到 MVC 5) 已透過 System.Web.dll 與 IIS 緊密結合。Traditional ASP.NET (up to MVC 5) is tightly coupled to IIS through System.Web.dll. ASP.NET Core 能區別網頁伺服器與 web 應用程式。ASP.NET Core provides a separation between the web server and your web application. 這種區隔可讓 web 應用程式在不同的 web 伺服器之間具有可攜性。This separation allows web applications to be portable between different web servers. 它也允許自我裝載網頁伺服器。It also allows web servers to be self-hosted. 這表示您可以在自己的進程中啟動網頁伺服器,而不是由專用的 web 伺服器軟體所擁有的進程(例如 IIS)。This means you can start a web server in your own process, as opposed to a process that's owned by dedicated web server software, such as IIS.

若要結合 Service Fabric 服務和 ASP.NET (可能是來賓可執行檔或在可靠的服務中),您必須能夠在服務主機進程內啟動 ASP.NET。To combine a Service Fabric service and ASP.NET, either as a guest executable or in a reliable service, you must be able to start ASP.NET inside your service host process. ASP.NET Core 自我裝載可讓您執行這項操作。ASP.NET Core self-hosting allows you to do this.

在可靠的服務中裝載 ASP.NET CoreHosting ASP.NET Core in a reliable service

一般而言,自我裝載的 ASP.NET Core 應用程式會在應用程式的進入點建立 WebHost,例如 Program.cs 方法中的 static void Main()Typically, self-hosted ASP.NET Core applications create a WebHost in an application's entry point, such as the static void Main() method in Program.cs. 在此情況下,WebHost 的生命週期會系結至進程的生命週期。In this case, the life cycle of the WebHost is bound to the life cycle of the process.

在處理序中裝載 ASP.NET Core

但應用程式進入點並不是在可靠的服務中建立 WebHost 的正確位置。But the application entry point isn't the right place to create a WebHost in a reliable service. 這是因為應用程式進入點只會用來向 Service Fabric 執行時間註冊服務類型,讓它可以建立該服務類型的實例。That's because the application entry point is only used to register a service type with the Service Fabric runtime, so that it can create instances of that service type. WebHost 應該建立在可靠的服務本身中。The WebHost should be created in a reliable service itself. 在服務主機進程內,服務實例和(或)複本可以經歷多個生命週期。Within the service host process, service instances and/or replicas can go through multiple life cycles.

Reliable Service 執行個體是由您衍生自 StatelessServiceStatefulService 的服務類別代表。A Reliable Service instance is represented by your service class deriving from StatelessService or StatefulService. 服務的通訊堆疊包含在您服務類別中的 ICommunicationListener 實作。The communication stack for a service is contained in an ICommunicationListener implementation in your service class. Microsoft.ServiceFabric.AspNetCore.* NuGet 套件包含的執行ICommunicationListener ,可在可靠的服務中啟動和管理 Kestrel 或 HTTP.sys 的 ASP.NET Core WebHost。The Microsoft.ServiceFabric.AspNetCore.* NuGet packages contain implementations of ICommunicationListener that start and manage the ASP.NET Core WebHost for either Kestrel or HTTP.sys in a reliable service.

在可靠的服務中裝載 ASP.NET Core 的圖表

ASP.NET Core ICommunicationListenersASP.NET Core ICommunicationListeners

NuGet ICommunicationListener套件中的 Kestrel 和 HTTP.sys 的執行方式Microsoft.ServiceFabric.AspNetCore.*具有類似的使用模式。The ICommunicationListener implementations for Kestrel and HTTP.sys in the Microsoft.ServiceFabric.AspNetCore.* NuGet packages have similar use patterns. 但是,它們執行的動作與每一部 web 伺服器稍有不同。But they perform slightly different actions specific to each web server.

這兩種通訊接聽程式都會提供使用下列引數的建構函式︰Both communication listeners provide a constructor that takes the following arguments:

  • ServiceContext serviceContext:這是包含ServiceContext執行中服務相關資訊的物件。ServiceContext serviceContext: This is the ServiceContext object that contains information about the running service.
  • string endpointName:這是 ServiceManifest 中的設定Endpoint名稱。string endpointName: This is the name of an Endpoint configuration in ServiceManifest.xml. 這主要是兩個通訊接聽程式不同的地方。It's primarily where the two communication listeners differ. Http.sys需要設定,而Endpoint Kestrel 則否。HTTP.sys requires an Endpoint configuration, while Kestrel doesn't.
  • Func<string, AspNetCoreCommunicationListener, IWebHost> build:這是您在其中建立並傳回的 lambda IWebHostFunc<string, AspNetCoreCommunicationListener, IWebHost> build: This is a lambda that you implement, in which you create and return an IWebHost. 它可以讓您以IWebHost平常的方式設定 ASP.NET Core 應用程式。It allows you to configure IWebHost the way you normally would in an ASP.NET Core application. Lambda 會提供為您產生的 URL,視您使用的 Service Fabric 整合選項和您提供的Endpoint設定而定。The lambda provides a URL that's generated for you, depending on the Service Fabric integration options you use and the Endpoint configuration you provide. 然後您可以修改或使用該 URL 來啟動 web 伺服器。You can then modify or use that URL to start the web server.

Service Fabric 整合中介軟體Service Fabric integration middleware

Microsoft.ServiceFabric.AspNetCore NuGet 套件包含上IWebHostBuilderUseServiceFabricIntegration擴充方法,可新增 Service Fabric 感知中介軟體。The Microsoft.ServiceFabric.AspNetCore NuGet package includes the UseServiceFabricIntegration extension method on IWebHostBuilder that adds Service Fabric–aware middleware. 此中介軟體會設定 Kestrel 或 HTTP.SYS ICommunicationListener ,以向 Service Fabric 命名服務註冊唯一的服務 URL。This middleware configures the Kestrel or HTTP.sys ICommunicationListener to register a unique service URL with the Service Fabric Naming Service. 然後,它會驗證用戶端要求,以確保用戶端連線至正確的服務。It then validates client requests to ensure clients are connecting to the right service.

若要防止用戶端不小心連線到錯誤的服務,則必須執行此步驟。This step is necessary to prevent clients from mistakenly connecting to the wrong service. 這是因為在共用主機環境(例如 Service Fabric)中,多個 web 應用程式可以在相同的實體或虛擬機器上執行,但不會使用唯一的主機名稱。That's because, in a shared-host environment such as Service Fabric, multiple web applications can run on the same physical or virtual machine but don't use unique host names. 此案例會在下一節中詳細說明。This scenario is described in more detail in the next section.

誤用身分識別的案例A case of mistaken identity

不論通訊協定,服務複本會接聽唯一 IP:port 組合。Service replicas, regardless of protocol, listen on a unique IP:port combination. 一旦服務複本開始接聽 IP:埠端點,它就會向 Service Fabric 命名服務報告該端點位址。Once a service replica has started listening on an IP:port endpoint, it reports that endpoint address to the Service Fabric Naming Service. 其中,用戶端或其他服務可以探索它。There, clients or other services can discover it. 如果服務使用動態指派的應用程式埠,服務複本可能會且剛好使用與先前在相同實體或虛擬機器上的另一個服務相同的 IP:埠端點。If services use dynamically assigned application ports, a service replica might coincidentally use the same IP:port endpoint of another service previously on the same physical or virtual machine. 這可能會造成用戶端不小心連線至錯誤的服務。This can cause a client to mistakenly connect to the wrong service. 如果發生下列事件序列,可能會產生此情況:This scenario can result if the following sequence of events occurs:

  1. 服務 A 透過 HTTP 接聽 10.0.0.1:30000。Service A listens on 10.0.0.1:30000 over HTTP.
  2. 用戶端會解析服務 A,並取得位址10.0.0.1:30000。Client resolves Service A and gets address 10.0.0.1:30000.
  3. 服務 A 移到另一個節點。Service A moves to a different node.
  4. 服務 B 置於 10.0.0.1 且碰巧使用相同的連接埠 30000。Service B is placed on 10.0.0.1 and coincidentally uses the same port 30000.
  5. 用戶端使用快取的位址 10.0.0.1:30000 嘗試連線到服務 A。Client attempts to connect to service A with cached address 10.0.0.1:30000.
  6. 用戶端現在已成功連線至服務 B,而未發現它已連線到錯誤的服務。Client is now successfully connected to service B, not realizing it's connected to the wrong service.

這會不定時造成 難以診斷的 Bug。This can cause bugs at random times that can be difficult to diagnose.

使用唯一的服務 URLUsing unique service URLs

為了避免這些錯誤,服務可以使用唯一識別碼將端點張貼到命名服務,然後在用戶端要求期間驗證該唯一識別碼。To prevent these bugs, services can post an endpoint to the Naming Service with a unique identifier, and then validate that unique identifier during client requests. 這在非惡意租用戶受信任環境中的服務之間為合作式動作。This is a cooperative action between services in a non-hostile-tenant trusted environment. 它不會在惡意租使用者環境中提供安全的服務驗證。It doesn't provide secure service authentication in a hostile-tenant environment.

在信任的環境中, UseServiceFabricIntegration方法所新增的中介軟體會自動將唯一識別碼附加至張貼至命名服務的位址。In a trusted environment, the middleware that's added by the UseServiceFabricIntegration method automatically appends a unique identifier to the address posted to the Naming Service. 它會在每個要求上驗證該識別碼。It validates that identifier on each request. 如果識別碼不相符,中介軟體會立即傳回 HTTP 410 消失的回應。If the identifier doesn't match, the middleware immediately returns an HTTP 410 Gone response.

使用動態指派連接埠的服務應該要使用此中介軟體。Services that use a dynamically assigned port should make use of this middleware.

使用固定唯一端口的服務在合作的環境中沒有這個問題。Services that use a fixed unique port don't have this problem in a cooperative environment. 固定的唯一連接埠通常是用於對外開放的服務,需要用戶端應用程式連線的知名通訊埠。A fixed unique port is typically used for externally facing services that need a well-known port for client applications to connect to. 例如,大部分網際網路面向的 web 應用程式會使用埠80或443進行網頁瀏覽器連線。For example, most internet-facing web applications will use port 80 or 443 for web browser connections. 在此情況下,不應啟用唯一識別碼。In this case, the unique identifier shouldn't be enabled.

下圖顯示已啟用中介軟體的要求流程︰The following diagram shows the request flow with the middleware enabled:

Service Fabric ASP.NET Core 整合

Kestrel 和 HTTP.SYS ICommunicationListener都會以完全相同的方式使用這項機制。Both Kestrel and HTTP.sys ICommunicationListener implementations use this mechanism in exactly the same way. 雖然 HTTP.sys 可以使用基礎HTTP.sys埠共用功能,根據唯一的 URL 路徑來內部區分要求,但 HTTP.sys 的ICommunicationListener執行並會使用該功能。Although HTTP.sys can internally differentiate requests based on unique URL paths by using the underlying HTTP.sys port sharing feature, that functionality is not used by the HTTP.sys ICommunicationListener implementation. 這是因為它會在稍早所述的案例中產生 HTTP 503 和 HTTP 404 錯誤狀態碼。That's because it results in HTTP 503 and HTTP 404 error status codes in the scenario described earlier. 這會讓用戶端難以判斷錯誤的意圖,因為 HTTP 503 和 HTTP 404 通常用來表示其他錯誤。That in turn makes it difficult for clients to determine the intent of the error, as HTTP 503 and HTTP 404 are commonly used to indicate other errors.

因此,Kestrel 和 HTTP.SYS ICommunicationListener會在擴充方法所UseServiceFabricIntegration提供的中介軟體上標準化。Thus, both Kestrel and HTTP.sys ICommunicationListener implementations standardize on middleware provided by the UseServiceFabricIntegration extension method. 因此,用戶端只需要在 HTTP 410 回應上執行服務端點重新解析動作。Therefore, clients only need to perform a service endpoint re-resolve action on HTTP 410 responses.

Reliable Services 中的 HTTP.sysHTTP.sys in Reliable Services

您可以藉由匯入ServiceFabric. AspNetCore. HttpSys NuGet 封裝,在 Reliable Services 中使用 HTTP.sys。You can use HTTP.sys in Reliable Services by importing the Microsoft.ServiceFabric.AspNetCore.HttpSys NuGet package. 此封裝包含HttpSysCommunicationListener,其為的ICommunicationListener執行。This package contains HttpSysCommunicationListener, an implementation of ICommunicationListener. HttpSysCommunicationListener可讓您使用 HTTP.SYS 作為 web 伺服器,在可靠的服務內建立 ASP.NET Core WebHost。HttpSysCommunicationListener allows you to create an ASP.NET Core WebHost inside a reliable service by using HTTP.sys as the web server.

Http.sys 是以WINDOWS Http 伺服器 API為基礎。HTTP.sys is built on the Windows HTTP Server API. 此 API 會使用HTTP.sys 核心驅動程式來處理 HTTP 要求,並將它們路由傳送至執行 web 應用程式的進程。This API uses the HTTP.sys kernel driver to process HTTP requests and route them to processes that run web applications. 這可讓相同實體或虛擬機器上的多個進程在相同的埠上裝載 web 應用程式,並以唯一的 URL 路徑或主機名稱來區分。This allows multiple processes on the same physical or virtual machine to host web applications on the same port, disambiguated by either a unique URL path or host name. 這些功能對於在 Service Fabric 中於相同叢集裝載多個網站很有用。These features are useful in Service Fabric for hosting multiple websites in the same cluster.

注意

Http.sys 的執行僅適用于 Windows 平臺。HTTP.sys implementation works only on the Windows platform.

下圖說明 HTTP.sys 如何在 Windows 上使用 HTTP.sys核心驅動程式進行埠共用:The following diagram illustrates how HTTP.sys uses the HTTP.sys kernel driver on Windows for port sharing:

Http.sys 圖表

無狀態服務中的 HTTP.sysHTTP.sys in a stateless service

若要在無狀態服務中使用 HttpSys,請覆寫 CreateServiceInstanceListeners 方法並傳回 HttpSysCommunicationListener 執行個體︰To use HttpSys in a stateless service, override the CreateServiceInstanceListeners method and return a HttpSysCommunicationListener instance:

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.sysHTTP.sys in a stateful service

HttpSysCommunicationListener目前不是設計用於具狀態服務,因為基本的HTTP.sys埠共用功能會有更複雜的情況。HttpSysCommunicationListener isn't currently designed for use in stateful services due to complications with the underlying HTTP.sys port sharing feature. 如需詳細資訊,請參閱下一節關於使用 HTTP.SYS 的動態埠配置。For more information, see the following section on dynamic port allocation with HTTP.sys. 對於具狀態服務,Kestrel 是建議的 web 伺服器。For stateful services, Kestrel is the suggested web server.

端點組態Endpoint configuration

Endpoint使用 Windows HTTP 伺服器 API 的 web 伺服器需要設定,包括 HTTP.sys。An Endpoint configuration is required for web servers that use the Windows HTTP Server API, including HTTP.sys. 使用 Windows HTTP 伺服器 API 的 Web 服務器必須先使用 HTTP.SYS 來保留其 URL (這通常是使用netsh工具來完成)。Web servers that use the Windows HTTP Server API must first reserve their URL with HTTP.sys (this is normally accomplished with the netsh tool).

此動作需要您的服務預設不具有的更高許可權。This action requires elevated privileges that your services don't have by default. ServiceManifest 中設定之Protocol Endpoint屬性的 "HTTP" 或 "HTTPs" 選項會特別用來指示 Service Fabric 執行時間代表您註冊 URL 與 HTTP.sys。The "http" or "https" options for the Protocol property of the Endpoint configuration in ServiceManifest.xml are used specifically to instruct the Service Fabric runtime to register a URL with HTTP.sys on your behalf. 它會使用強式萬用字元URL 前置詞來執行這項工作。It does this by using the strong wildcard URL prefix.

例如,若要保留http://+:80服務,請在 ServiceManifest 中使用下列設定:For example, to reserve http://+:80 for a service, use the following configuration in ServiceManifest.xml:

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

</ServiceManifest>

端點名稱必須傳遞給 HttpSysCommunicationListener 建構函式︰And the endpoint name must be passed to the HttpSysCommunicationListener constructor:

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

搭配靜態埠使用 HTTP.sysUse HTTP.sys with a static port

若要使用靜態埠搭配 HTTP.sys,請在設定中Endpoint提供埠號碼:To use a static port with HTTP.sys, provide the port number in the Endpoint configuration:

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

搭配使用 HTTP.SYS 與動態埠Use HTTP.sys with a dynamic port

若要使用動態指派的埠搭配 HTTP.sys,請省略設定PortEndpoint的屬性:To use a dynamically assigned port with HTTP.sys, omit the Port property in the Endpoint configuration:

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

設定所Endpoint配置的動態埠只提供每個主機進程一個埠。A dynamic port allocated by an Endpoint configuration provides only one port per host process. 目前的 Service Fabric 裝載模型可讓多個服務實例和/或複本在相同的進程中主控。The current Service Fabric hosting model allows multiple service instances and/or replicas to be hosted in the same process. 這表示當透過設定Endpoint配置時,每個通訊埠都會共用相同的埠。This means each one will share the same port when allocated through the Endpoint configuration. 多個HTTP.sys實例可以使用基礎的HTTP.sys埠共用功能來共用埠。Multiple HTTP.sys instances can share a port by using the underlying HTTP.sys port sharing feature. HttpSysCommunicationListener由於它針對用戶端要求所帶來的複雜性,並不受到支援。But it's not supported by HttpSysCommunicationListener due to the complications it introduces for client requests. 針對動態埠使用方式,Kestrel 是建議的 web 伺服器。For dynamic port usage, Kestrel is the suggested web server.

Reliable Services 中的 KestrelKestrel in Reliable Services

您可以藉由匯入ServiceFabric. AspNetCore. Kestrel NuGet 封裝,在 Reliable Services 中使用 Kestrel。You can use Kestrel in Reliable Services by importing the Microsoft.ServiceFabric.AspNetCore.Kestrel NuGet package. 此封裝包含KestrelCommunicationListener,其為的ICommunicationListener執行。This package contains KestrelCommunicationListener, an implementation of ICommunicationListener. KestrelCommunicationListener可讓您使用 Kestrel 作為 web 伺服器,在可靠的服務內建立 ASP.NET Core WebHost。KestrelCommunicationListener allows you to create an ASP.NET Core WebHost inside a reliable service by using Kestrel as the web server.

Kestrel 是 ASP.NET Core 的跨平台網頁伺服器。Kestrel is a cross-platform web server for ASP.NET Core. 不同于 HTTP.sys,Kestrel 不會使用集中式端點管理員。Unlike HTTP.sys, Kestrel doesn't use a centralized endpoint manager. 和 HTTP.SYS 不同的是,Kestrel 不支援多個進程之間的埠共用。Also unlike HTTP.sys, Kestrel doesn't support port sharing between multiple processes. Kestrel 的每個執行個體必須使用唯一的連接埠。Each instance of Kestrel must use a unique port. 如需 Kestrel 的詳細資訊,請參閱執行詳細資料For more on Kestrel, see the Implementation Details.

Kestrel 圖表

無狀態服務中的 KestrelKestrel in a stateless service

若要在無狀態服務中使用 Kestrel,請覆寫 CreateServiceInstanceListeners 方法並傳回 KestrelCommunicationListener 執行個體︰To use Kestrel in a stateless service, override the CreateServiceInstanceListeners method and return a KestrelCommunicationListener instance:

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

具狀態服務中的 KestrelKestrel in a stateful service

若要在具狀態服務中使用 Kestrel,請覆寫 CreateServiceReplicaListeners 方法並傳回 KestrelCommunicationListener 執行個體︰To use Kestrel in a stateful service, override the CreateServiceReplicaListeners method and return a KestrelCommunicationListener instance:

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 相依性插入容器。In this example, a singleton instance of IReliableStateManager is provided to the WebHost dependency injection container. 這不是絕對必要的,但可讓您IReliableStateManager在 MVC 控制器動作方法中使用和可靠的集合。This isn't strictly necessary, but it allows you to use IReliableStateManager and Reliable Collections in your MVC controller action methods.

Endpoint 組態名稱提供給具狀態服務中的 KestrelCommunicationListenerAn Endpoint configuration name is not provided to KestrelCommunicationListener in a stateful service. 我們會在下列各節中詳細說明這個部分。This is explained in more detail in the following section.

將 Kestrel 設定為使用 HTTPSConfigure Kestrel to use HTTPS

在您的服務中使用 Kestrel 啟用 HTTPS 時,您必須設定數個接聽選項。When enabling HTTPS with Kestrel in your service, you'll need to set several listening options. 更新ServiceInstanceListener以使用EndpointHttps端點,並在特定埠上接聽(例如埠443)。Update the ServiceInstanceListener to use an EndpointHttps endpoint and listen on a specific port (such as port 443). 將 web 主機設定為使用 Kestrel 網頁伺服器時,您必須將 Kestrel 設為接聽所有網路介面上的 IPv6 位址:When configuring the web host to use the Kestrel web server, you must configure Kestrel to listen for IPv6 addresses on all network interfaces:

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 設定為使用 HTTPSFor a full example in a tutorial, see Configure Kestrel to use HTTPS.

端點組態Endpoint configuration

Endpoint不需要設定就能使用 Kestrel。An Endpoint configuration isn't required to use Kestrel.

Kestrel 是簡單的獨立 web 伺服器。Kestrel is a simple standalone web server. 與 HTTP.sys (或 HttpListener)不同的是,它不需要Endpoint ServiceManifest 中的設定,因為它不需要在啟動之前進行 URL 註冊。Unlike HTTP.sys (or HttpListener), it doesn't need an Endpoint configuration in ServiceManifest.xml because it doesn't require URL registration before starting.

搭配使用 Kestrel 與靜態連接埠Use Kestrel with a static port

您可以設定 ServiceManifest 中Endpoint的靜態通訊埠,以搭配 Kestrel 使用。You can configure a static port in the Endpoint configuration of ServiceManifest.xml for use with Kestrel. 雖然這並非絕對必要,但它提供兩個可能的優點:Although this isn't strictly necessary, it offers two potential benefits:

  • 如果埠不在應用程式埠範圍內,則會藉由 Service Fabric,透過 OS 防火牆加以開啟。If the port doesn't fall in the application port range, it's opened through the OS firewall by Service Fabric.
  • 透過 KestrelCommunicationListener 提供給您的 URL 會使用此連接埠。The URL provided to you through KestrelCommunicationListener will use this port.
  <Resources>
    <Endpoints>
      <Endpoint Protocol="http" Name="ServiceEndpoint" Port="80" />
    </Endpoints>
  </Resources>

如果設定了 Endpoint,其名稱必須傳遞至 KestrelCommunicationListener 建構函式︰If an Endpoint is configured, its name must be passed into the KestrelCommunicationListener constructor:

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

如果 ServiceManifest 未使用設定,請Endpoint省略此KestrelCommunicationListener函式中的名稱。If ServiceManifest.xml doesn't use an Endpoint configuration, omit the name in the KestrelCommunicationListener constructor. 在此情況下,它會使用動態埠。In this case, it will use a dynamic port. 如需這方面的詳細資訊,請參閱下一節。See the next section for more information about this.

搭配使用 Kestrel 與動態連接埠Use Kestrel with a dynamic port

Kestrel 無法從 ServiceManifest 中的Endpoint設定使用自動埠指派。Kestrel can't use the automatic port assignment from the Endpoint configuration in ServiceManifest.xml. 這是因為從Endpoint設定自動指派埠會為每個主機進程指派一個唯一的埠,而單一主機進程可以包含多個 Kestrel 實例。That's because automatic port assignment from an Endpoint configuration assigns a unique port per host process, and a single host process can contain multiple Kestrel instances. 這不會與 Kestrel 搭配使用,因為它不支援埠共用。This doesn't work with Kestrel because it doesn't support port sharing. 因此,每個 Kestrel 實例都必須在唯一的埠上開啟。Therefore, each Kestrel instance must be opened on a unique port.

若要搭配 Kestrel 使用動態通訊埠指派, Endpoint請省略 ServiceManifest 中的設定,並不要將端點名稱傳遞給此KestrelCommunicationListener函式,如下所示:To use dynamic port assignment with Kestrel, omit the Endpoint configuration in ServiceManifest.xml entirely, and don't pass an endpoint name to the KestrelCommunicationListener constructor, as follows:

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

在此組態中,KestrelCommunicationListener 會自動從應用程式連接埠範圍選取未使用的連接埠。In this configuration, KestrelCommunicationListener will automatically select an unused port from the application port range.

針對 HTTPS,它應該有以 HTTPS 通訊協定設定的端點,而不需在 ServiceManifest 中指定埠,並將端點名稱傳遞至 KestrelCommunicationListener 的函式。For HTTPS, it should have the Endpoint configured with HTTPS protocol without a port specified in ServiceManifest.xml and pass the endpoint name to KestrelCommunicationListener constructor.

Service Fabric 設定提供者Service Fabric configuration provider

ASP.NET Core 中的應用程式設定是以設定提供者所建立的機碼值組為基礎。App configuration in ASP.NET Core is based on key-value pairs established by the configuration provider. 閱讀ASP.NET Core 中的設定,以深入瞭解一般 ASP.NET Core 設定支援。Read Configuration in ASP.NET Core to understand more on general ASP.NET Core configuration support.

本節說明如何藉由匯入Microsoft.ServiceFabric.AspNetCore.Configuration NuGet 套件,將 Service Fabric 設定提供者與 ASP.NET Core 設定整合。This section describes how the Service Fabric configuration provider integrates with ASP.NET Core configuration by importing the Microsoft.ServiceFabric.AspNetCore.Configuration NuGet package.

AddServiceFabricConfiguration 啟動擴充功能AddServiceFabricConfiguration startup extensions

匯入Microsoft.ServiceFabric.AspNetCore.Configuration NuGet 套件之後,您必須向 ASP.NET CORE 設定 API 註冊 Service Fabric 設定來源。After you import the Microsoft.ServiceFabric.AspNetCore.Configuration NuGet package, you need to register the Service Fabric Configuration source with ASP.NET Core configuration API. 若要這麼做, AddServiceFabricConfiguration請檢查命名空間Microsoft.ServiceFabric.AspNetCore.Configuration中的IConfigurationBuilderAddServiceFabricConfiguration 延伸模組。You do this by checking AddServiceFabricConfiguration extensions in the Microsoft.ServiceFabric.AspNetCore.Configuration namespace against 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 的設定,就像任何其他應用程式設定一樣。Now the ASP.NET Core service can access the Service Fabric configuration settings, just like any other application settings. 例如,您可以使用 [選項] 模式,將設定載入強型別物件。For example, you can use the options pattern to load settings into strongly typed objects.

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

預設金鑰組應Default key mapping

根據預設,Service Fabric 設定提供者會包含封裝名稱、區段名稱和屬性名稱。By default, the Service Fabric configuration provider includes the package name, section name, and property name. 這些會一起構成 ASP.NET Core 的設定金鑰,如下所示:Together, these form the ASP.NET Core configuration key, as follows:

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

例如,如果您有一個名為MyConfigPackage且具有下列內容的設定套件,則會在 ASP.NET Core IConfiguration透過MyConfigPackage: MyConfigSection: MyParameter提供設定值。For example, if you have a configuration package named MyConfigPackage with the following content, then the configuration value will be available on ASP.NET Core IConfiguration through 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 configuration options

Service Fabric 設定提供者也支援ServiceFabricConfigurationOptions變更金鑰組應的預設行為。The Service Fabric configuration provider also supports ServiceFabricConfigurationOptions to change the default behavior of key mapping.

加密設定Encrypted settings

Service Fabric 支援加密設定,如同 Service Fabric 設定提供者。Service Fabric supports encrypted settings, as does the Service Fabric configuration provider. 根據預設,加密的設定不IConfiguration會解密為 ASP.NET Core。The encrypted settings aren't decrypted to ASP.NET Core IConfiguration by default. 加密值會改為儲存在該處。The encrypted values are stored there instead. 但是,如果您想要將值解密以儲存在 ASP.NET Core IConfiguration 中,您可以DecryptValueAddServiceFabricConfiguration延伸模組中的 DecryptValue 旗標設定為 false,如下所示:But if you want to decrypt the value to store in ASP.NET Core IConfiguration, you can set the DecryptValue flag to false in the AddServiceFabricConfiguration extension, as follows:

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

多個設定套件Multiple configuration packages

Service Fabric 支援多個設定套件。Service Fabric supports multiple configuration packages. 根據預設,套件名稱會包含在設定機碼中。By default, the package name is included in the configuration key. 但您可以將IncludePackageName旗標設定為 false,如下所示:But you can set the IncludePackageName flag to false, as follows:

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

自訂索引鍵對應、值提取和資料填入Custom key mapping, value extraction, and data population

Service Fabric 設定提供者也支援更高階的案例,以自訂金鑰ExtractKeyFunc對應,並自訂使用ExtractValueFunc將值解壓縮。The Service Fabric configuration provider also supports more advanced scenarios to customize the key mapping with ExtractKeyFunc and custom-extract the values with ExtractValueFunc. 您甚至可以使用ConfigAction,將從 Service Fabric 設定填入資料的整個程式,變更為 ASP.NET Core 設定。You can even change the whole process of populating data from Service Fabric configuration to ASP.NET Core configuration by using ConfigAction.

下列範例說明如何使用ConfigAction自訂資料填入:The following examples illustrate how to use ConfigAction to customize data population:

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

設定更新Configuration updates

Service Fabric 設定提供者也支援設定更新。The Service Fabric configuration provider also supports configuration updates. 您可以使用 ASP.NET Core IOptionsMonitor來接收變更通知,然後使用IOptionsSnapshot來重載設定資料。You can use ASP.NET Core IOptionsMonitor to receive change notifications, and then use IOptionsSnapshot to reload configuration data. 如需詳細資訊,請參閱ASP.NET Core 選項For more information, see ASP.NET Core options.

預設支援這些選項。These options are supported by default. 不需要進一步撰寫程式碼來啟用設定更新。No further coding is needed to enable configuration updates.

案例和組態Scenarios and configurations

本節提供網頁伺服器、埠設定、Service Fabric 整合選項和其他設定的組合,建議您針對下列案例進行疑難排解:This section provides the combination of web server, port configuration, Service Fabric integration options, and miscellaneous settings we recommend to troubleshoot the following scenarios:

  • 外部公開 ASP.NET Core 無狀態服務Externally exposed ASP.NET Core stateless services
  • 僅限內部 ASP.NET Core 無狀態服務Internal-only ASP.NET Core stateless services
  • 僅限內部 ASP.NET Core 具狀態服務Internal-only ASP.NET Core stateful services

外部公開的服務是公開從叢集外部呼叫的端點,通常是透過負載平衡器。An externally exposed service is one that exposes an endpoint that's called from outside the cluster, usually through a load balancer.

僅供內部使用的服務,其端點只會從叢集內呼叫。An internal-only service is one whose endpoint is only called from within the cluster.

注意

具狀態服務端點通常不應該公開到網際網路。Stateful service endpoints generally shouldn't be exposed to the internet. 不知道 Service Fabric 服務解析的負載平衡器後方的叢集(例如 Azure Load Balancer)將無法公開具狀態服務。Clusters behind load balancers that are unaware of Service Fabric service resolution, such as Azure Load Balancer, will be unable to expose stateful services. 這是因為負載平衡器無法找出並將流量路由傳送至適當的具狀態服務複本。That's because the load balancer won't be able to locate and route traffic to the appropriate stateful service replica.

外部公開 ASP.NET Core 無狀態服務Externally exposed ASP.NET Core stateless services

Kestrel 是適用于前端服務的建議 web 伺服器,會公開外部、網際網路對向的 HTTP 端點。Kestrel is the suggested web server for front-end services that expose external, internet-facing HTTP endpoints. 在 Windows 上,HTTP.sys 可以提供埠共用功能,可讓您使用相同的埠在同一組節點上裝載多個 web 服務。On Windows, HTTP.sys can provide port sharing capability, which allows you to host multiple web services on the same set of nodes using the same port. 在此案例中,web 服務會以主機名稱或路徑來區分,而不需依賴前端 proxy 或閘道來提供 HTTP 路由。In this scenario, the web services are differentiated by host name or path, without relying on a front-end proxy or gateway to provide HTTP routing.

向網際網路公開時,無狀態服務應使用可透過負載平衡器連線的知名且穩定的端點。When exposed to the internet, a stateless service should use a well-known and stable endpoint that's reachable through a load balancer. 您會將此 URL 提供給應用程式的使用者。You'll provide this URL to your application's users. 建議使用下列設定:We recommend the following configuration:

附註Notes
網頁伺服器Web server KestrelKestrel Kestrel 是慣用的 web 伺服器,因為它在 Windows 和 Linux 上都有受到支援。Kestrel is the preferred web server, as it's supported across Windows and Linux.
連接埠組態Port configuration staticstatic 已知的靜態連接埠應在 ServiceManifest.xml 的 Endpoints 組態中設定,例如 HTTP 為 80 或 443 為 HTTPS。A well-known static port should be configured in the Endpoints configuration of ServiceManifest.xml, such as 80 for HTTP or 443 for HTTPS.
ServiceFabricIntegrationOptionsServiceFabricIntegrationOptions NoneNone 設定 Service Fabric ServiceFabricIntegrationOptions.None整合中介軟體時,請使用選項,如此一來,服務就不會嘗試驗證唯一識別碼的傳入要求。Use the ServiceFabricIntegrationOptions.None option when configuring Service Fabric integration middleware, so that the service doesn't attempt to validate incoming requests for a unique identifier. 您應用程式的外部使用者不會知道中介軟體所使用的唯一識別資訊。External users of your application won't know the unique identifying information that the middleware uses.
執行個體計數Instance Count -1-1 在一般使用案例中,實例計數設定應該設定為 -1In typical use cases, the instance count setting should be set to -1. 這是為了讓實例可在接收來自負載平衡器流量的所有節點上使用。This is done so that an instance is available on all nodes that receive traffic from a load balancer.

如果有多個外部公開的服務共用相同的節點集,您就可以使用 HTTP.SYS 搭配唯一但穩定的 URL 路徑。If multiple externally exposed services share the same set of nodes, you can use HTTP.sys with a unique but stable URL path. 您可以藉由修改設定 IWebHost 時所提供的 URL 來完成這項工作。You can accomplish this by modifying the URL provided when configuring IWebHost. 請注意,這只適用于 HTTP.sys。Note that this applies to HTTP.sys only.

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

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

僅供內部使用的無狀態 ASP.NET Core 服務Internal-only stateless ASP.NET Core service

只會從叢集內呼叫的無狀態服務應該使用唯一的 URL 並動態指派連接埠,以確保多個服務之間的合作。Stateless services that are only called from within the cluster should use unique URLs and dynamically assigned ports to ensure cooperation between multiple services. 建議使用下列設定:We recommend the following configuration:

附註Notes
網頁伺服器Web server KestrelKestrel 雖然您可以將 HTTP.SYS 用於內部無狀態服務,但 Kestrel 是允許多個服務實例共用主機的最佳伺服器。Although you can use HTTP.sys for internal stateless services, Kestrel is the best server to allow multiple service instances to share a host.
連接埠組態Port configuration 動態指派dynamically assigned 具狀態服務的多個複本可能會共用主機進程或主機作業系統,因此將需要唯一的埠。Multiple replicas of a stateful service might share a host process or host operating system and thus will need unique ports.
ServiceFabricIntegrationOptionsServiceFabricIntegrationOptions UseUniqueServiceUrlUseUniqueServiceUrl 使用動態連接埠指派,此設定可防止稍早所述的誤用識別問題。With dynamic port assignment, this setting prevents the mistaken identity issue described earlier.
InstanceCountInstanceCount 任意any 執行個體計數設定可以設定為操作本服務所需的任何值。The instance count setting can be set to any value necessary to operate the service.

僅供內部使用的具狀態 ASP.NET Core 服務Internal-only stateful ASP.NET Core service

只會從叢集內呼叫的具狀態服務應該使用動態指派連接埠,以確保多個服務之間的合作。Stateful services that are only called from within the cluster should use dynamically assigned ports to ensure cooperation between multiple services. 建議使用下列設定:We recommend the following configuration:

附註Notes
網頁伺服器Web server KestrelKestrel HttpSysCommunicationListener不是設計成可讓複本共用主機進程的具狀態服務使用。The HttpSysCommunicationListener isn't designed for use by stateful services in which replicas share a host process.
連接埠組態Port configuration 動態指派dynamically assigned 具狀態服務的多個複本可能會共用主機進程或主機作業系統,因此將需要唯一的埠。Multiple replicas of a stateful service might share a host process or host operating system and thus will need unique ports.
ServiceFabricIntegrationOptionsServiceFabricIntegrationOptions UseUniqueServiceUrlUseUniqueServiceUrl 使用動態連接埠指派,此設定可防止稍早所述的誤用識別問題。With dynamic port assignment, this setting prevents the mistaken identity issue described earlier.

後續步驟Next steps

使用 Visual Studio 偵錯 Service Fabric 應用程式Debug your Service Fabric application by using Visual Studio