Udostępnij za pośrednictwem


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:

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:

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-catchblok 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:

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.

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ść w false 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:

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ą idcleanupDiv . 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ę DOMCleanupJS z pliku DOMCleanup.razor.js i wywołuje jej funkcję createObserver w celu ustawienia wywołania zwrotnego MutationObserver. Te zadania są wykonywane w metodzie OnAfterRenderAsynccyklu ż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 na document.body.
  • Zamiast używać MutationObserver, rozważ użycie elementu niestandardowego i disconnectedCallback. 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:

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.