ASP.NET Core in Azure Service Fabric Reliable Services
ASP.NET Core è un framework open source e multipiattaforma. Questo framework è progettato per la creazione di applicazioni connesse a Internet basate sul cloud, ad esempio app Web, app IoT e back-end per dispositivi mobili.
Questo articolo è una guida approfondita all'hosting di servizi ASP.NET Core in Service Fabric Reliable Services tramite il set di pacchetti NuGet Microsoft.ServiceFabric.AspNetCore.
Per un'esercitazione introduttiva su ASP.NET Core in Service Fabric e istruzioni su come configurare l'ambiente di sviluppo, vedere Esercitazione: Creare e distribuire un'applicazione con un servizio front-end api Web ASP.NET Core e un servizio back-end con stato.
Il resto di questo articolo presuppone che si abbia già familiarità con ASP.NET Core. In caso contrario, leggere i concetti fondamentali ASP.NET Core.
ASP.NET Core nell'ambiente Service Fabric
Sia ASP.NET Core che le app di Service Fabric possono essere eseguite in .NET Core o in .NET Framework completo. È possibile usare ASP.NET Core in due modi diversi in Service Fabric:
- Ospitato come eseguibile guest. Questo modo viene usato principalmente per eseguire applicazioni ASP.NET Core esistenti in Service Fabric senza modifiche al codice.
- Eseguire all'interno di un servizio Reliable Services. In questo modo è possibile migliorare l'integrazione con il runtime di Service Fabric e consentire servizi di ASP.NET Core con stato.
Il resto di questo articolo illustra come usare ASP.NET Core all'interno di un servizio Reliable Services, tramite i componenti di integrazione ASP.NET Core forniti con Service Fabric SDK.
Hosting di servizi di Service Fabric
In Service Fabric una o più istanze e/o repliche del servizio vengono eseguite in un processo host del servizio: un file eseguibile che esegue il codice del servizio. L'utente, autore del servizio, è proprietario del processo host del servizio e Service Fabric lo attiva e lo monitora automaticamente.
La versione tradizionale di ASP.NET, fino a MVC 5, è strettamente associata a IIS tramite System.Web.dll. ASP.NET Core fornisce una separazione tra il server Web e l'applicazione Web. Questa separazione consente alle applicazioni Web di essere portabili tra server Web diversi. Consente anche ai server Web di essere self-hosted. Ciò significa che è possibile avviare un server Web nel proprio processo, anziché un processo di proprietà di software server Web dedicato, ad esempio IIS.
Per combinare un servizio di Service Fabric e ASP.NET, come eseguibile guest o in un servizio Reliable Service, è necessario essere in grado di avviare ASP.NET all'interno del processo host del servizio. Il self-hosting di ASP.NET Core consente di eseguire questa operazione.
Hosting di ASP.NET Core in un servizio Reliable Services
Le applicazioni ASP.NET Core con self-hosting creano in genere un WebHost in un punto di ingresso dell'applicazione, ad esempio il metodo static void Main()
in Program.cs
. In questo caso, il ciclo di vita di WebHost è associato al ciclo di vita del processo.
Ma il punto di ingresso dell'applicazione non è il posto giusto per creare un WebHost in un servizio Reliable Service. Questo perché il punto di ingresso dell'applicazione viene usato solo per registrare un tipo di servizio con il runtime di Service Fabric, in modo che possa creare istanze di tale tipo di servizio. WebHost deve essere creato in un servizio Reliable Service. All'interno del processo host del servizio, le istanze del servizio e/o le repliche possono passare attraverso più cicli di vita.
Un'istanza di Reliable Services è rappresentata dalla classe del servizio derivante da StatelessService
o StatefulService
. Lo stack di comunicazione di un servizio è contenuto in un'implementazione ICommunicationListener
nella classe del servizio. I Microsoft.ServiceFabric.AspNetCore.*
pacchetti NuGet contengono implementazioni di ICommunicationListener
che avviano e gestiscono il ASP.NET Core WebHost per Kestrel o HTTP.sys in un servizio Reliable Service.
ICommunicationListeners ASP.NET Core
Le ICommunicationListener
implementazioni per Kestrel e HTTP.sys nei Microsoft.ServiceFabric.AspNetCore.*
pacchetti NuGet hanno modelli di utilizzo simili. Tuttavia, eseguono azioni leggermente diverse specifiche per ogni server Web.
Entrambi i listener di comunicazione forniscono un costruttore che accetta gli argomenti seguenti:
ServiceContext serviceContext
: oggettoServiceContext
che contiene informazioni sul servizio in esecuzione.string endpointName
: nome di unaEndpoint
configurazione in ServiceManifest.xml. Si tratta principalmente della differenza tra i due listener di comunicazione. HTTP.sys richiede unaEndpoint
configurazione, mentre Kestrel non lo fa.Func<string, AspNetCoreCommunicationListener, IWebHost> build
: si tratta di un'espressione lambda implementata, in cui si crea e restituisce un oggettoIWebHost
. Consente di configurareIWebHost
il modo in cui normalmente si farebbe in un'applicazione ASP.NET Core. L'espressione lambda fornisce un URL generato automaticamente, a seconda delle opzioni di integrazione di Service Fabric usate e dellaEndpoint
configurazione fornita. È quindi possibile modificare o usare tale URL per avviare il server Web.
Middleware di integrazione di Service Fabric
Il Microsoft.ServiceFabric.AspNetCore
pacchetto NuGet include il metodo di estensione in IWebHostBuilder
che aggiunge middleware UseServiceFabricIntegration
compatibile con Service Fabric. Questo middleware configura Kestrel o HTTP.sys ICommunicationListener
per registrare un URL di servizio univoco con il servizio di denominazione di Service Fabric. Convalida quindi le richieste client per assicurarsi che i client si connettano al servizio corretto.
Questo passaggio è necessario per impedire ai client di connettersi erroneamente al servizio errato. Ciò è dovuto al fatto che, in un ambiente host condiviso, ad esempio Service Fabric, più applicazioni Web possono essere eseguite nella stessa macchina virtuale o fisica, ma non usano nomi host univoci. Questo scenario è descritto più dettagliatamente nella sezione successiva.
Un caso di identità errata
Le repliche del servizio, indipendentemente dal protocollo, sono in ascolto in una combinazione IP:porta univoca. Dopo che una replica del servizio ha avviato l'ascolto su un endpoint IP:port, segnala l'indirizzo dell'endpoint al servizio di denominazione di Service Fabric. Lì, i client o altri servizi possono individuarlo. Se i servizi usano porte dell'applicazione assegnate in modo dinamico, una replica del servizio potrebbe usare in modo casuale lo stesso endpoint IP:port di un altro servizio in precedenza nella stessa macchina virtuale o fisica. In questo modo un client può connettersi per errore al servizio sbagliato. Questo scenario può risultare se si verifica la sequenza di eventi seguente:
- Il servizio A è in ascolto in 10.0.0.1:30000 su HTTP.
- Il client risolve il servizio A e ottiene l'indirizzo 10.0.0.1:30000.
- Il servizio A si sposta in un nodo diverso.
- Il servizio B si trova in 10.0.0.1 e usa per coincidenza la stessa porta 30000.
- Il client prova a connettersi al servizio A con l'indirizzo 10.0.0.1:30000 memorizzato nella cache.
- Il client è ora connesso correttamente al servizio B, non rendendosi conto che è connesso al servizio errato.
Ciò può causare bug in momenti casuali che possono essere difficili da diagnosticare.
Uso di URL di servizio univoci
Per evitare questi bug, i servizi possono inviare un endpoint al servizio di denominazione con un identificatore univoco e quindi convalidare tale identificatore univoco durante le richieste client. Si tratta di un'azione cooperativa tra servizi in un ambiente attendibile di tenant non ostili. Non fornisce l'autenticazione sicura del servizio in un ambiente tenant ostile.
In un ambiente attendibile, il middleware aggiunto dal UseServiceFabricIntegration
metodo aggiunge automaticamente un identificatore univoco all'indirizzo inviato al servizio di denominazione. Convalida l'identificatore in ogni richiesta. Se l'identificatore non corrisponde, il middleware restituisce immediatamente una risposta HTTP 410 Gone.
I servizi che usano una porta assegnata dinamicamente devono usare questo middleware.
I servizi che usano una porta univoca fissa non presentano questo problema in un ambiente cooperativo. Una porta fissa univoca viene in genere usata per i servizi esterni che richiedono una porta nota per la connessione delle applicazioni client. Ad esempio, la maggior parte delle applicazioni Web con connessione Internet userà la porta 80 o 443 per le connessioni web browser. In questo caso, l'identificatore univoco non deve essere abilitato.
Il diagramma seguente illustra il flusso della richiesta con il middleware abilitato:
Le implementazioni di Kestrel e HTTP.sys ICommunicationListener
usano questo meccanismo esattamente allo stesso modo. Anche se HTTP.sys può distinguere internamente le richieste in base a percorsi URL univoci usando la funzionalità di condivisione delle porteHTTP.sys sottostante, tale funzionalità non viene usata dall'implementazione HTTP.sys ICommunicationListener
. Questo perché genera codici di stato di errore HTTP 503 e HTTP 404 nello scenario descritto in precedenza. Ciò rende a sua volta difficile per i client determinare la finalità dell'errore, perché HTTP 503 e HTTP 404 vengono comunemente usati per indicare altri errori.
Pertanto, sia Kestrel che HTTP.sys ICommunicationListener
implementazioni standardizzano nel middleware fornito dal UseServiceFabricIntegration
metodo di estensione. Pertanto, i client devono eseguire solo un'azione di risoluzione dell'endpoint di servizio nelle risposte HTTP 410.
HTTP.sys in Reliable Services
È possibile usare HTTP.sys in Reliable Services importando il pacchetto NuGet Microsoft.ServiceFabric.AspNetCore.HttpSys . Questo pacchetto contiene HttpSysCommunicationListener
, un'implementazione di ICommunicationListener
. HttpSysCommunicationListener
consente di creare un ASP.NET Core WebHost all'interno di un servizio Reliable Services usando HTTP.sys come server Web.
HTTP.sys è basato sull'API server HTTP di Windows. Questa API usa il driver del kernelHTTP.sys per elaborare le richieste HTTP e instradarle ai processi che eseguono applicazioni Web. Ciò consente a più processi nella stessa macchina virtuale o fisica di ospitare applicazioni Web sulla stessa porta, disambiguate da un percorso URL univoco o da un nome host. Queste funzionalità sono utili in Service Fabric per ospitare più siti Web nello stesso cluster.
Nota
HTTP.sys'implementazione funziona solo sulla piattaforma Windows.
Il diagramma seguente illustra come HTTP.sys usa il driver kernel HTTP.sys in Windows per la condivisione delle porte:
HTTP.sys in un servizio senza stato
Per usare HttpSys
in un servizio senza stato, eseguire l'override del metodo CreateServiceInstanceListeners
e restituire un'istanza 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 in un servizio con stato
HttpSysCommunicationListener
attualmente non è progettato per l'uso nei servizi con stato a causa di complicazioni con la funzionalità di condivisione delle porte sottostante HTTP.sys . Per altre informazioni, vedere la sezione seguente sull'allocazione dinamica delle porte con HTTP.sys. Per i servizi con stato, Kestrel è il server Web suggerito.
Configurazione dell'endpoint
È necessaria una Endpoint
configurazione per i server Web che usano l'API Server HTTP di Windows, inclusa la HTTP.sys. I server Web che usano l'API Di Windows HTTP Server devono prima riservare l'URL con HTTP.sys (questa operazione viene normalmente eseguita con lo strumento netsh ).
Questa azione richiede privilegi elevati che i servizi non hanno per impostazione predefinita. Le opzioni "http" o "https" per la Protocol
Endpoint
proprietà della configurazione in ServiceManifest.xml vengono usate in modo specifico per indicare al runtime di Service Fabric di registrare un URL con HTTP.sys per conto dell'utente. Questa operazione viene eseguita usando il prefisso URL con caratteri jolly forti .
Ad esempio, per riservare http://+:80
un servizio, usare la configurazione seguente in ServiceManifest.xml:
<ServiceManifest ... >
...
<Resources>
<Endpoints>
<Endpoint Name="ServiceEndpoint" Protocol="http" Port="80" />
</Endpoints>
</Resources>
</ServiceManifest>
Il nome dell'endpoint deve essere passato al costruttore HttpSysCommunicationListener
:
new HttpSysCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
{
return new WebHostBuilder()
.UseHttpSys()
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
.UseUrls(url)
.Build();
})
Usare HTTP.sys con una porta statica
Per usare una porta statica con HTTP.sys, specificare il numero di Endpoint
porta nella configurazione:
<Resources>
<Endpoints>
<Endpoint Protocol="http" Name="ServiceEndpoint" Port="80" />
</Endpoints>
</Resources>
Usare HTTP.sys con una porta dinamica
Per usare una porta assegnata dinamicamente con HTTP.sys, omettere la Port
proprietà nella Endpoint
configurazione:
<Resources>
<Endpoints>
<Endpoint Protocol="http" Name="ServiceEndpoint" />
</Endpoints>
</Resources>
Una porta dinamica allocata da una Endpoint
configurazione fornisce una sola porta per ogni processo host. Il modello di hosting di Service Fabric corrente consente di ospitare più istanze del servizio e/o repliche nello stesso processo. Ciò significa che ognuno condividerà la stessa porta quando viene allocata tramite la Endpoint
configurazione. Più istanze diHTTP.sys possono condividere una porta usando la funzionalità di condivisione delle porte sottostante HTTP.sys . Ma non è supportato da HttpSysCommunicationListener
causa delle complicazioni introdotte per le richieste client. Per l'utilizzo di porta dinamica, Kestrel è il server Web suggerito.
Kestrel in Reliable Services
È possibile usare Kestrel in Reliable Services importando il pacchetto NuGet Microsoft.ServiceFabric.AspNetCore.Kestrel . Questo pacchetto contiene KestrelCommunicationListener
, un'implementazione di ICommunicationListener
. KestrelCommunicationListener
consente di creare un ASP.NET Core WebHost all'interno di un servizio affidabile usando Kestrel come server Web.
Kestrel è un server Web per ASP.NET Core multipiattaforma. A differenza di HTTP.sys, Kestrel non usa un endpoint manager centralizzato. Diversamente da HTTP.sys, Kestrel non supporta anche la condivisione delle porte tra più processi. Ogni istanza di Kestrel deve usare una porta univoca. Per altre informazioni su Kestrel, vedere i dettagli dell'implementazione.
Kestrel in un servizio senza stato
Per usare Kestrel
in un servizio senza stato, eseguire l'override del metodo CreateServiceInstanceListeners
e restituire un'istanza 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 in un servizio con stato
Per usare Kestrel
in un servizio con stato, eseguire l'override del metodo CreateServiceReplicaListeners
e restituire un'istanza 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();
))
};
}
In questo esempio viene fornita un'istanza singleton di IReliableStateManager
al contenitore di inserimento delle dipendenze WebHost. Questo non è strettamente necessario, ma consente di usare IReliableStateManager
e Reliable Collections nei metodi di azione del controller MVC.
Non viene fornito un nome di configurazione Endpoint
a KestrelCommunicationListener
in un servizio con stato, come spiegato più dettagliatamente nella sezione seguente.
Configurare Kestrel per l'uso di HTTPS
Quando si abilita HTTPS con Kestrel nel servizio, è necessario impostare diverse opzioni di ascolto. Aggiornare l'oggetto ServiceInstanceListener
per usare un endpoint EndpointHttps e ascoltare una porta specifica (ad esempio la porta 443). Quando si configura l'host Web per usare il server Web Kestrel, è necessario configurare Kestrel per ascoltare gli indirizzi IPv6 in tutte le interfacce di rete:
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();
}))
Per un esempio completo in un'esercitazione, vedere Configurare Kestrel per l'uso di HTTPS.
Configurazione dell'endpoint
Non è necessaria una Endpoint
configurazione per l'uso di Kestrel.
Kestrel è un semplice server Web autonomo. A differenza di HTTP.sys (o HttpListener), non è necessaria una Endpoint
configurazione in ServiceManifest.xml perché non richiede la registrazione URL prima dell'avvio.
Usare Kestrel con una porta statica
È possibile configurare una porta statica nella Endpoint
configurazione di ServiceManifest.xml da usare con Kestrel. Anche se questo non è strettamente necessario, offre due potenziali vantaggi:
- Se la porta non rientra nell'intervallo di porte dell'applicazione, viene aperta tramite il firewall del sistema operativo da Service Fabric.
- L'URL fornito all'utente tramite
KestrelCommunicationListener
userà questa porta.
<Resources>
<Endpoints>
<Endpoint Protocol="http" Name="ServiceEndpoint" Port="80" />
</Endpoints>
</Resources>
Se è configurato un Endpoint
, il nome deve essere passato al costruttore KestrelCommunicationListener
:
new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) => ...
Se ServiceManifest.xml non usa una Endpoint
configurazione, omettere il nome nel KestrelCommunicationListener
costruttore. In questo caso, userà una porta dinamica. Per altre informazioni, vedere la sezione successiva.
Usare Kestrel con una porta dinamica
Kestrel non può usare l'assegnazione automatica della Endpoint
porta dalla configurazione in ServiceManifest.xml. Questo perché l'assegnazione automatica delle porte da una Endpoint
configurazione assegna una porta univoca per ogni processo host e un singolo processo host può contenere più istanze di Kestrel. Questo non funziona con Kestrel perché non supporta la condivisione delle porte. Pertanto, ogni istanza di Kestrel deve essere aperta su una porta univoca.
Per usare l'assegnazione dinamica della porta con Kestrel, omettere la Endpoint
configurazione in ServiceManifest.xml completamente e non passare un nome endpoint al KestrelCommunicationListener
costruttore, come indicato di seguito:
new KestrelCommunicationListener(serviceContext, (url, listener) => ...
In questa configurazione, KestrelCommunicationListener
selezionerà automaticamente una porta non usata dall'intervallo di porte dell'applicazione.
Per HTTPS, deve avere l'endpoint configurato con il protocollo HTTPS senza una porta specificata in ServiceManifest.xml e passare il nome dell'endpoint al costruttore KestrelCommunicationListener.
Integrazione di IHost e Minimal Hosting
Oltre a IWebHost/IWebHostBuilder e KestrelCommunicationListener
HttpSysCommunicationListener
supportare la compilazione di servizi di ASP.NET Core tramite IHost/IHostBuilder.
Questa opzione è disponibile a partire da v5.2.1363 di Microsoft.ServiceFabric.AspNetCore.Kestrel
e Microsoft.ServiceFabric.AspNetCore.HttpSys
pacchetti.
// Stateless Service
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new ServiceInstanceListener[]
{
new ServiceInstanceListener(serviceContext =>
new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
{
return Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel()
.UseStartup<Startup>()
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseUrls(url);
})
.ConfigureServices(services => services.AddSingleton<StatelessServiceContext>(serviceContext))
.Build();
}))
};
}
// Stateful Service
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return new ServiceReplicaListener[]
{
new ServiceReplicaListener(serviceContext =>
new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
{
return Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel()
.UseStartup<Startup>()
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseUrls(url);
})
.ConfigureServices(services =>
{
services.AddSingleton<StatefulServiceContext>(serviceContext);
services.AddSingleton<IReliableStateManager>(this.StateManager);
})
.Build();
}))
};
}
Nota
Poiché KestrelCommunicationListener e HttpSysCommunicationListener sono destinati ai servizi Web, è necessario registrare/configurare un server Web (usando ConfigureWebHostDefaults o ConfigureWebHost ) tramite IHost
ASP.NET 6 ha introdotto il modello di hosting minimo che è un modo più semplificato e semplificato per creare applicazioni Web. È anche possibile usare un modello di hosting minimo con KestrelCommunicationListener e HttpSysCommunicationListener.
// Stateless Service
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new ServiceInstanceListener[]
{
new ServiceInstanceListener(serviceContext =>
new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
{
var builder = WebApplication.CreateBuilder();
builder.Services.AddSingleton<StatelessServiceContext>(serviceContext);
builder.WebHost
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
.UseUrls(url);
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
return app;
}))
};
}
// Stateful Service
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return new ServiceReplicaListener[]
{
new ServiceReplicaListener(serviceContext =>
new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
{
var builder = WebApplication.CreateBuilder();
builder.Services
.AddSingleton<StatefulServiceContext>(serviceContext)
.AddSingleton<IReliableStateManager>(this.StateManager);
builder.WebHost
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl)
.UseUrls(url);
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
return app;
}))
};
}
Provider di configurazione di Service Fabric
La configurazione dell'app in ASP.NET Core si basa su coppie chiave-valore stabilite dal provider di configurazione. Leggere Configurazione in ASP.NET Core per altre informazioni sul supporto generale ASP.NET Core configurazione.
Questa sezione descrive come il provider di configurazione di Service Fabric si integra con ASP.NET Core configurazione importando il Microsoft.ServiceFabric.AspNetCore.Configuration
pacchetto NuGet.
Estensioni di avvio di AddServiceFabricConfiguration
Dopo aver importato il pacchetto NuGet, è necessario registrare l'origine Microsoft.ServiceFabric.AspNetCore.Configuration
configurazione di Service Fabric con l'API di configurazione ASP.NET Core. A tale scopo, controllare le estensioni AddServiceFabricConfiguration nello Microsoft.ServiceFabric.AspNetCore.Configuration
spazio dei nomi rispetto IConfigurationBuilder
a .
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; }
Ora il servizio ASP.NET Core può accedere alle impostazioni di configurazione di Service Fabric, esattamente come qualsiasi altra impostazione dell'applicazione. Ad esempio, è possibile usare il modello di opzioni per caricare le impostazioni in oggetti fortemente tipizzati.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration); // Strongly typed configuration object.
services.AddMvc();
}
Mapping delle chiavi predefinito
Per impostazione predefinita, il provider di configurazione di Service Fabric include il nome del pacchetto, il nome della sezione e il nome della proprietà. Insieme, questi formano la chiave di configurazione ASP.NET Core, come indicato di seguito:
$"{this.PackageName}{ConfigurationPath.KeyDelimiter}{section.Name}{ConfigurationPath.KeyDelimiter}{property.Name}"
Ad esempio, se si dispone di un pacchetto di configurazione denominato MyConfigPackage
con il contenuto seguente, il valore di configurazione sarà disponibile in ASP.NET Core IConfiguration
tramite 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>
Opzioni di configurazione di Service Fabric
Il provider di configurazione di Service Fabric supporta ServiceFabricConfigurationOptions
anche la modifica del comportamento predefinito del mapping delle chiavi.
Impostazioni crittografate
Service Fabric supporta le impostazioni crittografate, come fa il provider di configurazione di Service Fabric. Le impostazioni crittografate non vengono decrittografate per ASP.NET Core IConfiguration
per impostazione predefinita. I valori crittografati vengono archiviati invece. Tuttavia, se si vuole decrittografare il valore da archiviare in ASP.NET Core IConfiguration, è possibile impostare il flag DecryptValue su false nell'estensioneAddServiceFabricConfiguration
, come indicato di seguito:
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();
}
Più pacchetti di configurazione
Service Fabric supporta più pacchetti di configurazione. Per impostazione predefinita, il nome del pacchetto è incluso nella chiave di configurazione. È tuttavia possibile impostare il IncludePackageName
flag su false, come indicato di seguito:
public Startup()
{
ICodePackageActivationContext activationContext = FabricRuntime.GetActivationContext();
var builder = new ConfigurationBuilder()
// exclude package name from key.
.AddServiceFabricConfiguration(activationContext, (options) => options.IncludePackageName = false);
Configuration = builder.Build();
}
Mapping delle chiavi personalizzato, estrazione di valori e popolamento dei dati
Il provider di configurazione di Service Fabric supporta anche scenari più avanzati per personalizzare il mapping delle chiavi con ExtractKeyFunc
ed estrarre i valori con ExtractValueFunc
. È anche possibile modificare l'intero processo di popolamento dei dati dalla configurazione di Service Fabric a ASP.NET Core configurazione usando ConfigAction
.
Gli esempi seguenti illustrano come usare ConfigAction
per personalizzare il popolamento dei dati:
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();
}
Aggiornamenti della configurazione
Il provider di configurazione di Service Fabric supporta anche gli aggiornamenti della configurazione. È possibile usare ASP.NET Core IOptionsMonitor
per ricevere notifiche di modifica e quindi usare IOptionsSnapshot
per ricaricare i dati di configurazione. Per altre informazioni, vedere ASP.NET Core opzioni.
Queste opzioni sono supportate per impostazione predefinita. Non è necessaria ulteriore codifica per abilitare gli aggiornamenti della configurazione.
Scenari e configurazioni
In questa sezione viene fornita la combinazione di server Web, configurazione delle porte, opzioni di integrazione di Service Fabric e impostazioni varie che è consigliabile risolvere i problemi seguenti:
- Servizi ASP.NET Core senza stato esposti all'esterno
- Servizi senza stato solo interni ASP.NET Core
- Servizi con stato solo ASP.NET Core interni
Un servizio esposto esternamente è uno che espone un endpoint chiamato dall'esterno del cluster, in genere tramite un servizio di bilanciamento del carico.
Un servizio solo interno è uno il cui endpoint viene chiamato solo dall'interno del cluster.
Nota
Gli endpoint di servizio con stato in genere non devono essere esposti a Internet. I cluster protetti da servizi di bilanciamento del carico non a conoscenza della risoluzione del servizio di Service Fabric, ad esempio Azure Load Balancer, non potranno esporre i servizi con stato. Questo perché il servizio di bilanciamento del carico non sarà in grado di individuare e instradare il traffico alla replica del servizio con stato appropriata.
Servizi ASP.NET Core senza stato esposti all'esterno
Kestrel è il server Web consigliato per i servizi front-end che espongono endpoint HTTP esterni con connessione Internet. In Windows, HTTP.sys può fornire funzionalità di condivisione delle porte, che consente di ospitare più servizi Web nello stesso set di nodi usando la stessa porta. In questo scenario, i servizi Web vengono differenziati in base al nome host o al percorso, senza basarsi su un proxy front-end o un gateway per fornire il routing HTTP.
Se esposto a Internet, un servizio senza stato deve usare un endpoint noto e stabile raggiungibile tramite un servizio di bilanciamento del carico. Questo URL verrà fornito agli utenti dell'applicazione. È consigliabile la configurazione seguente:
Tipo | Recommendation | Note |
---|---|---|
Server Web | Kestrel | Kestrel è il server Web preferito, perché è supportato in Windows e Linux. |
Configurazione delle porte | static | È necessario configurare una porta statica nota nella configurazione Endpoints di ServiceManifest.xml, ad esempio 80 per HTTP o 443 per HTTPS. |
ServiceFabricIntegrationOptions | Nessuno | Usare l'opzione quando si configura il ServiceFabricIntegrationOptions.None middleware di integrazione di Service Fabric, in modo che il servizio non tenti di convalidare le richieste in ingresso per un identificatore univoco. Gli utenti esterni dell'applicazione non conoscono le informazioni di identificazione univoche usate dal middleware. |
Conteggio istanze | -1 | Nei casi d'uso tipici, l'impostazione del conteggio delle istanze deve essere impostata su -1. Questa operazione viene eseguita in modo che un'istanza sia disponibile in tutti i nodi che ricevono il traffico da un servizio di bilanciamento del carico. |
Se più servizi esposti esternamente condividono lo stesso set di nodi, è possibile usare HTTP.sys con un percorso URL univoco ma stabile. A tale scopo, è possibile modificare l'URL fornito durante la configurazione di IWebHost. Si noti che questo vale solo per HTTP.sys.
new HttpSysCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
{
url += "/MyUniqueServicePath";
return new WebHostBuilder()
.UseHttpSys()
...
.UseUrls(url)
.Build();
})
Servizio ASP.NET Core senza stato solo interno
I servizi senza stato che vengono chiamati solo dall'interno del cluster devono usare URL univoci e porte assegnate dinamicamente per assicurare la cooperazione tra più servizi. È consigliabile la configurazione seguente:
Tipo | Recommendation | Note |
---|---|---|
Server Web | Kestrel | Sebbene sia possibile usare HTTP.sys per i servizi interni senza stato, Kestrel è il server migliore per consentire a più istanze del servizio di condividere un host. |
Configurazione delle porte | assegnate in modo dinamico | Più repliche di un servizio con stato potrebbero condividere un processo host o un sistema operativo host e quindi richiederanno porte univoche. |
ServiceFabricIntegrationOptions | UseUniqueServiceUrl | Con l'assegnazione dinamica delle porte, questa impostazione evita il problema di errata identificazione descritto in precedenza. |
InstanceCount | any | Il numero di istanze può essere impostato su qualsiasi valore necessario per il funzionamento del servizio. |
Servizio ASP.NET Core con stato solo interno
I servizi con stato che vengono chiamati solo dall'interno del cluster devono usare porte assegnate dinamicamente per assicurare la cooperazione tra più servizi. È consigliabile la configurazione seguente:
Tipo | Recommendation | Note |
---|---|---|
Server Web | Kestrel | non HttpSysCommunicationListener è progettato per l'uso da parte di servizi con stato in cui le repliche condividono un processo host. |
Configurazione delle porte | assegnate in modo dinamico | Più repliche di un servizio con stato potrebbero condividere un processo host o un sistema operativo host e quindi richiederanno porte univoche. |
ServiceFabricIntegrationOptions | UseUniqueServiceUrl | Con l'assegnazione dinamica delle porte, questa impostazione evita il problema di errata identificazione descritto in precedenza. |
Passaggi successivi
Debug dell'applicazione di Service Fabric mediante Visual Studio