ASP.NET Core Blazor JavaScript-samverkan (JS interop)
Notera
Det här är inte den senaste versionen av den här artikeln. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln.
Varning
Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i .NET och .NET Core Support Policy. Den nuvarande utgåvan hittas i .NET 9 versionen av den här artikeln.
Viktig
Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.
Den aktuella versionen finns i den .NET 9-versionen av den här artikeln.
En Blazor app kan anropa JavaScript-funktioner (JS) från .NET-metoder och .NET-metoder från JS funktioner. Dessa scenarier kallas JavaScript-samverkan (JS interop).
Ytterligare riktlinjer för JS interoperabilitet finns i följande artiklar:
- Anropa JavaScript-funktioner från .NET-metoder i ASP.NET Core Blazor
- Anropa .NET-metoder från JavaScript-funktioner i ASP.NET Core Blazor
Not
JavaScript [JSImport]
/[JSExport]
interop API är tillgängligt för komponenter på klientsidan i ASP.NET Core i .NET 7 eller senare.
Mer information finns i JavaScript JSImport/JSExport interop med ASP.NET Core Blazor.
Komprimering för interaktiva serverkomponenter med ej betrodda data
Med komprimering, som är aktiverad som standard, undviker du att skapa säkra (autentiserade/auktoriserade) interaktiva komponenter på serversidan som återger data från ej betrodda källor. Ej betrodda källor omfattar routningsparametrar, frågesträngar, data från JS interop och alla andra datakällor som en användare från tredje part kan kontrollera (databaser, externa tjänster). Mer information finns i vägledningen ASP.NET Core BlazorSignalR och Threat mitigation guidance for ASP.NET Core Blazor interactive server-side rendering.
JavaScript-interopabstraktioner och funktionspaket
@microsoft/dotnet-js-interop
-paketet (npmjs.com
) (Microsoft.JSInterop
NuGet-paket) innehåller abstraktioner och funktioner för interop mellan .NET- och JavaScript-kod (JS). Referenskällan är tillgänglig på dotnet/aspnetcore
GitHub-lagringsplats (/src/JSInterop
mapp). Mer information finns i GitHub-lagringsplatsens README.md
-fil.
Not
Dokumentationslänkar till .NET-referenskällan läser vanligtvis in lagringsplatsens standardgren, vilket representerar den aktuella utvecklingen för nästa version av .NET. Om du vill välja en tagg för en specifik version använder du listrutan Växla grenar eller taggar. Mer information finns i Så här väljer du en versionstagg för ASP.NET Core-källkod (dotnet/AspNetCore.Docs #26205).
Ytterligare resurser för att skriva JS interop-skript i TypeScript:
- TypeScript-
- Självstudie: Skapa en ASP.NET Core-app med TypeScript i Visual Studio
- Hantera npm-paket i Visual Studio
Interaktion med DOM
Mutera endast DOM med JavaScript (JS) när objektet inte interagerar med Blazor. Blazor upprätthåller representationer av DOM och interagerar direkt med DOM-objekt. Om ett element som återges av Blazor ändras externt med hjälp av JS direkt eller via JS Interop, kanske DOM inte längre matchar Blazorinterna representation, vilket kan resultera i odefinierat beteende. Odefinierat beteende kan bara störa presentationen av element eller deras funktioner, men kan också medföra säkerhetsrisker för appen eller servern.
Den här vägledningen gäller inte bara din egen JS interop-kod utan även för alla JS bibliotek som appen använder, inklusive allt som tillhandahålls av ett ramverk från tredje part, till exempel Bootstrap JS och jQuery.
I några dokumentationsexempel används JS interop för att mutera ett element enbart i demonstrationssyfte som en del av ett exempel. I dessa fall visas en varning i texten.
Mer information finns i Anropa JavaScript-funktioner från .NET-metoder i ASP.NET Core Blazor.
JavaScript-klass med ett fält av typen funktion
En JavaScript-klass med ett fält av typen funktion stöds inte av BlazorJS interop. Använd Javascript-funktioner i klasser.
stöds inte:GreetingHelpers.sayHello
i följande klass som ett fält av typen funktion identifieras inte av Blazor: s JS-interoperabilitet och kan inte exekveras från C#-kod:
export class GreetingHelpers {
sayHello = function() {
...
}
}
✔️ stöds som funktion i följande klass:GreetingHelpers.sayHello
export class GreetingHelpers {
sayHello() {
...
}
}
Pilfunktioner stöds också:
export class GreetingHelpers {
sayHello = () => {
...
}
}
Undvik infogade händelsehanterare
En JavaScript-funktion kan anropas direkt från en infogad händelsehanterare. I följande exempel är alertUser
en JavaScript-funktion som anropas när knappen väljs av användaren:
<button onclick="alertUser">Click Me!</button>
Användningen av infogade händelsehanterare är dock ett dåligt designval för att anropa JavaScript-funktioner:
- Att blanda HTML-kod och JavaScript-kod leder ofta till ouppnåelig kod.
- Körning av infogad händelsehanterare kan blockeras av en CSP (Content Security Policy) (MDN-dokumentation).
Vi rekommenderar att du undviker infogade händelsehanterare till förmån för metoder som tilldelar hanterare i JavaScript med addEventListener
, vilket visas i följande exempel:
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)
{
}
}
}
}
I det föregående exemplet fångas JSDisconnectedException under moduldemontering om Blazor:s SignalR-krets går förlorad. Om föregående kod används i en Blazor WebAssembly app finns det ingen SignalR anslutning att förlora, så du kan ta bort try
-catch
-blocket och behålla raden som tar bort modulen (await module.DisposeAsync();
). Mer information finns i ASP.NET Core Blazor JavaScript-samverkan (JS interop).
Mer information finns i följande resurser:
Asynkrona JavaScript-anrop
JS interop-anrop är asynkrona, oavsett om den anropade koden är synkron eller asynkron. Anrop är asynkrona för att säkerställa att komponenterna är kompatibla över server- och klientsidans återgivningsmodeller. När du använder återgivning på serversidan måste JS interop-anrop vara asynkrona eftersom de skickas via en nätverksanslutning. Synkrona JS interop-anrop stöds för appar som uteslutande använder återgivning på klientsidan.
Mer information finns i följande artiklar:
Mer information finns i Anropa JavaScript-funktioner från .NET-metoder i ASP.NET Core Blazor.
Objektserialisering
Blazor använder System.Text.Json för serialisering med följande krav och standardbeteenden:
- Typer måste ha en standardkonstruktor,
get
/set
måste vara offentliga och fälten serialiseras aldrig. - Global standard serialisering är inte anpassningsbar för att undvika att bryta befintliga komponentbibliotek, påverka prestanda och säkerhet och minska tillförlitligheten.
- Serialisering av .NET-medlemsnamn resulterar i gemener av JSON-nyckelnamn.
- JSON deserialiseras som JsonElement C#-instanser, vilket tillåter blandat hölje. Intern typkonvertering för tilldelning till egenskaper i C#-modell fungerar som förväntat trots eventuella skillnader mellan JSON-nyckelnamn och C#-egenskapsnamn.
- Komplexa ramverkstyper, till exempel KeyValuePair, kan trimmas bort av IL Trimmer när publiceras och inte finns för JS interop. Vi rekommenderar att du skapar anpassade typer för typer som IL Trimmer trimmar bort.
-
Blazor förlitar sig alltid på reflektion för JSON-serialisering, inklusive när du använder C# källgenerering. Om du anger
JsonSerializerIsReflectionEnabledByDefault
tillfalse
i appens projektfil resulterar det i ett fel när serialisering görs.
JsonConverter API är tillgängligt för anpassad serialisering. Egenskaper kan kommenteras med ett [JsonConverter]
attribut för att åsidosätta standard serialisering för en befintlig datatyp.
Mer information finns i följande resurser i .NET-dokumentationen:
- JSON-serialisering och deserialisering (marshalling och unmarshalling) i .NET
-
Anpassa egenskapsnamn och värden med
System.Text.Json
- Så här skriver du anpassade konverterare för JSON-serialisering (marshalling) i .NET
Blazor stöder optimerad bytematris JS interop som undviker kodning/avkodning av bytematriser till Base64. Appen kan tillämpa anpassad serialisering och skicka de resulterande byteen. Mer information finns i Anropa JavaScript-funktioner från .NET-metoder i ASP.NET Core Blazor.
Blazor stöder odirigerad JS interop när en stor mängd .NET-objekt snabbt serialiseras eller när stora .NET-objekt eller många .NET-objekt måste serialiseras. Mer information finns i Anropa JavaScript-funktioner från .NET-metoder i ASP.NET Core Blazor.
DOM-rensningsuppgifter vid bortskaffande av komponenter
Kör inte JS interop-kod för DOM-rensningsuppgifter under komponentens bortskaffande. Använd i stället MutationObserver
-mönstret i JavaScript (JS) på klienten av följande skäl:
- Komponenten kan ha tagits bort från DOM när rensningskoden körs i
Dispose{Async}
. - Vid serverside-rendering kan Blazor-renderaren ha avyttrats av ramverket vid den tidpunkt då din rensningskod körs i
Dispose{Async}
.
Med MutationObserver
-mönstret kan du köra en funktion när ett element tas bort från DOM.
I följande exempel, komponenten DOMCleanup
:
- Innehåller en
<div>
med enid
avcleanupDiv
. Elementet<div>
tas bort från DOM tillsammans med resten av komponentens DOM-markering när komponenten tas bort från DOM. - Läser in
DOMCleanup
JS-klassen frånDOMCleanup.razor.js
-filen och anropar desscreateObserver
-funktion för att konfigureraMutationObserver
återanrop. Dessa uppgifter utförs iOnAfterRenderAsync
livscykelmetod.
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)
{
}
}
}
}
I föregående exempel fångas JSDisconnectedException under modulens avveckling om Blazor:s SignalR-kretsen förloras. Om föregående kod används i en Blazor WebAssembly app finns det ingen SignalR anslutning att förlora, så du kan ta bort try
-catch
-blocket och behålla raden som tar bort modulen (await module.DisposeAsync();
). Mer information finns i ASP.NET Core Blazor JavaScript-samverkan (JS interop).
I följande exempel körs MutationObserver
återanrop varje gång en DOM-ändring sker. Kör rensningskoden när if
-instruktionen bekräftar att målelementet (cleanupDiv
) har tagits bort (if (targetRemoved) { ... }
). Det är viktigt att koppla från och ta bort MutationObserver
för att undvika en minnesläcka när rensningskoden har körts.
DOMCleanup.razor.js
placeras sida vid sida med den föregående DOMCleanup
komponenten:
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;
Föregående metoder kopplar MutationObserver
till target.parentNode
, som fungerar tills själva parentNode
tas bort från DOM. Det här är ett vanligt scenario, till exempel när du navigerar till en ny sida, vilket gör att hela sidkomponenten tas bort från DOM. I sådana fall rensas inte barnkomponenter som observerar ändringar på sidan korrekt.
Anta inte att det är ett bättre mål att observera document.body
i stället för target.parentNode
. Att observera
- I de fall där du kan identifiera en lämplig överordnad nod att observera använder du
MutationObserver
med den. Helst är denna förfader begränsad till de ändringar som du vill observera snarare än tilldocument.body
. - I stället för att använda
MutationObserver
bör du överväga att använda ett anpassat element ochdisconnectedCallback
. Händelsen utlöses alltid när ditt anpassade element kopplas från, oavsett var det finns i DOM i förhållande till DOM-ändringen.
JavaScript-interopanrop utan krets
Det här avsnittet gäller endast för appar på serversidan.
JavaScript (JS) interop-anrop kan inte utfärdas efter att Blazor:s SignalR-krets är frånkopplad. Utan en krets under komponentens bortskaffande eller vid någon annan tidpunkt som en krets inte finns, anropar följande metod fel och loggar ett meddelande om att kretsen är frånkopplad som en JSDisconnectedException:
- JS interop-metodanrop
-
Dispose
/DisposeAsync
anropar alla IJSObjectReference.
För att undvika loggning JSDisconnectedException eller logga anpassad information fångar du undantaget i en try-catch
-instruktion.
För följande exempel på bortskaffande av komponenter:
- Komponenten på serversidan implementerar IAsyncDisposable.
-
module
är en IJSObjectReference för en JS-modul. - JSDisconnectedException fångas och loggas inte.
- Du kan också logga anpassad information i
catch
-instruktionen på vilken loggnivå du vill. I följande exempel loggas inte anpassad information eftersom det förutsätter att utvecklaren inte bryr sig om när eller var kretsar kopplas från under komponentens bortskaffande.
async ValueTask IAsyncDisposable.DisposeAsync()
{
try
{
if (module is not null)
{
await module.DisposeAsync();
}
}
catch (JSDisconnectedException)
{
}
}
Om du måste rensa dina egna JS objekt eller köra annan JS kod på klienten efter att en krets har förlorats i en Blazor app på serversidan använder du MutationObserver
-mönstret i JS på klienten. Med MutationObserver
-mönstret kan du köra en funktion när ett element tas bort från DOM.
Mer information finns i följande artiklar:
- Hantera fel i ASP.NET Core Blazor-appar: I avsnittet JavaScript-interop beskrivs felhantering i JS interop-scenarier.
-
ASP.NET Core Razor komponentens livscykel: Avsnittet Komponenthantering med
IDisposable
ochIAsyncDisposable
beskriver hur du implementerar bortskaffandemönster i Razor komponenter.
Cachelagrade JavaScript-filer
JavaScript-filer (JS) och andra statiska tillgångar cachelagras vanligtvis inte på klienter under utveckling i Development
miljö. Under utvecklingen inkluderar begäranden om statiska resurser Cache-Control
headern med värdet no-cache
eller max-age
med värdet noll (0
).
I Production
-miljönunder produktion brukar JS-filer cachelagras av klienter.
För att inaktivera cachelagring på klientsidan i webbläsare använder utvecklare vanligtvis någon av följande metoder:
- Inaktivera cachelagring när webbläsarens utvecklarverktygskonsol är öppen. Vägledning finns i utvecklarverktygsdokumentationen för varje webbläsarunderhållare:
- Chrome DevTools
- översikt över Microsoft Edge Developer Tools
- Utför en manuell webbläsaruppdatering av en webbsida i Blazor-appen för att läsa in JS filer från servern igen. ASP.NET Cores HTTP Caching Middleware respekterar alltid ett giltigt
Cache-Control
- som skickas av en klient.
Mer information finns i:
- ASP.NET Core Blazor miljöer
- cachelagring av svar i ASP.NET Core
Storleksbegränsningar för JavaScript-interop-anrop
Det här avsnittet gäller endast interaktiva komponenter i appar på serversidan. För komponenter på klientsidan inför ramverket ingen gräns för storleken på JavaScript (JS) interop-indata och utdata.
För interaktiva komponenter i appar på serversidan är JS interop-anrop som skickar data från klienten till servern begränsade i storlek av den maximala inkommande SignalR meddelandestorlek som tillåts för hubbmetoder, vilket framtvingas av HubOptions.MaximumReceiveMessageSize (standard: 32 KB). JS till .NET SignalR meddelanden större än MaximumReceiveMessageSize utlöser ett fel. Ramverket har ingen gräns för storleken på ett SignalR meddelande från hubben till en klient. Mer information om storleksgräns, felmeddelanden och vägledning om hur du hanterar storleksbegränsningar för meddelanden finns i ASP.NET Core BlazorSignalR vägledning.
Ta reda på var appen körs
Om det är relevant för appen att veta var koden körs för JS interop-anrop använder du OperatingSystem.IsBrowser för att avgöra om komponenten körs i webbläsarens kontext på WebAssembly.
ASP.NET Core