Współdziałanie języka JavaScript platformy ASP.NET Core Blazor (współdziałanie języka JS)
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz artykuł w wersji .NET 9.
Ostrzeżenie
Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz zasady pomocy technicznej platformy .NET i platformy .NET Core. Aby zapoznać się z bieżącą wersją, zobacz artykuł w wersji platformy .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu dla .NET 9.
Aplikacja platformy Blazor może wywoływać funkcje języka JavaScript (JS) z metod platformy .NET oraz metody platformy.NET z funkcji języka JS. Te scenariusze nazywane są interoperacyjnością JavaScript (JS interoperacyjność).
Dalsze wskazówki dotyczące interoperacyjności JS są dostępne w następujących artykułach:
- Wywoływanie funkcji języka JavaScript z metod platformy .NET na platformie ASP.NET Core Blazor
- Wywoływanie metod platformy .NET z funkcji języka JavaScript z na platformie ASP.NET Core Blazor
Uwaga
Interfejs API międzyoperacyjny języka JavaScript [JSImport]
/[JSExport]
jest dostępny dla składników po stronie klienta w programie ASP.NET Core na platformie .NET 7 lub nowszym.
Aby uzyskać więcej informacji, zobacz JavaScript JSImport/JSExport interop with ASP.NET Core (Interopcja javaScript JSImport/JSExport with ASP.NET Core Blazor).
Kompresja składników interakcyjnych serwerów z niezaufanymi danymi
Dzięki kompresji, która jest domyślnie włączona, unikaj tworzenia bezpiecznych (uwierzytelnionych/autoryzowanych) interaktywnych składników po stronie serwera, które renderuje dane z niezaufanych źródeł. Niezaufane źródła obejmują parametry trasy, ciągi zapytań, dane z JS międzyoperacyjności i wszelkie inne źródło danych, które użytkownik zewnętrzny może kontrolować (bazy danych, usługi zewnętrzne). Aby uzyskać więcej informacji, zobacz wskazówki dotyczące ASP.NET CoreBlazorSignalR oraz wskazówki dotyczące łagodzenia zagrożeń dla interaktywnego renderowania po stronie serwera w ASP.NET CoreBlazor.
Pakiet abstrakcji i funkcji międzyoperacyjnych JavaScript
Pakiet @microsoft/dotnet-js-interop
(npmjs.com
) (Microsoft.JSInterop
pakiet NuGet) zapewnia abstrakcje i funkcje do współpracy między kodem .NET a JavaScript (JS). Źródło referencyjne jest dostępne w dotnet/aspnetcore
repozytorium GitHub (/src/JSInterop
folder). Aby uzyskać więcej informacji, zobacz plik repozytorium README.md
GitHub.
Uwaga
Linki w dokumentacji do źródła referencyjnego .NET zwykle otwierają domyślną gałąź repozytorium, która odzwierciedla aktualny rozwój dla następnej wersji .NET. Aby wybrać tag dla określonej wersji, użyj listy rozwijanej Przełącz gałęzie lub tagi. Aby uzyskać więcej informacji, zobacz Jak wybrać tag wersji kodu źródłowego platformy ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Dodatkowe zasoby do pisania JS skryptów interop w języku TypeScript:
- TypeScript
- Samouczek: tworzenie aplikacji ASP.NET Core za pomocą języka TypeScript w programie Visual Studio
- Zarządzanie pakietami npm w programie Visual Studio
Interakcja z DOM
Modyfikuj DOM tylko za pomocą JavaScript (JS), gdy obiekt nie wchodzi w interakcję z Blazor. Platforma Blazor utrzymuje reprezentacje modelu DOM i współdziała bezpośrednio z obiektami modelu DOM. Jeśli element renderowany przez platformę Blazor jest modyfikowany zewnętrznie przy użyciu języka JS bezpośrednio lub przez współdziałanie języka JS, model DOM może być już niezgodny z wewnętrzną reprezentacją platformy Blazor, co może spowodować niezdefiniowane zachowanie. Niezdefiniowane zachowanie może tylko zakłócać prezentację elementów lub ich funkcji, ale może również powodować zagrożenia bezpieczeństwa dla aplikacji lub serwera.
Te wskazówki dotyczą nie tylko własnego kodu współdziałania języka JS, ale także wszystkich bibliotek języka JS używanych przez aplikację, w tym wszystkich elementów udostępnianych przez platformę innej firmy, takich jak Bootstrap JS i jQuery.
W kilku przykładach dokumentacji współdziałanie języka JS jest używane do modyfikowania elementu wyłącznie do celów demonstracyjnych w ramach przykładu. W takich przypadkach w tekście pojawia się ostrzeżenie.
Aby uzyskać więcej informacji, zobacz Wywoływanie funkcji języka JavaScript z metod platformy .NET na platformie ASP.NET Core Blazor.
Klasa JavaScript z polem funkcji typu
Klasa JavaScript z polem typu funkcja nie jest obsługiwana przez BlazorJS interop. Używanie funkcji Języka JavaScript w klasach.
Nieobsługiwane:GreetingHelpers.sayHello
w następującej klasie jako pole typu funkcja nie jest wykrywane przez mechanizm Blazor interoperacyjny JS i nie można go wykonać w kodzie C#:
export class GreetingHelpers {
sayHello = function() {
...
}
}
Obsługiwane:GreetingHelpers.sayHello
w następującej klasie jako funkcja jest obsługiwana:
export class GreetingHelpers {
sayHello() {
...
}
}
Obsługiwane są również funkcje strzałek:
export class GreetingHelpers {
sayHello = () => {
...
}
}
Unikaj wbudowanych programów obsługi zdarzeń
Funkcję JavaScript można wywołać bezpośrednio z wbudowanej procedury obsługi zdarzeń. W poniższym przykładzie alertUser
jest funkcją Języka JavaScript wywoływaną po wybraniu przycisku przez użytkownika:
<button onclick="alertUser">Click Me!</button>
Jednak użycie wbudowanych procedur obsługi zdarzeń jest złym wyborem w przypadku wywoływania funkcji języka JavaScript:
- Mieszanie znaczników HTML i kodu JavaScript często prowadzi do trudnego do utrzymania kodu.
- Wykonywanie wbudowanej procedury obsługi zdarzeń może zostać zablokowane przez Zasadę Bezpieczeństwa Treści (CSP) (dokumentacja MDN).
Zalecamy unikanie wbudowanych procedur obsługi zdarzeń na rzecz podejść, które przypisują procedury obsługi w języku JavaScript za pomocą addEventListener
, jak pokazano w poniższym przykładzie:
AlertUser.razor.js
:
export function alertUser() {
alert('The button was selected!');
}
export function addHandlers() {
const btn = document.getElementById("btn");
btn.addEventListener("click", alertUser);
}
AlertUser.razor
:
@page "/alert-user"
@implements IAsyncDisposable
@inject IJSRuntime JS
<h1>Alert User</h1>
<p>
<button id="btn">Click Me!</button>
</p>
@code {
private IJSObjectReference? module;
protected async override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/AlertUser.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
W poprzednim przykładzie JSDisconnectedException jest uwięziony w trakcie usuwania modułu w przypadku utraty obwodu SignalRBlazor. Jeśli poprzedni kod jest używany w Blazor WebAssembly aplikacji, nie ma SignalR połączenia do utraty, więc możesz usunąćtry
-catch
blok i pozostawić wiersz, który usuwa moduł ().await module.DisposeAsync();
Aby uzyskać więcej informacji, zobacz ASP.NET Core Blazor JavaScript interoperability (JS interop).
Aby uzyskać więcej informacji, zobacz następujące zasoby:
- Lokalizacja języka JavaScript w aplikacjach ASP.NET Core Blazor
- Wprowadzenie do zdarzeń (dokumentacja MDN)
Asynchroniczne wywołania języka JavaScript
JS wywołania międzyoperacyjne są asynchroniczne, niezależnie od tego, czy wywoływany kod jest synchroniczny, czy asynchroniczny. Wywołania są asynchroniczne, aby zapewnić, że komponenty są zgodne z modelami renderowania po stronie serwera i po stronie klienta. Podczas wdrażania renderowania po stronie serwera wywołania międzyoperacyjne muszą być asynchroniczne, JS ponieważ są wysyłane za pośrednictwem połączenia sieciowego. W przypadku aplikacji, które korzystają wyłącznie z renderowania po stronie klienta, obsługiwane są synchroniczne wywołania interoperacyjne JS.
Aby uzyskać więcej informacji, zobacz następujące artykuły:
Aby uzyskać więcej informacji, zobacz Wywoływanie funkcji języka JavaScript z metod platformy .NET na platformie ASP.NET Core Blazor.
Serializacja obiektów
Platforma Blazor używa obiektu System.Text.Json do serializacji z następującymi wymaganiami i zachowaniami domyślnymi:
- Typy muszą mieć konstruktor domyślny, metody dostępu
get
/set
muszą być publiczne, a pola nigdy nie są serializowane. - Globalna domyślna serializacja nie jest dostosowywalna, aby uniknąć przerywania istniejących bibliotek składników, wpływu na wydajność i bezpieczeństwo oraz zmniejszeń niezawodności.
- Serializowanie nazw członków w .NET skutkuje tym, że nazwy kluczy JSON są zapisywane małymi literami.
- Dane JSON są deserializowane jako JsonElement instancje C#, które pozwalają na użycie różnych wielkości liter. Pomimo różnic przypadków między nazwami kluczy JSON a nazwami właściwości C#, rzutowanie wewnętrzne do przypisania właściwościom modelu C# działa zgodnie z oczekiwaniami.
- Złożone typy struktur, takie jak KeyValuePair, mogą być przycinane przez IL Trimmer w przypadku publikowania i nie są obecne dla JS międzyoperacjonalizacji lub serializacji/deserializacji JSON. Zalecamy utworzenie typów niestandardowych dla typów, które trymer IL przycina.
-
Blazorzawsze opiera się na refleksji do serializacji JSON, w tym w przypadku używania generowania kodu źródłowego w C#. Ustawienie
JsonSerializerIsReflectionEnabledByDefault
na wartość wfalse
pliku projektu aplikacji powoduje błąd podczas próby serializacji.
Interfejs API JsonConverter jest dostępny na potrzeby serializacji niestandardowej. Właściwości można oznaczyć adnotacją za pomocą atrybutu [JsonConverter]
, aby zastąpić domyślną serializację dla istniejącego typu danych.
Aby uzyskać więcej informacji, zobacz następujące zasoby w dokumentacji platformy .NET:
- Serializacja i deserializacja JSON (serializacja obiektów i deserializacja obiektów) na platformie .NET
-
Jak dostosować nazwy i wartości właściwości przy użyciu obiektu
System.Text.Json
- Jak pisać niestandardowe konwertery na potrzeby serializacji JSON (marshalling) na platformie .NET
Platforma Blazor obsługuje zoptymalizowane współdziałanie z tablicami bajtów JS, które unika kodowania/dekodowania tych tablic do formatu Base64. Aplikacja może stosować serializację niestandardową i przekazywać bajty wynikowe. Aby uzyskać więcej informacji, zobacz Wywoływanie funkcji języka JavaScript z metod platformy .NET na platformie ASP.NET Core Blazor.
Blazor obsługuje interoperacyjność dla obiektów platformy JS po ich unmarshalingu, gdy duża liczba obiektów .NET jest szybko serializowana lub gdy należy serializować duże obiekty .NET albo wiele obiektów .NET. Aby uzyskać więcej informacji, zobacz Wywoływanie funkcji języka JavaScript z metod platformy .NET na platformie ASP.NET Core Blazor.
Zadania czyszczenia DOM podczas usuwania komponentów
Nie wykonuj JS kodu międzyoperacyjnego dla zadań oczyszczania modelu DOM podczas usuwania składników. Zamiast tego zastosuj wzorzec MutationObserver
w języku JavaScript (JS) po stronie klienta z tych powodów:
- Składnik mógł zostać usunięty z modelu DOM przez czas wykonywania kodu oczyszczania w pliku
Dispose{Async}
. - Podczas renderowania po stronie serwera, w momencie wykonywania kodu oczyszczania w
Dispose{Async}
program renderujący Blazor mógł zostać usunięty przez framework.
Wzorzec MutationObserver
umożliwia uruchamianie funkcji po usunięciu elementu z modelu DOM.
W poniższym przykładzie komponent DOMCleanup
:
- Zawiera element
<div>
z wartościąid
cleanupDiv
. Element<div>
jest usuwany z modelu DOM wraz z resztą znacznika DOM składnika, gdy składnik zostanie usunięty z modelu DOM. - Ładuje klasę
DOMCleanup
JS z plikuDOMCleanup.razor.js
i wywołuje jej funkcjęcreateObserver
w celu ustawienia wywołania zwrotnegoMutationObserver
. Te zadania są wykonywane w metodzieOnAfterRenderAsync
cyklu życia.
DOMCleanup.razor
:
@page "/dom-cleanup"
@implements IAsyncDisposable
@inject IJSRuntime JS
<h1>DOM Cleanup Example</h1>
<div id="cleanupDiv"></div>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>(
"import", "./Components/Pages/DOMCleanup.razor.js");
await module.InvokeVoidAsync("DOMCleanup.createObserver");
}
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
W poprzednim przykładzie JSDisconnectedException jest zatrzymywany podczas usuwania modułu, gdy utracony zostaje obwód BlazorSignalR. Jeśli poprzedni kod jest używany w Blazor WebAssembly aplikacji, nie ma SignalR połączenia do utraty, więc możesz usunąć bloktry
-catch
i pozostawić wiersz, który likwiduje moduł (await module.DisposeAsync();
). Aby uzyskać więcej informacji, zobacz ASP.NET Core Blazor JavaScript interoperability (JS interop).
W poniższym przykładzie MutationObserver
wywołanie zwrotne jest wykonywane za każdym razem, gdy nastąpi zmiana w DOM. Wykonaj kod czyszczący, kiedy instrukcja if
potwierdza, że element docelowy (cleanupDiv
) został usunięty (if (targetRemoved) { ... }
). Ważne jest rozłączenie i usunięcie MutationObserver
elementu , aby uniknąć przecieku pamięci po wykonaniu kodu oczyszczania.
DOMCleanup.razor.js
umieszczony obok poprzedniego DOMCleanup
składnika:
export class DOMCleanup {
static observer;
static createObserver() {
const target = document.querySelector('#cleanupDiv');
this.observer = new MutationObserver(function (mutations) {
const targetRemoved = mutations.some(function (mutation) {
const nodes = Array.from(mutation.removedNodes);
return nodes.indexOf(target) !== -1;
});
if (targetRemoved) {
// Cleanup resources here
// ...
// Disconnect and delete MutationObserver
this.observer && this.observer.disconnect();
delete this.observer;
}
});
this.observer.observe(target.parentNode, { childList: true });
}
}
window.DOMCleanup = DOMCleanup;
Powyższe podejścia dołączają MutationObserver
do target.parentNode
, co działa do momentu usunięcia samego parentNode
z struktury DOM. Jest to typowy scenariusz, na przykład podczas przechodzenia do nowej strony, co powoduje usunięcie całego składnika strony z modelu DOM. W takich przypadkach, jakiekolwiek podkomponenty obserwujące zmiany na stronie nie są odpowiednio usuwane.
Nie zakładaj, że obserwowanie document.body
, zamiast target.parentNode
, jest lepszym celem. Obserwowanie document.body
ma implikacje wydajnościowe, ponieważ logika funkcji wywoławczej jest wykonywana dla wszystkich aktualizacji DOM, niezależnie od tego, czy mają coś wspólnego z twoim elementem. Użyj jednej z następujących metod:
- W przypadkach, w których można zidentyfikować odpowiedni węzeł przodka do obserwowania, użyj z nim
MutationObserver
. Najlepiej, aby ten nadrzędny element był skierowany na zmiany, które mają być obserwowane, a nie nadocument.body
. - Zamiast używać
MutationObserver
, rozważ użycie elementu niestandardowego idisconnectedCallback
. Zdarzenie jest zawsze wywoływane, gdy element niestandardowy jest odłączony, niezależnie od tego, gdzie znajduje się w DOM względem zmiany w DOM.
Wywołania międzyoperacyjne języka JavaScript bez użycia obwodu
Ta sekcja dotyczy tylko aplikacji po stronie serwera.
Wywołania interop języka JavaScript (JS) nie mogą być wykonywane po rozłączeniu obwodu BlazorSignalR. Gdy obwód nie istnieje, podczas usuwania składników lub w dowolnym innym czasie, następujące wywołania metod kończą się niepowodzeniem, a rejestrowany jest komunikat o odłączeniu obwodu jako JSDisconnectedException:
- JS wywołania metod interoperacyjnych
-
Dispose
/DisposeAsync
wywołuje dowolną IJSObjectReference.
Aby uniknąć rejestrowania JSDisconnectedException lub zalogować informacje niestandardowe, przechwyć wyjątek w instrukcji try-catch
.
W poniższym przykładzie usuwania składników:
- Składnik po stronie serwera implementuje element IAsyncDisposable.
-
module
jest elementem IJSObjectReference dla modułu JS . - JSDisconnectedException został przechwycony i nie został zarejestrowany.
- Opcjonalnie, możesz rejestrować informacje niestandardowe w instrukcji
catch
na dowolnym poziomie dziennika, który preferujesz. Poniższy przykład nie rejestruje informacji niestandardowych, ponieważ zakłada, że deweloper nie dba o to, kiedy lub gdzie obwody są rozłączane podczas usuwania składników.
async ValueTask IAsyncDisposable.DisposeAsync()
{
try
{
if (module is not null)
{
await module.DisposeAsync();
}
}
catch (JSDisconnectedException)
{
}
}
Jeśli musisz wyczyścić własne JS obiekty lub wykonać inny JS kod na kliencie po utracie obwodu w aplikacji po stronie serwera Blazor, użyj wzorca MutationObserver
na kliencie JS. Wzorzec MutationObserver
umożliwia uruchamianie funkcji po usunięciu elementu z modelu DOM.
Aby uzyskać więcej informacji, zobacz następujące artykuły:
- Obsługiwane błędów w aplikacjach ASP.NET Core: Sekcja JavaScript interop omawia obsługę błędów w scenariuszach międzyoperacyjnych.
- ASP.NET core Razor składników: w artykule opisano sposób implementowania wzorców usuwania w składnikach Razor.
Buforowane pliki JavaScript
Pliki JavaScript (JS) i inne zasoby statyczne nie są zwykle buforowane na klientach podczas programowania w środowisku Development
. Podczas tworzenia oprogramowania, statyczne żądania dotyczące zasobów zawierają nagłówek Cache-Control
z wartością no-cache
lub max-age
z wartością zero (0
).
Podczas produkcji w środowisku Production
pliki JS są zwykle buforowane przez klientów.
Aby wyłączyć buforowanie po stronie klienta w przeglądarkach, deweloperzy zwykle stosują jedną z następujących metod:
- Wyłącz buforowanie, gdy konsola narzędzi deweloperskich przeglądarki jest otwarta. Wskazówki można znaleźć w dokumentacji narzędzi deweloperskich każdego z dostawców przeglądarek.
- Wykonaj ręczne odświeżanie przeglądarki dowolnej strony internetowej aplikacji platformy Blazor w celu ponownego załadowania plików JS z serwera. Oprogramowanie pośredniczące HTTP platformy ASP.NET Core zawsze honoruje prawidłowy nagłówek
Cache-Control
no-cache wysyłany przez klienta.
Aby uzyskać więcej informacji, zobacz:
Limity rozmiaru wywołań interop JavaScript
Ta sekcja dotyczy tylko składników interaktywnych w aplikacjach po stronie serwera. W przypadku komponentów po stronie klienta framework nie nakłada limitu na rozmiar danych wejściowych i wyjściowych w JavaScript (JS).
W przypadku składników interaktywnych w aplikacjach JS po stronie serwera, wywołania międzyoperacyjne przesyłania danych z klienta do serwera są ograniczone maksymalnym rozmiarem przychodzących komunikatów SignalR, dozwolonych dla metod koncentratora, co jest wymuszane przez HubOptions.MaximumReceiveMessageSize (domyślnie: 32 KB). JS komunikaty platformy .NET SignalR większe niż MaximumReceiveMessageSize zgłaszają błąd. Struktura nie nakłada limitu rozmiaru komunikatu SignalR z centrum na klienta. Aby uzyskać więcej informacji na temat limitu rozmiaru, komunikatów o błędach i wskazówek dotyczących obsługi limitów rozmiaru komunikatów, zobacz wskazówki dotyczące ASP.NET CoreBlazorSignalR.
Określanie, gdzie aplikacja jest uruchomiona
Jeśli to istotne dla aplikacji, aby wiedzieć, gdzie działa kod na potrzeby JS wywołań współdziałających, użyj OperatingSystem.IsBrowser, aby określić, czy składnik jest wykonywany w kontekście przeglądarki w WebAssembly.