Novinky v ASP.NET Core 9.0
Tento článek popisuje nejvýznamnější změny v ASP.NET Core 9.0 s odkazy na příslušnou dokumentaci.
Optimalizace doručování statických aktiv
MapStaticAssets
Konvence koncového bodu směrování je nová funkce, která optimalizuje doručování statických prostředků v aplikacích ASP.NET Core.
Informace o doručování statických prostředků pro Blazor aplikace najdete v tématu ASP.NET Core Blazor statické soubory.
Dodržování osvědčených postupů v produkčním prostředí pro poskytování statických prostředků vyžaduje značné množství pracovních a technických odborných znalostí. Bez optimalizace, jako je komprese, ukládání do mezipaměti a otisky prstů:
- Prohlížeč musí při každém načtení stránky vyhovět dalším požadavkům.
- Více bajtů, než je potřeba, se přenáší přes síť.
- Někdy se klientům doručují zastaralé verze souborů.
Vytváření výkonných webových aplikací vyžaduje optimalizaci doručování assetů do prohlížeče. Mezi možné optimalizace patří:
- Nevydávejte daný prostředek více než jedinkrát, pokud se soubor nezmění nebo prohlížeč nevymaže jeho mezipaměť. Nastavte hlavičku ETag.
- Zabrání prohlížeči v používání starých nebo zastaralých souborů po aktualizaci aplikace. Nastavte hlavičku Last-Modified.
- Nastavte správné hlavičky ukládání do mezipaměti.
- Použijte middleware pro ukládání do mezipaměti.
- Pokud je to možné, poskytujte komprimované verze prostředků.
- Použijte CDN k poskytování prostředků blíže k uživateli.
- Minimalizujte velikost prostředků doručovaných do prohlížeče. Tato optimalizace nezahrnuje minifikace.
MapStaticAssets je nová funkce, která optimalizuje předávání statických prostředků v aplikaci. Je navržená tak, aby fungovala se všemi architekturami uživatelského rozhraní, včetně Blazor, Razor Pages a MVC. Obvykle se jedná o přímou náhradu za 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
funguje tak, že zkombinuje procesy sestavení a publikování a shromažďuje informace o všech statických prostředcích v aplikaci. Tyto informace pak knihovna modulu runtime využívá k efektivnímu poskytování těchto souborů do prohlížeče.
MapStaticAssets
může nahradit UseStaticFiles
ve většině situací, ale je optimalizovaná pro poskytování prostředků, o kterých má aplikace znalosti při sestavování a publikování. Pokud aplikace obsluhuje prostředky z jiných umístění, jako je disk nebo vložené prostředky, mělo by se použít UseStaticFiles
.
MapStaticAssets
poskytuje následující výhody, které nenabízí UseStaticFiles
:
- Komprese času sestavení pro všechny soubory v aplikaci.
-
gzip
během vývoje agzip + brotli
během publikování. - Všechny prostředky jsou komprimovány s cílem zmenšit velikost prostředků na minimum.
-
- Obsah založený
ETags
: ProEtags
každý prostředek jsou řetězec kódovaný kódem Base64 hodnoty hash SHA-256 obsahu. Tím se zajistí, že prohlížeč znovu načte soubor pouze v případě, že se změnil jeho obsah.
Následující tabulka ukazuje původní a komprimované velikosti CSS a JS souborů ve výchozí Pages šabloně:
Soubor | Původní | Komprimované | % redukce |
---|---|---|---|
bootstrap.min.css | 163 | 17.5 | 89.26% |
jquery.js | 89.6 | 28 | 68.75% |
bootstrap.min.js | 78,5 | 20 | 74.52% |
Celkem | 331.1 | 65.5 | 80.20% |
Následující tabulka uvádí původní a komprimované velikosti při použití knihovny komponent
Soubor | Původní | Komprimované | % redukce |
---|---|---|---|
fluent.js | 384 | 73 | 80.99% |
fluent.css | 94 | 11 | 88.30% |
Celkem | 478 | 84 | 82.43% |
Celkem činí 478 kB nekomprimovaných dat do 84 kB komprimovaných.
Následující tabulka uvádí původní a komprimované velikosti pomocí knihovny komponent MudBlazorBlazor :
Soubor | Původní | Komprimované | Redukce |
---|---|---|---|
MudBlazor.min.css | 541 | 37.5 | 93.07% |
MudBlazor.min.js | 47.4 | 9.2 | 80.59% |
Celkem | 588.4 | 46,7 | 92.07% |
Optimalizace probíhá automaticky při použití MapStaticAssets
. Při přidání nebo aktualizaci knihovny, například pomocí nového JavaScriptu nebo šablon stylů CSS, se prostředky optimalizují jako součást sestavení. Optimalizace je zvlášť přínosná pro mobilní prostředí, která můžou mít nižší šířku pásma nebo nespolehlivé připojení.
Další informace o nových funkcích doručování souborů najdete v následujících zdrojích informací:
Povolení dynamické komprese na serveru vs. použití MapStaticAssets
MapStaticAssets
má následující výhody oproti dynamické kompresi na serveru:
- Je jednodušší, protože neexistuje žádná konfigurace specifická pro server.
- Je výkonnější, protože soubory jsou komprimovány během sestavení.
- Umožňuje vývojáři strávit během procesu sestavení více času, aby se zajistilo, že prostředky mají minimální velikost.
Podívejte se na následující tabulku, která porovnává kompresi MudBlazor s dynamickou kompresí služby IIS a MapStaticAssets
:
IIS gzip | MapStaticAssets |
MapStaticAssets redukce |
---|---|---|
≅ 90 | 37.5 | 59% |
Blazor
Tato část popisuje nové funkce pro Blazor.
.NET MAUI Blazor Hybrid a šablona řešení webové aplikace
Nová šablona řešení usnadňuje vytváření .NET MAUI nativních a Blazor webových klientských aplikací, které sdílejí stejné uživatelské rozhraní. Tato šablona ukazuje, jak vytvářet klientské aplikace, které maximalizují opakované použití kódu a cílí na Android, iOS, Mac, Windows a Web.
Mezi klíčové funkce této šablony patří:
- Možnost zvolit Blazor interaktivní režim vykreslování pro webovou aplikaci
- Automatické vytváření příslušných projektů, včetně Blazor Web App (interaktivního automatického globálního vykreslování) a aplikace .NET MAUIBlazor Hybrid.
- Vytvořené projekty používají ke správě komponent uživatelského rozhraní Razor knihovnu sdílených Razor tříd (RCL).
- Součástí ukázkového kódu je ukázka použití injektáže závislostí k poskytování různých implementací rozhraní pro Blazor Hybrid aplikaci a aplikaci Blazor Web App.
Pokud chcete začít, nainstalujte sadu .NET 9 SDK a nainstalujte .NET MAUI úlohu, která obsahuje šablonu:
dotnet workload install maui
Pomocí následujícího příkazu vytvořte řešení ze šablony projektu v příkazovém prostředí:
dotnet new maui-blazor-web
Šablona je také k dispozici v sadě Visual Studio.
Poznámka:
V současné době dojde k výjimce, pokud Blazor jsou režimy vykreslování definovány na úrovni jednotlivých stránek nebo komponent. Další informace naleznete v tématu BlazorWebView potřebuje způsob, jak povolit přepsání funkce ResolveComponentForRenderMode (dotnet/aspnetcore
#51235).
Další informace naleznete v tématu Vytvoření .NET MAUIBlazor Hybrid aplikace pomocí .Blazor Web App
Zjišťování umístění vykreslování, interaktivity a přiřazeného režimu vykreslování za běhu
Zavedli jsme nové rozhraní API navržené tak, aby zjednodušilo proces dotazování stavů komponent za běhu. Toto rozhraní API poskytuje následující možnosti:
- Určete aktuální umístění spuštění komponenty: To může být užitečné pro ladění a optimalizaci výkonu komponent.
- Zkontrolujte, jestli je komponenta spuštěná v interaktivním prostředí: To může být užitečné pro komponenty, které mají různá chování na základě interaktivity jejich prostředí.
- Načtení přiřazeného režimu vykreslování pro komponentu: Pochopení režimu vykreslování může pomoct optimalizovat proces vykreslování a zlepšit celkový výkon komponenty.
Další informace najdete v tématu ASP.NET Core Blazor režimy vykreslování.
Vylepšené možnosti opětovného připojení na straně serveru:
Ve výchozím prostředí pro opětovné připojení na straně serveru jsme provedli následující vylepšení:
Když se uživatel vrátí do aplikace s odpojeným okruhem, pokusí se o opětovné připojení okamžitě, a nečeká na dobu trvání dalšího intervalu opětovného připojení. Tím se zlepší uživatelské prostředí při navigaci do aplikace na kartě prohlížeče, která přešla do režimu spánku.
Když pokus o opětovné připojení dorazí na server, ale server již uzavřel spojení, stránka se automaticky obnoví. Tím zabráníte uživateli v ruční aktualizaci stránky, pokud pravděpodobně dojde k úspěšnému opětovnému připojení.
Časování opětovného připojení využívá vypočítanou strategii zpětného odpojení. Ve výchozím nastavení se první několikanásobné pokusy o opětovné připojení uskutečňují v rychlém sledu bez intervalů mezi pokusy, než jsou zavedeny vypočítané prodlevy. Chování intervalu opakování můžete přizpůsobit zadáním funkce pro výpočet intervalu opakování, jak ukazuje následující příklad exponenciálního opakování:
Blazor.start({ circuit: { reconnectionOptions: { retryIntervalMilliseconds: (previousAttempts, maxRetries) => previousAttempts >= maxRetries ? null : previousAttempts * 1000 }, }, });
Styl výchozího uživatelského rozhraní pro opětovné připojení byl modernizován.
Další informace najdete v pokynech k ASP.NET CoreBlazorSignalR.
Zjednodušená serializace stavu ověřování pro Blazor Web Apps
Nová rozhraní API usnadňují přidávání ověřování do stávajícího systému/aplikace Blazor Web App. Když vytvoříte nový Blazor Web App s ověřováním pomocí jednotlivých účtů a povolíte interaktivitu založenou na WebAssembly, projekt zahrnuje vlastní AuthenticationStateProvider v serverových i klientských projektech.
Tito poskytovatelé přenášejí uživatelský stav ověření do prohlížeče. Ověřování na serveru místo klienta umožňuje aplikaci přístup ke stavu ověřování během předvykreslování a před inicializováním modulu runtime .NET WebAssembly.
Vlastní AuthenticationStateProvider implementace používají službu persistentního stavu komponenty (PersistentComponentState) k tomu, aby serializovaly ověřovací stav do HTML komentářů, a poté tuto informaci přečetly z WebAssembly pro vytvoření nové instance AuthenticationState.
To funguje dobře, pokud jste začali ze Blazor Web App šablony projektu a vybrali možnost Individuální Účty, ale pokud se pokoušíte přidat ověřování do existujícího projektu, je to mnoho kódu, který musíte sami implementovat nebo zkopírovat. Teď jsou k dispozici rozhraní API, která jsou teď součástí Blazor Web App šablony projektu, která se dají volat na serverových a klientských projektech a přidat tak tuto funkci:
- AddAuthenticationStateSerialization: Přidá potřebné služby pro serializaci stavu ověřování na serveru.
- AddAuthenticationStateDeserialization: Přidá nezbytné služby pro deserializaci stavu ověřování v prohlížeči.
Ve výchozím nastavení rozhraní API serializuje pouze jméno a deklarace rolí na straně serveru pro přístup v prohlížeči. Do AddAuthenticationStateSerialization může být předána možnost zahrnout všechny nároky.
Další informace najdete v následujících sekcích ASP.NET Core autentizace a autorizace:
Přidání stránek statického vykreslování na straně serveru (SSR) do globálně interaktivní Blazor Web App
S vydáním .NET 9 je teď jednodušší přidat statické stránky SSR do aplikací, které přijímají globální interaktivitu.
Tento přístup je užitečný jenom, když aplikace obsahuje konkrétní stránky, které nemůžou pracovat s interaktivním vykreslováním serveru nebo vykreslováním v WebAssembly. Použijte například tento přístup pro stránky, které jsou závislé na čtení a zápisu souborů cookie HTTP a můžou pracovat pouze v cyklu požadavků a odpovědí místo interaktivního vykreslování. U stránek, které pracují s interaktivním vykreslováním, byste je neměli vynutit, aby používaly statické vykreslování SSR, protože je pro koncového uživatele méně efektivní a méně responzivní.
Označte libovolnou Razor stránku komponenty s novým[ExcludeFromInteractiveRouting]
atributem přiřazeným direktivou@attribute
Razor:
@attribute [ExcludeFromInteractiveRouting]
Použití atributu způsobí, že navigace na stránku se ukončí z interaktivního směrování. Příchozí navigace je přinucena znovu načíst celou stránku, místo aby byla vyřešena prostřednictvím interaktivního směrování. Opětovné načtení celé stránky vynutí načtení kořenové komponenty nejvyšší úrovně, obvykle komponenty (App
), aby se znovu vykreslila ze serveru, což aplikaci umožňuje přepnout do jiného režimu vykreslování nejvyšší úrovně.
Metoda RazorComponentsEndpointHttpContextExtensions.AcceptsInteractiveRouting rozšíření umožňuje komponentě zjistit, zda [ExcludeFromInteractiveRouting]
je atribut použit na aktuální stránce.
V komponentě App
použijte vzor v následujícím příkladu:
- Stránky, které nejsou opatřeny poznámkami s atributem
[ExcludeFromInteractiveRouting]
, ve výchozím nastavení používají režim vykresleníInteractiveServer
s globální interaktivitou. Můžete nahraditInteractiveServer
symbolemInteractiveWebAssembly
neboInteractiveAuto
, abyste určili jiný výchozí globální režim vykreslování. - Stránky anotované atributem
[ExcludeFromInteractiveRouting]
přijímají statické SSR (PageRenderMode
je přiřazenonull
).
<!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;
}
Alternativou k použití RazorComponentsEndpointHttpContextExtensions.AcceptsInteractiveRouting metody rozšíření je ruční čtení metadat koncového bodu pomocí HttpContext.GetEndpoint()?.Metadata
.
Tato funkce je popsána v referenční dokumentaci v
Injektáž konstruktoru
Razor komponenty podporují injektáž konstruktoru.
V následujícím příkladu částečná třída (za kódem) vloží NavigationManager
službu pomocí primárního konstruktoru:
public partial class ConstructorInjection(NavigationManager navigation)
{
private void HandleClick()
{
navigation.NavigateTo("/counter");
}
}
Další informace najdete v tématu Injektáž závislostí v ASP.NET CoreBlazor.
Komprese protokolu Websocket pro komponenty interaktivního serveru
Komponenty interaktivního serveru ve výchozím nastavení umožňují kompresi pro připojení WebSocket a nastavují direktivu Content Security Policy (CSP)'self'
, která povoluje pouze vkládání aplikace na počátek původu, ze kterého je aplikace obsluhována, a to pouze při povolení komprese nebo při poskytování konfigurace kontextu WebSocket.
Kompresi je možné zakázat nastavením ConfigureWebSocketOptions
na null
, což snižuje zranitelnost aplikace vůči útokům, ale může vést ke snížení výkonu:
.AddInteractiveServerRenderMode(o => o.ConfigureWebSocketOptions = null)
Nakonfigurujte přísnější frame-ancestors
CSP s hodnotou 'none'
(vyžaduje se jednoduché uvozovky), která umožňuje kompresi Protokolu WebSocket, ale brání prohlížečům v vložení aplikace do libovolné <iframe>
:
.AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")
Další informace naleznete v následujících zdrojích:
- Pokyny pro ASP.NET Core BlazorSignalR
- Pokyny ke zmírnění hrozeb pro interaktivní vykreslování na straně serveru ASP.NET Core Blazor
Zpracovat události zadávání z klávesnice v Blazor
Nová KeyboardEventArgs.IsComposing
vlastnost označuje, jestli je událost klávesnice součástí kompozičního procesu. Sledování stavu složení událostí klávesnice je zásadní pro zpracování mezinárodních metod zadávání znaků.
Přidání parametru OverscanCount
do QuickGrid
Komponenta QuickGrid
nyní zveřejňuje OverscanCount
vlastnost, která určuje, kolik dalších řádků se vykresluje před a za viditelnou oblastí, když je povolená virtualizace.
Výchozí hodnota OverscanCount
je 3. Následující příklad zvýší OverscanCount
na 4:
<QuickGrid ItemsProvider="itemsProvider" Virtualize="true" OverscanCount="4">
...
</QuickGrid>
InputNumber
komponenta type="range"
podporuje atribut
Komponenta InputNumber<TValue> nyní podporuje atribut type="range"
, který vytváří rozsahový vstup s podporou vazby modelu a ověřování formulářů, běžně se zobrazuje jako posuvník nebo číselník místo textového pole:
<EditForm Model="Model" OnSubmit="Submit" FormName="EngineForm">
<div>
<label>
Nacelle Count (2-6):
<InputNumber @bind-Value="Model!.NacelleCount" max="6" min="2"
step="1" type="range" />
</label>
</div>
<div>
<button type="submit">Submit</button>
</div>
</EditForm>
@code {
[SupplyParameterFromForm]
private EngineSpecifications? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
private void Submit() {}
public class EngineSpecifications
{
[Required, Range(minimum: 2, maximum: 6)]
public int NacelleCount { get; set; }
}
}
Nové vylepšené navigační události
Spuštění JavaScript callbacků buď před nebo po vylepšené navigaci pomocí nových posluchačů událostí:
blazor.addEventListener("enhancednavigationstart", {CALLBACK})
blazor.addEventListener("enhancednavigationend", {CALLBACK})
Další informace najdete v tématu ASP.NET Core Blazor JavaScript s vykreslováním na serveru (statické SSR).
Streamování požadavků na straně klienta
Interaktivní vykreslování WebAssembly v Blazor nyní podporuje streamování požadavků na straně klienta pomocí volby request.SetBrowserReqeustStreamingEnabled(true)
na HttpRequestMessage
.
Další informace naleznete v následujících zdrojích:
SignalR
Tato část popisuje nové funkce pro SignalR.
Podpora polymorfních typů v SignalR Hubs
Metody Hub teď mohou přijímat základní třídu místo odvozené třídy pro umožnění polymorfních scénářů. Základní typ musí být opatřen poznámkami, aby bylo možné polymorfismus.
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; }
}
Vylepšené aktivity pro SignalR
SignalR teď má Zdroj aktivit pro centrální server i klienta.
Zdroj aktivit serveru .NET SignalR
SignalR ActivitySource s názvem Microsoft.AspNetCore.SignalR.Server
generuje události pro volání metod rozhraní:
- Každá metoda je vlastní aktivita, takže vše, co generuje aktivitu během volání metody centra, je pod aktivitou metody centra.
- Aktivity metody typu hub nemají nadřazený prvek. To znamená, že nejsou součástí dlouhotrvajícího SignalR připojení.
Následující příklad používá .NET Aspire řídicí panel a balíčky 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" />
Do Program.cs
souboru přidejte následující spouštěcí kód:
using OpenTelemetry.Trace;
using SignalRChat.Hubs;
// 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())
{
// View all traces only in development environment.
tracing.SetSampler(new AlwaysOnSampler());
}
tracing.AddAspNetCoreInstrumentation();
tracing.AddSource("Microsoft.AspNetCore.SignalR.Server");
});
builder.Services.ConfigureOpenTelemetryTracerProvider(tracing => tracing.AddOtlpExporter());
var app = builder.Build();
Následuje příklad výstupu z řídicího panelu Aspire:
Zdroj aktivit klienta .NET SignalR
SignalR ActivitySource s názvem Microsoft.AspNetCore.SignalR.Client
generuje události pro klienta SignalR:
- Klient .NET SignalR má
ActivitySource
s názvemMicrosoft.AspNetCore.SignalR.Client
. Vyvolání hubu teď vytvoří klientský úsek. Upozorňujeme, že ostatní klienti SignalR, jako je klient JavaScript, nepodporují trasování. Tato funkce se přidá do dalších klientů v budoucích verzích. - Volání hubu na straně klienta a serveru podporují šíření kontextu. Šíření kontextu trasování umožňuje skutečné distribuované trasování. Teď je možné vidět tok vyvolání z klienta na server a zpět.
Takhle vypadají tyto nové aktivity v řídicím panelu .NET Aspire:
SignalR podporuje ořezávání a Native AOT.
Pokračováním v cestě nativní AOT, která začala v .NET 8, jsme povolili ořezávání a podporu nativní kompilace AOT pro scénáře jak na straně klienta, tak serveru. Nyní můžete využít výhody výkonu při použití nativní AOT v aplikacích, které používají SignalR pro webovou komunikaci v reálném čase.
Začínáme
Nainstalujte nejnovější .NET 9 SDK.
Pomocí následujícího příkazu vytvořte řešení ze webapiaot
šablony v příkazovém prostředí:
dotnet new webapiaot -o SignalRChatAOTExample
Program.cs
Obsah souboru nahraďte následujícím SignalR kódem:
using Microsoft.AspNetCore.SignalR;
using System.Text.Json.Serialization;
var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.AddSignalR();
builder.Services.Configure<JsonHubProtocolOptions>(o =>
{
o.PayloadSerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});
var app = builder.Build();
app.MapHub<ChatHub>("/chatHub");
app.MapGet("/", () => Results.Content("""
<!DOCTYPE html>
<html>
<head>
<title>SignalR Chat</title>
</head>
<body>
<input id="userInput" placeholder="Enter your name" />
<input id="messageInput" placeholder="Type a message" />
<button onclick="sendMessage()">Send</button>
<ul id="messages"></ul>
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/8.0.7/signalr.min.js"></script>
<script>
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chatHub")
.build();
connection.on("ReceiveMessage", (user, message) => {
const li = document.createElement("li");
li.textContent = `${user}: ${message}`;
document.getElementById("messages").appendChild(li);
});
async function sendMessage() {
const user = document.getElementById("userInput").value;
const message = document.getElementById("messageInput").value;
await connection.invoke("SendMessage", user, message);
}
connection.start().catch(err => console.error(err));
</script>
</body>
</html>
""", "text/html"));
app.Run();
[JsonSerializable(typeof(string))]
internal partial class AppJsonSerializerContext : JsonSerializerContext { }
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
Předchozí příklad vytvoří nativní spustitelný soubor Windows 10 MB a spustitelný soubor Linuxu o velikosti 10,9 MB.
Omezení
- V současné době se podporuje jenom protokol JSON:
- Jak je znázorněno v předchozím kódu, aplikace, které používají serializaci JSON a nativní AOT, musí používat
System.Text.Json
generátor zdrojů. - To se řídí stejným přístupem jako minimální rozhraní API.
- Jak je znázorněno v předchozím kódu, aplikace, které používají serializaci JSON a nativní AOT, musí používat
- Na serveru SignalR nejsou podporovány parametry metody Hub typu
IAsyncEnumerable<T>
aChannelReader<T>
, kdeT
je typ hodnoty (struct
). Použití těchto typů vede k výjimce za běhu při spuštění během vývoje a v publikované aplikaci. Další informace naleznete v tématu SignalR: Použití IAsyncEnumerable<T> a ChannelReader<T> s ValueTypes v nativním AOT (dotnet/aspnetcore
#56179). -
Silně typované huby nejsou podporovány s Native AOT (
PublishAot
). Použití center se silným typováním s nativním AOT způsobí upozornění během sestavování a publikování a výjimku za běhu programu. Použití silně typovaných rozhraní s ořezáváním (PublishedTrimmed
) je podporováno. - Pouze
Task
, ,Task<T>
ValueTask
neboValueTask<T>
jsou podporovány pro asynchronní návratové typy.
Minimální rozhraní API
Tato část popisuje nové funkce pro minimální rozhraní API.
Přidáno InternalServerError
a InternalServerError<TValue>
do TypedResults
Třída TypedResults je užitečným nástrojem pro vracení odpovědí založených na stavových kódech HTTP se silným typováním z minimálního API.
TypedResults
nyní obsahuje tovární metody a typy pro zpracování odpovědí "500 Internal Server Error" z koncových bodů. Tady je příklad, který vrátí odpověď 500:
var app = WebApplication.Create();
app.MapGet("/", () => TypedResults.InternalServerError("Something went wrong!"));
app.Run();
Zavolejte ProducesProblem
a ProducesValidationProblem
na skupinách tras
Tyto metody rozšíření ProducesProblem
a ProducesValidationProblem
byly aktualizovány kvůli podpoře jejich použití na skupinách tras. Tyto metody označují, že všechny koncové body ve skupině tras mohou vracet ProblemDetails
nebo ValidationProblemDetails
odpovědi pro účely metadat OpenAPI.
var app = WebApplication.Create();
var todos = app.MapGroup("/todos")
.ProducesProblem();
todos.MapGet("/", () => new Todo(1, "Create sample app", false));
todos.MapPost("/", (Todo todo) => Results.Ok(todo));
app.Run();
record Todo(int Id, string Title, boolean IsCompleted);
Problem
a ValidationProblem
typy výsledků podporují vytváření s IEnumerable<KeyValuePair<string, object?>>
hodnotami
Před verzí .NET 9 vyžadovalo vytvoření Problem a ValidationProblem jako typů výsledků v minimálních API, aby byly vlastnosti errors
a extensions
inicializovány implementací IDictionary<string, object?>
. V této verzi tato rozhraní API pro vytváření podporují přetížení, která spotřebovávají IEnumerable<KeyValuePair<string, object?>>
.
var app = WebApplication.Create();
app.MapGet("/", () =>
{
var extensions = new List<KeyValuePair<string, object?>> { new("test", "value") };
return TypedResults.Problem("This is an error with extensions",
extensions: extensions);
});
Díky uživateli GitHubu joegoldman2 za tento příspěvek!
OpenAPI
Tato část popisuje nové funkce pro OpenAPI.
Integrovaná podpora generování dokumentů OpenAPI
Specifikace OpenAPI je standard pro popis rozhraní HTTP API. Standard umožňuje vývojářům definovat tvar rozhraní API, která se dají připojit k generátorům klientů, generátorům serverů, testovacím nástrojům, dokumentaci a dalším funkcím. V .NET 9 poskytuje ASP.NET Core integrovanou podporu pro generování dokumentů OpenAPI představujících rozhraní API založená na kontroleru nebo minimální rozhraní API prostřednictvím balíčku Microsoft.AspNetCore.OpenApi .
Následující zvýrazněný kód volá:
-
AddOpenApi
a zaregistrujte požadované závislosti do kontejneru DI aplikace. -
MapOpenApi
pro zaregistrování požadovaných koncových bodů OpenAPI v trasách aplikace.
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
Nainstalujte balíček do projektu pomocí následujícího příkazu:
dotnet add package Microsoft.AspNetCore.OpenApi
Spusťte aplikaci a přejděte na openapi/v1.json
pro zobrazení vygenerovaného dokumentu OpenAPI.
Dokumenty OpenAPI lze také vygenerovat v době sestavení přidáním Microsoft.Extensions.ApiDescription.Server
balíčku:
dotnet add package Microsoft.Extensions.ApiDescription.Server
Pokud chcete upravit umístění vygenerovaných dokumentů OpenAPI, nastavte cílovou cestu ve vlastnosti OpenApiDocumentsDirectory v souboru projektu aplikace:
<PropertyGroup>
<OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)</OpenApiDocumentsDirectory>
</PropertyGroup>
Spusťte a zkontrolujte dotnet build
vygenerovaný soubor JSON v adresáři projektu.
Vestavěné generování dokumentů OpenAPI v ASP.NET Core poskytuje podporu pro různá přizpůsobení a možnosti. Poskytuje transformátory dokumentů, operací a schémat a umožňuje spravovat více dokumentů OpenAPI pro stejnou aplikaci.
Další informace o nových funkcích dokumentů OpenAPI pro ASP.NET Core najdete v nových dokumentech Microsoft.AspNetCore.OpenApi.
Microsoft.AspNetCore.OpenApi podporuje optimalizaci a nativní AOT.
OpenAPI na platformě ASP.NET Core podporuje trimming a nativní AOT. Následující postup vytvoří a publikuje aplikaci OpenAPI s ořezáváním a nativním AOT.
Vytvořte nový projekt webového rozhraní API ASP.NET Core (nativní AOT).
dotnet new webapiaot
Přidejte balíček Microsoft.AspNetCore.OpenAPI.
dotnet add package Microsoft.AspNetCore.OpenApi
Aktualizujte Program.cs
, aby bylo možné generovat dokumenty OpenAPI.
+ builder.Services.AddOpenApi();
var app = builder.Build();
+ app.MapOpenApi();
Publikuj aplikaci.
dotnet publish
Ověřování a autorizace
Tato část popisuje nové funkce pro ověřování a autorizaci.
OpenIdConnectHandler přidává podporu pro nabízené žádosti o autorizaci (PAR)
Chtěli bychom poděkovat Joeu DeCockovi ze společnosti Duende Software za přidání nabízených žádostí o autorizaci (PAR) do ASP.NET Core OpenIdConnectHandler. Joe popsal pozadí a motivaci pro povolení PAR v návrhu rozhraní API následujícím způsobem:
Pushed Authorization Requests (PAR) je relativně nový standard OAuth, který zlepšuje zabezpečení toků OAuth a OIDC přesunutím parametrů autorizace z předního kanálu do zadního kanálu. To znamená přesunout parametry autorizace z přesměrování URL adres v prohlížeči do přímých strojových HTTP volání na pozadí.
Tím zabráníte cyberattackeru v prohlížeči z následujících možností:
- Zobrazují se parametry autorizace, které by mohly uniknout osobní údaje.
- Manipulace s těmito parametry. Například cyberattacker může změnit rozsah požadovaného přístupu.
Odesláním ověřovacích parametrů se také zachovají krátké adresy URL požadavků. Při použití složitějších funkcí OAuth a OIDC, jako je bohatý autorizační požadavek, mohou být parametry autorizace velmi dlouhé. Adresy URL, které jsou dlouhé příčiny problémů v mnoha prohlížečích a síťových infrastrukturách.
Použití funkce PAR doporučuje pracovní skupina FAPI v rámci Nadace OpenID. Například profil zabezpečení FAPI2.0 vyžaduje použití funkce PAR. Tento profil zabezpečení používá řada skupin pracujících na otevřeném bankovnictví (především v Evropě), zdravotní péči a v jiných odvětvích s vysokými požadavky na zabezpečení.
PAR je podporováno řadou poskytovatelů identity, včetně
Pro .NET 9 jsme se rozhodli, že ve výchozím nastavení povolíme PAR, pokud dokument identifikace poskytovatele inzeruje podporu PAR, protože poskytuje zvýšené zabezpečení pro poskytovatele, kteří jej podporují. Dokument pro zjišťování identity poskytovatele se obvykle nachází v .well-known/openid-configuration
. Pokud to způsobí problémy, můžete PAR zakázat prostřednictvím OpenIdConnectOptions.PushedAuthorizationBehavior následujícím způsobem:
builder.Services
.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect("oidc", oidcOptions =>
{
// Other provider-specific configuration goes here.
// The default value is PushedAuthorizationBehavior.UseIfAvailable.
// 'OpenIdConnectOptions' does not contain a definition for 'PushedAuthorizationBehavior'
// and no accessible extension method 'PushedAuthorizationBehavior' accepting a first argument
// of type 'OpenIdConnectOptions' could be found
oidcOptions.PushedAuthorizationBehavior = PushedAuthorizationBehavior.Disable;
});
Pokud chcete zajistit, aby ověřování proběhlo úspěšně jenom v případě použití funkce PAR, použijte místo toho PushedAuthorizationBehavior.Require. Tato změna také zavádí novou událost OnPushAuthorization pro OpenIdConnectEvents , která se dá použít k přizpůsobení žádosti o nabízenou autorizaci nebo k jeho ručnímu zpracování. Další podrobnosti najdete v návrhu rozhraní API.
Přizpůsobení parametrů OIDC a OAuth
Obslužné rutiny ověřování OAuth a OIDC nyní nabízejí AdditionalAuthorizationParameters
možnost, která usnadňuje přizpůsobení parametrů autorizační zprávy, jež jsou obvykle součástí řetězce dotazu při přesměrování. V .NET 8 a starších verzích to vyžaduje vlastní OnRedirectToIdentityProvider zpětnou volbu nebo přepsanou BuildChallengeUrl metodu ve vlastní obslužné rutině. Tady je příklad kódu .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;
};
});
Předchozí příklad je teď možné zjednodušit následujícím kódem:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.AdditionalAuthorizationParameters.Add("prompt", "login");
options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});
Konfigurace HTTP.sys rozšířených příznaků ověřování
Teď můžete nakonfigurovat příznaky HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING
a HTTP_AUTH_EX_FLAG_CAPTURE_CREDENTIAL
na HTTP.sys pomocí nových vlastností EnableKerberosCredentialCaching
a CaptureCredentials
v AuthenticationManager HTTP.sys, aby se optimalizovalo, jak je ověřování systému Windows zpracováváno. Příklad:
webBuilder.UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.Negotiate;
options.Authentication.EnableKerberosCredentialCaching = true;
options.Authentication.CaptureCredentials = true;
});
Různé
Následující části popisují různé nové funkce.
Nová HybridCache
knihovna
Důležité
HybridCache
v současné době je stále ve verzi Preview, ale bude plně vydána po .NET 9.0 v budoucí dílčí verzi rozšíření .NET.
Rozhraní HybridCache
API překlenuje některé mezery v existujících rozhraních IDistributedCache a IMemoryCache API. Přidává také nové funkce, například:
- Ochrana před "Stampede" pro zamezení paralelního načítání stejné úlohy.
- Konfigurovatelná serializace
HybridCache
je navržen tak, aby byl náhradou bez potřeby úprav stávajícího použití IDistributedCache
a IMemoryCache
, a poskytuje jednoduché rozhraní API pro přidání nového kódu pro ukládání do mezipaměti. Poskytuje jednotné rozhraní API pro ukládání do mezipaměti v procesu i mimo proces.
Pokud chcete zjistit, jak HybridCache
je rozhraní API zjednodušené, porovnejte ho s kódem, který používá IDistributedCache
. Tady je příklad, jak vypadá použití 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)
{ /* ... */ }
}
To je hodně práce, aby se všechno udělalo správně pokaždé, včetně věcí, jako je serializace. A ve scénáři cache miss můžete skončit s několika souběžnými vlákny, všechna mají cache miss, všechna načítají podkladová data, všechna je serializují a odesílají do mezipaměti.
Abychom tento kód HybridCache
zjednodušili a vylepšili, musíme nejprve přidat novou knihovnu Microsoft.Extensions.Caching.Hybrid
:
<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="9.0.0" />
HybridCache
Zaregistrujte službu, jako byste zaregistrovali implementaciIDistributedCache
:
builder.Services.AddHybridCache(); // Not shown: optional configuration API.
Teď je možné většinu problémů s ukládáním do mezipaměti přesměrovat na 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
);
}
}
Poskytujeme konkrétní implementaci HybridCache
abstraktní třídy prostřednictvím injektáže závislostí, ale je zamýšleno, aby vývojáři mohli poskytovat vlastní implementace rozhraní API. Implementace HybridCache
se zabývá vším, co souvisí s ukládáním do mezipaměti, včetně zpracování souběžných operací. Token cancel
zde představuje kombinované zrušení všech souběžných volajících – nejen zrušení volajícího, kterého vidíme (to znamená, token
).
Scénáře s vysokou propustností je možné dále optimalizovat pomocí TState
modelu, aby nedocházelo k určitým režijním nákladům na zachycené proměnné a zpětná volání jednotlivých instancí:
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
používá nakonfigurovanou IDistributedCache
implementaci ( pokud existuje) pro sekundární mezipaměť mimo proces, například pomocí Redis. Ale i bez IDistributedCache
bude služba HybridCache
i nadále poskytovat meziprocesovou mezipaměť a ochranu proti přetížení.
Poznámka k opakovanému použití objektu
V typickém existujícím kódu, který používá IDistributedCache
, každé načtení objektu z mezipaměti má za následek deserializaci. Toto chování znamená, že každý souběžný volající získá samostatnou instanci objektu, která nemůže komunikovat s jinými instancemi. Výsledkem je bezpečnost vláken, protože neexistuje riziko souběžných úprav stejné instance objektu.
Vzhledem k tomu, že se hodně HybridCache
využití přizpůsobí existujícímu IDistributedCache
kódu, HybridCache
ve výchozím nastavení zachovává toto chování, aby nedocházelo k chybám souběžnosti. Daný případ použití je však ze své podstaty bezpečný pro přístup z více vláken:
- Pokud jsou typy uložené v mezipaměti neměnné.
- Pokud je kód neupraví.
V takových případech informujte HybridCache
, že je bezpečné opakovaně používat instance pomocí:
- Označení typu jako
sealed
. Klíčovésealed
slovo v jazyce C# znamená, že třídu nelze dědit. - Použití atributu
[ImmutableObject(true)]
na něj Atribut[ImmutableObject(true)]
označuje, že stav objektu nelze po vytvoření změnit.
Opětovným použitím instancí může HybridCache
snížit režii související s alokacemi procesoru a objektů při deserializaci po jednotlivých voláních. To může vést ke zlepšení výkonu ve scénářích, kdy jsou objekty uložené v mezipaměti velké nebo často přístupné.
Další HybridCache
funkce
Podobně jako IDistributedCache
podporuje HybridCache
odebrání pomocí klíče pomocí RemoveKeyAsync
metody.
HybridCache
také poskytuje volitelná API pro IDistributedCache
implementace, aby se zabránilo přidělení byte[]
. Tuto funkci implementují předběžné verze balíčků Microsoft.Extensions.Caching.StackExchangeRedis
a Microsoft.Extensions.Caching.SqlServer
.
Serializace se konfiguruje jako součást procesu registrace služby, s podporou jak typově specifických, tak generalizovaných serializátorů prostřednictvím metod WithSerializer
a metod .WithSerializerFactory
, které jsou zřetězené z volání AddHybridCache
. Ve výchozím nastavení knihovna zpracovává string
a byte[]
interně a System.Text.Json
používá pro všechno ostatní, ale můžete použít Protobuf, XML nebo cokoli jiného.
HybridCache
podporuje starší runtime .NET, až do .NET Framework 4.7.2 a .NET Standard 2.0.
Pro více informací o HybridCache
viz knihovna HybridCache v ASP.NET Core
Vylepšení stránky výjimek pro vývojáře
Stránka výjimky pro vývojáře ASP.NET Core se zobrazí, když aplikace během vývoje vyvolá neošetřenou výjimku. Stránka výjimky vývojáře obsahuje podrobné informace o výjimce a požadavku.
Verze Preview 3 přidala na stránku pro správu výjimek metadata koncového bodu. ASP.NET Core používá metadata koncového bodu k řízení chování koncových bodů, jako je směrování, ukládání odpovědí do mezipaměti, omezování rychlosti, generování OpenAPI a další. Následující obrázek znázorňuje nové informace o metadatech v Routing
části stránky výjimky vývojáře:
Při testování stránky výjimek pro vývojáře byly identifikovány malé vylepšení kvality života. Odeslali je ve verzi Preview 4:
- Lepší obtékání textu. Dlouhé soubory cookie, hodnoty řetězce dotazu a názvy metod už nepřidávají vodorovné posuvníky ve webovém prohlížeči.
- Větší text, který se nachází v moderních návrzích.
- Konzistentnější velikosti tabulek
Následující animovaný obrázek znázorňuje novou stránku výjimky vývojáře:
Vylepšení ladění slovníku
Zobrazení ladění slovníků a dalších kolekcí klíč-hodnota má vylepšené rozložení. Klíč se místo zřetězení s hodnotou zobrazí ve sloupci klíče ladicího programu. Následující obrázky ukazují staré a nové zobrazení slovníku v ladicím programu.
Před:
Po:
ASP.NET Core obsahuje mnoho kolekcí klíč-hodnota. Toto vylepšené možnosti ladění platí pro:
- Záhlaví HTTP
- Řetězce dotazů
- Formuláře
- Soubory cookie
- Zobrazit data
- Směrování dat
- Funkce
Oprava chyby 503 při recyklaci aplikace v IIS
Ve výchozím nastavení je nyní mezi okamžikem, kdy je služba IIS informována o recyklaci nebo vypnutí, a okamžikem, kdy služba ANCM oznámí spravovanému serveru, že má zahájit vypínání, 1sekundové zpoždění. Zpoždění je možné konfigurovat prostřednictvím proměnné prostředí ANCM_shutdownDelay
nebo nastavením obslužné rutiny shutdownDelay
. Obě hodnoty jsou v milisekundách. Zpoždění spočívá hlavně ve snížení pravděpodobnosti závodu, kdy:
- Služba IIS nezačala řadit požadavky do fronty pro přechod do nové aplikace.
- ANCM začne odmítat nové požadavky, které přicházejí do staré aplikace.
Pomalejší počítače nebo počítače s těžším využitím procesoru můžou chtít tuto hodnotu upravit, aby se snížila pravděpodobnost 503.
Příklad nastavení 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>
Oprava je v globálně nainstalovaném modulu ANCM, který pochází z hostitelské sady.
ASP0026: Analyzátor, který upozorní, když je [Authorize] přepsán uživatelem [AllowAnonymous] z "daleko"
Zdá se intuitivní, že atribut [Authorize]
, umístěný "blíž" k akci MVC než atribut [AllowAnonymous]
, by přepsalo atribut [AllowAnonymous]
a vynucovalo autorizaci. To ale nemusí být nutně případ. Záleží na relativním pořadí atributů.
Následující kód ukazuje příklady, kde atribut blíže [Authorize]
se přepíše atributem [AllowAnonymous]
, který je vzdálenější.
[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
{
}
V .NET 9 Preview 6 jsme představili analyzátor, který zvýrazní případy, jako jsou ty, kdy je blízký atribut [Authorize]
přepsán atributem [AllowAnonymous]
, který je dále od akce MVC. Upozornění odkazuje na přepsaný [Authorize]
atribut s následující zprávou:
ASP0026 [Authorize] overridden by [AllowAnonymous] from farther away
Správná akce, která se má provést, pokud se zobrazí toto upozornění, závisí na záměru atributů. Pokud se koncový bod nechtěně vystavuje anonymním uživatelům, měl by být atribut odsud [AllowAnonymous]
odebrán. Pokud byl atribut [AllowAnonymous]
určen k přepsání bližšího atributu [Authorize]
, můžete atribut [AllowAnonymous]
opakovat za atributem [Authorize]
pro objasnění záměru.
[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;
}
Vylepšené Kestrel metriky připojení
Výrazně jsme vylepšili Kestrelmetriky připojení zahrnutím metadat o tom, proč připojení selhalo. Metrika kestrel.connection.duration
teď obsahuje důvod uzavření připojení v atributu error.type
.
Tady je malý vzorek error.type
hodnot:
-
tls_handshake_failed
– Připojení vyžaduje protokol TLS a metoda handshake protokolu TLS se nezdařila. -
connection_reset
– Během probíhajících požadavků klient připojení neočekávaně zavřel. -
request_headers_timeout
– Kestrel uzavřelo připojení, protože neobdrželo hlavičky žádostí včas. -
max_request_body_size_exceeded
- Kestrel zavřel připojení, protože nahraná data překročila maximální velikost.
Kestrel Diagnostika problémů s připojením dříve vyžadovala, aby server zaznamenával podrobné protokolování nízké úrovně. Generování a ukládání protokolů ale může být nákladné a může být obtížné najít správné informace mezi šumem.
V produkčním prostředí mohou zůstat metriky jako mnohem levnější alternativa s minimálním dopadem. Shromážděné metriky můžou řídit řídicí panely a výstrahy. Jakmile je problém identifikován na vysoké úrovni s metrikami, může začít další šetření pomocí protokolování a dalších nástrojů.
Očekáváme, že lepší metriky připojení budou užitečné v mnoha scénářích:
- Zkoumání problémů s výkonem způsobených krátkou životností připojení
- Sledujeme probíhající externí útoky na Kestrel, které ovlivňují výkon a stabilitu.
- Zaznamenávání pokusů o externí útoky na Kestrel, které integrované posílení zabezpečení Kestrel zabránilo.
Další informace najdete v tématu ASP.NET základní metriky.
Přizpůsobení Kestrel koncových bodů pojmenovaného kanálu
KestrelPodpora pojmenovaných kanálů byla vylepšena pomocí pokročilých možností přizpůsobení. Nová CreateNamedPipeServerStream
metoda v možnostech pojmenovaného kanálu umožňuje přizpůsobit kanály pro každý koncový bod.
Příkladem, kde je to užitečné, je Kestrel aplikace, která vyžaduje dva koncové body kanálu s odlišným zabezpečením přístupu. Možnost CreateNamedPipeServerStream
lze použít k vytváření kanálů s vlastním nastavením zabezpečení v závislosti na názvu kanálu.
var builder = WebApplication.CreateBuilder();
builder.WebHost.ConfigureKestrel(options =>
{
options.ListenNamedPipe("pipe1");
options.ListenNamedPipe("pipe2");
});
builder.WebHost.UseNamedPipes(options =>
{
options.CreateNamedPipeServerStream = (context) =>
{
var pipeSecurity = CreatePipeSecurity(context.NamedPipeEndpoint.PipeName);
return NamedPipeServerStreamAcl.Create(context.NamedPipeEndPoint.PipeName, PipeDirection.InOut,
NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte,
context.PipeOptions, inBufferSize: 0, outBufferSize: 0, pipeSecurity);
};
});
ExceptionHandlerMiddleware
možnost zvolit stavový kód na základě typu výjimky
Nová možnost při konfiguraci ExceptionHandlerMiddleware
aplikací umožňuje vývojářům aplikací zvolit, jaký stavový kód se má vrátit, když během zpracování žádosti dojde k výjimce. Nová možnost změní stavový kód, který je nastaven v ProblemDetails
odpovědi z ExceptionHandlerMiddleware
.
app.UseExceptionHandler(new ExceptionHandlerOptions
{
StatusCodeSelector = ex => ex is TimeoutException
? StatusCodes.Status503ServiceUnavailable
: StatusCodes.Status500InternalServerError,
});
Odhlášení z metrik HTTP u určitých koncových bodů a požadavků
.NET 9 zavádí možnost vyjádřit výslovný nesouhlas s metrikami HTTP pro konkrétní koncové body a požadavky. Odhlášení z zaznamenávání metrik je výhodné pro koncové body často volané automatizovanými systémy, jako jsou kontroly stavu. Zaznamenávání metrik pro tyto požadavky je obecně zbytečné.
Požadavky HTTP na koncový bod je možné vyloučit z metrik přidáním metadat. Buď:
-
[DisableHttpMetrics]
Přidejte atribut do kontroleru webového rozhraní API, SignalR centra nebo služby gRPC. - Při spuštění aplikace zavolejte DisableHttpMetrics při mapování koncových bodů.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHealthChecks();
var app = builder.Build();
app.MapHealthChecks("/healthz").DisableHttpMetrics();
app.Run();
Vlastnost MetricsDisabled
byla přidána pro IHttpMetricsTagsFeature
:
- Pokročilé situace, kdy požadavek neodpovídá žádnému koncovému bodu.
- Dynamické zakazování shromažďování metrik pro konkrétní požadavky HTTP
// Middleware that conditionally opts-out HTTP requests.
app.Use(async (context, next) =>
{
var metricsFeature = context.Features.Get<IHttpMetricsTagsFeature>();
if (metricsFeature != null &&
context.Request.Headers.ContainsKey("x-disable-metrics"))
{
metricsFeature.MetricsDisabled = true;
}
await next(context);
});
Podpora ochrany dat pro odstranění klíčů
Před rozhraním .NET 9 nebyly klíče ochrany dat záměrně smazatelné, aby se zabránilo ztrátě dat. Odstranění klíče způsobí, že chráněná data budou navždy nedostupná. Vzhledem k jejich malé velikosti, akumulace těchto klíčů obecně představovala minimální dopad. Abychom však vyhověli extrémně dlouhotrvajícím službám, zavedli jsme možnost odstranit klíče. Obecně platí, že by se měly odstranit jenom staré klíče. Odstraňte klíče pouze v případě, že můžete přijmout riziko ztráty dat výměnou za úspory úložiště. Doporučujeme, aby klíče ochrany dat nebyly odstraněny.
using Microsoft.AspNetCore.DataProtection.KeyManagement;
var services = new ServiceCollection();
services.AddDataProtection();
var serviceProvider = services.BuildServiceProvider();
var keyManager = serviceProvider.GetService<IKeyManager>();
if (keyManager is IDeletableKeyManager deletableKeyManager)
{
var utcNow = DateTimeOffset.UtcNow;
var yearAgo = utcNow.AddYears(-1);
if (!deletableKeyManager.DeleteKeys(key => key.ExpirationDate < yearAgo))
{
Console.WriteLine("Failed to delete keys.");
}
else
{
Console.WriteLine("Old keys deleted successfully.");
}
}
else
{
Console.WriteLine("Key manager does not support deletion.");
}
Middleware podporuje klíčované DI
Middleware nyní podporuje klíčovaný DI jak v konstruktoru, tak v metodě:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddKeyedSingleton<MySingletonClass>("test");
builder.Services.AddKeyedScoped<MyScopedClass>("test2");
var app = builder.Build();
app.UseMiddleware<MyMiddleware>();
app.Run();
internal class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next,
[FromKeyedServices("test")] MySingletonClass service)
{
_next = next;
}
public Task Invoke(HttpContext context,
[FromKeyedServices("test2")]
MyScopedClass scopedService) => _next(context);
}
Důvěřovat vývojovému certifikátu ASP.NET Core HTTPS v Linuxu
Na distribucích Linuxu založených na Ubuntu a Fedora dotnet dev-certs https --trust
teď konfiguruje vývojový certifikát ASP.NET Core HTTPS jako důvěryhodný certifikát pro:
- Prohlížeče Chromium, například Google Chrome, Microsoft Edge a Chromium.
- Mozilla Firefox a prohlížeče odvozené od Mozilla.
- Rozhraní .NET API, například HttpClient
--trust
Dříve fungovalo jenom ve Windows a macOS. Důvěryhodnost certifikátu se uplatňuje pro každého uživatele.
Chcete-li vytvořit důvěryhodnost v OpenSSL, použijte nástroj dev-certs
.
- Vloží certifikát do
~/.aspnet/dev-certs/trust
- Spustí zjednodušenou verzi nástroje c_rehash OpenSSL v adresáři.
- Požádá uživatele, aby aktualizoval proměnnou
SSL_CERT_DIR
prostředí.
Pokud chcete vytvořit vztah důvěryhodnosti v dotnetu, nástroj umístí certifikát do My/Root
úložiště certifikátů.
Chcete-li vytvořit důvěru v databáze NSS ,, pokud existují, nástroj vyhledá ve vašem domovském adresáři profily Firefoxu, ~/.pki/nssdb
a ~/snap/chromium/current/.pki/nssdb
. Pro každý nalezený adresář nástroj přidá položku do nssdb
souboru .
Šablony aktualizované na nejnovější verze Bootstrap, jQuery a jQuery Validation
Šablony a knihovny projektů ASP.NET Core byly aktualizovány tak, aby používaly nejnovější verze Bootstrap, jQuery a jQuery Validation, konkrétně:
- Bootstrap 5.3.3
- jQuery 3.7.1
- jQuery Validation 1.21.0