ASP.NET Core dalam Azure Service Fabric Reliable Service

ASP.NET Core adalah kerangka kerja open-source dan lintas platform. Kerangka kerja ini dirancang untuk membangun aplikasi berbasis cloud yang terhubung dengan internet, seperti aplikasi web, aplikasi IoT, dan backend seluler.

Artikel ini adalah panduan mendalam untuk menghosting layanan ASP.NET Core dalam Service Fabric Reliable Services menggunakan set Microsoft.ServiceFabric.AspNetCore. paket NuGet.

Untuk tutorial pengantar tentang ASP.NET Core di Service Fabric dan instruksi cara menyiapkan lingkungan pengembangan Anda, lihat Tutorial: Membuat dan menyebarkan aplikasi dengan layanan front-end ASP.NET Core Web API dan layanan back-end stateful.

Bagian berikutnya artikel ini mengasumsikan bahwa Anda sudah terbiasa dengan ASP.NET Core. Jika tidak, silakan baca Dasar-dasar ASP.NET Core.

ASP.NET Core di lingkungan Service Fabric

Baik ASP.NET Core dan Service Fabric dapat berjalan di .NET Core atau .NET Framework penuh. Anda dapat menggunakan ASP.NET Core dengan dua cara berbeda dalam Service Fabric:

  • Dihosting sebagai executable tamu. Cara ini terutama digunakan untuk menjalankan aplikasi ASP.NET Core yang ada pada Service Fabric tanpa perubahan kode.
  • Jalankan di dalam reliable service. Cara ini memungkinkan integrasi yang lebih baik dengan runtime Service Fabric dan memungkinkan layanan ASP.NET Core stateful.

Bagian berikutnya artikel ini menjelaskan cara menggunakan core ASP.NET dalam reliable service, melalui komponen integrasi ASP.NET Core yang dikirim dengan Service Fabric SDK.

Hosting layanan Service Fabric

Dalam Service Fabric, satu atau beberapa instans dan/atau replika layanan Anda berjalan dalam proses host layanan: file executable yang menjalankan kode layanan Anda. Anda, sebagai penulis layanan, memiliki proses host layanan, dan Service Fabric mengaktifkan dan memantaunya untuk Anda.

Layanan ASP.NET tradisional (hingga MVC 5) digabungkan erat dengan IIS melalui System.Web.dll. ASP.NET Core menyediakan pemisahan antara server web dan aplikasi web Anda. Pemisahan ini memungkinkan aplikasi web portabel di antara server web yang berbeda. Ini juga memungkinkan server web untuk melakukan hosting-mandiri. Ini berarti Anda dapat memulai server web dalam proses Anda sendiri, dibandingkan dengan proses yang dimiliki oleh perangkat lunak server web khusus, seperti IIS.

Untuk menggabungkan layanan Service Fabric dan ASP.NET, baik sebagai executable tamu atau dalam reliable service, Anda harus dapat memulai ASP.NET dalam proses host layanan Anda. Hosting-mandiri ASP.NET Core memungkinkan Anda untuk melakukan ini.

Hosting ASP.NET Core dalam reliable service

Biasanya, aplikasi Core ASP.NET hosting-mandiri membuat WebHost di titik masuk aplikasi, seperti metode static void Main() dalam Program.cs. Dalam hal ini, siklus hidup WebHost terikat pada siklus hidup proses.

Menghosting ASP.NET Core dalam sebuah proses

Tetapi titik masuk aplikasi bukanlah tempat yang tepat untuk membuat WebHost dalam reliable service. Itu karena titik masuk aplikasi hanya digunakan untuk mendaftarkan jenis layanan dengan runtime Service Fabric, sehingga dapat membuat instans jenis layanan tersebut. WebHost harus dibuat dalam reliable service itu sendiri. Dalam proses host layanan, instans layanan dan/atau replika dapat melalui beberapa siklus hidup.

Instans Reliable Service diwakili oleh kelas layanan Anda yang berasal dari StatelessService atau StatefulService. Tumpukan komunikasi untuk layanan terkandung dalam implementasi ICommunicationListener di kelas layanan Anda. Paket Microsoft.ServiceFabric.AspNetCore.* NuGet berisi implementasi ICommunicationListener yang memulai dan mengelola Core WebHost ASP.NET untuk Kestrel atau HTTP.sys dalam reliable service.

Diagram untuk menghosting ASP.NET Core dalam reliable service

ASP.NET Core ICommunicationListeners

Implementasi ICommunicationListener untuk Kestrel dan HTTP.sys paket NuGet Microsoft.ServiceFabric.AspNetCore.* memiliki pola penggunaan yang sama. Namun, tindakan yang dilakukan sedikit berbeda, yang spesifik untuk setiap server web.

Kedua listener komunikasi menyediakan konstruktor yang mengambil argumen berikut:

  • ServiceContext serviceContext : Ini adalah objek ServiceContext yang berisi informasi tentang layanan yang sedang berjalan.
  • string endpointName : Ini adalah nama konfigurasi Endpoint di ServiceManifest.xml. Ini terutama ketika kedua listener komunikasi berbeda. HTTP.sys memerlukan konfigurasi Endpoint, sementara Kestrel tidak.
  • Func<string, AspNetCoreCommunicationListener, IWebHost> build : Ini adalah lambda yang Anda terapkan, yang Anda membuat dan mengembalikan IWebHost. Ini memungkinkan Anda untuk mengkonfigurasi IWebHost cara yang biasanya Anda lakukan dalam ASP.NET Core. Lambda menyediakan URL yang dihasilkan untuk Anda, tergantung opsi integrasi Service Fabric yang Anda gunakan dan konfigurasi Endpoint yang Anda berikan. Anda kemudian dapat mengubah atau menggunakan URL tersebut untuk memulai server web.

Middleware integrasi Service Fabric

Paket Microsoft.ServiceFabric.AspNetCore NuGet mencakup metode ekstensi UseServiceFabricIntegration pada IWebHostBuilder yang menambahkan middleware Service Fabric-aware. Middleware ini mengonfigurasi Kestrel atau HTTP.sys ICommunicationListener untuk mendaftarkan URL layanan unik dengan Service Fabric Naming Service. Kemudian memvalidasi permintaan klien untuk memastikan klien terhubung ke layanan yang tepat.

Langkah ini diperlukan untuk mencegah klien secara keliru terhubung ke layanan yang salah. Hal ini dikarenakan, dalam lingkungan shared-host seperti Service Fabric, beberapa aplikasi web dapat berjalan pada mesin fisik atau virtual yang sama tetapi tidak menggunakan nama host yang unik. Skenario ini dijelaskan secara lebih rinci di bagian berikutnya.

Kasus identitas yang keliru

Replika layanan, terlepas dari protokol, dengarkan kombinasi IP:port yang unik. Setelah replika layanan mulai mendengarkan di titik akhir IP:port, akan dilaporkan bahwa alamat titik akhir mengarah ke Service Fabric Naming Service. Di sana, klien atau layanan lain dapat menemukannya. Jika layanan menggunakan port aplikasi yang ditetapkan secara dinamis, replika layanan mungkin secara kebetulan menggunakan titik akhir IP:port yang sama dari layanan lain yang sebelumnya pada komputer fisik atau virtual yang sama. Ini dapat menyebabkan klien keliru terhubung ke layanan yang salah. Skenario ini dapat terjadi jika urutan peristiwa berikut terjadi:

  1. Layanan A mendengarkan di 10.0.0.1:30000 melalui HTTP.
  2. Klien menyelesaikan Layanan A dan mendapatkan alamat 10.0.0.1:30000.
  3. Layanan A berpindah ke node yang berbeda.
  4. Layanan B ditempatkan pada 10.0.0.1 dan kebetulan menggunakan port yang sama 30000.
  5. Klien mencoba menyambungkan ke layanan A dengan alamat singgahan 10.0.0.1:30000.
  6. Klien sekarang berhasil terhubung ke layanan B, tidak menyadari bahwa itu terhubung ke layanan yang salah.

Ini dapat menyebabkan bug pada waktu acak yang bisa sulit didiagnosis.

Menggunakan URL layanan unik

Untuk mencegah bug ini, layanan dapat memposting titik akhir ke Naming Service dengan pengidentifikasi unik, lalu memvalidasi pengidentifikasi unik tersebut selama permintaan klien. Ini adalah tindakan kooperatif antara layanan di lingkungan tepercaya non-hostile-tenant. Ini tidak menyediakan autentikasi layanan yang aman di lingkungan hostile-tenant.

Dalam lingkungan tepercaya, middleware yang ditambahkan oleh metode UseServiceFabricIntegration secara otomatis menambahkan pengidentifikasi unik ke alamat yang diposting ke Naming Service. Ini memvalidasi pengidentifikasi tersebut pada setiap permintaan. Jika pengidentifikasi tidak cocok, middleware segera mengembalikan respons HTTP 410 Gone.

Layanan yang menggunakan port yang ditetapkan secara dinamis harus menggunakan middleware ini.

Layanan yang menggunakan port unik tetap tidak memiliki masalah ini di lingkungan kerja sama. Port unik tetap biasanya digunakan untuk layanan yang terkoneksi ke jaringan eksternal yang membutuhkan port yang sangat dikenali untuk terkoneksi ke aplikasi klien. Misalnya, sebagian besar aplikasi web yang terkoneksi ke internet akan menggunakan port 80 atau 443 untuk koneksi browser web. Dalam hal ini, pengidentifikasi unik tidak boleh diaktifkan.

Diagram berikut menunjukkan alur permintaan dengan middleware diaktifkan:

Integrasi Service Fabric ASP.NET Core

Baik implementasi ICommunicationListener Kestrel maupun HTTP.sys menggunakan mekanisme ini dengan cara yang sama persis. Meskipun HTTP.sys dapat membedakan permintaan secara internal berdasarkan jalur URL unik menggunakan fitur berbagi port HTTP.sys yang mendasarinya, fungsi tersebut tidak digunakan oleh implementasi ICommunicationListener HTTP.sys. Itu karena menghasilkan kode status kesalahan HTTP 503 dan HTTP 404 dalam skenario yang dijelaskan sebelumnya. Itu pada gilirannya menyulitkan klien untuk menentukan maksud kesalahan, karena HTTP 503 dan HTTP 404 biasanya digunakan untuk menunjukkan kesalahan lain.

Dengan demikian, baik implementasi ICommunicationListener Kestrel maupun HTTP.sys standardisasi pada middleware yang disediakan oleh metode ekstensi UseServiceFabricIntegration. Oleh karena itu, klien hanya perlu melakukan tindakan penyelesaian ulang titik akhir layanan pada respons HTTP 410.

HTTP.sys dalam Reliable Service

Anda dapat menggunakan HTTP.sys di Reliable Service dengan mengimpor paket Microsoft.ServiceFabric.AspNetCore.HttpSys NuGet. Paket ini berisi HttpSysCommunicationListener, implementasi ICommunicationListener. HttpSysCommunicationListener memungkinkan Anda untuk membuat ASP.NET Core WebHost di dalam reliable service dengan HTTP.sys sebagai server web.

HTTP.sys dibangun di Windows HTTP Server API. API ini menggunakan driver kernel HTTP.sys untuk memproses permintaan HTTP dan merutekannya ke proses yang menjalankan aplikasi web. Ini memungkinkan beberapa proses pada komputer fisik atau virtual yang sama untuk menghosting aplikasi web pada port yang sama, didisambiguasikan oleh jalur URL atau nama host yang unik. Fitur-fitur ini berguna dalam Service Fabric untuk menghosting beberapa situs web di kluster yang sama.

Catatan

Implementasi HTTP.sys hanya berfungsi pada platform Windows.

Diagram berikut menggambarkan bagaimana HTTP.sys menggunakan driver kernel HTTP.sys di Windows untuk berbagi port:

Diagram HTTP.sys

HTTP.sys dalam layanan stateless

Untuk menggunakan HttpSys dalam layanan stateless, ganti metode CreateServiceInstanceListeners dan kembalikan instans 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 dalam layanan stateful

HttpSysCommunicationListener saat ini tidak dirancang untuk digunakan dalam layanan stateful karena komplikasi dengan fitur berbagi port HTTP.sys yang mendasarinya. Untuk informasi selengkapnya, lihat bagian berikut tentang alokasi port dinamis dengan HTTP.sys. Untuk layanan stateful, Kestrel adalah server web yang disarankan.

Konfigurasi titik akhir

Konfigurasi Endpoint diperlukan untuk server web yang menggunakan Windows HTTP Server API, termasuk HTTP.sys. Server web yang menggunakan Windows HTTP Server API harus terlebih dahulu memesan URL dengan HTTP.sys (ini biasanya dicapai dengan alat netsh).

Tindakan ini memerlukan hak istimewa tinggi yang tidak dimiliki layanan Anda secara default. Opsi "http" atau "https" untuk properti Protocol konfigurasi Endpoint di ServiceManifest.xml digunakan khusus untuk menginstruksikan runtime Service Fabric guna mendaftarkan URL dengan HTTP.sys atas nama Anda. Ini dilakukan menggunakan awalan URL wildcard kuat.

Misalnya, guna memesan http://+:80 untuk suatu layanan, gunakan konfigurasi berikut di ServiceManifest.xml:

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

</ServiceManifest>

Dan nama titik akhir harus diteruskan ke konstruktor HttpSysCommunicationListener:

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

Menggunakan HTTP.sys dengan port statis

Untuk menggunakan port statis dengan HTTP.sys, sediakan nomor port dalam konfigurasi Endpoint:

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

Gunakan HTTP.sys dengan port dinamis

Untuk menggunakan port yang ditetapkan dengan HTTP.sys, hilangkan properti Port dalam konfigurasi Endpoint:

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

Port dinamis yang dialokasikan oleh konfigurasi Endpoint hanya menyediakan satu port per proses hosting. Model hosting Service Fabric saat ini memungkinkan beberapa instans layanan dan/atau replika untuk dihosting dalam proses yang sama. Ini berarti masing-masing akan berbagi port yang sama ketika dialokasikan melalui konfigurasi Endpoint. Beberapa HTTP.sys dapat berbagi port menggunakan fitur berbagi port HTTP.sys yang mendasarinya. Tapi itu tidak didukung oleh HttpSysCommunicationListener karena komplikasi yang ditimbulkannya untuk permintaan klien. Untuk penggunaan port dinamis, Kestrel adalah server web yang disarankan.

Kestrel dalam Reliable Service

Anda dapat menggunakan Kestrel di Reliable Service dengan mengimpor paket Microsoft.ServiceFabric.AspNetCore.Kestrel NuGet. Paket ini berisi KestrelCommunicationListener, implementasi ICommunicationListener. KestrelCommunicationListener memungkinkan Anda untuk membuat ASP.NET Core WebHost di dalam reliable service menggunakan Kestrel sebagai server web.

Kestrel adalah server web lintas platform untuk ASP.NET Core. Tidak HTTP.sys, Kestrel tidak menggunakan pengelola titik akhir terpusat. Juga tidak seperti HTTP.sys, Kestrel tidak mendukung berbagi port antara beberapa proses. Setiap instans Kestrel harus menggunakan port yang unik. Untuk informasi selengkapnya tentang Kestrel, lihat Detail Implementasi.

Diagram Kestrel

Kestrel dalam layanan stateless

Untuk menggunakan Kestrel dalam layanan stateless, ganti metode CreateServiceInstanceListeners dan kembalikan instans 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 dalam layanan yang stateful

Untuk menggunakan Kestrel dalam layanan stateful, ganti metode CreateServiceReplicaListeners dan kembalikan instans 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();
            ))
    };
}

Dalam contoh ini, instans singleton IReliableStateManager disediakan untuk kontainer injeksi dependensi WebHost. Ini tidak benar-benar diperlukan, tetapi memungkinkan Anda untuk menggunakan IReliableStateManager dan Reliable Collection dalam metode tindakan pengontrol MVC Anda.

Nama konfigurasi Endpointtidak disediakan untuk KestrelCommunicationListener dalam layanan stateful. Ini dijelaskan secara lebih rinci di bagian berikut.

Mengonfigurasi Kestrel untuk menggunakan HTTPS

Saat mengaktifkan HTTPS dengan Kestrel dalam layanan Anda, Anda harus mengatur beberapa opsi mendengarkan. Perbarui ServiceInstanceListener untuk menggunakan titik akhir EndpointHttps dan mendengarkan port tertentu (seperti port 443). Saat mengonfigurasi host web untuk menggunakan server web Kestrel, Anda harus mengonfigurasi Kestrel untuk mendengarkan alamat IPv6 di semua antarmuka jaringan:

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

Untuk contoh lengkap dalam tutorial, lihat Mengonfigurasi Kestrel untuk menggunakan HTTPS.

Konfigurasi titik akhir

Konfigurasi Endpoint tidak diperlukan untuk menggunakan Kestrel.

Kestrel adalah server web mandiri sederhana. Tidak HTTP.sys (atau HttpListener), tidak diperlukan konfigurasi Endpoint ServiceManifest.xml karena tidak memerlukan pendaftaran URL sebelum memulai.

Menggunakan Kestrel dengan port statis

Anda dapat mengonfigurasi port statis dalam konfigurasi Endpoint ServiceManifest.xml untuk digunakan dengan Kestrel. Meskipun ini tidak benar-benar diperlukan, namun menawarkan dua manfaat potensial:

  • Jika port tidak jatuh dalam rentang port aplikasi, maka akan dibuka melalui firewall OS oleh Service Fabric.
  • URL yang diberikan kepada Anda melalui KestrelCommunicationListener akan menggunakan port ini.
  <Resources>
    <Endpoints>
      <Endpoint Protocol="http" Name="ServiceEndpoint" Port="80" />
    </Endpoints>
  </Resources>

Jika Endpoint sudah dikonfigurasi, namanya harus diteruskan ke konstruktor KestrelCommunicationListener:

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

Jika ServiceManifest.xml tidak menggunakan konfigurasi Endpoint, hilangkan namanya di konstruktor KestrelCommunicationListener. Dalam hal ini, akan digunakan port dinamis. Lihat bagian berikutnya untuk informasi selengkapnya tentang hal ini.

Gunakan Kestrel dengan port dinamis

Kestrel tidak dapat menggunakan penetapan port otomatis dari konfigurasi Endpoint di ServiceManifest.xml. Itu karena penetapan port otomatis dari konfigurasi Endpoint menetapkan port unik per proses host, dan satu proses host dapat berisi beberapa instans Kestrel. Ini tidak berfungsi dengan Kestrel karena tidak mendukung berbagi port. Oleh karena itu, setiap instans Kestrel harus dibuka pada port yang unik.

Untuk menggunakan penetapan port dinamis dengan Kestrel, hilangkan konfigurasi Endpoint dalam ServiceManifest.xml secara keseluruhan, dan jangan berikan nama titik akhir ke konstruktor KestrelCommunicationListener, sebagai berikut:

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

Dalam konfigurasi ini, KestrelCommunicationListener secara otomatis akan memilih port yang tidak digunakan dari jajaran port aplikasi.

Untuk HTTPS, harus sudah mengonfigurasi Titik Akhir dengan protokol HTTPS tanpa port yang ditentukan dalam ServiceManifest.xml dan meneruskan nama titik akhir ke konstruktor KestrelCommunicationListener.

Integrasi IHost dan Hosting Minimal

Selain IWebHost/IWebHostBuilder, KestrelCommunicationListener dan HttpSysCommunicationListener mendukung pembuatan layanan ASP.NET Core menggunakan IHost/IHostBuilder. Ini tersedia mulai v5.2.1363 dari paket Microsoft.ServiceFabric.AspNetCore.Kestrel dan 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();
            }))
    };
}

Catatan

Karena KestrelCommunicationListener dan HttpSysCommunicationListener dimaksudkan untuk layanan web, server web harus didaftarkan/dikonfigurasi (menggunakan metode ConfigureWebHostDefaults atau ConfigureWebHost ) melalui IHost

ASP.NET 6 memperkenalkan model Minimal Hosting yang merupakan cara yang lebih mudah dan singkat untuk membuat aplikasi web. Model hosting minimal juga dapat digunakan dengan KestrelCommunicationListener dan 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;
            }))
    };
}

Penyedia konfigurasi Service Fabric

Konfigurasi aplikasi ASP.NET Core didasarkan pada pasangan nilai kunci yang ditetapkan oleh penyedia konfigurasi. Baca Konfigurasi di ASP.NET Core untuk memahami lebih lanjut tentang dukungan konfigurasi ASP.NET Core umum.

Bagian ini menjelaskan bagaimana penyedia konfigurasi Service Fabric terintegrasi dengan ASP.NET Core dengan mengimpor paket Microsoft.ServiceFabric.AspNetCore.Configuration NuGet.

Ekstensi startup AddServiceFabricConfiguration

Setelah mengimpor paket Microsoft.ServiceFabric.AspNetCore.Configuration NuGet, Anda perlu mendaftarkan sumber Konfigurasi Service Fabric dengan API konfigurasi ASP.NET Core. Anda melakukan ini dengan memeriksa ekstensi AddServiceFabricConfiguration di namespace Microsoft.ServiceFabric.AspNetCore.Configuration terhadap 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; }

Sekarang layanan ASP.NET Core dapat mengakses pengaturan konfigurasi Service Fabric, sama seperti pengaturan aplikasi lainnya. Misalnya, Anda dapat menggunakan pola opsi untuk memuat pengaturan ke objek yang strongly typed.

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

Pemetaan kunci default

Secara default, penyedia konfigurasi Service Fabric menyertakan nama paket, nama bagian, dan nama properti. Bersama-sama, ini membentuk kunci konfigurasi ASP.NET Core, sebagai berikut:

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

Misalnya, jika Anda memiliki paket konfigurasi bernama MyConfigPackage dengan konten berikut, maka nilai konfigurasi akan tersedia di ASP.NET Core IConfiguration melalui 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>

Opsi konfigurasi Service Fabric

Penyedia konfigurasi Service Fabric juga mendukung ServiceFabricConfigurationOptions untuk mengubah perilaku default pemetaan kunci.

Setelan terenkripsi

Service Fabric mendukung pengaturan terenkripsi, seperti halnya penyedia konfigurasi Service Fabric. Pengaturan terenkripsi tidak didekripsi untuk ASP.NET Core IConfiguration secara default. Sebagai gantinya akan disimpan nilai terenkripsi. Tetapi jika Anda ingin mendekripsi nilai untuk disimpan di ASP.NET Core IConfiguration, Anda dapat mengatur bendera DecryptValue ke false di ekstensi AddServiceFabricConfiguration, sebagai berikut:

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

Beberapa paket konfigurasi

Service Fabric mendukung beberapa paket konfigurasi. Secara default, nama paket disertakan dalam kunci konfigurasi. Tetapi Anda dapat mengatur bendera IncludePackageName ke false, sebagai berikut:

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

Pemetaan kunci kustom, ekstraksi nilai, dan populasi data

Penyedia konfigurasi Service Fabric juga mendukung skenario yang lebih canggih untuk menyesuaikan pemetaan kunci dengan ExtractKeyFunc dan mengekstrak nilai dengan ExtractValueFunc. Anda bahkan dapat mengubah seluruh proses pengisian data dari konfigurasi Service Fabric menjadi konfigurasi ASP.NET Core menggunakan ConfigAction.

Contoh berikut mengilustrasikan cara menggunakan ConfigAction untuk mengkustomisasi populasi data:

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

Pembaruan konfigurasi

Penyedia konfigurasi Service Fabric juga mendukung pembaruan konfigurasi. Anda dapat menggunakan ASP.NET Core IOptionsMonitor untuk menerima notifikasi perubahan, lalu menggunakan IOptionsSnapshot untuk memuat ulang data konfigurasi. Untuk informasi selengkapnya, lihat Opsi ASP.NET Core.

Opsi ini didukung secara default. Tidak diperlukan pengkodean lebih lanjut untuk mengaktifkan pembaruan konfigurasi.

Skenario dan konfigurasi

Bagian ini menyediakan kombinasi server web, konfigurasi port, opsi integrasi Service Fabric, dan pengaturan lain-lain yang kami sarankan untuk memecahkan masalah skenario berikut:

  • Layanan stateless core ASP.NET Core yang diekspos secara eksternal
  • Layanan stateless ASP.NET Core internal-saja
  • Layanan stateful ASP.NET Core internal-saja

Layanan yang terekspos eksternal adalah layanan yang mengekspos titik akhir yang dipanggil dari luar kluster, biasanya melalui load balancer.

Layanan internal saja adalah layanan yang titik akhirnya hanya dipanggil dari dalam kluster.

Catatan

Titik akhir layanan stateful umumnya tidak boleh terekspos ke internet. Kluster di balik load balancer yang tidak menyadari resolusi layanan Service Fabric, seperti Azure Load Balancer, tidak akan dapat mengekspos layanan stateful. Itu karena load balancer tidak akan dapat menemukan dan merutekan lalu lintas ke replika layanan stateful yang sesuai.

Layanan stateless core ASP.NET Core yang diekspos secara eksternal

Kestrel adalah server web yang disarankan untuk layanan front-end yang terekspos eksternal, titik akhir HTTP eksternal yang terkoneksi ke internet. Pada Windows, HTTP.sys dapat menyediakan kemampuan berbagi port, yang memungkinkan Anda menghosting beberapa layanan web pada kumpulan node yang sama menggunakan port yang sama. Dalam skenario ini, layanan web dibedakan berdasarkan nama atau jalur host, tanpa mengandalkan proksi front-end atau gateway untuk menyediakan perutean HTTP.

Ketika terekspos ke internet, layanan stateless harus menggunakan titik akhir yang terkenal dan stabil yang dapat dijangkau melalui load balancer. Anda akan memberikan URL ini kepada pengguna aplikasi Anda. Kami merekomendasikan konfigurasi berikut:

Jenis Rekomendasi Catatan
Server Web Kestrel Kestrel adalah server web pilihan, karena didukung di Windows dan Linux.
Konfigurasi port static Port statis terkenal harus dikonfigurasi dalam konfigurasi Endpoints ServiceManifest.xml, seperti 80 untuk HTTP atau 443 untuk HTTPS.
ServiceFabricIntegrationOptions Tidak ada Gunakan opsi ServiceFabricIntegrationOptions.None saat mengonfigurasi middleware integrasi Service Fabric, sehingga layanan tidak mencoba memvalidasi permintaan masuk untuk pengidentifikasi unik. Pengguna eksternal aplikasi Anda tidak akan mengetahui informasi identifikasi unik yang digunakan middleware.
Jumlah Instans -1 Dalam kasus penggunaan umum, pengaturan jumlah instans harus diatur ke -1. Ini dilakukan agar instans tersedia di semua node yang menerima lalu lintas dari load balancer.

Jika beberapa layanan yang diekspos secara eksternal memiliki serangkaian node yang sama, Anda dapat menggunakan HTTP.sys dengan jalur URL yang unik namun stabil. Anda dapat menyelesaikan ini dengan memodifikasi URL yang disediakan saat mengonfigurasi IWebHost. Perhatikan bahwa ini hanya berlaku untuk HTTP.sys ini.

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

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

Layanan ASP.NET Core internal-saja

Layanan stateless yang hanya dipanggil dari dalam kluster akan menggunakan URL unik dan port yang ditetapkan secara dinamis untuk memastikan kerja sama antara beberapa layanan. Kami merekomendasikan konfigurasi berikut:

Jenis Rekomendasi Catatan
Server Web Kestrel Meskipun Anda dapat menggunakan HTTP.sys untuk layanan stateless internal, Kestrel adalah server terbaik untuk memungkinkan beberapa instans layanan untuk berbagi host.
Konfigurasi port ditetapkan secara dinamis Beberapa replika layanan stateful mungkin berbagi proses host atau sistem operasi host dan dengan demikian akan membutuhkan port yang unik.
ServiceFabricIntegrationOptions GunakanUniqueServiceUrl Dengan penetapan port dinamis, pengaturan ini mencegah masalah kesalahan identitas yang dijelaskan sebelumnya.
InstanceCount apa pun Pengaturan jumlah instans dapat diatur ke nilai apa pun yang diperlukan untuk mengoperasikan layanan.

Layanan Core ASP.NET internal-saja

Layanan stateful yang hanya dipanggil dari dalam kluster akan menggunakan port yang ditetapkan secara dinamis untuk memastikan kerja sama antara beberapa layanan. Kami merekomendasikan konfigurasi berikut:

Jenis Rekomendasi Catatan
Server Web Kestrel HttpSysCommunicationListener tidak dirancang untuk digunakan oleh layanan stateful ketika replika berbagi proses host yang sama.
Konfigurasi port ditetapkan secara dinamis Beberapa replika layanan stateful mungkin berbagi proses host atau sistem operasi host dan dengan demikian akan membutuhkan port yang unik.
ServiceFabricIntegrationOptions GunakanUniqueServiceUrl Dengan penetapan port dinamis, pengaturan ini mencegah masalah kesalahan identitas yang dijelaskan sebelumnya.

Langkah berikutnya

Debug aplikasi Service Fabric Anda dengan menggunakan Visual Studio