Apa yang baru dalam ASP.NET Core 9.0
Artikel ini menyoroti perubahan paling signifikan dalam ASP.NET Core 9.0 dengan tautan ke dokumentasi yang relevan.
Artikel ini telah diperbarui untuk Pratinjau .NET 9 6.
Blazor
Bagian ini menjelaskan fitur baru untuk Blazor.
.NET MAUIBlazor Hybrid dan templat solusi Aplikasi Web
Templat solusi baru memudahkan untuk membuat .NET MAUI aplikasi klien asli dan Blazor web yang memiliki UI yang sama. Templat ini menunjukkan cara membuat aplikasi klien yang memaksimalkan penggunaan kembali kode dan target Android, iOS, Mac, Windows, dan Web.
Fitur utama templat ini meliputi:
- Kemampuan untuk memilih Blazor mode render interaktif untuk aplikasi web.
- Pembuatan otomatis proyek yang sesuai, termasuk Blazor Aplikasi Web (rendering Otomatis Interaktif global) dan aplikasi .NET MAUIBlazor Hybrid .
- Proyek yang dibuat menggunakan pustaka kelas bersama Razor (RCL) untuk mempertahankan komponen UI Razor .
- Kode sampel disertakan yang menunjukkan cara menggunakan injeksi dependensi untuk menyediakan implementasi antarmuka yang berbeda untuk Blazor Hybrid aplikasi dan Blazor Aplikasi Web.
Untuk memulai, instal .NET 9 SDK dan instal .NET MAUI beban kerja, yang berisi templat:
dotnet workload install maui
Buat solusi dari templat proyek di shell perintah menggunakan perintah berikut:
dotnet new maui-blazor-web
Templat juga tersedia di Visual Studio.
Catatan
Saat ini, pengecualian terjadi jika Blazor mode penyajian ditentukan pada tingkat per halaman/komponen. Untuk informasi selengkapnya, lihat BlazorWebView memerlukan cara untuk mengaktifkan penggantian ResolveComponentForRenderMode (dotnet/aspnetcore
#51235).
Untuk informasi selengkapnya, lihat Membuat .NET MAUIBlazor Hybrid aplikasi dengan Blazor Aplikasi Web.
Pengoptimalan pengiriman aset statis
MapStaticAssets
adalah middleware baru yang membantu mengoptimalkan pengiriman aset statis di aplikasi ASP.NET Core apa pun, termasuk Blazor aplikasi.
Untuk informasi selengkapnya, lihat salah satu sumber daya berikut ini:
- Bagian Mengoptimalkan pengiriman aset web statis dari artikel ini.
- ASP.NET File statis intiBlazor.
Mendeteksi lokasi penyajian, interaktivitas, dan mode render yang ditetapkan saat runtime
Kami telah memperkenalkan API baru yang dirancang untuk menyederhanakan proses kueri status komponen saat runtime. API ini menyediakan kemampuan berikut:
- Tentukan lokasi eksekusi komponen saat ini: Ini dapat sangat berguna untuk penelusuran kesalahan dan mengoptimalkan performa komponen.
- Periksa apakah komponen berjalan di lingkungan interaktif: Ini dapat membantu komponen yang memiliki perilaku yang berbeda berdasarkan interaktivitas lingkungan mereka.
- Ambil mode render yang ditetapkan untuk komponen: Memahami mode render dapat membantu mengoptimalkan proses penyajian dan meningkatkan performa keseluruhan komponen.
Untuk informasi selengkapnya, lihat mode render ASP.NET CoreBlazor.
Pengalaman koneksi ulang sisi server yang disempurnakan:
Penyempurnaan berikut telah dilakukan pada pengalaman koneksi ulang sisi server default:
Saat pengguna menavigasi kembali ke aplikasi dengan sirkuit yang terputus, koneksi ulang dicoba segera daripada menunggu durasi interval koneksi ulang berikutnya. Ini meningkatkan pengalaman pengguna saat menavigasi ke aplikasi di tab browser yang telah tidur.
Ketika upaya koneksi ulang mencapai server tetapi server telah merilis sirkuit, refresh halaman terjadi secara otomatis. Ini mencegah pengguna harus menyegarkan halaman secara manual jika kemungkinan akan menghasilkan koneksi ulang yang berhasil.
Waktu koneksi ulang menggunakan strategi backoff komputasi. Secara default, beberapa upaya koneksi ulang pertama terjadi berturut-turut dengan cepat tanpa interval coba lagi sebelum penundaan komputasi diperkenalkan di antara upaya. Anda dapat menyesuaikan perilaku interval coba lagi dengan menentukan fungsi untuk menghitung interval coba lagi, seperti yang ditunjukkan contoh backoff eksponensial berikut:
Blazor.start({ circuit: { reconnectionOptions: { retryIntervalMilliseconds: (previousAttempts, maxRetries) => previousAttempts >= maxRetries ? null : previousAttempts * 1000 }, }, });
Gaya antarmuka pengguna koneksi ulang default telah dimodernisasi.
Untuk informasi selengkapnya, lihat panduan ASP.NET CoreBlazorSignalR.
Serialisasi status autentikasi yang disederhanakan untuk Blazor Web Apps
API baru memudahkan untuk menambahkan autentikasi ke Aplikasi Web yang sudah ada Blazor . Saat Anda membuat Aplikasi Web baru Blazor dengan autentikasi menggunakan Akun Individual dan Anda mengaktifkan interaktivitas berbasis WebAssembly, proyek menyertakan kustom AuthenticationStateProvider di proyek server dan klien.
Penyedia ini mengalirkan status autentikasi pengguna ke browser. Mengautentikasi di server daripada klien memungkinkan aplikasi mengakses status autentikasi selama pra-penyajian Blazor WebAssembly dan sebelum runtime diinisialisasi.
Implementasi kustom menggunakan layanan Status Komponen Persisten (PersistentComponentState) untuk membuat serialisasi status autentikasi ke dalam komentar HTML dan membacanya kembali dari WebAssembly untuk membuat instans baruAuthenticationState. AuthenticationStateProvider
Ini berfungsi dengan baik jika Anda telah memulai dari Blazor templat proyek Aplikasi Web dan memilih opsi Akun Individual, tetapi banyak kode untuk mengimplementasikan diri Anda atau menyalin jika Anda mencoba menambahkan autentikasi ke proyek yang ada. Sekarang ada API, yang sekarang menjadi bagian Blazor dari templat proyek Aplikasi Web, yang dapat dipanggil di server dan proyek klien untuk menambahkan fungsionalitas ini:
AddAuthenticationStateSerialization
: Menambahkan layanan yang diperlukan untuk membuat serialisasi status autentikasi di server.AddAuthenticationStateDeserialization
: Menambahkan layanan yang diperlukan untuk mendeserialisasi status autentikasi di browser.
Secara default, API hanya menserialisasikan nama sisi server dan klaim peran untuk akses di browser. Opsi dapat diteruskan ke AddAuthenticationStateSerialization
untuk menyertakan semua klaim.
Untuk informasi selengkapnya, lihat bagian berikut dari artikel **:
Menambahkan halaman penyajian sisi server statis (SSR) ke Aplikasi Web interaktif Blazor global
Dengan rilis .NET 9, sekarang lebih sederhana untuk menambahkan halaman SSR statis ke aplikasi yang mengadopsi interaktivitas global.
Pendekatan ini hanya berguna ketika aplikasi memiliki halaman tertentu yang tidak dapat bekerja dengan Server interaktif atau penyajian WebAssembly. Misalnya, adopsi pendekatan ini untuk halaman yang bergantung pada pembacaan/penulisan HTTP cookiedan hanya dapat berfungsi dalam siklus permintaan/respons alih-alih penyajian interaktif. Untuk halaman yang berfungsi dengan penyajian interaktif, Anda tidak boleh memaksanya untuk menggunakan penyajian SSR statis, karena kurang efisien dan kurang responsif bagi pengguna akhir.
Tandai halaman komponen apa pun Razor dengan atribut baru [ExcludeFromInteractiveRouting]
yang ditetapkan dengan direktif @attribute
Razor :
@attribute [ExcludeFromInteractiveRouting]
Menerapkan atribut menyebabkan navigasi ke halaman keluar dari perutean interaktif. Navigasi masuk dipaksa untuk melakukan pemuatan ulang halaman penuh sebagai gantinya menyelesaikan halaman melalui perutean interaktif. Pemuatan ulang halaman penuh memaksa komponen akar tingkat atas, biasanya App
komponen (App.razor
), untuk merender dari server, memungkinkan aplikasi beralih ke mode render tingkat atas yang berbeda.
Metode HttpContext.AcceptsInteractiveRouting
ekstensi memungkinkan komponen mendeteksi apakah [ExcludeFromInteractiveRouting]
diterapkan ke halaman saat ini.
App
Dalam komponen, gunakan pola dalam contoh berikut:
- Halaman yang tidak dianotasi dengan
[ExcludeFromInteractiveRouting]
default keInteractiveServer
mode render dengan interaktivitas global. Anda dapat menggantiInteractiveServer
denganInteractiveWebAssembly
atauInteractiveAuto
untuk menentukan mode render global default yang berbeda. - Halaman yang dianotasi dengan
[ExcludeFromInteractiveRouting]
mengadopsi SSR statis (PageRenderMode
ditetapkannull
).
<!DOCTYPE html>
<html>
<head>
...
<HeadOutlet @rendermode="@PageRenderMode" />
</head>
<body>
<Routes @rendermode="@PageRenderMode" />
...
</body>
</html>
@code {
[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
private IComponentRenderMode? PageRenderMode
=> HttpContext.AcceptsInteractiveRouting() ? InteractiveServer : null;
}
Alternatif untuk menggunakan HttpContext.AcceptsInteractiveRouting
metode ekstensi adalah membaca metadata titik akhir secara manual menggunakan HttpContext.GetEndpoint()?.Metadata
.
Fitur ini dicakup oleh dokumentasi referensi dalam mode render ASP.NET CoreBlazor.
Injeksi konstruktor
Razor komponen mendukung injeksi konstruktor.
Dalam contoh berikut, kelas parsial (code-behind) menyuntikkan NavigationManager
layanan menggunakan konstruktor utama:
public partial class ConstructorInjection(NavigationManager navigation)
{
protected NavigationManager Navigation { get; } = navigation;
}
Untuk informasi selengkapnya, lihat Injeksi dependensi ASP.NET Core Blazor.
Kompresi Websocket untuk komponen Server Interaktif
Secara default, komponen Server Interaktif memungkinkan pemadatan untuk koneksi WebSocket dan mengatur frame-ancestors
direktif Kebijakan Keamanan Konten (CSP) yang diatur ke 'self'
, yang hanya mengizinkan penyematan aplikasi di <iframe>
asal tempat aplikasi dilayani saat pemadatan diaktifkan atau saat konfigurasi untuk konteks WebSocket disediakan.
Pemadatan dapat dinonaktifkan dengan mengatur ConfigureWebSocketOptions
ke null
, yang mengurangi kerentanan aplikasi untuk menyerang tetapi dapat mengakibatkan penurunan performa:
.AddInteractiveServerRenderMode(o => o.ConfigureWebSocketOptions = null)
Konfigurasikan CSP yang lebih frame-ancestors
ketat dengan nilai 'none'
(tanda kutip tunggal diperlukan), yang memungkinkan kompresi WebSocket tetapi mencegah browser menyematkan aplikasi ke dalam :<iframe>
.AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")
Untuk informasi selengkapnya, lihat sumber daya berikut:
- panduan ASP.NET Core BlazorSignalR
- Panduan mitigasi ancaman untuk penyajian sisi server interaktif ASP.NET Core Blazor
Menangani peristiwa komposisi keyboard di Blazor
Properti baru KeyboardEventArgs.IsComposing
menunjukkan apakah peristiwa keyboard adalah bagian dari sesi komposisi. Melacak status komposisi peristiwa keyboard sangat penting untuk menangani metode input karakter internasional.
Menambahkan parameter OverscanCount
ke QuickGrid
Komponen QuickGrid
sekarang mengekspos OverscanCount
properti yang menentukan berapa banyak baris tambahan yang dirender sebelum dan sesudah wilayah yang terlihat saat virtualisasi diaktifkan.
OverscanCount
Defaultnya adalah 3. Contoh berikut meningkatkan menjadi OverscanCount
4:
<QuickGrid ItemsProvider="itemsProvider" Virtualize="true" OverscanCount="4">
...
</QuickGrid>
SignalR
Bagian ini menjelaskan fitur baru untuk SignalR.
Dukungan jenis polimorfik di SignalR Hub
Metode hub sekarang dapat menerima kelas dasar alih-alih kelas turunan untuk mengaktifkan skenario polimorfik. Jenis dasar perlu diannotasi untuk memungkinkan polimorfisme.
public class MyHub : Hub
{
public void Method(JsonPerson person)
{
if (person is JsonPersonExtended)
{
}
else if (person is JsonPersonExtended2)
{
}
else
{
}
}
}
[JsonPolymorphic]
[JsonDerivedType(typeof(JsonPersonExtended), nameof(JsonPersonExtended))]
[JsonDerivedType(typeof(JsonPersonExtended2), nameof(JsonPersonExtended2))]
private class JsonPerson
{
public string Name { get; set; }
public Person Child { get; set; }
public Person Parent { get; set; }
}
private class JsonPersonExtended : JsonPerson
{
public int Age { get; set; }
}
private class JsonPersonExtended2 : JsonPerson
{
public string Location { get; set; }
}
Aktivitas yang Ditingkatkan untuk SignalR
SignalR sekarang memiliki ActivitySource bernama Microsoft.AspNetCore.SignalR.Server
yang memancarkan peristiwa untuk panggilan metode hub:
- Setiap metode adalah aktivitasnya sendiri, sehingga apa pun yang memancarkan aktivitas selama panggilan metode hub berada di bawah aktivitas metode hub.
- Aktivitas metode hub tidak memiliki induk. Ini berarti mereka tidak dibundel di bawah koneksi yang berjalan SignalR lama.
Contoh berikut menggunakan dasbor .NET Aspire dan paket OpenTelemetry:
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
Tambahkan kode startup berikut ke Program.cs
file:
// Set OTEL_EXPORTER_OTLP_ENDPOINT environment variable depending on where your OTEL endpoint is
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
if (builder.Environment.IsDevelopment())
{
// We want to view all traces in development
tracing.SetSampler(new AlwaysOnSampler());
}
tracing.AddAspNetCoreInstrumentation();
tracing.AddSource("Microsoft.AspNetCore.SignalR.Server");
});
builder.Services.ConfigureOpenTelemetryTracerProvider(tracing => tracing.AddOtlpExporter());
Berikut ini adalah contoh output dari Dasbor Aspire:
Minimal API
Bagian ini menjelaskan fitur baru untuk API minimal.
Menambahkan InternalServerError
dan InternalServerError<TValue>
ke TypedResults
Kelas TypedResults ini adalah kendaraan bermanfaat untuk mengembalikan respons berbasis kode status HTTP yang sangat ditik dari API minimal. TypedResults
sekarang termasuk metode dan jenis pabrik untuk mengembalikan respons "500 Kesalahan Server Internal" dari titik akhir. Berikut adalah contoh yang mengembalikan respons 500:
var app = WebApplication.Create();
app.MapGet("/", () => TypedResults.InternalServerError("Something went wrong!"));
app.Run();
OpenAPI
Dukungan bawaan untuk pembuatan dokumen OpenAPI
Spesifikasi OpenAPI adalah standar untuk menjelaskan API HTTP. Standar ini memungkinkan pengembang untuk menentukan bentuk API yang dapat dicolokkan ke generator klien, generator server, alat pengujian, dokumentasi, dan banyak lagi. Dalam Pratinjau .NET 9, ASP.NET Core menyediakan dukungan bawaan untuk menghasilkan dokumen OpenAPI yang mewakili API berbasis pengontrol atau minimal melalui paket Microsoft.AspNetCore.OpenApi .
Panggilan kode yang disorot berikut:
AddOpenApi
untuk mendaftarkan dependensi yang diperlukan ke dalam kontainer DI aplikasi.MapOpenApi
untuk mendaftarkan titik akhir OpenAPI yang diperlukan dalam rute aplikasi.
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/hello/{name}", (string name) => $"Hello {name}"!);
app.Run();
Microsoft.AspNetCore.OpenApi
Instal paket dalam proyek menggunakan perintah berikut:
dotnet add package Microsoft.AspNetCore.OpenApi --prerelease
Jalankan aplikasi dan navigasikan ke untuk openapi/v1.json
melihat dokumen OpenAPI yang dihasilkan:
Dokumen OpenAPI juga dapat dihasilkan pada waktu build dengan menambahkan Microsoft.Extensions.ApiDescription.Server
paket:
dotnet add package Microsoft.Extensions.ApiDescription.Server --prerelease
Dalam file proyek aplikasi, tambahkan yang berikut ini:
<PropertyGroup>
<OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)</OpenApiDocumentsDirectory>
<OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
</PropertyGroup>
Jalankan dotnet build
dan periksa file ON yang dihasilkan JSdi direktori proyek.
ASP.NET pembuatan dokumen OpenAPI bawaan Core menyediakan dukungan untuk berbagai penyesuaian dan opsi. Ini menyediakan transformator dokumen dan operasi dan memiliki kemampuan untuk mengelola beberapa dokumen OpenAPI untuk aplikasi yang sama.
Untuk mempelajari selengkapnya tentang kemampuan dokumen OpenAPI baru ASP.NET Core, lihat dokumen Microsoft.AspNetCore.OpenApi baru.
Peningkatan penyelesaian Intellisense untuk paket OpenAPI
ASP.NET dukungan OpenAPI Core sekarang lebih mudah diakses dan ramah pengguna. API OpenAPI dikirim sebagai paket independen, terpisah dari kerangka kerja bersama. Hingga saat ini, ini berarti bahwa pengembang tidak memiliki kenyamanan fitur penyelesaian kode seperti Intellisense untuk API OpenAPI.
Mengenali kesenjangan ini, kami telah memperkenalkan penyedia penyelesaian baru dan perbaikan kode. Alat-alat ini dirancang untuk memfasilitasi penemuan dan penggunaan API OpenAPI, sehingga memudahkan pengembang untuk mengintegrasikan OpenAPI ke dalam proyek mereka. Penyedia penyelesaian menawarkan saran kode real-time, sementara perbaikan kode membantu memperbaiki kesalahan umum dan meningkatkan penggunaan API. Peningkatan ini adalah bagian dari komitmen berkelanjutan kami untuk meningkatkan pengalaman pengembang dan menyederhanakan alur kerja terkait API.
Saat pengguna mengetik pernyataan di mana API terkait OpenAPI tersedia, penyedia penyelesaian menampilkan rekomendasi untuk API. Misalnya, dalam cuplikan layar berikut, penyelesaian untuk AddOpenApi dan MapOpenApi disediakan saat pengguna memasukkan pernyataan pemanggilan pada jenis yang didukung, seperti IEndpointConventionBuilder:
Ketika penyelesaian diterima dan Microsoft.AspNetCore.OpenApi
paket tidak diinstal, codefixer menyediakan pintasan untuk menginstal dependensi secara otomatis dalam proyek.
Dukungan untuk [Required]
atribut dan [DefaultValue]
pada parameter dan properti
Ketika [Required]
atribut dan [DefaultValue]
diterapkan pada parameter atau properti dalam jenis kompleks, implementasi OpenAPI memetakan ini ke required
properti dan default
dalam dokumen OpenAPI yang terkait dengan parameter atau skema jenis.
Misalnya, API berikut menghasilkan skema yang menyertainya untuk jenis tersebut Todo
.
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.MapPost("/todos", (Todo todo) => { });
app.Run();
class Todo
{
public int Id { get; init; }
public required string Title { get; init; }
[DefaultValue("A new todo")]
public required string Description { get; init; }
[Required]
public DateTime CreatedOn { get; init; }
}
{
"required": [
"title",
"description",
"createdOn"
],
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"title": {
"type": "string"
},
"description": {
"type": "string",
"default": "A new todo"
},
"createdOn": {
"type": "string",
"format": "date-time"
}
}
}
Dukungan untuk transformator skema pada dokumen OpenAPI
Dukungan OpenAPI bawaan sekarang dikirim dengan dukungan untuk transformator skema yang dapat digunakan untuk memodifikasi skema yang dihasilkan oleh System.Text.Json dan implementasi OpenAPI. Seperti transformator dokumen dan operasi, transformator skema dapat didaftarkan pada objek OpenApiOptions . Misalnya, sampel kode berikut menunjukkan menggunakan transformator skema untuk menambahkan contoh ke skema jenis.
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Microsoft.OpenApi.Any;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options =>
{
options.UseSchemaTransformer((schema, context, cancellationToken) =>
{
if (context.Type == typeof(Todo))
{
schema.Example = new OpenApiObject
{
["id"] = new OpenApiInteger(1),
["title"] = new OpenApiString("A short title"),
["description"] = new OpenApiString("A long description"),
["createdOn"] = new OpenApiDateTime(DateTime.Now)
};
}
return Task.CompletedTask;
});
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.MapPost("/todos", (Todo todo) => { });
app.Run();
class Todo
{
public int Id { get; init; }
public required string Title { get; init; }
[DefaultValue("A new todo")]
public required string Description { get; init; }
[Required]
public DateTime CreatedOn { get; init; }
}
Autentikasi dan otorisasi
Bagian ini menjelaskan fitur baru untuk autentikasi dan otorisasi.
Kustomisasi Parameter OIDC dan OAuth
Handler autentikasi OAuth dan OIDC sekarang memiliki AdditionalAuthorizationParameters
opsi untuk mempermudah kustomisasi parameter pesan otorisasi yang biasanya disertakan sebagai bagian dari string kueri pengalihan. Di .NET 8 dan yang lebih lama, ini memerlukan metode panggilan balik kustom OnRedirectToIdentityProvider atau ditimpa BuildChallengeUrl dalam handler kustom. Berikut adalah contoh kode .NET 8:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.Events.OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.SetParameter("prompt", "login");
context.ProtocolMessage.SetParameter("audience", "https://api.example.com");
return Task.CompletedTask;
};
});
Contoh sebelumnya sekarang dapat disederhanakan ke kode berikut:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.AdditionalAuthorizationParameters.Add("prompt", "login");
options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});
Mengonfigurasi HTTP.sys bendera autentikasi yang diperluas
Anda sekarang dapat mengonfigurasi HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING
bendera dan HTTP_AUTH_EX_FLAG_CAPTURE_CREDENTIAL
HTTP.sys dengan menggunakan properti baru EnableKerberosCredentialCaching
dan CaptureCredentials
pada HTTP.sys AuthenticationManager untuk mengoptimalkan cara autentikasi Windows ditangani. Contohnya:
webBuilder.UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.Negotiate;
options.Authentication.EnableKerberosCredentialCaching = true;
options.Authentication.CaptureCredentials = true;
});
Lain-lain
Bagian berikut menjelaskan fitur baru lainnya.
Pustaka baru HybridCache
HybridCache
API menjenjang beberapa celah di API dan IMemoryCache yang adaIDistributedCache. Ini juga menambahkan kemampuan baru, seperti:
- Perlindungan "Stampede" untuk mencegah pengambilan paralel dari pekerjaan yang sama.
- Serialisasi yang dapat dikonfigurasi.
HybridCache
dirancang untuk menjadi pengganti drop-in untuk yang ada IDistributedCache
dan IMemoryCache
penggunaan, dan menyediakan API sederhana untuk menambahkan kode penembolokan baru. Ini menyediakan API terpadu untuk penembolokan dalam proses dan di luar proses.
Untuk melihat bagaimana API disederhanakan HybridCache
IDistributedCache
, bandingkan dengan kode yang menggunakan . Berikut adalah contoh tampilan penggunaan IDistributedCache
:
public class SomeService(IDistributedCache cache)
{
public async Task<SomeInformation> GetSomeInformationAsync
(string name, int id, CancellationToken token = default)
{
var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
var bytes = await cache.GetAsync(key, token); // Try to get from cache.
SomeInformation info;
if (bytes is null)
{
// Cache miss; get the data from the real source.
info = await SomeExpensiveOperationAsync(name, id, token);
// Serialize and cache it.
bytes = SomeSerializer.Serialize(info);
await cache.SetAsync(key, bytes, token);
}
else
{
// Cache hit; deserialize it.
info = SomeSerializer.Deserialize<SomeInformation>(bytes);
}
return info;
}
// This is the work we're trying to cache.
private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
CancellationToken token = default)
{ /* ... */ }
}
Itu banyak pekerjaan yang harus disempurnakan setiap kali, termasuk hal-hal seperti serialisasi. Dan dalam skenario cache miss, Anda bisa berakhir dengan beberapa utas bersamaan, semua mendapatkan cache miss, semua mengambil data yang mendasarinya, semua menserialisasikannya, dan semua mengirim data tersebut ke cache.
Untuk menyederhanakan dan meningkatkan kode ini dengan HybridCache
, pertama-tama kita perlu menambahkan pustaka Microsoft.Extensions.Caching.Hybrid
baru :
<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="9.0.0" />
Daftarkan HybridCache
layanan, seperti anda akan mendaftarkan implementasi IDistributedCache
:
services.AddHybridCache(); // Not shown: optional configuration API.
Sekarang sebagian besar masalah penembolokan dapat dilepaskan ke HybridCache
:
public class SomeService(HybridCache cache)
{
public async Task<SomeInformation> GetSomeInformationAsync
(string name, int id, CancellationToken token = default)
{
return await cache.GetOrCreateAsync(
$"someinfo:{name}:{id}", // Unique key for this combination.
async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
token: token
);
}
}
Kami menyediakan implementasi konkret dari HybridCache
kelas abstrak melalui injeksi dependensi, tetapi dimaksudkan agar pengembang dapat memberikan implementasi kustom API. Implementasi HybridCache
ini berkaitan dengan segala sesuatu yang terkait dengan penembolokan, termasuk penanganan operasi bersamaan. Token cancel
di sini mewakili pembatalan gabungan semua pemanggil bersamaan—bukan hanya pembatalan pemanggil yang dapat kita lihat (yaitu, token
).
Skenario throughput tinggi dapat dioptimalkan lebih lanjut dengan menggunakan TState
pola, untuk menghindari beberapa overhead dari variabel yang ditangkap dan panggilan balik per instans:
public class SomeService(HybridCache cache)
{
public async Task<SomeInformation> GetSomeInformationAsync(string name, int id, CancellationToken token = default)
{
return await cache.GetOrCreateAsync(
$"someinfo:{name}:{id}", // unique key for this combination
(name, id), // all of the state we need for the final call, if needed
static async (state, token) =>
await SomeExpensiveOperationAsync(state.name, state.id, token),
token: token
);
}
}
HybridCache
menggunakan implementasi yang dikonfigurasi IDistributedCache
, jika ada, untuk penembolokan di luar proses sekunder, misalnya, menggunakan Redis. Tetapi bahkan tanpa IDistributedCache
, HybridCache
layanan masih akan memberikan perlindungan penembolokan dalam proses dan "stempel".
Catatan tentang penggunaan kembali objek
Dalam kode umum yang ada yang menggunakan IDistributedCache
, setiap pengambilan objek dari cache menghasilkan deserialisasi. Perilaku ini berarti bahwa setiap pemanggil bersamaan mendapatkan instans terpisah dari objek, yang tidak dapat berinteraksi dengan instans lain. Hasilnya adalah keamanan utas, karena tidak ada risiko modifikasi bersamaan pada instans objek yang sama.
Karena banyak HybridCache
penggunaan akan diadaptasi dari kode yang ada IDistributedCache
, HybridCache
mempertahankan perilaku ini secara default untuk menghindari memperkenalkan bug konkurensi. Namun, kasus penggunaan tertentu secara inheren aman utas:
- Jika jenis yang di-cache tidak dapat diubah.
- Jika kode tidak mengubahnya.
Dalam kasus seperti itu, informasikan HybridCache
bahwa aman untuk menggunakan kembali instans dengan:
- Menandai jenis sebagai
sealed
. Katasealed
kunci dalam C# berarti bahwa kelas tidak dapat diwariskan. - Menerapkan atribut ke
[ImmutableObject(true)]
atribut tersebut. Atribut[ImmutableObject(true)]
menunjukkan bahwa status objek tidak dapat diubah setelah dibuat.
Dengan menggunakan kembali instans, HybridCache
dapat mengurangi overhead CPU dan alokasi objek yang terkait dengan deserialisasi per panggilan. Hal ini dapat menyebabkan peningkatan performa dalam skenario di mana objek yang di-cache besar atau sering diakses.
Fitur lain HybridCache
Seperti IDistributedCache
, HybridCache
mendukung penghapusan dengan kunci dengan RemoveKeyAsync
metode .
HybridCache
juga menyediakan API opsional untuk IDistributedCache
implementasi, untuk menghindari byte[]
alokasi. Fitur ini diimplementasikan oleh versi pratinjau paket Microsoft.Extensions.Caching.StackExchangeRedis
dan Microsoft.Extensions.Caching.SqlServer
.
Serialisasi dikonfigurasi sebagai bagian dari mendaftarkan layanan, dengan dukungan untuk serializer khusus jenis dan umum melalui WithSerializer
metode dan .WithSerializerFactory
, ditautkan dari AddHybridCache
panggilan. Secara default, pustaka menangani string
dan byte[]
secara internal, dan menggunakan System.Text.Json
untuk yang lain, tetapi Anda dapat menggunakan protobuf, xml, atau apa pun.
HybridCache
mendukung runtime .NET yang lebih lama, hingga .NET Framework 4.7.2 dan .NET Standard 2.0.
Untuk informasi selengkapnya tentang HybridCache
, lihat Pustaka HybridCache di ASP.NET Core
Penyempurnaan halaman pengecualian pengembang
Halaman pengecualian pengembang ASP.NET Core ditampilkan saat aplikasi melemparkan pengecualian yang tidak tertangani selama pengembangan. Halaman pengecualian pengembang menyediakan informasi terperinci tentang pengecualian dan permintaan.
Pratinjau 3 menambahkan metadata titik akhir ke halaman pengecualian pengembang. ASP.NET Core menggunakan metadata titik akhir untuk mengontrol perilaku titik akhir, seperti perutean, penembolokan respons, pembatasan laju, pembuatan OpenAPI, dan banyak lagi. Gambar berikut menunjukkan informasi metadata baru di bagian Routing
halaman pengecualian pengembang:
Saat menguji halaman pengecualian pengembang, peningkatan kualitas hidup yang kecil diidentifikasi. Mereka dikirim dalam Pratinjau 4:
- Pembungkusan teks yang lebih baik. Panjang cookie, nilai string kueri, dan nama metode tidak lagi menambahkan bilah gulir browser horizontal.
- Teks yang lebih besar yang ditemukan dalam desain modern.
- Ukuran tabel yang lebih konsisten.
Gambar animasi berikut menunjukkan halaman pengecualian pengembang baru:
Peningkatan penelusuran kesalahan kamus
Tampilan debugging kamus dan koleksi nilai kunci lainnya memiliki tata letak yang ditingkatkan. Kunci ditampilkan di kolom kunci debugger alih-alih digabungkan dengan nilai . Gambar berikut menunjukkan tampilan lama dan baru kamus di debugger.
Sebelum:
Setelah:
ASP.NET Core memiliki banyak koleksi kunci-nilai. Pengalaman penelusuran kesalahan yang ditingkatkan ini berlaku untuk:
- Header HTTP
- String kueri
- Formulir
- Cookies
- Menampilkan data
- Merutekan data
- Fitur
Perbaikan untuk 503 selama daur ulang aplikasi di IIS
Secara default sekarang ada penundaan 1 detik antara ketika IIS diberi tahu tentang daur ulang atau matikan dan ketika ANCM memberi tahu server terkelola untuk mulai dimatikan. Penundaan dapat dikonfigurasi melalui ANCM_shutdownDelay
variabel lingkungan atau dengan mengatur shutdownDelay
pengaturan handler. Kedua nilai berada dalam milidetik. Penundaan ini terutama untuk mengurangi kemungkinan perlombaan di mana:
- IIS belum mulai mengantre permintaan untuk masuk ke aplikasi baru.
- ANCM mulai menolak permintaan baru yang masuk ke aplikasi lama.
Komputer atau mesin yang lebih lambat dengan penggunaan CPU yang lebih berat mungkin ingin menyesuaikan nilai ini untuk mengurangi kemungkinan 503.
Contoh pengaturan shutdownDelay
:
<aspNetCore processPath="dotnet" arguments="myapp.dll" stdoutLogEnabled="false" stdoutLogFile=".logsstdout">
<handlerSettings>
<!-- Milliseconds to delay shutdown by.
this doesn't mean incoming requests will be delayed by this amount,
but the old app instance will start shutting down after this timeout occurs -->
<handlerSetting name="shutdownDelay" value="5000" />
</handlerSettings>
</aspNetCore>
Perbaikannya ada dalam modul ANCM yang diinstal secara global yang berasal dari bundel hosting.
Mengoptimalkan pengiriman aset web statis
Mengikuti praktik terbaik produksi untuk melayani aset statis membutuhkan sejumlah besar keahlian kerja dan teknis. Tanpa pengoptimalan seperti kompresi, penembolokan, dan sidik jari:
- Browser harus membuat permintaan tambahan pada setiap pemuatan halaman.
- Lebih banyak byte daripada yang diperlukan ditransfer melalui jaringan.
- Terkadang versi file kedaluarsa disajikan kepada klien.
Membuat aplikasi web berkinerja memerlukan pengoptimalan pengiriman aset ke browser. Kemungkinan pengoptimalan meliputi:
- Layani aset tertentu sekali sampai file berubah atau browser menghapus cache-nya. Atur header ETag .
- Cegah browser menggunakan aset lama atau kedaluarsa setelah aplikasi diperbarui. Atur header Terakhir Diubah .
- Siapkan header penembolokan yang tepat.
- Gunakan middleware penembolokan.
- Menyajikan versi aset yang dikompresi jika memungkinkan.
- Gunakan CDN untuk melayani aset yang lebih dekat dengan pengguna.
- Minimalkan ukuran aset yang disajikan ke browser. Pengoptimalan ini tidak termasuk minifikasi.
MapStaticAssets
adalah middleware baru yang membantu mengoptimalkan pengiriman aset statis dalam aplikasi. Ini dirancang untuk bekerja dengan semua kerangka kerja UI, termasuk Blazor, Razor Pages, dan MVC. Ini biasanya merupakan pengganti drop-in untuk UseStaticFiles:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
+app.MapStaticAssets();
-app.UseStaticFiles();
app.MapRazorPages();
app.Run();
MapStaticAssets
beroperasi dengan menggabungkan proses build dan publish-time untuk mengumpulkan informasi tentang semua sumber daya statis dalam aplikasi. Informasi ini kemudian digunakan oleh pustaka runtime untuk melayani file-file ini secara efisien ke browser.
MapStaticAssets
dapat menggantikan UseStaticFiles
dalam sebagian besar situasi, namun, hal ini dioptimalkan untuk melayani aset yang memiliki pengetahuan tentang aplikasi saat membangun dan menerbitkan waktu. Jika aplikasi melayani aset dari lokasi lain, seperti disk atau sumber daya yang disematkan, UseStaticFiles
harus digunakan.
MapStaticAssets
memberikan manfaat berikut yang tidak ditemukan dengan UseStaticFiles
:
- Kompresi waktu build untuk semua aset di aplikasi:
gzip
selama pengembangan dangzip + brotli
selama penerbitan.- Semua aset dikompresi dengan tujuan mengurangi ukuran aset menjadi minimum.
ETags
Berbasis konten :Etags
untuk setiap sumber daya adalah string yang dikodekan Base64 dari hash SHA-256 konten. Ini memastikan bahwa browser hanya mengunduh ulang file jika kontennya telah berubah.
Tabel berikut ini memperlihatkan ukuran asli dan terkompresi CSS dan JS file dalam templat Halaman default Razor :
File | Asli | Dikompresi | % Pengurangan |
---|---|---|---|
bootstrap.min.css | 163 | 17.5 | 89.26% |
jquery.js | 89.6 | 28 | 68.75% |
bootstrap.min.js | 78.5 | 20 | 74.52% |
Total | 331.1 | 65.5 | 80.20% |
Tabel berikut ini memperlihatkan ukuran asli dan terkompresi menggunakan pustaka komponen UI Blazor Fasih:
File | Asli | Dikompresi | % Pengurangan |
---|---|---|---|
fluent.js | 384 | 73 | 80.99% |
fluent.css | 94 | 11 | 88.30% |
Total | 478 | 84 | 82.43% |
Untuk total 478 KB yang tidak dikompresi menjadi 84 KB dikompresi.
Tabel berikut ini memperlihatkan ukuran asli dan terkompresi menggunakan pustaka komponen LumpurBlazorBlazor:
File | Asli | Dikompresi | Pengurangan |
---|---|---|---|
LumpurBlazor.min.css | 541 | 37,5 | 93.07% |
BlazorLumpur.min.js | 47.4 | 9.2 | 80.59% |
Total | 588.4 | 46.7 | 92.07% |
Pengoptimalan terjadi secara otomatis saat menggunakan MapStaticAssets
. Saat pustaka ditambahkan atau diperbarui, misalnya dengan JavaScript atau CSS baru, aset dioptimalkan sebagai bagian dari build. Pengoptimalan sangat bermanfaat bagi lingkungan seluler yang dapat memiliki bandwidth yang lebih rendah atau koneksi yang tidak dapat diandalkan.
Untuk informasi selengkapnya tentang fitur pengiriman file baru, lihat sumber daya berikut ini:
Mengaktifkan kompresi dinamis di server vs menggunakan MapStaticAssets
MapStaticAssets
memiliki keuntungan berikut daripada kompresi dinamis di server:
- Lebih sederhana karena tidak ada konfigurasi spesifik server.
- Lebih berkinerja karena aset dikompresi pada waktu build.
- Memungkinkan pengembang untuk menghabiskan waktu tambahan selama proses build untuk memastikan bahwa aset adalah ukuran minimum.
Pertimbangkan tabel berikut membandingkan kompresi LumpurBlazor dengan kompresi dinamis IIS dan MapStaticAssets
:
IIS gzip | MapStaticAssets | Pengurangan MapStaticAssets |
---|---|---|
≅ 90 | 37,5 | 59% |
ASP0026: Penganalisis untuk memperingatkan ketika [Otorisasi] ditimpa oleh [AllowAnonymous] dari "lebih jauh"
Tampaknya intuitif bahwa atribut ditempatkan [Authorize]
"lebih dekat" ke tindakan MVC daripada [AllowAnonymous]
atribut akan mengambil alih [AllowAnonymous]
atribut dan memaksa otorisasi. Namun, ini belum tentu terjadi. Yang penting adalah urutan relatif atribut.
Kode berikut menunjukkan contoh di mana atribut yang lebih dekat [Authorize]
ditimpa oleh [AllowAnonymous]
atribut yang lebih jauh.
[AllowAnonymous]
public class MyController
{
[Authorize] // Overridden by the [AllowAnonymous] attribute on the class
public IActionResult Private() => null;
}
[AllowAnonymous]
public class MyControllerAnon : ControllerBase
{
}
[Authorize] // Overridden by the [AllowAnonymous] attribute on MyControllerAnon
public class MyControllerInherited : MyControllerAnon
{
}
public class MyControllerInherited2 : MyControllerAnon
{
[Authorize] // Overridden by the [AllowAnonymous] attribute on MyControllerAnon
public IActionResult Private() => null;
}
[AllowAnonymous]
[Authorize] // Overridden by the preceding [AllowAnonymous]
public class MyControllerMultiple : ControllerBase
{
}
Di .NET 9 Pratinjau 6, kami telah memperkenalkan penganalisis yang akan menyoroti instans seperti ini di mana atribut yang lebih dekat [Authorize]
ditimpa oleh [AllowAnonymous]
atribut yang lebih jauh dari tindakan MVC. Peringatan menunjuk ke atribut yang ditimpa [Authorize]
dengan pesan berikut:
ASP0026 [Authorize] overridden by [AllowAnonymous] from farther away
Tindakan yang benar untuk diambil jika Anda melihat peringatan ini tergantung pada niat di balik atribut. Atribut yang lebih [AllowAnonymous]
jauh harus dihapus jika tidak sengaja mengekspos titik akhir ke pengguna anonim. [AllowAnonymous]
Jika atribut dimaksudkan untuk mengambil alih atribut yang lebih dekat[Authorize]
, Anda dapat mengulangi [AllowAnonymous]
atribut setelah [Authorize]
atribut untuk mengklarifikasi niat.
[AllowAnonymous]
public class MyController
{
// This produces no warning because the second, "closer" [AllowAnonymous]
// clarifies that [Authorize] is intentionally overridden.
// Specifying AuthenticationSchemes can still be useful
// for endpoints that allow but don't require authenticated users.
[Authorize(AuthenticationSchemes = "Cookies")]
[AllowAnonymous]
public IActionResult Privacy() => null;
}
ASP.NET Core
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk