Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym artykule przedstawiono najważniejsze zmiany w programie ASP.NET Core na platformie .NET 10 z linkami do odpowiedniej dokumentacji.
Blazor
W tej sekcji opisano nowe funkcje Blazor.
Nowe i zaktualizowane Blazor Web App przykłady zabezpieczeń
Dodaliśmy i zaktualizowaliśmy Blazor Web App przykłady zabezpieczeń powiązane z następującymi artykułami:
- Zabezpieczanie ASP.NET Core Blazor Web App za pomocą technologii OpenID Connect (OIDC)
- Zabezpieczanie ASP.NET Core Blazor Web App za pomocą identyfikatora Entra firmy Microsoft
- Zabezpieczanie ASP.NET Core Blazor Web App przy użyciu uwierzytelniania systemu Windows
Wszystkie nasze przykładowe rozwiązania OIDC i Entra zawierają teraz oddzielny projekt internetowego interfejsu API (MinimalApiJwt), aby zademonstrować sposób bezpiecznego konfigurowania i wywoływania zewnętrznego internetowego interfejsu API. Wywoływanie interfejsów API jest pokazywane za pomocą programu obsługi tokenów i nazwanego klienta HTTP dla dostawcy tożsamości OIDC lub pakietów Web/API dla Microsoft Entra ID Identity.
Przykładowe rozwiązania są konfigurowane w kodzie C# w tych plikach Program. Aby skonfigurować rozwiązania z plików ustawień aplikacji (na przykład appsettings.json), zobacz nowąkonfigurację dostarczania przy użyciu dostawcy konfiguracji JSON (ustawień aplikacji) w artykułach OIDC lub Entra.
Nasz artykuł Entra i przykładowe aplikacje zawierają również nowe wskazówki dotyczące następujących podejść:
- Jak używać zaszyfrowanej rozproszonej pamięci podręcznej tokenów na potrzeby scenariuszy hostingu farmy internetowej.
- Jak używać usługi Azure Key Vault z tożsamościami zarządzanymi platformy Azure w celu ochrony danych.
parametr QuickGridRowClass
Zastosuj klasę stylu do wiersza siatki na podstawie elementu wiersza przy użyciu nowego parametru RowClass. W poniższym przykładzie metoda GetRowCssClass jest wywoływana w każdym wierszu, aby warunkowo zastosować klasę arkusza stylów na podstawie elementu wiersza:
<QuickGrid ... RowClass="GetRowCssClass">
...
</QuickGrid>
@code {
private string GetRowCssClass(MyGridItem item) =>
item.IsArchived ? "row-archived" : null;
}
Aby uzyskać więcej informacji, zobacz ASP.NET Core Blazor "QuickGrid" składnik.
Blazor skrypt jako statyczny zasób internetowy
W poprzednich wersjach platformy .NET skrypt Blazor jest obsługiwany z zasobu osadzonego w strukturze udostępnionej ASP.NET Core. W programie .NET 10 lub nowszym skrypt Blazor jest obsługiwany jako statyczny zasób internetowy z automatyczną kompresją i odciskiem palca.
Skrypt Blazor (blazor.web.js lub blazor.server.js) jest dołączany przez platformę, jeśli projekt zawiera co najmniej jeden Razor plik składnika (.razor). Jeśli aplikacja wymaga skryptu Blazor , ale nie zawiera co najmniej jednego składnika, dodaj następującą właściwość MSBuild do pliku projektu aplikacji, aby wymusić dołączenie skryptu bezwarunkowego:
<RequiresAspNetWebAssets>true</RequiresAspNetWebAssets>
Aby uzyskać więcej informacji, zobacz następujące zasoby:
Wyróżnienia szablonów tras
Atrybut [Route] obsługuje teraz wyróżnianie składni tras, aby ułatwić wizualizację struktury szablonu trasy:
NavigateTo nie przewija się już do góry w przypadku nawigacji na tej samej stronie
Wcześniej NavigationManager.NavigateTo przewijał się do góry strony podczas nawigacji na tej samej stronie. To zachowanie zostało zmienione na platformie .NET 10, aby przeglądarka nie przewijała się do góry strony podczas przechodzenia do tej samej strony. Oznacza to, że port widoku nie jest już resetowany podczas wprowadzania aktualizacji adresu bieżącej strony, na przykład zmiany ciągu zapytania lub fragmentu.
Składnik reconnect UI dodany do szablonu projektu Blazor Web App
Szablon projektu Blazor Web App zawiera teraz składnik ReconnectModal, w tym arkusz stylów i pliki JavaScript umieszczone w tym samym miejscu, dla lepszej kontroli dewelopera nad interfejsem użytkownika odbudowania połączenia, gdy klient utraci połączenie WebSocket z serwerem. Składnik nie wstawia stylów programowo, zapewniając zgodność z bardziej rygorystycznymi ustawieniami zasad Polityki Bezpieczeństwa Zawartości (CSP) dla polityki style-src. W poprzednich wersjach domyślny interfejs użytkownika ponownego nawiązywania połączenia został utworzony przez framework w sposób, który może powodować naruszenia polityki CSP. Należy pamiętać, że domyślny interfejs użytkownika ponownego łączenia jest nadal używany jako rezerwowy, gdy aplikacja nie definiuje interfejsu użytkownika ponownego łączenia, na przykład przy użyciu składnika ReconnectModal szablonu projektu lub podobnego składnika niestandardowego.
Nowe funkcje interfejsu użytkownika do ponownego łączenia:
- Oprócz wskazywania stanu ponownego nawiązywania połączenia poprzez ustawienie określonej klasy CSS na elemencie interfejsu użytkownika ponownego łączenia, nowe zdarzenie
components-reconnect-state-changedjest wysyłane przy zmianie stanu ponownego połączenia. - Kod może lepiej odróżnić etapy procesu ponownego łączenia z nowym stanem ponownego połączenia "
retrying", wskazywane zarówno przez klasę CSS, jak i nowe zdarzenie.
Aby uzyskać więcej informacji, zobacz wskazówki dotyczące platformy ASP.NET CoreBlazorSignalR.
Ignoruj ciąg zapytania i fragment podczas korzystania z NavLinkMatch.All
Składnik NavLink ignoruje teraz ciąg zapytania i fragment podczas używania wartości NavLinkMatch.All parametru Match. To oznacza, że link zachowuje klasę active, jeśli ścieżka adresu URL się zgadza, ale ciąg zapytania lub fragment mogą ulec zmianie. Aby przywrócić oryginalne zachowanie, użyj przełącznika ustawionego Microsoft.AspNetCore.Components.Routing.NavLink.EnableMatchAllForQueryStringAndFragmentAppContext na true.
Możesz również zastąpić metodę ShouldMatch w NavLink, aby dostosować zgodne zachowanie:
public class CustomNavLink : NavLink
{
protected override bool ShouldMatch(string currentUriAbsolute)
{
// Custom matching logic
}
}
Aby uzyskać więcej informacji, zobacz nawigację ASP.NET CoreBlazor.
Zamknij opcje kolumny QuickGrid
Teraz możesz zamknąć interfejs opcji kolumny QuickGrid za pomocą nowej metody HideColumnOptionsAsync.
W poniższym przykładzie użyto metody HideColumnOptionsAsync, aby zamknąć interfejs opcji kolumn natychmiast po zastosowaniu filtru tytułu.
<QuickGrid @ref="movieGrid" Items="movies">
<PropertyColumn Property="@(m => m.Title)" Title="Title">
<ColumnOptions>
<input type="search" @bind="titleFilter" placeholder="Filter by title"
@bind:after="@(() => movieGrid.HideColumnOptionsAsync())" />
</ColumnOptions>
</PropertyColumn>
<PropertyColumn Property="@(m => m.Genre)" Title="Genre" />
<PropertyColumn Property="@(m => m.ReleaseYear)" Title="Release Year" />
</QuickGrid>
@code {
private QuickGrid<Movie>? movieGrid;
private string titleFilter = string.Empty;
private IQueryable<Movie> movies = new List<Movie> { ... }.AsQueryable();
private IQueryable<Movie> filteredMovies =>
movies.Where(m => m.Title!.Contains(titleFilter));
}
Przesyłanie strumieniowe odpowiedzi HttpClient jest domyślnie włączone
W poprzednich Blazor wersjach przesyłanie strumieniowe odpowiedzi dla HttpClient żądań było dobrowolne. Teraz przesyłanie strumieniowe odpowiedzi jest domyślnie włączone.
Jest to kluczowa zmiana, ponieważ wywołanie HttpContent.ReadAsStreamAsync dla elementu HttpResponseMessage.Content (response.Content.ReadAsStreamAsync()) zwraca BrowserHttpReadStream zamiast MemoryStream.
BrowserHttpReadStream nie obsługuje operacji synchronicznych, takich jak Stream.Read(Span<Byte>). Jeśli Twój kod używa operacji synchronicznych, możesz zrezygnować z przesyłania danych odpowiedzi strumieniowo lub skopiować Stream do MemoryStream samodzielnie.
Aby zrezygnować z przesyłania strumieniowego odpowiedzi na całym świecie, użyj jednej z następujących metod:
<WasmEnableStreamingResponse>Dodaj właściwość do pliku projektu z wartościąfalse:<WasmEnableStreamingResponse>false</WasmEnableStreamingResponse>Ustaw zmienną środowiskową
DOTNET_WASM_ENABLE_STREAMING_RESPONSEnafalselub0.
Aby zrezygnować z przesyłania strumieniowego odpowiedzi dla pojedynczego żądania, ustaw SetBrowserResponseStreamingEnabled na false w elemencie HttpRequestMessage (requestMessage w poniższym przykładzie):
requestMessage.SetBrowserResponseStreamingEnabled(false);
Aby uzyskać więcej informacji, zobacz HttpClient i HttpRequestMessage z opcjami żądania Fetch API (artykuł Wywoływanie internetowego interfejsu API).
Odciski palców po stronie klienta
Wydanie platformy .NET 9 wprowadziło odciski palców po stronie serwera statycznych zasobów w programie Blazor Web Apps z wprowadzeniem konwencji punktów końcowych routingu zasobów statycznych map (MapStaticAssets), ImportMap składnika i ComponentBase.Assets właściwości (@Assets["..."]) w celu rozpoznania za pomocą odcisków palców modułów Języka JavaScript (JS). W przypadku platformy .NET 10 można wyrazić zgodę na odciski palców po stronie klienta modułów JS dla aplikacji autonomicznych Blazor WebAssembly .
W autonomicznych aplikacjach Blazor WebAssembly podczas kompilacji i publikacji framework zastępuje symbole zastępcze w index.html wartościami obliczonymi podczas budowania, aby nadać statycznym zasobom unikalny identyfikator. Odcisk palca jest umieszczany w nazwie pliku skryptu blazor.webassembly.js .
Aby zastosować funkcję odcisków palców, następujący znacznik musi być obecny w pliku wwwroot/index.html:
<head>
...
+ <script type="importmap"></script>
</head>
<body>
...
- <script src="_framework/blazor.webassembly.js"></script>
+ <script src="_framework/blazor.webassembly#[.{fingerprint}].js"></script>
</body>
</html>
W pliku projektu (.csproj) dodaj właściwość ustawioną <OverrideHtmlAssetPlaceholders> na :true
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
+ <OverrideHtmlAssetPlaceholders>true</OverrideHtmlAssetPlaceholders>
</PropertyGroup>
</Project>
W poniższym przykładzie wszystkie pliki, które dostarczył deweloper, są modułami z rozszerzeniem JS.
Moduł o nazwie scripts.js w folderze aplikacji wwwroot/js jest znakowany cyfrowym odciskiem palca poprzez dodanie #[.{fingerprint}] przed rozszerzeniem pliku (.js).
<script type="module" src="js/scripts#[.{fingerprint}].js"></script>
Określ wyrażenie odcisku palca za pomocą właściwości <StaticWebAssetFingerprintPattern> w pliku projektu aplikacji (.csproj):
<ItemGroup>
<StaticWebAssetFingerprintPattern Include="JSModule" Pattern="*.js"
Expression="#[.{fingerprint}]!" />
</ItemGroup>
Dowolny JS plik (*.js) z index.html znacznikiem odcisku palca jest oznaczany przez framework, również po opublikowaniu aplikacji.
Jeśli przyjmujesz .mjs rozszerzenie pliku dla JS modułów, ustaw rozszerzenie pliku za pomocą parametru Pattern :
<ItemGroup>
<StaticWebAssetFingerprintPattern Include="JSModule" Pattern="*.mjs"
Expression="#[.{fingerprint}]!" />
</ItemGroup>
Pliki są umieszczane na mapie importu:
- Automatycznie w przypadku Blazor Web App renderowania po stronie klienta (CSR).
- Podczas wybierania opcji odcisków palców modułu w aplikacjach samodzielnych Blazor WebAssembly zgodnie z poprzednimi instrukcjami.
Podczas obsługi importu dla międzyoperacyjności JavaScript, przeglądarka używa mapy importu do rozwiązywania plików z odciskami.
Statyczne zasoby wstępnie załadowanego frameworka Blazor
W Blazor Web App, zasoby statyczne są ładowane automatycznie przy użyciu Link nagłówków, co umożliwia przeglądarce wstępne ładowanie zasobów przed pobraniem i renderowaniem strony początkowej.
W aplikacjach autonomicznych Blazor WebAssembly zasoby platformy mają wysoki priorytet w pobieraniu i buforowaniu na wczesnym etapie przetwarzania strony w przeglądarce index.html , gdy:
Właściwość
OverrideHtmlAssetPlaceholdersMSBuild w pliku projektu aplikacji (.csproj) jest ustawiona na :true<PropertyGroup> <OverrideHtmlAssetPlaceholders>true</OverrideHtmlAssetPlaceholders> </PropertyGroup>Następujący element
<link>, zawierającyrel="preload", znajduje się w zawartości<head>wwwroot/index.html.<link rel="preload" id="webassembly" />
Aby uzyskać więcej informacji, zobacz ASP.NET Core Blazor plików statycznych.
Skonfiguruj środowisko w aplikacjach autonomicznych Blazor WebAssembly
Plik Properties/launchSettings.json nie jest już używany do kontrolowania środowiska w aplikacjach autonomicznych Blazor WebAssembly .
Od wersji .NET 10, środowisko można ustawić za pomocą właściwości <WasmApplicationEnvironmentName> w pliku projektu aplikacji (.csproj).
Poniższy przykład ustawia środowisko aplikacji na wartość Staging:
<WasmApplicationEnvironmentName>Staging</WasmApplicationEnvironmentName>
Domyślne środowiska to:
-
Developmentdo kompilacji. -
Productiondo publikowania.
Aby uzyskać więcej informacji, zobacz ASP.NET Core Blazor environments (Środowiska podstawowe ASP.NET).
Wbudowany plik konfiguracji rozruchu
BlazorKonfiguracja rozruchu programu , która przed wydaniem programu .NET 10 istniała w pliku o nazwie blazor.boot.json, została wstawiona do skryptu dotnet.js . Ma to wpływ tylko na deweloperów, którzy korzystają bezpośrednio z pliku blazor.boot.json, na przykład w sytuacjach, gdy:
- Sprawdzanie integralności plików dla opublikowanych zasobów za pomocą skryptu PowerShell do sprawdzania integralności zgodnie ze wskazówkami zawartymi w Blazor WebAssembly.
- Zmiana rozszerzenia plików DLL, jeśli nie jest używany domyślny format pliku Webcil, jak wskazano w temacie Host i wdróż ASP.NET Core Blazor WebAssembly.
Obecnie nie ma udokumentowanych strategii wymiany dla powyższych podejść. Jeśli potrzebujesz jednej z powyższych strategii, otwórz nowy problem z dokumentacją opisujący scenariusz, korzystając z linku Otwórz problem z dokumentacją w dolnej części dowolnego artykułu.
Model deklaratywny do zapisywania stanu z komponentów i usług
Możesz teraz deklaratywnie określić stan, który ma być utrwalany w składnikach i usługach, używając atrybutu [PersistentState]. Właściwości z tym atrybutem są automatycznie utrwalane przy użyciu PersistentComponentState usługi podczas prerenderingu. Stan jest pobierany, gdy składnik jest renderowany interaktywnie lub usługa jest tworzona.
W poprzednich Blazor wersjach utrwalanie stanu składnika podczas prerenderingu przy użyciu PersistentComponentState usługi obejmowało znaczną ilość kodu, jak pokazano w poniższym przykładzie:
@page "/movies"
@implements IDisposable
@inject IMovieService MovieService
@inject PersistentComponentState ApplicationState
@if (MoviesList == null)
{
<p><em>Loading...</em></p>
}
else
{
<QuickGrid Items="MoviesList.AsQueryable()">
...
</QuickGrid>
}
@code {
public List<Movie>? MoviesList { get; set; }
private PersistingComponentStateSubscription? persistingSubscription;
protected override async Task OnInitializedAsync()
{
if (!ApplicationState.TryTakeFromJson<List<Movie>>(nameof(MoviesList),
out var movies))
{
MoviesList = await MovieService.GetMoviesAsync();
}
else
{
MoviesList = movies;
}
persistingSubscription = ApplicationState.RegisterOnPersisting(() =>
{
ApplicationState.PersistAsJson(nameof(MoviesList), MoviesList);
return Task.CompletedTask;
});
}
public void Dispose() => persistingSubscription?.Dispose();
}
Ten kod można teraz uprościć przy użyciu nowego modelu deklaratywnego:
@page "/movies"
@inject IMovieService MovieService
@if (MoviesList == null)
{
<p><em>Loading...</em></p>
}
else
{
<QuickGrid Items="MoviesList.AsQueryable()">
...
</QuickGrid>
}
@code {
[PersistentState]
public List<Movie>? MoviesList { get; set; }
protected override async Task OnInitializedAsync()
{
MoviesList ??= await MovieService.GetMoviesAsync();
}
}
Stan może być serializowany dla wielu komponentów tego samego typu, a stan deklaratywny można ustanowić w usłudze do wykorzystania w całej aplikacji, wywołując RegisterPersistentService na budowniku komponentów Razor (AddRazorComponents) z niestandardowym typem usługi i trybem renderowania. Aby uzyskać więcej informacji, zobacz Trwałość stanu wstępnego ASP.NET CoreBlazor.
Nowe funkcje międzyoperacyjne języka JavaScript
Blazor Dodaje obsługę następujących JS funkcji międzyoperaowych:
- Utwórz instancję obiektu JS za pomocą funkcji konstruktora i uzyskaj dojście .NET IJSObjectReference/IJSInProcessObjectReference w celu odwoływania się do tej instancji.
- Odczytaj lub modyfikuj wartość JS właściwości obiektu, zarówno dla właściwości danych, jak i dla akcesorów.
Następujące metody asynchroniczne są dostępne dla IJSRuntime i IJSObjectReference z tym samym zakresem działania, co istniejąca metoda IJSRuntime.InvokeAsync.
InvokeConstructorAsync(string identifier, object?[]? args): wywołuje asynchronicznie określoną JS funkcję konstruktora. Funkcja jest wywoływana z operatoremnew. W poniższym przykładziejsInterop.TestClassjest klasą z funkcją konstruktora, aclassRefjest IJSObjectReference.var classRef = await JSRuntime.InvokeConstructorAsync("jsInterop.TestClass", "Blazor!"); var text = await classRef.GetValueAsync<string>("text"); var textLength = await classRef.InvokeAsync<int>("getTextLength");GetValueAsync<TValue>(string identifier): odczytuje wartość określonej JS właściwości asynchronicznie. Właściwość nie może być właściwościąset-only. Zgłaszany jest wyjątek JSException, jeśli właściwość nie istnieje. Poniższy przykład zwraca wartość z właściwości danych:var valueFromDataPropertyAsync = await JSRuntime.GetValueAsync<int>( "jsInterop.testObject.num");SetValueAsync<TValue>(string identifier, TValue value): aktualizuje wartość określonej JS właściwości asynchronicznie. Właściwość nie może być właściwościąget-only. Jeśli właściwość nie jest zdefiniowana w obiekcie docelowym, zostanie utworzona właściwość . Obiekt JSException jest zgłaszany, jeśli właściwość istnieje, ale nie jest zapisywalna lub gdy do obiektu nie można dodać nowej właściwości. W poniższym przykładzienumjest tworzony natestObjectz wartością 30, jeśli nie istnieje.await JSRuntime.SetValueAsync("jsInterop.testObject.num", 30);
Przeciążenia są dostępne dla każdej z powyższych metod, które przyjmują CancellationToken argument lub TimeSpan argument limitu czasu.
Następujące metody synchroniczne są dostępne na IJSInProcessRuntime i IJSInProcessObjectReference z tym samym zachowaniem określania zakresu, co istniejąca metoda IJSInProcessObjectReference.Invoke.
InvokeConstructor(string identifier, object?[]? args): Wywołuje określoną JS funkcję konstruktora synchronicznie. Funkcja jest wywoływana z operatoremnew. W poniższym przykładziejsInterop.TestClassjest klasą z funkcją konstruktora, aclassRefjest IJSInProcessObjectReference.var inProcRuntime = ((IJSInProcessRuntime)JSRuntime); var classRef = inProcRuntime.InvokeConstructor("jsInterop.TestClass", "Blazor!"); var text = classRef.GetValue<string>("text"); var textLength = classRef.Invoke<int>("getTextLength");GetValue<TValue>(string identifier): odczytuje wartość określonej JS właściwości synchronicznie. Właściwość nie może być właściwościąset-only. Zgłaszany jest wyjątek JSException, jeśli właściwość nie istnieje. Poniższy przykład zwraca wartość z właściwości danych:var inProcRuntime = ((IJSInProcessRuntime)JSRuntime); var valueFromDataProperty = inProcRuntime.GetValue<int>( "jsInterop.testObject.num");SetValue<TValue>(string identifier, TValue value): aktualizuje wartość określonej JS właściwości synchronicznie. Właściwość nie może być właściwościąget-only. Jeśli właściwość nie jest zdefiniowana w obiekcie docelowym, zostanie utworzona właściwość . Obiekt JSException jest zgłaszany, jeśli właściwość istnieje, ale nie jest zapisywalna lub gdy do obiektu nie można dodać nowej właściwości. W poniższym przykładzie,numjest tworzony natestObjectz wartością 20, jeśli nie istnieje:var inProcRuntime = ((IJSInProcessRuntime)JSRuntime); inProcRuntime.SetValue("jsInterop.testObject.num", 20);
Aby uzyskać więcej informacji, zobacz następujące sekcje artykułu Wywoływanie funkcji Języka JavaScript z metod platformy .NET :
- Tworzenie wystąpienia JS obiektu przy użyciu funkcji konstruktora
- Odczytywanie lub modyfikowanie wartości JS właściwości obiektu
Blazor WebAssembly profilowanie wydajności i liczniki diagnostyczne
Nowe profilowanie wydajności i liczniki diagnostyczne są dostępne dla Blazor WebAssembly aplikacji. Aby uzyskać więcej informacji, zobacz następujące artykuły:
- Diagnostyka narzędzi deweloperskich przeglądarki ASP.NET Core Blazor WebAssembly
- diagnostyka potoku zdarzeń podstawowych Blazor WebAssembly ASP.NET
Wyrażanie NavigationException zgody na unikanie renderowania po stronie serwera statycznego za pomocą polecenia NavigationManager.NavigateTo
Wywołanie NavigationManager.NavigateTo podczas renderowania statycznego po stronie serwera (statyczne SSR) zgłasza NavigationExceptionbłąd , przerywając wykonywanie przed przekonwertowaniem na odpowiedź przekierowania. Może to spowodować zamieszanie podczas debugowania i jest niespójne z zachowaniem renderowania interakcyjnego, w którym kod po NavigateTo kontynuowaniu jest wykonywany normalnie.
Na platformie .NET 10 można ustawić <BlazorDisableThrowNavigationException> właściwość MSBuild na true w pliku projektu aplikacji, aby uniknąć zgłaszania wyjątku podczas statycznego rejestrowania SSR:
<PropertyGroup>
<BlazorDisableThrowNavigationException>true</BlazorDisableThrowNavigationException>
</PropertyGroup>
W przypadku zestawu właściwości MSBuild wywołanie metody NavigationManager.NavigateTo podczas statycznego przewodnika SSR nie zgłasza już wartości NavigationException. Zamiast tego zachowuje się zgodnie z renderowaniem interaktywnym, nawigując bez zgłaszania wyjątku. Kod po wykonaniu przed NavigationManager.NavigateTo wystąpieniem przekierowania.
Szablon projektu .NET 10 Blazor Web App domyślnie ustawia właściwość true MSBuild. Zalecamy, aby aplikacje aktualizowane na platformie .NET 10 używały nowej właściwości MSBuild i unikały wcześniejszego zachowania.
Jeśli jest używana właściwość MSBuild, należy zaktualizować kod, który polegał na NavigationException zgłaszaniu. W domyślnym BlazorIdentity interfejsie Blazor Web App użytkownika szablonu projektu przed wydaniem platformy .NET 10 element zgłasza błąd IdentityRedirectManager po wywołaniuInvalidOperationException, aby upewnić się, RedirectTo że metoda nie została wywołana podczas renderowania interaktywnego. Ten wyjątek i [DoesNotReturn] atrybuty powinny zostać usunięte po użyciu właściwości MSBuild. Aby uzyskać więcej informacji, zobacz Migrowanie z platformy ASP.NET Core na platformie .NET 9 do ASP.NET Core na platformie .NET 10.
Blazor router ma parametr NotFoundPage
Blazor Teraz zapewnia ulepszony sposób wyświetlania strony "Nie znaleziono" podczas przechodzenia do nieistniejącej strony. Możesz ustalić, którą stronę ma być renderowana, gdy NavigationManager.NotFound (opisane w kolejnej sekcji) jest wywoływane przez przekazanie typu strony do komponentu Router za pomocą parametru NotFoundPage. Funkcja obsługuje routing, działa w ramach ponownego wykonywania pośrednikowego stron kodu statusu i jest zgodna nawet ze scenariuszami, które nie dotyczą Blazor.
Fragment renderowaniaNotFound (<NotFound>...</NotFound>) nie jest obsługiwany na platformie .NET 10 lub nowszym.
<Router AppAssembly="@typeof(Program).Assembly" NotFoundPage="typeof(Pages.NotFound)">
<Found Context="routeData">
<RouteView RouteData="@routeData" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>This content is ignored because NotFoundPage is defined.</NotFound>
</Router>
Domyślnie, szablon Blazor projektu zawiera stronę NotFound.razor. Ta strona jest automatycznie renderowana za każdym razem, gdy NotFound jest używana w aplikacji, co ułatwia obsługę brakujących tras przy użyciu spójnego doświadczenia użytkownika.
Aby uzyskać więcej informacji, zobacz nawigację ASP.NET CoreBlazor.
Nie znaleziono odpowiedzi używanych NavigationManager na potrzeby statycznego renderowania SSR i globalnego interaktywnego renderowania
Teraz NavigationManager zawiera metodę NotFound do obsługiwania scenariuszy, w których żądany zasób nie został odnaleziony podczas renderowania statycznego po stronie serwera (statyczne SSR) lub globalnego interaktywnego renderowania.
Statyczne renderowanie po stronie serwera (statyczne SSR): wywołanie NotFound ustawia kod stanu HTTP na wartość 404.
Renderowanie interakcyjne: sygnalizuje, że Blazor router (
Routerskładnik) renderuje zawartość Nie znaleziono.Renderowanie strumieniowe: jeśli rozszerzona nawigacja jest aktywna, renderowanie strumieniowe wyświetla zawartość oznaczoną jako "nie znaleziono" bez ponownego ładowania strony. Po zablokowaniu rozszerzonej nawigacji framework przekierowuje do zawartości "Not Found" poprzez odświeżenie strony.
Renderowanie strumieniowe może renderować tylko te składniki, które mają trasę, takie jak NotFoundPage przypisanie trasy (NotFoundPage="...") lub przypisanie strony pośredniczącej do ponownego wykonania kodów stanu (UseStatusCodePagesWithReExecute).
DefaultNotFound Zawartość 404 ("Not found" zwykły tekst) nie ma trasy, więc nie można jej używać podczas renderowania strumieniowego.
NotFound renderowanie zawartości używa następujących elementów, niezależnie od tego, czy odpowiedź została uruchomiona, czy nie (w kolejności):
- Jeśli NotFoundEventArgs.Path jest ustawiona, renderuj zawartość przypisanej strony.
- Jeśli
Router.NotFoundPagejest ustawiona, renderuj przypisaną stronę. - Strona ponownego uruchamiania oprogramowania pośredniczącego z kodami statusu, jeśli została skonfigurowana.
- Brak działań, jeśli żadne z powyższych podejść nie zostanie przyjęte.
Strony kodu stanu Ponowne wykonywanie oprogramowania pośredniczącego ma pierwszeństwo przed problemami UseStatusCodePagesWithReExecute routingu opartymi na przeglądarce, takimi jak niepoprawny adres URL wpisany na pasku adresu przeglądarki lub wybranie linku, który nie ma punktu końcowego w aplikacji.
Możesz użyć zdarzenia NavigationManager.OnNotFound do powiadomień, gdy wywoływane jest NotFound.
Aby uzyskać więcej informacji i przykładów, zobacz nawigacja ASP.NET CoreBlazor.
Obsługa odpowiedzi 'Nie znaleziono' w aplikacjach bez routera Blazor
Aplikacje, które implementują niestandardowy router, mogą używać NotFound. Istnieją dwa sposoby informowania modułu renderowania o tym, jaka strona powinna być renderowana po NotFound wywołaniu.
Zalecaną metodą, która działa niezależnie od stanu odpowiedzi, jest wywołanie metody UseStatusCodePagesWithReExecute. Gdy wywołane zostanie NotFound, middleware renderuje ścieżkę przekazaną do metody.
app.UseStatusCodePagesWithReExecute(
"/not-found", createScopeForStatusCodePages: true);
Jeśli nie chcesz używać UseStatusCodePagesWithReExecute, aplikacja może nadal obsługiwać NotFound odpowiedzi, które zostały już uruchomione. Zasubskrybuj w routerze i przypisz ścieżkę strony Nie znaleziono do OnNotFoundEvent, aby poinformować mechanizm renderowania, jaka zawartość ma być renderowana, gdy zostanie wywołany NotFoundEventArgs.Path.
CustomRouter.razor:
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Http
@implements IDisposable
@inject NavigationManager NavigationManager
@code {
protected override void OnInitialized() =>
NavigationManager.OnNotFound += OnNotFoundEvent;
[CascadingParameter]
public HttpContext? HttpContext { get; set; }
private void OnNotFoundEvent(object sender, NotFoundEventArgs e)
{
// Only execute the logic if HTTP response has started
// because setting NotFoundEventArgs.Path blocks re-execution
if (HttpContext?.Response.HasStarted == false)
{
return;
}
e.Path = GetNotFoundRoutePath();
}
// Return the path of the Not Found page that you want to display
private string GetNotFoundRoutePath()
{
...
}
public void Dispose() => NavigationManager.OnNotFound -= OnNotFoundEvent;
}
Jeśli używasz obu metod w aplikacji, ścieżka Nie znaleziono określona w OnNotFoundEvent procedurze obsługi ma pierwszeństwo przed ścieżką skonfigurowaną w programie pośredniczącym ponownego wykonywania.
Metryki i śledzenie
W tej wersji wprowadzono kompleksowe metryki i funkcje śledzenia dla Blazor aplikacji, zapewniając szczegółową obserwację cyklu życia składnika, nawigację, obsługę zdarzeń i zarządzanie obwodem.
Aby uzyskać więcej informacji, zobacz Blazor dotyczące wydajności ASP.NET Core).
Obsługa bundlera JavaScript
BlazorDane wyjściowe kompilacji nie są zgodne z pakietami JavaScript, takimi jak Gulp, Webpack i Rollup. Program może teraz generować dane wyjściowe przyjazne dla bundlera podczas publikowania, ustawiając właściwość MSBuild na Blazor.
Aby uzyskać więcej informacji, zobacz Host and deploy ASP.NET Core Blazor.
Blazor WebAssemblywstępne ładowanie statycznych zasobów w Blazor Web App
Zastąpiliśmy nagłówki <link> komponentem ResourcePreloader (<ResourcePreloader />), aby wstępnie ładować zasoby WebAssembly w Blazor Web App. Dzięki temu konfiguracja ścieżki podstawowej aplikacji (<base href="..." />) pozwala na poprawne zidentyfikowanie katalogu głównego aplikacji.
Usunięcie składnika powoduje wyłączenie funkcji, jeżeli aplikacja wykorzystuje wywołanie zwrotneloadBootResource do zmiany adresów URL.
Szablon Blazor Web App domyślnie przyjmuje tę funkcję w .NET 10, a aplikacje uaktualniane do .NET 10 mogą wdrożyć tę funkcję, umieszczając składnik ResourcePreloader po tagu podstawowego adresu URL <base> w zawartości head komponentu App (App.razor).
<head>
...
<base href="/" />
+ <ResourcePreloader />
...
</head>
Aby uzyskać więcej informacji, zobacz
Ulepszona walidacja formularza
Teraz Blazor ma ulepszone możliwości walidacji formularzy, w tym obsługę sprawdzania poprawności właściwości zagnieżdżonych obiektów i elementów kolekcji.
Aby utworzyć zweryfikowany formularz, użyj DataAnnotationsValidator składnika wewnątrz EditForm składnika, tak jak wcześniej.
Aby wyrazić zgodę na nową funkcję weryfikacji:
- Wywołaj metodę
AddValidationrozszerzenia w plikuProgram, w którym są zarejestrowane usługi. - Zadeklaruj typy modeli formularzy w pliku klasy języka C#, a nie w składniku Razor (
.razor). - Dodaj adnotację do typu modelu formularza głównego za pomocą atrybutu
[ValidatableType].
Bez wykonywania powyższych kroków zachowanie walidacji pozostaje takie samo jak w poprzednich wersjach platformy .NET.
W poniższym przykładzie pokazano zamówienia klientów z ulepszoną weryfikacją formularza (szczegóły pominięte dla zwięzłości):
W Program.cs, wywołaj AddValidation na kolekcji usług, aby włączyć nowe zachowanie weryfikacji.
builder.Services.AddValidation();
W poniższej klasie Order, atrybut [ValidatableType] jest wymagany dla modelu najwyższego poziomu. Inne typy są wykrywane automatycznie.
OrderItem i ShippingAddress nie są wyświetlane dla uproszczenia, ale zagnieżdżone i weryfikacja kolekcji działa tak samo w przypadku wyświetlania tych typów.
Order.cs:
[ValidatableType]
public class Order
{
public Customer Customer { get; set; } = new();
public List<OrderItem> OrderItems { get; set; } = [];
}
public class Customer
{
[Required(ErrorMessage = "Name is required.")]
public string? FullName { get; set; }
[Required(ErrorMessage = "Email is required.")]
public string? Email { get; set; }
public ShippingAddress ShippingAddress { get; set; } = new();
}
W poniższym składniku OrderPage składnik DataAnnotationsValidator znajduje się w składniku EditForm.
OrderPage.razor:
<EditForm Model="Model">
<DataAnnotationsValidator />
<h3>Customer Details</h3>
<div class="mb-3">
<label>
Full Name
<InputText @bind-Value="Model!.Customer.FullName" />
</label>
<ValidationMessage For="@(() => Model!.Customer.FullName)" />
</div>
@* ... form continues ... *@
</EditForm>
@code {
public Order? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
// ... code continues ...
}
Wymaganie deklarowania typów modeli poza składnikami Razor (.razor plikami) wynika z faktu, że zarówno nowa funkcja walidacji, jak i Razor sam kompilator używają generatora źródłowego. Obecnie dane wyjściowe jednego generatora źródłowego nie mogą być używane jako dane wejściowe dla innego generatora źródła.
Obsługa walidacji obejmuje teraz:
- Walidacja zagnieżdżonych złożonych obiektów i kolekcji jest teraz obsługiwana.
- Obejmuje to reguły walidacji zdefiniowane przez atrybuty właściwości, atrybuty klasy i implementację IValidatableObject .
- Atrybut
[SkipValidation]może wykluczać właściwości lub typy z walidacji.
- Walidacja używa teraz implementacji opartej na generatorze źródła zamiast implementacji opartej na odbiciu w celu zwiększenia wydajności i zgodności z kompilacją przed czasem (AOT).
Składnik DataAnnotationsValidator ma teraz taką samą kolejność walidacji i zachowanie zwarcie co System.ComponentModel.DataAnnotations.Validator. Podczas sprawdzania poprawności wystąpienia typu Tsą stosowane następujące reguły:
- Właściwości składowe
Tsą weryfikowane, w tym rekursywnie weryfikowanie zagnieżdżonych obiektów. - Atrybuty
Tna poziomie typu są weryfikowane. - Metoda IValidatableObject.Validate jest wykonywana, jeśli
Tją implementuje.
Jeśli jeden z powyższych kroków generuje błąd weryfikacji, pozostałe kroki zostaną pominięte.
Używanie modeli weryfikacji z innego zestawu
Formularze można weryfikować przy użyciu modeli zdefiniowanych w innym zestawie, takich jak biblioteka lub projekt .ClientBlazor Web App, tworząc metodę w bibliotece lub projekcie .Client, która przyjmuje wystąpienie IServiceCollection jako argument i wywołuje AddValidation.
- W aplikacji wywołaj zarówno metodę , jak i
AddValidation.
Aby uzyskać więcej informacji i przykład, zobacz sprawdzanie poprawności formularzy ASP.NET CoreBlazor.
Usunięto niestandardową Blazor pamięć podręczną i BlazorCacheBootResources właściwość MSBuild
Teraz, gdy wszystkie Blazor pliki po stronie klienta są oznaczone unikalnym identyfikatorem i przechowywane w pamięci podręcznej przez przeglądarkę, Blazor niestandardowy mechanizm cache'owania i BlazorCacheBootResources właściwość MSBuild zostały usunięte z frameworku. Jeśli plik projektu po stronie klienta zawiera właściwość MSBuild, usuń właściwość , ponieważ nie ma już żadnego wpływu:
- <BlazorCacheBootResources>...</BlazorCacheBootResources>
Aby uzyskać więcej informacji, zobacz błędy buforowania i sprawdzania integralności ASP.NET CoreBlazor WebAssembly.
Obsługa internetowego interfejsu API uwierzytelniania (klucz dostępu) dla platformy ASP.NET Core Identity
Obsługa interfejsu API uwierzytelniania internetowego (WebAuthn), znana powszechnie jako klucze dostępu, to nowoczesna, odporna na wyłudzanie informacji metoda uwierzytelniania, która zwiększa bezpieczeństwo i środowisko użytkownika dzięki wykorzystaniu kryptografii klucza publicznego i uwierzytelniania opartego na urządzeniach. ASP.NET Core Identity obsługuje teraz uwierzytelnianie za pomocą klucza dostępu oparte na standardach WebAuthn i FIDO2. Ta funkcja umożliwia użytkownikom logowanie się bez haseł przy użyciu bezpiecznych metod uwierzytelniania opartych na urządzeniach, takich jak biometryczne lub klucze zabezpieczeń.
Szablon Blazor Web App projektu zapewnia gotowe funkcje zarządzania kluczami dostępu i logowania.
Aby uzyskać więcej informacji, zobacz następujące artykuły:
- Włączanie kluczy dostępu interfejsu API uwierzytelniania sieci Web (WebAuthn)
- Implementowanie kluczy dostępu w ASP.NET Core Blazor Web App
Trwałość stanu obwodu
Podczas renderowania po stronie serwera Blazor Web App, można teraz utrwalać stan sesji użytkownika (obwodu serwera), kiedy połączenie z serwerem jest utracone przez dłuższy czas lub aktywnie wstrzymane, pod warunkiem że nie jest wyzwalane odświeżanie pełnostronicowe. Dzięki temu użytkownicy mogą wznowić swoją sesję bez utraty niezapisanej pracy w następujących scenariuszach:
- Ograniczanie zasobów kart przeglądarki
- Użytkownicy urządzeń przenośnych przełączający aplikacje
- Przerwy w działaniu sieci
- Proaktywne zarządzanie zasobami (wstrzymywanie nieaktywnych obwodów)
- Ulepszona nawigacja
Aby uzyskać więcej informacji, zobacz zarządzanie stanem po stronie serwera ASP.NET CoreBlazor.
Przeładowywanie na gorąco dla platformy Blazor WebAssembly i .NET w technologii WebAssembly
Zestaw SDK zmigrowany do ogólnego przeznaczenia — przeładowywanie na gorąco dla scenariuszy zestawu WebAssembly. Istnieje nowa właściwość MSBuild WasmEnableHotReload, która jest domyślnie true dla konfiguracji Debug (Configuration == "Debug"), która umożliwia Hot Reload.
W przypadku innych konfiguracji z niestandardowymi nazwami konfiguracji ustaw wartość na true w pliku projektu aplikacji, aby włączyć przeładowywanie na gorąco:
<PropertyGroup>
<WasmEnableHotReload>true</WasmEnableHotReload>
</PropertyGroup>
Aby wyłączyć przeładowywanie na gorąco dla Debug konfiguracji, ustaw wartość na false:
<PropertyGroup>
<WasmEnableHotReload>false</WasmEnableHotReload>
</PropertyGroup>
Zaktualizowano rejestrację service worker PWA, aby zapobiec problemom z buforowaniem
Rejestracja pracownika serwisu w szablonie
- navigator.serviceWorker.register('service-worker.js');
+ navigator.serviceWorker.register('service-worker.js', { updateViaCache: 'none' });
Opcja zapewnia, że:
- Przeglądarka nie używa buforowanych wersji skryptu service worker.
- Aktualizacje pracowników serwisowych są niezawodnie stosowane bez blokowania przez buforowanie HTTP.
- Aplikacje PWA mogą aktualizować swoich pracowników usług bardziej przewidywalnie.
Rozwiązuje to problemy z buforowaniem, które mogą uniemożliwić poprawne stosowanie aktualizacji service workerów, co jest szczególnie ważne w przypadku aplikacji PWA korzystających z service workerów do zapewnienia funkcji offline.
Zalecamy użycie opcji ustawionej na none we wszystkich programach PWA, w tym tych, które celują w .NET 9 lub starsze wersje.
Rozszerzalność serializacji dla stanu trwałego składnika
Zaimplementuj niestandardowy serializator za pomocą polecenia PersistentComponentStateSerializer<T>. Bez zarejestrowanego serializatora niestandardowego serializacja wraca do istniejącej serializacji JSON.
Niestandardowy serializator jest zarejestrowany w pliku aplikacji Program . W poniższym przykładzie CustomUserSerializer jest zarejestrowany dla typu TUser.
builder.Services.AddSingleton<PersistentComponentStateSerializer<TUser>,
CustomUserSerializer>();
Typ jest automatycznie utrwalany i przywracany za pomocą niestandardowego serializatora:
[PersistentState]
public User? CurrentUser { get; set; } = new();
OwningComponentBase teraz implementuje IAsyncDisposable
OwningComponentBase teraz obejmuje obsługę asynchronicznego usuwania, co poprawia zarządzanie zasobami. Istnieją nowe metody DisposeAsync, DisposeAsyncCore i zaktualizowana metoda Dispose do obsługi zarówno synchronicznego, jak i asynchronicznego usuwania zakresu usługi.
Nowy InputHidden składnik do obsługi ukrytych pól wejściowych w formularzach
Nowy InputHidden składnik udostępnia ukryte pole wejściowe do przechowywania wartości ciągów.
W poniższym przykładzie dla właściwości formularza Parameter jest tworzone ukryte pole wejściowe. Po przesłaniu formularza zostanie wyświetlona wartość ukrytego pola:
<EditForm Model="Parameter" OnValidSubmit="Submit" FormName="InputHidden Example">
<InputHidden id="hidden" @bind-Value="Parameter" />
<button type="submit">Submit</button>
</EditForm>
@if (submitted)
{
<p>Hello @Parameter!</p>
}
@code {
private bool submitted;
[SupplyParameterFromForm]
public string Parameter { get; set; } = "stranger";
private void Submit() => submitted = true;
}
Obsługa stanu składnika trwałego na potrzeby rozszerzonej nawigacji
Blazor obsługuje teraz obsługę trwałego stanu składnika podczas rozszerzonej nawigacji. Stan utrwalone podczas nawigacji rozszerzonej może być odczytywany przez interaktywne składniki na stronie.
Domyślnie stan składnika trwałego jest ładowany tylko przez składniki interakcyjne, gdy są one początkowo ładowane na stronie. Zapobiega to zastępowaniu ważnych stanów, takich jak dane w edytowanym formularzu internetowym, jeśli po załadowaniu składnika wystąpią dodatkowe rozszerzone zdarzenia nawigacji na tej samej stronie.
Jeśli dane są tylko do odczytu i nie zmieniają się często, należy wyrazić zgodę na zezwalanie na aktualizacje podczas rozszerzonej nawigacji przez ustawienie AllowUpdates = trueatrybutu[PersistentState]. Jest to przydatne w scenariuszach, takich jak wyświetlanie buforowanych danych, które są kosztowne do pobrania, ale nie zmienia się często. W poniższym przykładzie pokazano użycie danych AllowUpdates prognozy pogody:
[PersistentState(AllowUpdates = true)]
public WeatherForecast[]? Forecasts { get; set; }
protected override async Task OnInitializedAsync()
{
Forecasts ??= await ForecastService.GetForecastAsync();
}
Aby pominąć przywracanie stanu podczas prerenderingu, ustaw wartość RestoreBehaviorSkipInitialValue:
[PersistentState(RestoreBehavior = RestoreBehavior.SkipInitialValue)]
public string NoPrerenderedData { get; set; }
Aby pominąć przywracanie stanu podczas ponownego nawiązywania połączenia, ustaw wartość RestoreBehaviorSkipLastSnapshot. Może to być przydatne, aby zapewnić nowe dane po ponownym połączeniu:
[PersistentState(RestoreBehavior = RestoreBehavior.SkipLastSnapshot)]
public int CounterNotRestoredOnReconnect { get; set; }
Wywołaj metodę PersistentComponentState.RegisterOnRestoring rejestrowania wywołania zwrotnego w celu imperatywnego kontrolowania sposobu przywracania stanu, podobnie jak PersistentComponentState.RegisterOnPersisting zapewnia pełną kontrolę nad stanem utrwalonego.
Blazor WebAssembly uwzględnia bieżące ustawienie kultury interfejsu użytkownika
W .NET 9 lub starszych wersjach aplikacje Blazor WebAssembly autonomicznie ładują zasoby globalizacji interfejsu użytkownika na podstawie CultureInfo.DefaultThreadCurrentCulture. Jeśli chcesz dodatkowo załadować dane globalizacji dla kultury lokalizacyjnej zdefiniowanej przez CultureInfo.DefaultThreadCurrentUICulture, zaktualizuj aplikację do .NET 10 lub nowszej.
Blazor Hybrid
W tej sekcji opisano nowe funkcje Blazor Hybrid.
Nowe .NET MAUIBlazor Hybrid z artykułem Blazor Web App i ASP.NET Core Identity oraz przykładem
Został dodany nowy artykuł i przykładowa aplikacja dla .NET MAUIBlazor Hybrid oraz aplikacji internetowej z użyciem ASP.NET Core Identity.
Aby uzyskać więcej informacji, zobacz następujące zasoby:
- .NET MAUI Blazor Hybrid i aplikacja internetowa z ASP.NET Core Identity
- przykładowa aplikacja
MauiBlazorWebIdentity(dotnet/blazor-samplesrepozytorium GitHub)
SignalR
W tej sekcji opisano nowe funkcje SignalR.
Minimalne API
W tej sekcji opisano nowe funkcje minimalnych interfejsów API.
Traktowanie pustego ciągu w formularzu jako wartości null dla typów wartości mogących przyjmować wartość null
W przypadku używania atrybutu [FromForm] z obiektem złożonym w minimalnych interfejsach API puste wartości ciągów w wpisie formularza są teraz konwertowane na null zamiast powodować błąd analizy. To zachowanie jest zgodne z logiką przetwarzania dla wpisów formularzy, które nie są skojarzone z obiektami złożonymi w minimalnych interfejsach API.
using Microsoft.AspNetCore.Http;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapPost("/todo", ([FromForm] Todo todo) => TypedResults.Ok(todo));
app.Run();
public class Todo
{
public int Id { get; set; }
public DateOnly? DueDate { get; set; } // Empty strings map to `null`
public string Title { get; set; }
public bool IsCompleted { get; set; }
}
Dzięki @nvmkpk za wniesienie tej zmiany!
Obsługa walidacji w minimalnych interfejsach API
Obsługa walidacji w minimalnych API jest teraz dostępna. Ta funkcja umożliwia żądanie weryfikacji danych wysyłanych do punktów końcowych interfejsu API. Włączenie walidacji umożliwia środowisku uruchomieniowemu ASP.NET Core wykonywanie wszelkich weryfikacji zdefiniowanych w następujących elementach:
- Query
- Header
- Ciało żądania
Walidacje są definiowane przy użyciu atrybutów w DataAnnotations przestrzeni nazw. Deweloperzy dostosują zachowanie systemu weryfikacji, wykonując następujące działania:
- Tworzenie implementacji atrybutów niestandardowych
[Validation]. - Implementowanie interfejsu dla złożonej
IValidatableObjectlogiki walidacji.
Jeśli walidacja zakończy się niepowodzeniem, środowisko uruchomieniowe zwróci odpowiedź 400 Nieprawidłowe żądanie ze szczegółami błędów walidacji.
Włączanie wbudowanej obsługi walidacji dla minimalnych interfejsów API
Włącz wbudowaną obsługę walidacji dla minimalnych interfejsów API, wywołując metodę AddValidation rozszerzenia w celu zarejestrowania wymaganych usług w kontenerze usługi dla aplikacji:
builder.Services.AddValidation();
Implementacja automatycznie odnajduje typy zdefiniowane w minimalnych programach obsługi interfejsu API lub jako podstawowe typy typów zdefiniowanych w minimalnych programach obsługi interfejsu API. Filtr punktu końcowego przeprowadza walidację tych typów i jest dodawany dla każdego punktu końcowego.
Walidację można wyłączyć dla określonych punktów końcowych przy użyciu DisableValidation metody rozszerzenia, jak w poniższym przykładzie:
app.MapPost("/products",
([EvenNumber(ErrorMessage = "Product ID must be even")] int productId, [Required] string name)
=> TypedResults.Ok(productId))
.DisableValidation();
Note
Wprowadzono kilka drobnych ulepszeń i poprawek generatora weryfikacji minimalnych interfejsów API wprowadzonych w ASP.NET Core dla platformy .NET 10. Aby zapewnić obsługę przyszłych ulepszeń, podstawowe interfejsy API narzędzia do rozpoznawania poprawności są teraz oznaczone jako eksperymentalne. Interfejsy API najwyższego poziomu AddValidation oraz wbudowany filtr weryfikacji pozostają stabilne i nie należą do eksperymentalnych.
Walidacja przy użyciu typów rekordów
Minimalne interfejsy API obsługują również walidację przy użyciu typów rekordów języka C#. Typy rekordów można zweryfikować przy użyciu atrybutów z System.ComponentModel.DataAnnotations przestrzeni nazw, podobnie jak w przypadku klas. Przykład:
public record Product(
[Required] string Name,
[Range(1, 1000)] int Quantity);
W przypadku używania typów rekordów jako parametrów w minimalnych punktach końcowych interfejsu API atrybuty weryfikacji są automatycznie stosowane w taki sam sposób jak typy klas:
app.MapPost("/products", (Product product) =>
{
// Endpoint logic here
return TypedResults.Ok(product);
});
Minimalna integracja weryfikacji interfejsu API z usługą IProblemDetailsService
Odpowiedzi na błędy z logiki walidacji dla Minimal API można teraz dostosować za pomocą implementacji dostarczonej w kolekcji usług aplikacji (kontenerze wstrzykiwania zależności). Umożliwia to bardziej spójne i specyficzne dla użytkownika odpowiedzi na błędy.
Wsparcie dla zdarzeń wysyłanych przez serwer (SSE)
ASP.NET Core obsługuje teraz zwracanie wyniku ServerSentEvents przy użyciu interfejsu API TypedResults.ServerSentEvents . Ta funkcja jest obsługiwana zarówno w przypadku minimalnych interfejsów API, jak i aplikacji opartych na kontrolerach.
Technologie Server-Sent Events to technologia aktywnego przesyłania danych przez serwer, która pozwala serwerowi na wysyłanie strumienia komunikatów o zdarzeniach do klienta za pomocą pojedynczego połączenia HTTP. Na platformie .NET komunikaty o zdarzeniach są reprezentowane jako SseItem<T> obiekty, które mogą zawierać typ zdarzenia, identyfikator i ładunek danych typu T.
Klasa TypedResults ma nową metodę statyczną o nazwie ServerSentEvents , która może służyć do zwracania ServerSentEvents wyniku. Pierwszym parametrem tej metody jest to IAsyncEnumerable<SseItem<T>> , który reprezentuje strumień komunikatów zdarzeń, które mają być wysyłane do klienta.
W poniższym przykładzie pokazano, jak używać interfejsu TypedResults.ServerSentEvents API do zwracania strumienia zdarzeń tętna jako obiektów JSON do klienta:
app.MapGet("/json-item", (CancellationToken cancellationToken) =>
{
async IAsyncEnumerable<HeartRateRecord> GetHeartRate(
[EnumeratorCancellation] CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
var heartRate = Random.Shared.Next(60, 100);
yield return HeartRateRecord.Create(heartRate);
await Task.Delay(2000, cancellationToken);
}
}
return TypedResults.ServerSentEvents(GetHeartRate(cancellationToken),
eventType: "heartRate");
});
Aby uzyskać więcej informacji, zobacz:
- Server-Sent Events na MDN.
-
Przykładowa aplikacja minimalnego interfejsu API korzystająca z interfejsu
TypedResults.ServerSentEventsAPI, aby zwrócić klientowi strumień zdarzeń tętna w postaci ciągów tekstowych oraz obiektów JSON. -
Przykładowa aplikacja interfejsu API kontrolera używająca interfejsu
TypedResults.ServerSentEventsAPI do zwracania strumienia zdarzeń tętna jako ciągów,ServerSentEventsi obiektów JSON do klienta.
Interfejsy API sprawdzania poprawności zostały przeniesione do pliku Microsoft.Extensions.Validation
Interfejsy API walidacji zostały przeniesione do przestrzeni nazw Microsoft.Extensions.Validation oraz pakietu NuGet. Ta zmiana sprawia, że interfejsy API mogą być używane poza scenariuszami http platformy ASP.NET Core. Publiczne interfejsy API i zachowanie pozostają niezmienione — tylko pakiet i przestrzeń nazw są inne. Istniejące projekty nie wymagają zmian w kodzie, ponieważ stare odwołania przekierowują do nowej implementacji.
Rozszerzona walidacja klas i rekordów
Atrybuty weryfikacji można teraz stosować zarówno do klas, jak i rekordów ze spójnym generowaniem kodu i zachowaniem walidacji. To ulepszenie zwiększa elastyczność podczas projektowania modeli przy użyciu rekordów w aplikacjach ASP.NET Core.
Wkład społeczności: Dzięki @marcominerva!
OpenAPI
W tej sekcji opisano nowe funkcje interfejsu OpenAPI.
Obsługa interfejsu OpenAPI 3.1
W ASP.NET Core dodano obsługę generowania dokumentów OpenAPI w wersji 3.1 w .NET 10. Pomimo niewielkiej aktualizacji wersji, OpenAPI 3.1 jest znaczącą aktualizacją specyfikacji OpenAPI, w szczególności z pełną obsługą wersji projektu schematu JSON 2020-12.
Niektóre zmiany widoczne w wygenerowanych dokumentach OpenAPI obejmują:
- Typy dopuszczające wartości null nie mają już właściwości
nullable: truew schemacie. - Zamiast właściwości
nullable: truemają słowo kluczowetype, którego wartość jest tablicą zawierającąnulljako jeden z typów. - Właściwości lub parametry zdefiniowane jako C#
intlublongteraz są wyświetlane w wygenerowanym dokumencie OpenAPI beztype: integerpola i mająpatternpole ograniczające wartość do cyfr. Dzieje się tak, gdy właściwość NumberHandling w JsonSerializerOptions jest ustawiona naAllowReadingFromString, co jest wartością domyślną dla aplikacji webowych ASP.NET Core. Aby umożliwić językowi C#intorazlong, aby były reprezentowane w dokumencie OpenAPI jakotype: integer, ustaw właściwość NumberHandling naStrict.
W przypadku tej funkcji domyślna wersja interfejsu OpenAPI dla wygenerowanych dokumentów jest3.1. Wersję można zmienić, ustawiając jawnie właściwość OpenApiVersion elementu OpenApiOptions w parametrze delegowanym configureOptionsaddOpenApi:
builder.Services.AddOpenApi(options =>
{
options.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_1;
});
Podczas generowania dokumentu OpenAPI w czasie kompilacji, wersję OpenAPI można wybrać, ustawiając element --openapi-version w MSBuild OpenApiGenerateDocumentsOptions.
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
<!-- Configure build-time OpenAPI generation to produce an OpenAPI 3.1 document. -->
<OpenApiGenerateDocumentsOptions>--openapi-version OpenApi3_1</OpenApiGenerateDocumentsOptions>
</PropertyGroup>
Obsługa OpenAPI 3.1 została głównie dodana w następującym pull request .
Zmiany łamiące zgodność OpenAPI 3.1
Obsługa interfejsu OpenAPI 3.1 wymaga aktualizacji podstawowej biblioteki OpenAPI.NET do nowej wersji głównej 2.0. Ta nowa wersja ma pewne zmiany wprowadzające niekompatybilności z poprzednią wersją. Zmiany powodujące niezgodność mogą mieć wpływ na te aplikacje, jeśli mają jakiekolwiek transformatory dokumentów, operacji lub schematów. Zmiany łamiące zgodność w tej iteracji obejmują następujące elementy:
- Jednostki w dokumencie OpenAPI, takie jak operacje i parametry, są wpisywane jako interfejsy. Istnieją konkretne implementacje dla wbudowanych i przywoływanych wariantów jednostki. Na przykład
IOpenApiSchemamoże być wbudowanymOpenApiSchemalubOpenApiSchemaReferencewskazującym schemat zdefiniowany w innym miejscu dokumentu. - Właściwość
Nullablezostała usunięta z typuOpenApiSchema. Aby określić, czy typ ma wartość null, sprawdź, czy właściwośćOpenApiSchema.TypeustawiaJsonSchemaType.Null.
Jedną z najważniejszych zmian jest to, że klasa OpenApiAny została odrzucona na rzecz bezpośredniego używania JsonNode. Aby można było używać OpenApiAny, należy zaktualizować transformatory używające JsonNode . Poniżej przedstawiono różnice w transformatorze schematów z .NET 9 na .NET 10:
options.AddSchemaTransformer((schema, context, cancellationToken) =>
{
if (context.JsonTypeInfo.Type == typeof(WeatherForecast))
{
- schema.Example = new OpenApiObject
+ schema.Example = new JsonObject
{
- ["date"] = new OpenApiString(DateTime.Now.AddDays(1).ToString("yyyy-MM-dd")),
+ ["date"] = DateTime.Now.AddDays(1).ToString("yyyy-MM-dd"),
- ["temperatureC"] = new OpenApiInteger(0),
+ ["temperatureC"] = 0,
- ["temperatureF"] = new OpenApiInteger(32),
+ ["temperatureF"] = 32,
- ["summary"] = new OpenApiString("Bracing"),
+ ["summary"] = "Bracing",
};
}
return Task.CompletedTask;
});
Należy pamiętać, że te zmiany są niezbędne nawet w przypadku konfigurowania tylko wersji interfejsu OpenAPI do wersji 3.0.
OpenAPI w języku YAML
ASP.NET obsługuje teraz obsługę wygenerowanego dokumentu OpenAPI w formacie YAML. Kod YAML może być bardziej zwięzły niż JSON, eliminując nawiasy klamrowe i znaki cudzysłowu, gdy można je wywnioskować z kontekstu. Język YAML obsługuje również ciągi wielowierszowe, które mogą być przydatne dla długich opisów tekstowych.
Aby skonfigurować aplikację do obsługi wygenerowanego dokumentu OpenAPI w formacie YAML, określ punkt końcowy w wywołaniu MapOpenApi z sufiksem ".yaml" lub ".yml", jak pokazano w poniższym przykładzie:
if (app.Environment.IsDevelopment())
{
app.MapOpenApi("/openapi/{documentName}.yaml");
}
Wsparcie dla:
- YAML jest obecnie dostępny tylko dla interfejsu OpenAPI obsługiwanego z punktu końcowego OpenAPI.
- Generowanie dokumentów OpenAPI w formacie YAML w czasie kompilacji jest dodawane w przyszłej wersji zapoznawczej.
Zobacz to żądanie zmiany, które dodało obsługę udostępniania wygenerowanego dokumentu OpenAPI w formacie YAML.
Opis odpowiedzi kontrolerów interfejsu API na ProducesResponseType
Parametr ProducesAttribute, ProducesResponseTypeAttributei ProducesDefaultResponseTypeAttribute teraz akceptuje opcjonalny parametr ciągu , Descriptionktóry ustawia opis odpowiedzi:
[HttpGet(Name = "GetWeatherForecast")]
[ProducesResponseType<IEnumerable<WeatherForecast>>(StatusCodes.Status200OK,
Description = "The weather forecast for the next 5 days.")]
public IEnumerable<WeatherForecast> Get()
{
Wygenerowane dane interfejsu OpenAPI:
"responses": {
"200": {
"description": "The weather forecast for the next 5 days.",
"content": {
Ta funkcja jest obsługiwana zarówno w kontrolerach interfejsów API , jak i minimalnych interfejsach API. W przypadku minimalnych interfejsów API właściwość Description jest poprawnie ustawiana, nawet gdy typ atrybutu i wnioskowany typ zwracania nie są dokładnym dopasowaniem.
Wkład społeczności (dotnet/aspnetcore #58193)autorstwa Sander ten Brinke.
Przenoszenie komentarzy dokumentu XML w dokument OpenAPI
Generowanie dokumentów OpenAPI w ASP.NET Core będzie teraz zawierać metadane z komentarzy XML do metod, klas i składowych w dokumencie OpenAPI. Aby korzystać z tej funkcji, musisz włączyć komentarze do dokumentu XML w pliku projektu. Można to zrobić, dodając następującą właściwość do pliku projektu:
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
W czasie kompilacji pakiet OpenAPI będzie używać generatora źródła do odnajdywania komentarzy XML w bieżącym zestawie aplikacji i wszelkich odwołań do projektu i emitowania kodu źródłowego w celu wstawienia ich do dokumentu za pomocą transformatora dokumentu OpenAPI.
Należy pamiętać, że proces kompilacji języka C# nie przechwytuje komentarzy dokumentacji XML umieszczonych na wyrażeniach lambda, więc aby użyć komentarzy dokumentacji XML do dodania metadanych do punktu końcowego Minimalnego API, musisz zdefiniować obsługę punktu końcowego jako metodę, umieścić komentarze dokumentacji XML w tej metodzie, a następnie odwołać się do tej metody z metody MapXXX. Aby na przykład użyć komentarzy do dokumentu XML w celu dodania metadanych do minimalnego punktu końcowego interfejsu API pierwotnie zdefiniowanego jako wyrażenie lambda:
app.MapGet("/hello", (string name) =>$"Hello, {name}!");
Zmień wywołanie MapGet w celu odwołania się do metody:
app.MapGet("/hello", Hello);
Zdefiniuj metodę Hello z komentarzami doc XML:
static partial class Program
{
/// <summary>
/// Sends a greeting.
/// </summary>
/// <remarks>
/// Greeting a person by their name.
/// </remarks>
/// <param name="name">The name of the person to greet.</param>
/// <returns>A greeting.</returns>
public static string Hello(string name)
{
return $"Hello, {name}!";
}
}
W poprzednim przykładzie metoda Hello jest dodawana do klasy Program, ale można dodać ją do dowolnej klasy w projekcie.
W poprzednim przykładzie przedstawiono komentarze doc <summary>, <remarks>i <param> w pliku XML.
Aby uzyskać więcej informacji na temat komentarzy doc XML, w tym wszystkich obsługiwanych tagów, zobacz dokumentację C#.
Ponieważ podstawowe funkcje są udostępniane za pośrednictwem generatora źródłowego, można ją wyłączyć, dodając następujący program MSBuild do pliku projektu.
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0-preview.2.*" GeneratePathProperty="true" />
</ItemGroup>
<Target Name="DisableCompileTimeOpenApiXmlGenerator" BeforeTargets="CoreCompile">
<ItemGroup>
<Analyzer Remove="$(PkgMicrosoft_AspNetCore_OpenApi)/analyzers/dotnet/cs/Microsoft.AspNetCore.OpenApi.SourceGenerators.dll" />
</ItemGroup>
</Target>
Proces generatora źródłowego obsługuje pliki XML zawarte we właściwości AdditionalFiles. Aby dodać (lub usunąć), źródła modyfikują właściwość w następujący sposób:
<Target Name="AddXmlSources" BeforeTargets="CoreCompile">
<ItemGroup>
<AdditionalFiles Include="$(PkgSome_Package)/lib/net10.0/Some.Package.xml" />
</ItemGroup>
</Target>
Dodano Microsoft.AspNetCore.OpenApi do szablonu interfejsu API internetowego (natywnego AOT) ASP.NET Core.
Szablon projektu ASP.NET Core Web API (Native AOT) (krótka nazwa webapiaot) obejmuje teraz obsługę generowania dokumentów OpenAPI przy użyciu Microsoft.AspNetCore.OpenApi pakietu domyślnie. Ta obsługa jest wyłączona przy użyciu flagi --no-openapi podczas tworzenia nowego projektu.
Wkład społeczności (dotnet/aspnetcore #60337)autorstwa Sander ten Brinke.
Obsługa elementu IOpenApiDocumentProvider w kontenerze DI.
ASP.NET Core na platformie .NET 10 obsługuje element IOpenApiDocumentProvider w kontenerze wstrzykiwania zależności (DI). Deweloperzy mogą wstrzykiwać IOpenApiDocumentProvider do swoich aplikacji i używać ich do uzyskiwania dostępu do dokumentu OpenAPI. Takie podejście jest przydatne w przypadku uzyskiwania dostępu do dokumentów OpenAPI poza kontekstem żądań HTTP, takich jak usługi w tle lub niestandardowe oprogramowanie pośredniczące.
Wcześniej uruchamianie logiki startowej aplikacji bez uruchamiania serwera HTTP można było przeprowadzić przy użyciu HostFactoryResolver z implementacją no-op IServer. Nowa funkcja upraszcza ten proces, zapewniając usprawniony interfejs API inspirowany modułem Aspire w ramach IDistributedApplicationPublisher, który stanowi część struktury Aspire do hostingu i publikowania rozproszonych aplikacji.
Aby uzyskać więcej informacji, zobacz dotnet/aspnetcore #61463.
Ulepszenia generatora komentarzy XML
Generowanie komentarzy XML obsługuje złożone typy na platformie .NET 10 lepiej niż starsze wersje platformy .NET.
- Tworzy dokładne i kompletne komentarze XML dla szerszego zakresu typów.
- Obsługuje bardziej złożone scenariusze.
- Bezpiecznie pomija przetwarzanie złożonych typów, które powodują błędy kompilacji we wcześniejszych wersjach.
Te ulepszenia zmieniają tryb awarii dla niektórych scenariuszy z błędów kompilacji na brakujące metadane.
Ponadto przetwarzanie komentarzy doc XML można teraz skonfigurować pod kątem dostępu do komentarzy XML w innych zestawach. Jest to przydatne do generowania dokumentacji dla typów zdefiniowanych poza bieżącym zestawem, takich jak typ ProblemDetails w przestrzeni nazw Microsoft.AspNetCore.Http.
Ta konfiguracja jest wykonywana z dyrektywami w pliku kompilacji projektu. W poniższym przykładzie pokazano, jak skonfigurować generator komentarzy XML w celu uzyskania dostępu do komentarzy XML dla typów w Microsoft.AspNetCore.Http zestawie, który zawiera klasę ProblemDetails .
<Target Name="AddOpenApiDependencies" AfterTargets="ResolveReferences">
<ItemGroup>
<!-- Include XML documentation from Microsoft.AspNetCore.Http.Abstractions
to get metadata for ProblemDetails -->
<AdditionalFiles
Include="@(ReferencePath->'
%(RootDir)%(Directory)%(Filename).xml')"
Condition="'%(ReferencePath.Filename)' ==
'Microsoft.AspNetCore.Http.Abstractions'"
KeepMetadata="Identity;HintPath" />
</ItemGroup>
</Target>
Oczekujemy, że w przyszłych wersjach próbnych uwzględnimy komentarze XML z wybranego zbioru bibliotek w ramach współdzielonego frameworka, co pozwoli uniknąć potrzeby tej konfiguracji w większości przypadków.
Ujednolicone zarządzanie identyfikatorami dokumentacji w generatorze komentarzy XML interfejsu OpenAPI
Komentarze dokumentacji XML z odwoływanych zestawów są prawidłowo łączone nawet wtedy, gdy ich identyfikatory dokumentacji zawierają sufiksy zwracanych typów. W związku z tym wszystkie prawidłowe komentarze XML są niezawodnie uwzględniane w wygenerowanej dokumentacji OpenAPI, co poprawia dokładność i kompletność dokumentacji dla interfejsów API, wykorzystując odwoływane zestawy.
Parametry typu wyliczeniowego danych formularza wykorzystują rzeczywisty typ wyliczeniowy w OpenAPI
Parametry danych formularza w akcjach kontrolera MVC teraz generują metadane OpenAPI, używając rzeczywistego typu wyliczenia zamiast domyślnego ciągu.
Wkład społeczności: Dzięki @ascott18!
Obsługa generowania funkcji OpenApiSchemas w transformatorach
Deweloperzy mogą teraz wygenerować schemat dla typu C# przy użyciu tej samej logiki co generowanie dokumentu OpenAPI w języku ASP.NET Core i dodać go do dokumentu OpenAPI. Następnie można odwoływać się do schematu z innego miejsca w dokumencie OpenAPI.
Kontekst przekazywany do przekształtników dokumentów, operacji i schematu zawiera nową metodę GetOrCreateSchemaAsync, która może być używana do generowania schematu dla określonego typu.
Ta metoda ma również opcjonalny ApiParameterDescription parametr służący do określania dodatkowych metadanych dla wygenerowanego schematu.
Aby umożliwić dodawanie schematu do dokumentu OpenAPI, Document właściwość została dodana do kontekstów przekształcania operacji i schematu. Dzięki temu dowolny transformator może dodać schemat do dokumentu OpenAPI przy użyciu metody dokumentu AddComponent .
Example
Aby użyć tej funkcji w dokumencie, operacji lub transformatorze schematu, utwórz schemat przy użyciu metody podanej w kontekście i dodaj go do dokumentu OpenAPI, używając metody dokumentu GetOrCreateSchemaAsyncAddComponent.
builder.Services.AddOpenApi(options =>
{
options.AddOperationTransformer(async (operation, context, cancellationToken) =>
{
// Generate schema for error responses
var errorSchema = await context.GetOrCreateSchemaAsync(typeof(ProblemDetails), null, cancellationToken);
context.Document?.AddComponent("Error", errorSchema);
operation.Responses ??= new OpenApiResponses();
// Add a "4XX" response to the operation with the newly created schema
operation.Responses["4XX"] = new OpenApiResponse
{
Description = "Bad Request",
Content = new Dictionary<string, OpenApiMediaType>
{
["application/problem+json"] = new OpenApiMediaType
{
Schema = new OpenApiSchemaReference("Error", context.Document)
}
}
};
});
});
Transformatory operacji OpenAPI specyficzne dla punktu końcowego
Transformatory operacji specyficznych dla punktów końcowych umożliwiają szczegółowe dostosowanie dokumentacji OpenAPI dla poszczególnych tras. Ta funkcja umożliwia deweloperom dostosowywanie metadanych i opisów struktury Swagger/OpenAPI na podstawie akcji lub trasy, co zwiększa rozszerzalność zaawansowanych scenariuszy interfejsu API.
Aby uzyskać szczegółowe informacje o implementacji i przykłady kodu, zobacz Dostosowywanie dokumentów interfejsu OpenAPI.
Uaktualnianie interfejsu Microsoft.OpenApi do wersji 2.0.0
Biblioteka Microsoft.OpenApi używana do generowania dokumentów OpenAPI w programie ASP.NET Core została uaktualniona do wersji 2.0.0 (GA).
Zmiany powodujące niezgodność w wersji 2.0.0
Następujące zmiany powodujące niezgodność zostały wprowadzone w wersjach zapoznawczych i pozostają w wersji ogólnodostępnej. Mają one wpływ głównie na użytkowników, którzy implementują przekształcanie dokumentów, operacji lub schematu:
- Właściwości obiektu efemerycznego znajdują się teraz w metadanych
- Używanie obiektu metody HTTP zamiast wyliczenia
W przypadku aktualizacji do wersji ogólnie dostępnej żadne dalsze zmiany powodujące niezgodność nie są oczekiwane w generowaniu dokumentów OpenAPI.
Ulepszenia generowania schematów interfejsu OpenAPI
Modelowanie typów nullowalnych przy użyciu konstruktu oneOf w schemacie OpenAPI
Ulepszone generowanie schematu OpenAPI przy użyciu wzorca oneOf dla nulowalnych typów zamiast właściwości nulowalnej dla typów złożonych i kolekcji. Implementacja:
- Używa
oneOfrazem znulloraz rzeczywistego schematu typu dla typów złożonych, które mogą mieć wartość null w schematach żądań i odpowiedzi. - Wykrywa nullowalność parametrów, właściwości i typów zwracanych przy użyciu reflection i
NullabilityInfoContext. - Usuwa typy null ze schematów składowych, aby uniknąć duplikowania.
Poprawki i ulepszenia dotyczące rozwiązywania odwołań do schematu
Ta wersja usprawnia obsługę schematów JSON dla generowania dokumentów OpenAPI przez prawidłowe rozpoznawanie odwołań schematu względnego JSON ($ref) w głównym dokumencie schematu.
Dołączanie opisów właściwości jako elementów równorzędnych $ref w schemacie interfejsu OpenAPI
Przed wersją .NET 10 ASP.NET Core odrzucał opisy właściwości zdefiniowanych $ref w wygenerowanym dokumencie OpenAPI, ponieważ OpenAPI v3.0 nie pozwalało na równorzędne właściwości obok $ref definicji w schemacie. OpenAPI 3.1 umożliwia teraz dołączanie opisów razem z $ref. RC1 dodaje obsługę dodawania opisów właściwości jako elementów równorzędnych $ref w wygenerowanym schemacie OpenAPI.
To był wkład społeczności. Dziękujemy @desjoerd!
Dodaj metadane z komentarzy XML na temat typów [AsParameters] do schematu OpenAPI.
Generowanie schematu interfejsu OpenAPI przetwarza teraz komentarze XML dotyczące właściwości klas parametrów [AsParameters] w celu wyodrębnienia metadanych dla dokumentacji.
Wykluczanie nieznanych metod HTTP z interfejsu OpenAPI
Generowanie schematu interfejsu OpenAPI wyklucza teraz nieznane metody HTTP z wygenerowanego dokumentu OpenAPI. Metody zapytań, które są standardowymi metodami HTTP, ale nie są rozpoznawane przez interfejs OpenAPI, są teraz bezpiecznie wykluczone z wygenerowanego dokumentu OpenAPI.
To był wkład społeczności. Dziękujemy @martincostello!
Ulepszanie opisu treści żądań poprawek JSON
Generowanie schematu OpenAPI dla operacji JSON Patch teraz prawidłowo stosuje typ nośnika application/json-patch+json do treści żądań używających JSON Patch. Dzięki temu wygenerowany dokument OpenAPI dokładnie odzwierciedla oczekiwany typ nośnika dla operacji poprawek JSON. Ponadto treść żądania poprawki JSON zawiera szczegółowy schemat opisujący strukturę dokumentu poprawki JSON, w tym operacje, które można wykonać.
To był wkład społeczności. Dziękujemy @martincostello!
Używanie niezmiennej kultury na potrzeby generowania dokumentów OpenAPI
Generowanie dokumentów openAPI używa teraz niezmiennej kultury do formatowania liczb i dat w wygenerowanym dokumencie OpenAPI. Dzięki temu wygenerowany dokument jest spójny i nie różni się w zależności od ustawień kultury serwera.
To był wkład społeczności. Dziękujemy @martincostello!
Uwierzytelnianie i autoryzacja
Metryki uwierzytelniania i autoryzacji
Metryki zostały dodane dla niektórych zdarzeń uwierzytelniania i autoryzacji w ASP.NET Core. Dzięki tej zmianie można teraz uzyskać metryki dla następujących zdarzeń:
- Authentication:
- Czas trwania uwierzytelnionych żądań
- Liczba wyzwań
- Zabroń liczenie
- Liczba logowań
- Liczba wylogowań
- Authorization:
- Liczba żądań wymagających autoryzacji
Na poniższej ilustracji przedstawiono przykład metryki czasu trwania żądania uwierzytelnionego na pulpicie nawigacyjnym Aspire.
Aby uzyskać więcej informacji, zobacz ASP.NET Core wbudowane metryki.
Metryki ASP.NET Core Identity
ASP.NET Core Identity ulepszono możliwość obserwowania na platformie .NET 10 z metrykami. Metryki to liczniki, histogramy i mierniki, które zapewniają pomiary szeregów czasowych zachowania systemu lub aplikacji.
Na przykład użyj nowych metryk ASP.NET Core Identity do obserwowania:
- Zarządzanie użytkownikami: nowe tworzenie użytkowników, zmiany haseł i przypisania ról.
- Obsługa logowania/sesji: próby logowania, logowania, wylogowywanie i użytkownicy korzystający z uwierzytelniania dwuskładnikowego.
Nowe metryki znajdują się w mierniku Microsoft.AspNetCore.Identity :
aspnetcore.identity.user.create.durationaspnetcore.identity.user.update.durationaspnetcore.identity.user.delete.durationaspnetcore.identity.user.check_password_attemptsaspnetcore.identity.user.generated_tokensaspnetcore.identity.user.verify_token_attemptsaspnetcore.identity.sign_in.authenticate.durationaspnetcore.identity.sign_in.check_password_attemptsaspnetcore.identity.sign_in.sign_insaspnetcore.identity.sign_in.sign_outsaspnetcore.identity.sign_in.two_factor_clients_rememberedaspnetcore.identity.sign_in.two_factor_clients_forgotten
Aby uzyskać więcej informacji na temat używania metryk w usłudze ASP.NET Core, zobacz ASP.NET Core metrics (Metryki podstawowe usługi ASP.NET Core).
Unikaj cookie przekierowań logowania dla znanych punktów końcowych API
Domyślnie nieuwierzytelnione i nieautoryzowane żądania wysyłane do znanych punktów końcowych interfejsu API chronionych przez cookie uwierzytelnianie powodują teraz odpowiedzi 401 lub 403 zamiast przekierowywania do logowania lub odmowy dostępu na URI.
Ta zmiana była bardzo żądana, ponieważ przekierowywanie nieuwierzytelnionych żądań do strony logowania zwykle nie ma sensu w przypadku punktów końcowych interfejsu API, które zwykle korzystają z kodów stanu 401 i 403, a nie przekierowań HTML do przekazywania błędów uwierzytelniania.
Znane punkty końcowe interfejsu API są identyfikowane przy użyciu nowego IApiEndpointMetadata interfejsu, a metadane implementowania nowego interfejsu zostały dodane automatycznie do następujących elementów:
-
[ApiController]Punkty końcowe - Minimalne punkty końcowe interfejsu API odczytujące treści żądań JSON lub zapisujące odpowiedzi JSON
- Punkty końcowe korzystające z
TypedResultstypów wartości zwracanych - SignalR Punkty końcowe
Gdy IApiEndpointMetadata jest obecny, cookie program obsługi uwierzytelniania zwraca teraz odpowiednie kody stanu HTTP (401 dla nieuwierzytelnionych żądań, 403 dla niedozwolonych żądań) zamiast przekierowywania.
Jeśli chcesz zapobiec temu nowemu zachowaniu i zawsze przekierowujesz do URI logowania i URI odmowy dostępu dla niezalogowanych lub nieautoryzowanych żądań niezależnie od docelowego punktu końcowego, możesz nadpisać zdarzenia RedirectToLogin i RedirectToAccessDenied w następujący sposób:
builder.Services.AddAuthentication()
.AddCookie(options =>
{
options.Events.OnRedirectToLogin = context =>
{
context.Response.Redirect(context.RedirectUri);
return Task.CompletedTask;
};
options.Events.OnRedirectToAccessDenied = context =>
{
context.Response.Redirect(context.RedirectUri);
return Task.CompletedTask;
};
});
Aby uzyskać więcej informacji na temat tej zmiany krytycznej, zobacz ogłoszenie o zmianach krytycznych w ASP.NET Core.
Miscellaneous
W tej sekcji opisano różne nowe funkcje na platformie .NET 10.
Konfigurowanie pomijania diagnostyki programu obsługi wyjątków
Dodano nową opcję konfiguracji do oprogramowania pośredniczącego (middleware) programu obsługi wyjątków platformy ASP.NET Core w celu kontrolowania danych diagnostycznych wyjściowych: ExceptionHandlerOptions.SuppressDiagnosticsCallback. Ten kontekst wywołania zwrotnego jest przekazywany w kontekście żądania i wyjątku, co umożliwia dodanie logiki określającej, czy oprogramowanie pośredniczące powinno zapisywać dzienniki wyjątków i inne dane telemetryczne.
To ustawienie jest przydatne, gdy wiadomo, że wyjątek jest przejściowy lub został obsłużony przez oprogramowanie pośredniczące obsługi wyjątków i nie chcesz, aby dzienniki błędów były zapisywane na platformie możliwości obserwowania.
Domyślne zachowanie oprogramowania pośredniczącego również uległo zmianie: nie zapisuje już diagnostyki wyjątków dla wyjątków obsługiwanych przez IExceptionHandlerprogram . Na podstawie opinii użytkowników rejestrowanie obsłużonych wyjątków na poziomie błędu było często niepożądane, gdy IExceptionHandler.TryHandleAsync zwrócił true.
Możesz przywrócić poprzednie zachowanie, konfigurując element SuppressDiagnosticsCallback:
app.UseExceptionHandler(new ExceptionHandlerOptions
{
SuppressDiagnosticsCallback = context => false;
});
Aby uzyskać więcej informacji na temat tej zmiany powodującej niezgodność, zobacz https://github.com/aspnet/Announcements/issues/524.
Obsługa domeny .localhost Top-Level
Domena .localhost najwyższego poziomu (TLD) jest definiowana w RFC2606 i RFC6761 jako zarezerwowana do celów testowych i dostępna dla użytkowników do używania lokalnie, tak jak każda inna nazwa domeny. Oznacza to, że użycie nazwy takiej jak myapp.localhost lokalnie, odpowiadającej adresowi pętli zwrotnej IP, jest dozwolone i oczekiwane zgodnie z tymi RFC. Ponadto nowoczesne przeglądarki evergreen już automatycznie rozpoznają dowolną *.localhost nazwę adresu sprzężenia zwrotnego adresu IP (127.0.0.1/::1), co skutecznie czyni je aliasem dla dowolnej usługi już hostowanej localhost na komputerze lokalnym, czyli każda usługa http://localhost:6789 odpowiadająca na nie odpowie również na http://anything-here.localhost:6789, zakładając, że usługa nie będzie wykonywać dalszej konkretnej weryfikacji nazwy hosta lub wymuszania przez usługę.
ASP.NET Core został zaktualizowany na platformie .NET 10 (wersja zapoznawcza 7), aby lepiej obsługiwać .localhost tlD, dzięki czemu można go teraz łatwo używać podczas tworzenia i uruchamiania aplikacji ASP.NET Core w lokalnym środowisku projektowym. Używanie różnych aplikacji działających lokalnie za pośrednictwem różnych nazw umożliwia lepsze rozdzielenie niektórych zasobów witryny internetowej skojarzonych z nazwą domeny, np. plików cookie i ułatwia zidentyfikowanie aplikacji przeglądanej za pośrednictwem nazwy wyświetlanej na pasku adresu przeglądarki.
ASP.NET Core wbudowany serwer HTTP, Kestrel, będzie teraz prawidłowo traktować nazwę ustawioną przy użyciu dowolnego z *.localhost za pośrednictwem obsługiwanych mechanizmów konfiguracji punktu końcowego jako lokalny adres sprzężenia zwrotnego, a tym samym powiązać się z nim, zamiast ze wszystkimi adresami zewnętrznymi (tj. powiązać z 127.0.0.1/::1 zamiast z 0.0.0.0/::).
"applicationUrl" Obejmuje to właściwość w profilach uruchamiania skonfigurowanych w pliku launchSettings.jsoni zmiennej środowiskowejASPNETCORE_URLS. Jeśli skonfigurowano nasłuchiwanie adresu .localhost , Kestrel będzie rejestrować komunikat informacyjny dla adresów .localhostilocalhost , aby wyjaśnić, że można użyć obu nazw.
Podczas gdy przeglądarki internetowe automatycznie rozpoznają *.localhost nazwy lokalnego adresu sprzężenia zwrotnego, inne aplikacje mogą traktować *.localhost nazwy jako zwykłe nazwy domen i próbować je rozpoznać za pośrednictwem odpowiedniego stosu DNS. Jeśli konfiguracja DNS nie rozpoznaje *.localhost nazw na adres, nie można nawiązać połączenia. Możesz nadal używać regularnej localhost nazwy, aby adresować aplikacje, gdy nie ma ich w przeglądarce internetowej.
Certyfikat ASP.NET Core HTTPS dla deweloperów (łącznie z poleceniami dotnet dev-certs https) zostały zaktualizowane, aby upewnić się, że certyfikat jest prawidłowy do użycia z nazwą domeny *.dev.localhost. Po zainstalowaniu zestawu .NET 10 SDK (wersja zapoznawcza 7) ufaj nowemu certyfikatowi dewelopera, uruchamiając polecenie dotnet dev-certs https --trust w wierszu polecenia, aby upewnić się, że system jest skonfigurowany do zaufania nowemu certyfikatowi.
Certyfikat wyświetla *.dev.localhost nazwę jako alternatywną nazwę podmiotu (SAN), a nie *.localhost dlatego, że używanie certyfikatu z symbolami wieloznacznymi dla nazwy domeny najwyższego poziomu jest nieprawidłowe.
Szablony projektów dla ASP.NET Core Empty (web) i Blazor Web App (blazor) zostały zaktualizowane przy użyciu nowej opcji, która po określeniu konfiguruje utworzony projekt do używania .dev.localhost sufiksu nazwy domeny, łącząc ją z nazwą projektu, aby umożliwić przeglądanie aplikacji pod adresem takim jak https://myapp.dev.localhost:5036:
$ dotnet new web -n MyApp --localhost-tld
The template "ASP.NET Core Empty" was created successfully.
Processing post-creation actions...
Restoring D:\src\MyApp\MyApp.csproj:
Restore succeeded.
$ cd .\MyApp\
$ dotnet run --launch-profile https
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://myapp.dev.localhost:7099
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7099/
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://myapp.dev.localhost:5036
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5036/
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: D:\src\local\10.0.1xx\MyApp
Obsługa deserializacji Json+PipeReader w wzorcach MVC i minimalnych interfejsach API
PR: https://github.com/dotnet/aspnetcore/pull/62895
MVC, Minimal APIs i HttpRequestJsonExtensions.ReadFromJsonAsync zostały zaktualizowane w celu korzystania z obsługi Json+PipeReader bez potrzeby wprowadzania zmian w kodzie przez aplikacje.
W przypadku większości aplikacji dodanie tej obsługi nie ma wpływu na ich zachowanie. Jeśli jednak aplikacja używa niestandardowego JsonConverterelementu , istnieje prawdopodobieństwo, że konwerter nie obsługuje Utf8JsonReader.HasValueSequence poprawnie. Może to spowodować brak danych i błędów, takich jak ArgumentOutOfRangeException, podczas deserializacji.
Szybkie obejście (zwłaszcza jeśli nie jesteś właścicielem używanego niestandardowego) JsonConverter polega na ustawieniu przełącznika "Microsoft.AspNetCore.UseStreamBasedJsonParsing"AppContext na "true". Powinno to być tymczasowe obejście, a element powinien zostać zaktualizowany JsonConverter w celu obsługi HasValueSequenceprogramu .
Aby naprawić JsonConverter implementacje, istnieje szybka poprawka, która przydziela tablicę z obiektu ReadOnlySequence i wyglądałaby jak w poniższym przykładzie:
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
// previous code
}
Istnieje również bardziej skomplikowana (ale wydajna) poprawka, która wymaga oddzielnej ReadOnlySequence ścieżki kodu do obsługi:
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.HasValueSequence)
{
reader.ValueSequence;
// ReadOnlySequence optimized path
}
else
{
reader.ValueSpan;
// ReadOnlySpan optimized path
}
}
Automatyczna eksmisja z puli pamięci
Pule pamięci używane przez Kestrel, usługi IIS i HTTP.sys teraz automatycznie usuwają bloki pamięci, gdy aplikacja jest bezczynna lub podlega mniejszemu obciążeniu. Funkcja jest uruchamiana automatycznie i nie musi być włączona ani skonfigurowana ręcznie.
Dlaczego usuwanie pamięci ma znaczenie
Wcześniej pamięć przydzielona przez pulę pozostawała zarezerwowana, nawet jeśli nie była używana. Ta funkcja zwalnia pamięć z powrotem do systemu, gdy aplikacja jest bezczynna przez pewien czas. To usunięcie zmniejsza ogólne użycie pamięci i pomaga aplikacjom zachować responsywność podczas różnych obciążeń.
Użycie metryk eksmisji pamięci
Metryki zostały dodane do domyślnej puli pamięci używanej przez implementacje serwera. Nowe metryki są pod nazwą "Microsoft.AspNetCore.MemoryPool".
Aby uzyskać informacje o metrykach i sposobie ich używania, zobacz ASP.NET Metryki podstawowe.
Zarządzanie pulami pamięci
Poza bardziej wydajnym używaniem pul pamięci przez eksmitowanie niepotrzebnych bloków pamięci, platforma .NET 10 poprawia środowisko tworzenia pul pamięci. Robi to przez udostępnienie wbudowanego komponentu IMemoryPoolFactory oraz implementacji MemoryPoolFactory. Dzięki iniekcji zależności implementacja jest dostępna dla aplikacji.
Poniższy przykład kodu przedstawia prostą usługę działającą w tle, która używa wbudowanej implementacji fabryki puli pamięci do tworzenia pul pamięci. Te pule korzystają z funkcji automatycznego eksmitowania:
public class MyBackgroundService : BackgroundService
{
private readonly MemoryPool<byte> _memoryPool;
public MyBackgroundService(IMemoryPoolFactory<byte> factory)
{
_memoryPool = factory.Create();
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
await Task.Delay(20, stoppingToken);
// do work that needs memory
var rented = _memoryPool.Rent(100);
rented.Dispose();
}
catch (OperationCanceledException)
{
return;
}
}
}
}
Aby użyć własnej fabryki puli pamięci, stwórz klasę implementującą IMemoryPoolFactory i zarejestruj ją za pomocą iniekcji zależności, jak w poniższym przykładzie. Pule pamięci utworzone w ten sposób nie korzystają z funkcji automatycznego usuwania, chyba że implementujesz podobną logikę usuwania w fabryce dostosowanej.
services.AddSingleton<IMemoryPoolFactory<byte>,
CustomMemoryPoolFactory>();
public class CustomMemoryPoolFactory : IMemoryPoolFactory<byte>
{
public MemoryPool<byte> Create()
{
// Return a custom MemoryPool implementation
// or the default, as is shown here.
return MemoryPool<byte>.Shared;
}
}
Dostosowywalne deskryptory zabezpieczeń dla HTTP.sys
Teraz można określić niestandardowy deskryptor zabezpieczeń dla kolejek żądań HTTP.sys. Nowa właściwość RequestQueueSecurityDescriptor w systemie HttpSysOptions umożliwia bardziej szczegółową kontrolę nad prawami dostępu do kolejki żądań. Ta szczegółowa kontrola umożliwia dostosowanie zabezpieczeń do potrzeb aplikacji.
Co można zrobić za pomocą nowej właściwości
Kolejka żądań w HTTP.sys to struktura na poziomie jądra, która tymczasowo przechowuje przychodzące żądania HTTP, dopóki aplikacja nie będzie gotowa do ich przetworzenia. Dostosowując deskryptor zabezpieczeń, można zezwolić określonym użytkownikom lub grupom na dostęp do kolejki żądań oraz odmówić tego dostępu. Jest to przydatne w sytuacjach, gdy chcesz ograniczyć lub delegować obsługę żądań HTTP.sys na poziomie systemu operacyjnego.
Jak używać nowej właściwości
Właściwość RequestQueueSecurityDescriptor ma zastosowanie tylko podczas tworzenia nowej kolejki żądań. Właściwość nie ma wpływu na istniejące kolejki żądań. Aby użyć tej właściwości, ustaw ją na wystąpienie GenericSecurityDescriptor podczas konfigurowania serwera HTTP.sys.
Na przykład poniższy kod umożliwia wszystkim uwierzytelnionym użytkownikom, a odmawia dostępu gościom.
using System.Security.AccessControl;
using System.Security.Principal;
using Microsoft.AspNetCore.Server.HttpSys;
// Create a new security descriptor
var securityDescriptor = new CommonSecurityDescriptor(isContainer: false, isDS: false, sddlForm: string.Empty);
// Create a discretionary access control list (DACL)
var dacl = new DiscretionaryAcl(isContainer: false, isDS: false, capacity: 2);
dacl.AddAccess(
AccessControlType.Allow,
new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null),
-1,
InheritanceFlags.None,
PropagationFlags.None
);
dacl.AddAccess(
AccessControlType.Deny,
new SecurityIdentifier(WellKnownSidType.BuiltinGuestsSid, null),
-1,
InheritanceFlags.None,
PropagationFlags.None
);
// Assign the DACL to the security descriptor
securityDescriptor.DiscretionaryAcl = dacl;
// Configure HTTP.sys options
var builder = WebApplication.CreateBuilder();
builder.WebHost.UseHttpSys(options =>
{
options.RequestQueueSecurityDescriptor = securityDescriptor;
});
Aby uzyskać więcej informacji, zobacz Implementacja serwera internetowego HTTP.sys w środowisku ASP.NET Core.
Lepsza obsługa testowania aplikacji za pomocą instrukcji najwyższego poziomu
Platforma .NET 10 ma teraz lepszą obsługę testowania aplikacji korzystających z instrukcji najwyższego poziomu. Wcześniej deweloperzy musieli ręcznie dodać public partial class Program do pliku Program.cs, aby projekt testowy mógł odwoływać się do Program class.
public partial class Program była wymagana, ponieważ funkcja deklaracji najwyższego poziomu w języku C# 9 wygenerowała Program class, która została zadeklarowana jako wewnętrzna.
W programie .NET 10 generator źródła jest używany do generowania deklaracji public partial class Program, jeśli programista nie zadeklarował go jawnie. Ponadto analizator został dodany do wykrywania, kiedy public partial class Program jest zadeklarowany jawnie i zaleca deweloperowi jego usunięcie.
Następujące pull requesty przyczyniły się do tej funkcjonalności:
Nowa implementacja poprawek JSON za pomocą polecenia System.Text.Json
- To standardowy format opisujący zmiany, które mają być stosowane do dokumentu JSON.
- Jest definiowany w dokumencie RFC 6902 i jest powszechnie używany w interfejsach API RESTful do wykonywania częściowych aktualizacji zasobów JSON.
- Reprezentuje sekwencję operacji (na przykład Dodawanie, Usuwanie, Zastępowanie, Przenoszenie, Kopiowanie, Testowanie), które można zastosować do modyfikowania dokumentu JSON.
W aplikacjach internetowych poprawka JSON jest często używana w operacji PATCH do wykonywania częściowych aktualizacji zasobu. Zamiast wysyłać cały zasób aktualizacji, klienci mogą wysyłać dokument poprawki JSON zawierający tylko zmiany. Stosowanie poprawek zmniejsza rozmiar ładunku i zwiększa wydajność.
W tej wersji wprowadzono nową implementację Microsoft.AspNetCore.JsonPatch, opartą na System.Text.Json serializacji. Ta funkcja:
- Jest zgodny z nowoczesnymi rozwiązaniami platformy .NET dzięki wykorzystaniu
System.Text.Jsonbiblioteki zoptymalizowanej pod kątem platformy .NET. - Zapewnia lepszą wydajność i mniejsze użycie pamięci w porównaniu ze starszą implementacją opartą na
Newtonsoft.Json.
Poniższe testy porównawcze porównują wydajność nowej System.Text.Json implementacji ze starszą Newtonsoft.Json implementacją.
| Scenario | Implementation | Mean | Przydzielona pamięć |
|---|---|---|---|
| Testy porównawcze aplikacji | Newtonsoft.JsonPatch | 271,924 μs | 25 KB |
| System.Text.JsonPatch | 1,584 μs | 3 KB | |
| Testy porównawcze deserializacji | Newtonsoft.JsonPatch | 19,261 μs | 43 KB |
| System.Text.JsonPatch | 7,917 μs | 7 KB |
Te testy porównawcze podkreślają znaczne wzrosty wydajności i mniejsze użycie pamięci dzięki nowej implementacji.
Notes:
- Nowa implementacja nie zastępuje starszej implementacji. W szczególności nowa implementacja nie obsługuje typów dynamicznych, na przykład ExpandoObject.
- Standard poprawki JSON ma nieodłączne zagrożenia bezpieczeństwa. Ponieważ te zagrożenia są związane ze standardem poprawki JSON, nowa implementacja nie próbuje ograniczyć ryzyka związanego z zabezpieczeniami. Jest to odpowiedzialność dewelopera za zapewnienie, że dokument poprawki JSON jest bezpieczny do zastosowania do obiektu docelowego. Aby uzyskać więcej informacji, zobacz sekcję Ograniczanie ryzyka zabezpieczeń .
Usage
Aby włączyć obsługę JSON Patch za pomocą System.Text.Json, zainstaluj pakiet NuGet Microsoft.AspNetCore.JsonPatch.SystemTextJson.
dotnet add package Microsoft.AspNetCore.JsonPatch.SystemTextJson --prerelease
Ten pakiet zawiera klasę reprezentującą JsonPatchDocument<T> dokument poprawki JSON dla obiektów typu T oraz dedykowaną logikę do serializacji i deserializacji dokumentów poprawek JSON z użyciem System.Text.Json. Kluczową metodą JsonPatchDocument<T> klasy jest ApplyTo, która stosuje operacje poprawek do obiektu docelowego typu T.
W poniższych przykładach pokazano, jak za pomocą metody zastosować ApplyTo dokument poprawki JSON do obiektu.
Przykład: stosowanie elementu JsonPatchDocument
W poniższym przykładzie pokazano:
- Operacje
add,replaceiremove. - Operacje na właściwościach zagnieżdżonych.
- Dodawanie nowego elementu do tablicy.
- Używanie konwertera wyliczenia ciągów JSON w dokumencie poprawki JSON.
// Original object
var person = new Person {
FirstName = "John",
LastName = "Doe",
Email = "johndoe@gmail.com",
PhoneNumbers = [new() {Number = "123-456-7890", Type = PhoneNumberType.Mobile}],
Address = new Address
{
Street = "123 Main St",
City = "Anytown",
State = "TX"
}
};
// Raw JSON Patch document
var jsonPatch = """
[
{ "op": "replace", "path": "/FirstName", "value": "Jane" },
{ "op": "remove", "path": "/Email"},
{ "op": "add", "path": "/Address/ZipCode", "value": "90210" },
{
"op": "add",
"path": "/PhoneNumbers/-",
"value": { "Number": "987-654-3210", "Type": "Work" }
}
]
""";
// Deserialize the JSON Patch document
var patchDoc = JsonSerializer.Deserialize<JsonPatchDocument<Person>>(jsonPatch);
// Apply the JSON Patch document
patchDoc!.ApplyTo(person);
// Output updated object
Console.WriteLine(JsonSerializer.Serialize(person, serializerOptions));
// Output:
// {
// "firstName": "Jane",
// "lastName": "Doe",
// "address": {
// "street": "123 Main St",
// "city": "Anytown",
// "state": "TX",
// "zipCode": "90210"
// },
// "phoneNumbers": [
// {
// "number": "123-456-7890",
// "type": "Mobile"
// },
// {
// "number": "987-654-3210",
// "type": "Work"
// }
// ]
// }
Metoda ApplyTo zwykle jest zgodna z konwencjami i opcjami System.Text.Json przy przetwarzaniu JsonPatchDocument elementu, w tym z zachowaniem kontrolowanym przez następujące opcje:
-
NumberHandling: czy właściwości liczbowe są odczytywane z ciągów. -
PropertyNameCaseInsensitive: Czy nazwy właściwości są rozróżniane według wielkości liter.
Kluczowe różnice między System.Text.Json a nową implementacją JsonPatchDocument<T>:
- Typ wykonywania obiektu docelowego, a nie zadeklarowany typ, określa, które właściwości
ApplyTosą poprawiane. -
System.Text.Jsondeserializacja opiera się na zadeklarowanym typie w celu zidentyfikowania kwalifikujących się właściwości.
Przykład: stosowanie JsonPatchDocument z obsługą błędów
Podczas stosowania dokumentu poprawki JSON mogą wystąpić różne błędy. Na przykład obiekt docelowy może nie mieć określonej właściwości lub określona wartość może być niezgodna z typem właściwości.
JSON Patch obsługuje również operację test.
test Operacja sprawdza, czy określona wartość jest równa właściwości docelowej, a jeśli nie, zwraca błąd.
W poniższym przykładzie pokazano, jak bezpiecznie obsługiwać te błędy.
Important
Obiekt przekazany do ApplyTo metody jest modyfikowany na miejscu. Osoba wywołująca ponosi odpowiedzialność za odrzucenie tych zmian, jeśli jakakolwiek operacja zakończy się niepowodzeniem.
// Original object
var person = new Person {
FirstName = "John",
LastName = "Doe",
Email = "johndoe@gmail.com"
};
// Raw JSON Patch document
var jsonPatch = """
[
{ "op": "replace", "path": "/Email", "value": "janedoe@gmail.com"},
{ "op": "test", "path": "/FirstName", "value": "Jane" },
{ "op": "replace", "path": "/LastName", "value": "Smith" }
]
""";
// Deserialize the JSON Patch document
var patchDoc = JsonSerializer.Deserialize<JsonPatchDocument<Person>>(jsonPatch);
// Apply the JSON Patch document, catching any errors
Dictionary<string, string[]>? errors = null;
patchDoc!.ApplyTo(person, jsonPatchError =>
{
errors ??= new ();
var key = jsonPatchError.AffectedObject.GetType().Name;
if (!errors.ContainsKey(key))
{
errors.Add(key, new string[] { });
}
errors[key] = errors[key].Append(jsonPatchError.ErrorMessage).ToArray();
});
if (errors != null)
{
// Print the errors
foreach (var error in errors)
{
Console.WriteLine($"Error in {error.Key}: {string.Join(", ", error.Value)}");
}
}
// Output updated object
Console.WriteLine(JsonSerializer.Serialize(person, serializerOptions));
// Output:
// Error in Person: The current value 'John' at path 'FirstName' is not equal
// to the test value 'Jane'.
// {
// "firstName": "John",
// "lastName": "Smith", <<< Modified!
// "email": "janedoe@gmail.com", <<< Modified!
// "phoneNumbers": []
// }
Ograniczanie ryzyka zabezpieczeń
W przypadku korzystania z Microsoft.AspNetCore.JsonPatch.SystemTextJson pakietu kluczowe znaczenie ma zrozumienie i ograniczenie potencjalnych zagrożeń bezpieczeństwa. W poniższych sekcjach opisano zidentyfikowane zagrożenia bezpieczeństwa związane z poprawką JSON i przedstawiono zalecane środki zaradcze w celu zapewnienia bezpiecznego użycia pakietu.
Important
Nie jest to wyczerpująca lista zagrożeń. Deweloperzy aplikacji muszą przeprowadzać własne przeglądy modeli zagrożeń, aby określić kompleksową listę specyficzną dla aplikacji i w razie potrzeby wymyślić odpowiednie środki zaradcze. Na przykład aplikacje, które uwidaczniają kolekcje w operacjach poprawek, powinny rozważyć potencjalne ataki związane z złożonością algorytmiczną, jeśli te operacje wstawiają lub usuwają elementy na początku kolekcji.
Uruchamiając kompleksowe modele zagrożeń dla własnych aplikacji i zwracając się do zidentyfikowanych zagrożeń, stosując poniższe zalecane środki zaradcze, konsumenci tych pakietów mogą zintegrować funkcje poprawki JSON z aplikacjami, jednocześnie minimalizując zagrożenia bezpieczeństwa.
Użytkownicy tych pakietów mogą integrować funkcje poprawki JSON z aplikacjami, jednocześnie minimalizując zagrożenia bezpieczeństwa, w tym:
- Uruchamianie kompleksowych modeli zagrożeń dla własnych aplikacji.
- Rozwiązywanie zidentyfikowanych zagrożeń.
- Postępuj zgodnie z zalecanymi środkami zaradczymi w poniższych sekcjach.
Odmowa usługi (DoS) za pośrednictwem wzmacniania pamięci
-
Scenariusz: Złośliwy klient przesyła operację
copy, która duplikuje duże grafy obiektów wiele razy, co prowadzi do nadmiernego użycia pamięci. - Wpływ: Potencjalne warunkiOf-Memory out-Of-Memory (OOM), powodując zakłócenia usług.
-
Mitigation:
- Przed wywołaniem metody
ApplyTozweryfikuj przychodzące dokumenty poprawek JSON pod kątem rozmiaru i struktury. - Walidacja musi być specyficzna dla aplikacji, ale przykładowa weryfikacja może wyglądać podobnie do następującego:
- Przed wywołaniem metody
public void Validate(JsonPatchDocument<T> patch)
{
// This is just an example. It's up to the developer to make sure that
// this case is handled properly, based on the app's requirements.
if (patch.Operations.Where(op=>op.OperationType == OperationType.Copy).Count()
> MaxCopyOperationsCount)
{
throw new InvalidOperationException();
}
}
Podwersja logiki biznesowej
- Scenariusz: Operacje poprawek mogą manipulować polami niejawnymi zmiennymi (na przykład flagami wewnętrznymi, identyfikatorami lub polami obliczeniowymi), naruszając ograniczenia biznesowe.
- Wpływ: problemy z integralnością danych i niezamierzone zachowanie aplikacji.
-
Mitigation:
- Użyj obiektów POCO z jawnie zdefiniowanymi właściwościami, które można bezpiecznie modyfikować.
- Unikaj uwidaczniania poufnych lub krytycznych właściwości w obiekcie docelowym.
- Jeśli nie jest używany żaden obiekt POCO, zweryfikuj poprawiony obiekt po zastosowaniu operacji, aby upewnić się, że reguły biznesowe i niezmienne nie są naruszone.
Uwierzytelnianie i autoryzacja
- Scenariusz: Nieuwierzytelniony lub nieautoryzowani klienci wysyłają złośliwe żądania poprawek JSON.
- Wpływ: Nieautoryzowany dostęp do modyfikowania poufnych danych lub zakłócania działania aplikacji.
-
Mitigation:
- Ochrona punktów końcowych akceptujących żądania poprawek JSON przy użyciu odpowiednich mechanizmów uwierzytelniania i autoryzacji.
- Ogranicz dostęp do zaufanych klientów lub użytkowników z odpowiednimi uprawnieniami.
Wykrywanie, czy adres URL jest lokalny przy użyciu RedirectHttpResult.IsLocalUrl
Użyj nowej metody pomocnika RedirectHttpResult.IsLocalUrl(url), aby wykryć, czy adres URL jest lokalny. Adres URL jest uznawany za lokalny, jeśli są spełnione następujące warunki:
- Nie ma sekcji hosta ani sekcji autorytetu .
- Ma ścieżkę bezwzględną.
Adresy URL używające ścieżek wirtualnych"~/" są również lokalne.
IsLocalUrl przydaje się do sprawdzania poprawności adresów URL przed przekierowaniem do nich, aby zapobiec atakom typu open redirect.
if (RedirectHttpResult.IsLocalUrl(url))
{
return Results.LocalRedirect(url);
}
Dziękujemy @martincostello za ten wkład!
Zmiany przełomowe
Artykuły w artykule Zmiany powodujące niezgodność na platformie .NET umożliwiają znalezienie zmian powodujących niezgodność, które mogą być stosowane podczas uaktualniania aplikacji do nowszej wersji platformy .NET.
ASP.NET Core