Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Varning
Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i supportpolicyn för .NET och .NET Core. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Viktigt!
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.
För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Den här artikeln beskriver hur du anropar .NET-metoder från JavaScript (JS).
Information om hur du anropar JS funktioner från .NET finns i Anropa JavaScript-funktioner från .NET-metoder i ASP.NET Core Blazor.
Anropa en statisk .NET-metod
Om du vill anropa en statisk .NET-metod från JavaScript (JS) använder du JS funktionerna:
-
DotNet.invokeMethodAsync(rekommenderas): Asynkron för både komponenter på serversidan och på klientsidan. -
DotNet.invokeMethod: Synkron endast för komponenter på klientsidan.
Skicka in namnet på sammansättningen som innehåller metoden, identifieraren för den statiska .NET-metoden och eventuella argument.
I följande exempel:
- Platshållaren
{PACKAGE ID/ASSEMBLY NAME}är projektets paket-ID (<PackageId>i projektfilen) för ett bibliotek eller sammansättningsnamn för en app. - Platshållaren
{.NET METHOD ID}är .NET-metodidentifieraren. - Platshållaren
{ARGUMENTS}är valfria kommaavgränsade argument för att skicka till metoden, som var och en måste vara JSON-serialiserbara.
DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethodAsync returnerar ett JS Promise som representerar resultatet av åtgärden.
DotNet.invokeMethod (komponenter på klientsidan) returnerar resultatet av åtgärden.
Viktigt!
För komponenter på serversidan rekommenderar vi den asynkrona funktionen (invokeMethodAsync) över den synkrona versionen (invokeMethod).
.NET-metoden måste vara offentlig, statisk och ha attributet[JSInvokable] .
I följande exempel:
- Platshållaren
{<T>}anger returtypen, som endast krävs för metoder som returnerar ett värde. - Platshållaren
{.NET METHOD ID}är metodidentifieraren.
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
Anmärkning
Anropa öppna allmänna metoder stöds inte med statiska .NET-metoder, men stöds med instansmetoder. Mer information finns i avsnittet Anropa generiska klassmetoder för .NET .
I följande komponent ReturnArrayAsync returnerar C#-metoden en int matris.
Attributet[JSInvokable] tillämpas på metoden, vilket gör att metoden kan anropas av JS.
CallDotnet1.razor:
@page "/call-dotnet-1"
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 1</PageTitle>
<h1>Call .NET Example 1</h1>
<p>
<button id="btn">Trigger .NET static method</button>
</p>
<p>
See the result in the developer tools console.
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet1.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<int[]> ReturnArrayAsync() =>
Task.FromResult(new int[] { 11, 12, 13 });
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
CallDotnet1.razor.js:
export function returnArrayAsync() {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
}
export function addHandlers() {
const btn = document.getElementById("btn");
btn.addEventListener("click", returnArrayAsync);
}
Funktionen addHandlersJS lägger till en click händelse på knappen. Funktionen returnArrayAsyncJS tilldelas som hanterare.
Funktionen returnArrayAsyncJS anropar ReturnArrayAsync .NET-metoden för komponenten, som loggar resultatet till webbläsarens webbutvecklarverktygskonsol.
BlazorSample är appens sammansättningsnamn.
CallDotnet1.razor:
@page "/call-dotnet-1"
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 1</PageTitle>
<h1>Call .NET Example 1</h1>
<p>
<button id="btn">Trigger .NET static method</button>
</p>
<p>
See the result in the developer tools console.
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet1.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<int[]> ReturnArrayAsync() =>
Task.FromResult(new int[] { 11, 12, 13 });
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
CallDotnet1.razor.js:
export function returnArrayAsync() {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
}
export function addHandlers() {
const btn = document.getElementById("btn");
btn.addEventListener("click", returnArrayAsync);
}
Funktionen addHandlersJS lägger till en click händelse på knappen. Funktionen returnArrayAsyncJS tilldelas som hanterare.
Funktionen returnArrayAsyncJS anropar ReturnArrayAsync .NET-metoden för komponenten, som loggar resultatet till webbläsarens webbutvecklarverktygskonsol.
BlazorSample är appens sammansättningsnamn.
CallDotNetExample1.razor:
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
CallDotNetExample1.razor:
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
CallDotNetExample1.razor:
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
CallDotNetExample1.razor:
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
Elementets <button>onclick HTML-attribut är JavaScripts onclick händelsehanterartilldelning för bearbetning av click händelser, inte @onclickBlazordirektivattribut. Funktionen returnArrayAsyncJS tilldelas som hanterare.
returnArrayAsync
JS Följande funktion anropar ReturnArrayAsync .NET-metoden för komponenten, som loggar resultatet till webbläsarens webbutvecklarverktygskonsol.
BlazorSample är appens sammansättningsnamn.
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
Anmärkning
Allmän vägledning om JS plats och våra rekommendationer för produktionsappar finns i JavaScript-plats i ASP.NET Core Blazor-appar.
När knappen Trigger .NET static method väljs visar webbläsarens utvecklarverktygens konsol matrisdata. Utdataformatet skiljer sig något mellan webbläsare. Följande utdata visar det format som används av Microsoft Edge:
Array(3) [ 11, 12, 13 ]
Skicka data till en .NET-metod när du invokeMethodAsync anropar funktionen genom att skicka data som argument.
För att demonstrera överföring av data till .NET skickar du en startposition till metoden ReturnArrayAsync där metoden anropas i JS:
export function returnArrayAsync() {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', 14)
.then(data => {
console.log(data);
});
}
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', 14)
.then(data => {
console.log(data);
});
};
</script>
Komponentens anropande ReturnArrayAsync metod tar emot startpositionen och konstruerar matrisen från den. Matrisen returneras för loggning till konsolen:
[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition) =>
Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());
När appen har omkompilerats och webbläsaren har uppdaterats visas följande utdata i webbläsarens konsol när knappen är markerad:
Array(3) [ 14, 15, 16 ]
.NET-metodidentifieraren för anropet JS är .NET-metodnamnet, men du kan ange en annan identifierare med hjälp av [JSInvokable] attributkonstruktorn . I följande exempel DifferentMethodName är den tilldelade metodidentifieraren för ReturnArrayAsync metoden:
[JSInvokable("DifferentMethodName")]
I anropet till DotNet.invokeMethodAsync (komponenter på serversidan eller klientsidan) eller DotNet.invokeMethod (endast komponenter på klientsidan) anropar du DifferentMethodName för att köra ReturnArrayAsync .NET-metoden:
DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');-
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');(endast komponenter på klientsidan)
Anmärkning
Metodexemplet ReturnArrayAsync i det här avsnittet returnerar resultatet av ett Task utan att använda explicitA C# async och await nyckelord. Kodningsmetoder med async och await är typiska för metoder som använder nyckelordet await för att returnera värdet för asynkrona åtgärder.
ReturnArrayAsync -metod som består av async och await nyckelord:
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync() =>
await Task.FromResult(new int[] { 11, 12, 13 });
För mer information, se Asynkron programmering med async och await i C#-guiden.
Skapa JavaScript-objekt och datareferenser för att skicka till .NET
Anropa DotNet.createJSObjectReference(jsObject) för att skapa en JS objektreferens så att den kan skickas till .NET, där jsObject används JS Object för att skapa objektreferensen JS . I följande exempel skickas en referens till det icke-serialiserbara window objektet till .NET, som tar emot det i ReceiveWindowObject C#-metoden som :IJSObjectReference
DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
I föregående exempel {PACKAGE ID/ASSEMBLY NAME} är platshållaren projektets paket-ID (<PackageId> i projektfilen) för ett bibliotek eller sammansättningsnamn för en app.
Anmärkning
Föregående exempel kräver inte bortskaffande av JSObjectReference, eftersom en referens till window objektet inte finns i JS.
För att upprätthålla en referens till en JSObjectReference krävs det att den avyttras för att undvika läckage av JS-minne på klienten. Följande exempel omstrukturerar föregående kod för att fånga en referens till JSObjectReference, följt av ett anrop till DotNet.disposeJSObjectReference() för att ta bort referensen.
var jsObjectReference = DotNet.createJSObjectReference(window);
DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
I föregående exempel {PACKAGE ID/ASSEMBLY NAME} är platshållaren projektets paket-ID (<PackageId> i projektfilen) för ett bibliotek eller sammansättningsnamn för en app.
Anropa DotNet.createJSStreamReference(streamReference) för att skapa en JS strömreferens så att den kan skickas till .NET, där streamReference är en ArrayBuffer, Blob, eller en typad matris, till exempel Uint8Array eller Float32Array, som används för att skapa JS-strömreferensen.
Anropa en .NET-instansmetod
Så här anropar du en .NET-instansmetod från JavaScript (JS):
Skicka .NET-instansen med referens till JS genom att omsluta instansen i en DotNetObjectReference och anropa Create på den.
Anropa en .NET-instansmetod från JS med
invokeMethodAsync(rekommenderas) ellerinvokeMethod(endast komponenter på klientsidan) från den överförda DotNetObjectReference. Skicka identifieraren för instansens .NET-metod och eventuella argument. .NET-instansen kan också skickas som ett argument när du anropar andra .NET-metoder från JS.I följande exempel:
-
dotNetHelperär en DotNetObjectReference. - Platshållaren
{.NET METHOD ID}är .NET-metodidentifieraren. - Platshållaren
{ARGUMENTS}är valfria kommaavgränsade argument för att skicka till metoden, som var och en måste vara JSON-serialiserbara.
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});Anmärkning
invokeMethodAsyncochinvokeMethodacceptera inte en parameter för sammansättningsnamn när du anropar en instansmetod.invokeMethodAsyncreturnerar ett JSPromisesom representerar resultatet av åtgärden.invokeMethod(endast komponenter på klientsidan) returnerar resultatet av åtgärden.Viktigt!
För komponenter på serversidan rekommenderar vi den asynkrona funktionen (
invokeMethodAsync) över den synkrona versionen (invokeMethod).-
Ta bort DotNetObjectReference.
Följande avsnitt i den här artikeln visar olika metoder för att anropa en .NET-instansmetod:
Undvik att trimma JavaScript-anropande .NET-metoder
Det här avsnittet gäller för appar på klientsidan med AOT-kompilering (ahead-of-time) och omlänkning vid körning aktiverat.
Flera av exemplen i följande avsnitt baseras på en klassinstansmetod, där den JavaScript-anropande .NET-metoden som är markerad med [JSInvokable] attributet är medlem i en klass som inte är en Razor komponent. När sådana .NET-metoder finns i en Razor komponent skyddas de från runtime-omlänkning/trimning. För att skydda .NET-metoderna från att trimma utanför Razor komponenter implementerar du metoderna med DynamicDependency attributet på klassens konstruktor, vilket visas i följande exempel:
using System.Diagnostics.CodeAnalysis;
using Microsoft.JSInterop;
public class ExampleClass {
[DynamicDependency(nameof(ExampleJSInvokableMethod))]
public ExampleClass()
{
}
[JSInvokable]
public string ExampleJSInvokableMethod()
{
...
}
}
Mer information finns i Förbereda .NET-bibliotek för trimning: DynamicDependency.
Skicka en DotNetObjectReference till en enskild JavaScript-funktion
Exemplet i det här avsnittet visar hur du skickar en DotNetObjectReference till en enskild JavaScript-funktion (JS).
Följande sayHello1JS funktion tar emot en DotNetObjectReference och anropar invokeMethodAsync för att anropa GetHelloMessage .NET-metoden för en komponent:
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Anmärkning
Allmän vägledning om JS plats och våra rekommendationer för produktionsappar finns i JavaScript-plats i ASP.NET Core Blazor-appar.
I föregående exempel är variabelnamnet dotNetHelper godtyckligt och kan ändras till valfritt önskat namn.
För följande komponent:
- Komponenten har en JS-invokable .NET-metod med namnet
GetHelloMessage. -
Trigger .NET instance methodNär knappen har valts JS anropas funktionensayHello1med DotNetObjectReference. -
sayHello1:- Anropar
GetHelloMessageoch tar emot meddelanderesultatet. - Returnerar meddelanderesultatet till anropande
TriggerDotNetInstanceMethodmetod.
- Anropar
- Det returnerade meddelandet inifrån
sayHello1resultvisas för användaren. - För att undvika en minnesläcka och tillåta skräpinsamling tas .NET-objektreferensen som skapats av DotNetObjectReference bort i
Dispose-metoden.
CallDotnet2.razor:
@page "/call-dotnet-2"
@implements IDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 2</PageTitle>
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotnet2>? objRef;
protected override void OnInitialized() =>
objRef = DotNetObjectReference.Create(this);
public async Task TriggerDotNetInstanceMethod() =>
result = await JS.InvokeAsync<string>("sayHello1", objRef);
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose() => objRef?.Dispose();
}
CallDotnet2.razor:
@page "/call-dotnet-2"
@implements IDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 2</PageTitle>
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotnet2>? objRef;
protected override void OnInitialized() =>
objRef = DotNetObjectReference.Create(this);
public async Task TriggerDotNetInstanceMethod() =>
result = await JS.InvokeAsync<string>("sayHello1", objRef);
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose() => objRef?.Dispose();
}
CallDotNetExample2.razor:
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample2>? objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample2.razor:
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample2>? objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample2.razor:
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample2> objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample2.razor:
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample2> objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
I föregående exempel är variabelnamnet dotNetHelper godtyckligt och kan ändras till valfritt önskat namn.
Använd följande vägledning för att skicka argument till en instansmetod:
Lägg till parametrar i .NET-metodens anrop. I följande exempel skickas ett namn till metoden. Lägg till ytterligare parametrar i listan efter behov.
<script>
window.sayHello2 = (dotNetHelper, name) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage', name);
};
</script>
I föregående exempel är variabelnamnet dotNetHelper godtyckligt och kan ändras till valfritt önskat namn.
Ange parameterlistan till .NET-metoden.
CallDotnet3.razor:
@page "/call-dotnet-3"
@implements IDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 3</PageTitle>
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotnet3>? objRef;
protected override void OnInitialized() =>
objRef = DotNetObjectReference.Create(this);
public async Task TriggerDotNetInstanceMethod() =>
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose() => objRef?.Dispose();
}
CallDotnet3.razor:
@page "/call-dotnet-3"
@implements IDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 3</PageTitle>
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotnet3>? objRef;
protected override void OnInitialized() =>
objRef = DotNetObjectReference.Create(this);
public async Task TriggerDotNetInstanceMethod() =>
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose() => objRef?.Dispose();
}
CallDotNetExample3.razor:
@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample3>? objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
}
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample3.razor:
@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample3>? objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
}
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample3.razor:
@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample3> objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
}
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample3.razor:
@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample3> objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
}
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose()
{
objRef?.Dispose();
}
}
I föregående exempel är variabelnamnet dotNetHelper godtyckligt och kan ändras till valfritt önskat namn.
Skicka en DotNetObjectReference till en klass med flera JavaScript-funktioner
Exemplet i det här avsnittet visar hur du skickar en DotNetObjectReference till en JavaScript-klass (JS) med flera funktioner.
Skapa och skicka en DotNetObjectReference från OnAfterRenderAsync livscykelmetoden till en JS klass för att flera funktioner ska kunna använda den. Kontrollera att .NET-koden gör sig av med DotNetObjectReference, som visas i följande exempel.
I följande komponent anropar knapparna funktioner genom att ange JSonclick-egenskapen, inte Blazor@onclick-direktivattributet.
CallDotNetExampleOneHelper.razor:
@page "/call-dotnet-example-one-helper"
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET Example</PageTitle>
<h1>Pass <code>DotNetObjectReference</code> to a JavaScript class</h1>
<p>
<label>
Message: <input @bind="name" />
</label>
</p>
<p>
<button id="sayHelloBtn">
Trigger JS function <code>sayHello</code>
</button>
</p>
<p>
<button id="welcomeVisitorBtn">
Trigger JS function <code>welcomeVisitor</code>
</button>
</p>
@code {
private IJSObjectReference? module;
private string? name;
private DotNetObjectReference<CallDotNetExampleOneHelper>? dotNetHelper;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotNetExampleOneHelper.razor.js");
dotNetHelper = DotNetObjectReference.Create(this);
await module.InvokeVoidAsync("GreetingHelpers.setDotNetHelper",
dotNetHelper);
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
[JSInvokable]
public string GetWelcomeMessage() => $"Welcome, {name}!";
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
dotNetHelper?.Dispose();
}
}
I föregående exempel:
-
JSär en inmatad IJSRuntime instans. IJSRuntime registreras av Blazor ramverket. - Variabelnamnet
dotNetHelperär godtyckligt och kan ändras till valfritt önskat namn. - Komponenten måste uttryckligen ta bort för DotNetObjectReference att tillåta skräpinsamling och förhindra en minnesläcka.
-
JSDisconnectedException fångas under modulens bortskaffande om Blazors 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 lämna raden som avyttrar modulen (await module.DisposeAsync();). Mer information finns i ASP.NET Core Blazor JavaScript-samverkan (JS interop).
CallDotNetExampleOneHelper.razor.js:
export class GreetingHelpers {
static dotNetHelper;
static setDotNetHelper(value) {
GreetingHelpers.dotNetHelper = value;
}
static async sayHello() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetHelloMessage');
alert(`Message from .NET: "${msg}"`);
}
static async welcomeVisitor() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetWelcomeMessage');
alert(`Message from .NET: "${msg}"`);
}
}
export function addHandlers() {
const sayHelloBtn = document.getElementById("sayHelloBtn");
sayHelloBtn.addEventListener("click", GreetingHelpers.sayHello);
const welcomeVisitorBtn = document.getElementById("welcomeVisitorBtn");
welcomeVisitorBtn.addEventListener("click", GreetingHelpers.welcomeVisitor);
}
I föregående exempel är variabelnamnet dotNetHelper godtyckligt och kan ändras till valfritt önskat namn.
@page "/call-dotnet-example-one-helper"
@implements IDisposable
@inject IJSRuntime JS
<h1>Pass <code>DotNetObjectReference</code> to a JavaScript class</h1>
<p>
<label>
Message: <input @bind="name" />
</label>
</p>
<p>
<button onclick="GreetingHelpers.sayHello()">
Trigger JS function <code>sayHello</code>
</button>
</p>
<p>
<button onclick="GreetingHelpers.welcomeVisitor()">
Trigger JS function <code>welcomeVisitor</code>
</button>
</p>
@code {
private string? name;
private DotNetObjectReference<CallDotNetExampleOneHelper>? dotNetHelper;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
dotNetHelper = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("GreetingHelpers.setDotNetHelper",
dotNetHelper);
}
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
[JSInvokable]
public string GetWelcomeMessage() => $"Welcome, {name}!";
public void Dispose()
{
dotNetHelper?.Dispose();
}
}
I föregående exempel:
-
JSär en inmatad IJSRuntime instans. IJSRuntime registreras av Blazor ramverket. - Variabelnamnet
dotNetHelperär godtyckligt och kan ändras till valfritt önskat namn. - Komponenten måste uttryckligen frigöra DotNetObjectReference för att möjliggöra sophantering och förhindra en minnesläcka.
<script>
class GreetingHelpers {
static dotNetHelper;
static setDotNetHelper(value) {
GreetingHelpers.dotNetHelper = value;
}
static async sayHello() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetHelloMessage');
alert(`Message from .NET: "${msg}"`);
}
static async welcomeVisitor() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetWelcomeMessage');
alert(`Message from .NET: "${msg}"`);
}
}
window.GreetingHelpers = GreetingHelpers;
</script>
I föregående exempel:
- Klassen
GreetingHelpersläggs till iwindowobjektet för att globalt definiera klassen, vilket gör det möjligt Blazor att hitta klassen för JS interop. - Variabelnamnet
dotNetHelperär godtyckligt och kan ändras till valfritt önskat namn.
Anmärkning
Allmän vägledning om JS plats och våra rekommendationer för produktionsappar finns i JavaScript-plats i ASP.NET Core Blazor-appar.
Anropa generiska klassmetoder för .NET
JavaScript-funktioner (JS) kan anropa .NET generiska klassmetoder , där en JS funktion anropar en .NET-metod för en generisk klass.
I följande generiska typklass (GenericType<TValue>):
- Klassen har en parameter av en enda typ (
TValue) med en enda allmänValueegenskap. - Klassen har två icke-generiska metoder markerade med
[JSInvokable]attributet, var och en med en generisk typparameter med namnetnewValue:-
Updateuppdaterar synkront värdetValueför frånnewValue. -
UpdateAsyncuppdaterar asynkront värdet avValuefrånnewValueefter att ha skapat en väntbar uppgift med Task.Yield som asynkront återgår till den aktuella kontexten när den inväntas.
-
- Klassens metoder skriver typen av
TValueoch värdet avValuetill konsolen. Att skriva till konsolen är endast i demonstrationssyfte. Produktionsappar undviker vanligtvis att skriva till konsolen till förmån för apploggning. Mer information finns i ASP.NET Core-loggning Blazor och loggning i .NET Core och ASP.NET Core.
Anmärkning
Öppna allmänna typer och metoder anger inte typer för typplatshållare. Omvänt levererar slutna generiska typer för alla typplatshållare. Exemplen i det här avsnittet visar stängda generiska objekt, men det stöds att JS anropa interop-instansmetoder med öppna generiska objekt. Användning av öppna generiska objekt stöds inte för statiska .NET-metodanrop, som beskrevs tidigare i den här artikeln.
Mer information finns i följande artiklar:
- Allmänna klasser och metoder (C#-dokumentation)
- Allmänna klasser (C#-programmeringsguide)
- Generiska objekt i .NET (.NET-dokumentation)
GenericType.cs:
using Microsoft.JSInterop;
public class GenericType<TValue>
{
public TValue? Value { get; set; }
[JSInvokable]
public void Update(TValue newValue)
{
Value = newValue;
Console.WriteLine($"Update: GenericType<{typeof(TValue)}>: {Value}");
}
[JSInvokable]
public async Task UpdateAsync(TValue newValue)
{
await Task.Yield();
Value = newValue;
Console.WriteLine($"UpdateAsync: GenericType<{typeof(TValue)}>: {Value}");
}
}
I följande invokeMethodsAsync funktion:
- Den generiska typklassens
Update- ochUpdateAsync-metoder anropas med argument som representerar strängar och tal. - Komponenter på klientsidan stöder synkront anrop av .NET-metoder med
invokeMethod.syncInteropfår ett booleskt värde som anger om JS interop inträffar på klienten. NärsyncInteropärtrueanropasinvokeMethodpå ett säkert sätt. Om värdetsyncInteropför ärfalseanropas endast den asynkrona funktioneninvokeMethodAsynceftersom JS interop körs i en komponent på serversidan. - I demonstrationssyfte skrivs funktionsanropet DotNetObjectReference (
invokeMethodellerinvokeMethodAsync), .NET-metoden (UpdateellerUpdateAsync) och argumentet till konsolen. Argumenten använder ett slumptal för att tillåta matchning av JS funktionsanropet till .NET-metodanropet (skrivs också till konsolen på .NET-sidan). Produktionskoden skrivs vanligtvis inte till konsolen, varken på klienten eller servern. Produktionsappar förlitar sig vanligtvis på apploggning. Mer information finns i ASP.NET Core-loggning Blazor och loggning i .NET Core och ASP.NET Core.
<script>
const randomInt = () => Math.floor(Math.random() * 99999);
window.invokeMethodsAsync = async (syncInterop, dotNetHelper1, dotNetHelper2) => {
var n = randomInt();
console.log(`JS: invokeMethodAsync:Update('string ${n}')`);
await dotNetHelper1.invokeMethodAsync('Update', `string ${n}`);
n = randomInt();
console.log(`JS: invokeMethodAsync:UpdateAsync('string ${n}')`);
await dotNetHelper1.invokeMethodAsync('UpdateAsync', `string ${n}`);
if (syncInterop) {
n = randomInt();
console.log(`JS: invokeMethod:Update('string ${n}')`);
dotNetHelper1.invokeMethod('Update', `string ${n}`);
}
n = randomInt();
console.log(`JS: invokeMethodAsync:Update(${n})`);
await dotNetHelper2.invokeMethodAsync('Update', n);
n = randomInt();
console.log(`JS: invokeMethodAsync:UpdateAsync(${n})`);
await dotNetHelper2.invokeMethodAsync('UpdateAsync', n);
if (syncInterop) {
n = randomInt();
console.log(`JS: invokeMethod:Update(${n})`);
dotNetHelper2.invokeMethod('Update', n);
}
};
</script>
Anmärkning
Allmän vägledning om JS plats och våra rekommendationer för produktionsappar finns i JavaScript-plats i ASP.NET Core Blazor-appar.
I den följande GenericsExample-komponenten:
- Funktionen JS
invokeMethodsAsyncanropas närInvoke Interopknappen är markerad. - Ett par DotNetObjectReference-typer skapas och skickas till funktionen JS för instanser av
GenericTypesom enstringoch enint.
GenericsExample.razor:
@page "/generics-example"
@implements IDisposable
@inject IJSRuntime JS
<p>
<button @onclick="InvokeInterop">Invoke Interop</button>
</p>
<ul>
<li>genericType1: @genericType1?.Value</li>
<li>genericType2: @genericType2?.Value</li>
</ul>
@code {
private GenericType<string> genericType1 = new() { Value = "string 0" };
private GenericType<int> genericType2 = new() { Value = 0 };
private DotNetObjectReference<GenericType<string>>? objRef1;
private DotNetObjectReference<GenericType<int>>? objRef2;
protected override void OnInitialized()
{
objRef1 = DotNetObjectReference.Create(genericType1);
objRef2 = DotNetObjectReference.Create(genericType2);
}
public async Task InvokeInterop()
{
var syncInterop = OperatingSystem.IsBrowser();
await JS.InvokeVoidAsync(
"invokeMethodsAsync", syncInterop, objRef1, objRef2);
}
public void Dispose()
{
objRef1?.Dispose();
objRef2?.Dispose();
}
}
@page "/generics-example"
@implements IDisposable
@inject IJSRuntime JS
<p>
<button @onclick="InvokeInterop">Invoke Interop</button>
</p>
<ul>
<li>genericType1: @genericType1?.Value</li>
<li>genericType2: @genericType2?.Value</li>
</ul>
@code {
private GenericType<string> genericType1 = new() { Value = "string 0" };
private GenericType<int> genericType2 = new() { Value = 0 };
private DotNetObjectReference<GenericType<string>>? objRef1;
private DotNetObjectReference<GenericType<int>>? objRef2;
protected override void OnInitialized()
{
objRef1 = DotNetObjectReference.Create(genericType1);
objRef2 = DotNetObjectReference.Create(genericType2);
}
public async Task InvokeInterop()
{
var syncInterop = OperatingSystem.IsBrowser();
await JS.InvokeVoidAsync(
"invokeMethodsAsync", syncInterop, objRef1, objRef2);
}
public void Dispose()
{
objRef1?.Dispose();
objRef2?.Dispose();
}
}
I föregående exempel JS är en inmatad IJSRuntime instans.
IJSRuntime registreras av Blazor ramverket.
Följande visar typiska utdata från föregående exempel när Invoke Interop knappen väljs i en komponent på klientsidan:
JS: invokeMethodAsync:Update('string 37802')
.NET: Uppdatering: GenericType<System.String>: string 37802
JS: invokeMethodAsync:UpdateAsync('string 53051')
JS: invokeMethod:Update('string 26784')
.NET: Update: GenericType<System.String>: string 26784
JS: invokeMethodAsync:Update(14107)
.NET: Update: GenericType<System.Int32>: 14107
JS: invokeMethodAsync:UpdateAsync(48995)
JS: invokeMethod:Update(12872)
.NET: Update: GenericType<System.Int32>: 12872
.NET: UpdateAsync: GenericType<System.String>: string 53051
.NET: UpdateAsync: GenericType<System.Int32>: 48995
Om föregående exempel implementeras i en komponent på serversidan undviks de synkrona anropen med invokeMethod . För komponenter på serversidan rekommenderar vi den asynkrona funktionen (invokeMethodAsync) över den synkrona versionen (invokeMethod).
Typiska utdata för en komponent på serversidan:
JS: invokeMethodAsync:Update('string 34809')
.NET: Uppdatering: GenericTyp<System.String>: sträng 34809
JS: invokeMethodAsync:UpdateAsync('string 93059')
JS: invokeMethodAsync:Update(41997)
.NET: Update: GenericType<System.Int32>: 41997
JS: invokeMethodAsync:UpdateAsync(24652)
.NET: UpdateAsync: GenericType<System.String>: sträng 93059
.NET: UpdateAsync: GenericType<System.Int32>: 24652
Föregående utdataexempel visar att asynkrona metoder körs och slutförs i godtycklig ordning beroende på flera faktorer, inklusive trådschemaläggning och metodkörningshastighet. Det går inte att förutsäga slutförandeordningen för asynkrona metodanrop på ett tillförlitligt sätt.
Exempel på klassinstanser
Följande sayHello1JS funktion:
-
GetHelloMessageAnropar .NET-metoden på den skickade DotNetObjectReference. - Returnerar meddelandet från
GetHelloMessagetill anroparensayHello1.
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Anmärkning
Allmän vägledning om JS plats och våra rekommendationer för produktionsappar finns i JavaScript-plats i ASP.NET Core Blazor-appar.
I föregående exempel är variabelnamnet dotNetHelper godtyckligt och kan ändras till valfritt önskat namn.
Följande HelloHelper klass har en JS-invokable .NET-metod med namnet GetHelloMessage. När HelloHelper skapas används namnet i Name egenskapen för att returnera ett meddelande från GetHelloMessage.
HelloHelper.cs:
using Microsoft.JSInterop;
namespace BlazorSample;
public class HelloHelper(string? name)
{
public string? Name { get; set; } = name ?? "No Name";
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
namespace BlazorSample;
public class HelloHelper(string? name)
{
public string? Name { get; set; } = name ?? "No Name";
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string? name)
{
Name = name ?? "No Name";
}
public string? Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string? name)
{
Name = name ?? "No Name";
}
public string? Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string name)
{
Name = name;
}
public string Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string name)
{
Name = name;
}
public string Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
Metoden CallHelloHelperGetHelloMessage i följande JsInteropClasses3 klass anropar JS funktionen sayHello1 med en ny instans av HelloHelper.
JsInteropClasses3.cs:
using Microsoft.JSInterop;
namespace BlazorSample;
public class JsInteropClasses3(IJSRuntime js)
{
private readonly IJSRuntime js = js;
public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using Microsoft.JSInterop;
namespace BlazorSample;
public class JsInteropClasses3(IJSRuntime js)
{
private readonly IJSRuntime js = js;
public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using Microsoft.JSInterop;
public class JsInteropClasses3
{
private readonly IJSRuntime js;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using Microsoft.JSInterop;
public class JsInteropClasses3
{
private readonly IJSRuntime js;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using System.Threading.Tasks;
using Microsoft.JSInterop;
public class JsInteropClasses3
{
private readonly IJSRuntime js;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public async ValueTask<string> CallHelloHelperGetHelloMessage(string name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using System.Threading.Tasks;
using Microsoft.JSInterop;
public class JsInteropClasses3
{
private readonly IJSRuntime js;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public async ValueTask<string> CallHelloHelperGetHelloMessage(string name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
För att undvika en minnesläcka och tillåta skräpinsamling tas .NET-objektreferensen som skapas av DotNetObjectReference bort när objektreferensen hamnar utanför omfånget med using var syntax.
Trigger .NET instance method När knappen har valts i följande komponent JsInteropClasses3.CallHelloHelperGetHelloMessage anropas med värdet name.
CallDotnet4.razor:
@page "/call-dotnet-4"
@inject IJSRuntime JS
<PageTitle>Call .NET 4</PageTitle>
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
protected override void OnInitialized() =>
jsInteropClasses = new JsInteropClasses3(JS);
private async Task TriggerDotNetInstanceMethod()
{
if (jsInteropClasses is not null)
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
}
CallDotnet4.razor:
@page "/call-dotnet-4"
@inject IJSRuntime JS
<PageTitle>Call .NET 4</PageTitle>
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
protected override void OnInitialized() =>
jsInteropClasses = new JsInteropClasses3(JS);
private async Task TriggerDotNetInstanceMethod()
{
if (jsInteropClasses is not null)
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
}
CallDotNetExample4.razor:
@page "/call-dotnet-example-4"
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
protected override void OnInitialized()
{
jsInteropClasses = new JsInteropClasses3(JS);
}
private async Task TriggerDotNetInstanceMethod()
{
if (jsInteropClasses is not null)
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
}
CallDotNetExample4.razor:
@page "/call-dotnet-example-4"
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
protected override void OnInitialized()
{
jsInteropClasses = new JsInteropClasses3(JS);
}
private async Task TriggerDotNetInstanceMethod()
{
if (jsInteropClasses is not null)
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
}
CallDotNetExample4.razor:
@page "/call-dotnet-example-4"
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private JsInteropClasses3 jsInteropClasses;
protected override void OnInitialized()
{
jsInteropClasses = new JsInteropClasses3(JS);
}
private async Task TriggerDotNetInstanceMethod()
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
CallDotNetExample4.razor:
@page "/call-dotnet-example-4"
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private JsInteropClasses3 jsInteropClasses;
protected override void OnInitialized()
{
jsInteropClasses = new JsInteropClasses3(JS);
}
private async Task TriggerDotNetInstanceMethod()
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
Följande bild visar den renderade komponenten med namnet Amy Pond i fältet Name . När knappen har valts Hello, Amy Pond! visas den i användargränssnittet:
Föregående mönster som visas i JsInteropClasses3 klassen kan också implementeras helt i en komponent.
CallDotnet5.razor:
@page "/call-dotnet-5"
@inject IJSRuntime JS
<PageTitle>Call .NET 5</PageTitle>
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotnet5.razor:
@page "/call-dotnet-5"
@inject IJSRuntime JS
<PageTitle>Call .NET 5</PageTitle>
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotNetExample5.razor:
@page "/call-dotnet-example-5"
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotNetExample5.razor:
@page "/call-dotnet-example-5"
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotNetExample5.razor:
@page "/call-dotnet-example-5"
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotNetExample5.razor:
@page "/call-dotnet-example-5"
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
För att undvika en minnesläcka och tillåta skräpinsamling tas .NET-objektreferensen som skapas av DotNetObjectReference bort när objektreferensen hamnar utanför omfånget med using var syntax.
Utdata som visas av komponenten är Hello, Amy Pond! när namnet Amy Pond anges i fältet name .
I föregående komponent tas .NET-objektreferensen bort. Om en klass eller komponent inte avyttrar DotNetObjectReference, avyttra den från klienten genom att anropa dispose på den överförda DotNetObjectReference:
window.{JS FUNCTION NAME} = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}');
dotNetHelper.dispose();
}
I föregående exempel:
- Platshållaren
{JS FUNCTION NAME}är JS funktionens namn. - Variabelnamnet
dotNetHelperär godtyckligt och kan ändras till valfritt önskat namn. - Platshållaren
{.NET METHOD ID}är .NET-metodidentifieraren.
Komponentinstansens .NET-metodhjälpklass
En hjälpklass kan anropa en .NET-instansmetod som en Action. Hjälpklasser är användbara i scenarier där statiska .NET-metoder inte är tillämpliga:
- När flera komponenter av samma typ återges på samma sida.
- I appar på serversidan med flera användare samtidigt med samma komponent.
I följande exempel:
- Komponenten innehåller flera
ListItem1komponenter. - Varje
ListItem1komponent består av ett meddelande och en knapp. - När en
ListItem1komponentknapp har valtsListItem1UpdateMessageändrar metoden listobjektets text och döljer knappen.
MessageUpdateInvokeHelper Följande klass upprätthåller en JS-anropbar .NET-metod, UpdateMessageCaller, för att anropa Action när klassen instansieras.
MessageUpdateInvokeHelper.cs:
using Microsoft.JSInterop;
namespace BlazorSample;
public class MessageUpdateInvokeHelper(Action action)
{
private readonly Action action = action;
[JSInvokable]
public void UpdateMessageCaller() => action.Invoke();
}
using Microsoft.JSInterop;
namespace BlazorSample;
public class MessageUpdateInvokeHelper(Action action)
{
private readonly Action action = action;
[JSInvokable]
public void UpdateMessageCaller() => action.Invoke();
}
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
using System;
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
using System;
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
updateMessageCaller
JS Följande funktion anropar UpdateMessageCaller .NET-metoden.
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
Anmärkning
Allmän vägledning om JS plats och våra rekommendationer för produktionsappar finns i JavaScript-plats i ASP.NET Core Blazor-appar.
I föregående exempel är variabelnamnet dotNetHelper godtyckligt och kan ändras till valfritt önskat namn.
Följande ListItem1 komponent är en delad komponent som kan användas valfritt antal gånger i en överordnad komponent och skapar listobjekt (<li>...</li>) för en HTML-lista (<ul>...</ul> eller <ol>...</ol>). Varje ListItem1-komponentinstans etablerar en instans av MessageUpdateInvokeHelper med Action som är satt till sin UpdateMessage-metod.
När en ListItem1-komponents InteropCall-knapp har valts, anropas updateMessageCaller med en skapad DotNetObjectReference för MessageUpdateInvokeHelper-instansen. Detta gör det möjligt för ramverket att anropa UpdateMessageCaller på ListItem1s MessageUpdateInvokeHelper instans. Det överlämnade DotNetObjectReference kasseras i JS (dotNetHelper.dispose()).
ListItem1.razor:
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
StateHasChanged anropas för att uppdatera användargränssnittet när message har angetts i UpdateMessage. Om StateHasChanged inte anropas har Blazor ingen möjlighet att veta att användargränssnittet ska uppdateras när Action anropas.
Följande överordnade komponent innehåller fyra listobjekt, var och en en instans av komponenten ListItem1 .
CallDotnet6.razor:
@page "/call-dotnet-6"
<PageTitle>Call .NET 6</PageTitle>
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotnet6.razor:
@page "/call-dotnet-6"
<PageTitle>Call .NET 6</PageTitle>
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
Följande bild visar den renderade överordnade komponenten när den andra InteropCall knappen har valts:
- Den andra
ListItem1komponenten har visat meddelandetUpdateMessage Called!. - Knappen
InteropCallför den andraListItem1komponenten visas inte eftersom knappens CSS-egenskapdisplayär inställd pånone.
Komponentinstansens .NET-metod anropad från DotNetObjectReference tilldelad till en elementegenskap
Tilldelningen av en DotNetObjectReference till en egenskap för ett HTML-element tillåter anrop av .NET-metoder på en komponentinstans:
- En elementreferens samlas in (ElementReference).
- I komponentens
OnAfterRender{Async}-metod anropas en JavaScript-funktion (JS) med elementreferensen och komponentinstansen som en DotNetObjectReference. Funktionen JS kopplar DotNetObjectReference till elementet i en egenskap. - När en elementhändelse anropas i JS (till exempel
onclick) används det kopplade DotNetObjectReference elementet för att anropa en .NET-metod.
På samma sätt som den metod som beskrivs i avsnittet komponentinstans .NET-metodhjälpklass är den här metoden användbar i scenarier där användning av statiska .NET-metoder inte är tillämpliga:
- När flera komponenter av samma typ återges på samma sida.
- I appar på serversidan med flera användare samtidigt med samma komponent.
- .NET-metoden anropas från en JS händelse (till exempel
onclick), inte från en Blazor händelse (till exempel@onclick).
I följande exempel:
- Komponenten innehåller flera
ListItem2komponenter, som är en delad komponent. - Varje
ListItem2komponent består av ett listobjektmeddelande<span>och en sekund<span>med endisplayCSS-egenskap inställd påinline-blockför visning. - När ett
ListItem2komponentelement i listan är markerat, använderListItem2UpdateMessagemetoden för att ändra den angivna listobjektets text i den första<span>och döljer den andra<span>genom att ställa in dessdisplayegenskap tillnone.
Följande assignDotNetHelperJS funktion tilldelar DotNetObjectReference till ett element i en egenskap med namnet dotNetHelper. Följande interopCallJS funktion använder DotNetObjectReference för det skickade elementet för att anropa en .NET-metod med namnet UpdateMessage.
ListItem2.razor.js:
export function assignDotNetHelper(element, dotNetHelper) {
element.dotNetHelper = dotNetHelper;
}
export async function interopCall(element) {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
ListItem2.razor.js:
export function assignDotNetHelper(element, dotNetHelper) {
element.dotNetHelper = dotNetHelper;
}
export async function interopCall(element) {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
<script>
window.assignDotNetHelper = (element, dotNetHelper) => {
element.dotNetHelper = dotNetHelper;
}
window.interopCall = async (element) => {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
</script>
Anmärkning
Allmän vägledning om JS plats och våra rekommendationer för produktionsappar finns i JavaScript-plats i ASP.NET Core Blazor-appar.
I föregående exempel är variabelnamnet dotNetHelper godtyckligt och kan ändras till valfritt önskat namn.
Följande ListItem2 komponent är en delad komponent som kan användas valfritt antal gånger i en överordnad komponent och skapar listobjekt (<li>...</li>) för en HTML-lista (<ul>...</ul> eller <ol>...</ol>).
Varje ListItem2 komponentinstans anropar assignDotNetHelperJS funktionen i OnAfterRenderAsync med en elementreferens (det första <span> elementet i listobjektet) och komponentinstansen som en DotNetObjectReference.
När meddelandet från en ListItem2-komponent <span> har valts, anropas interopCall och elementet <span> skickas som en parameter (this), vilket i sin tur anropar .NET-metoden UpdateMessage. I UpdateMessage anropas StateHasChanged för att uppdatera användargränssnittet när message har ställts in och när display-egenskapen för den andra <span> uppdateras. Om StateHasChanged inte anropas har Blazor ingen möjlighet att veta att användargränssnittet ska uppdateras när metoden anropas.
DotNetObjectReference Tas bort när komponenten tas bort.
ListItem2.razor:
@inject IJSRuntime JS
@implements IAsyncDisposable
<li>
<span style="font-weight:bold;color:@color" @ref="elementRef"
@onclick="CallJSToInvokeDotnet">
@message
</span>
<span style="display:@display">
Not Updated Yet!
</span>
</li>
@code {
private IJSObjectReference? module;
private DotNetObjectReference<ListItem2>? objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
private string color = "initial";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/ListItem2.razor.js");
objRef = DotNetObjectReference.Create(this);
await module.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
public async Task CallJSToInvokeDotnet()
{
if (module is not null)
{
await module.InvokeVoidAsync("interopCall", elementRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
color = "MediumSeaGreen";
StateHasChanged();
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
objRef?.Dispose();
}
}
@inject IJSRuntime JS
@implements IAsyncDisposable
<li>
<span style="font-weight:bold;color:@color" @ref="elementRef"
@onclick="CallJSToInvokeDotnet">
@message
</span>
<span style="display:@display">
Not Updated Yet!
</span>
</li>
@code {
private IJSObjectReference? module;
private DotNetObjectReference<ListItem2>? objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
private string color = "initial";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/ListItem2.razor.js");
objRef = DotNetObjectReference.Create(this);
await module.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
public async Task CallJSToInvokeDotnet()
{
if (module is not null)
{
await module.InvokeVoidAsync("interopCall", elementRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
color = "MediumSeaGreen";
StateHasChanged();
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
objRef?.Dispose();
}
}
@inject IJSRuntime JS
<li>
<span @ref="elementRef" onclick="interopCall(this)">@message</span>
<span style="display:@display">Not Updated Yet!</span>
</li>
@code {
private DotNetObjectReference<ListItem2>? objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
public void Dispose() => objRef?.Dispose();
}
@inject IJSRuntime JS
<li>
<span @ref="elementRef" onclick="interopCall(this)">@message</span>
<span style="display:@display">Not Updated Yet!</span>
</li>
@code {
private DotNetObjectReference<ListItem2>? objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
public void Dispose() => objRef?.Dispose();
}
@inject IJSRuntime JS
<li>
<span @ref="elementRef" onclick="interopCall(this)">@message</span>
<span style="display:@display">Not Updated Yet!</span>
</li>
@code {
private DotNetObjectReference<ListItem2> objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
public void Dispose() => objRef?.Dispose();
}
@inject IJSRuntime JS
<li>
<span @ref="elementRef" onclick="interopCall(this)">@message</span>
<span style="display:@display">Not Updated Yet!</span>
</li>
@code {
private DotNetObjectReference<ListItem2> objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
public void Dispose() => objRef?.Dispose();
}
Följande överordnade komponent innehåller fyra listobjekt, var och en en instans av komponenten ListItem2 .
CallDotnet7.razor:
@page "/call-dotnet-7"
<PageTitle>Call .NET 7</PageTitle>
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotnet7.razor:
@page "/call-dotnet-7"
<PageTitle>Call .NET 7</PageTitle>
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
Synkrona JS-interoperabilitet i klientkomponenter
Det här avsnittet gäller endast komponenter på klientsidan.
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 i återgivningslägen på serversidan och på klientsidan. På servern måste alla JS interop-anrop vara asynkrona eftersom de skickas via en nätverksanslutning.
Om du vet att komponenten bara körs på WebAssembly kan du välja att göra synkrona JS interop-anrop. Detta har något mindre omkostnader än att göra asynkrona anrop och kan resultera i färre återgivningscykler eftersom det inte finns något mellanliggande tillstånd i väntan på resultat.
Om du vill göra ett synkront anrop från JavaScript till .NET i en komponent på klientsidan använder du DotNet.invokeMethod i stället för DotNet.invokeMethodAsync.
Synkrona anrop fungerar om:
JavaScript-plats
Läs in JavaScript-kod (JS) med någon av de metoder som beskrivs i -artikeln om JavaScript-plats:
Använd JS-moduler för att läsa in JS vilket beskrivs i artikelns avsnitt JavaScript-isolering i JavaScript-moduler.
Varning
Placera bara en <script>-tagg i en komponentfil (.razor) om komponenten garanterat använder statisk återgivning på serversidan (statisk SSR) eftersom taggen <script> inte kan uppdateras dynamiskt.
Varning
Placera inte en <script>-tagg i en komponentfil (.razor) eftersom taggen <script> inte kan uppdateras dynamiskt.
JavaScript-isolering i JavaScript-moduler
Blazor aktiverar JavaScript-isolering (JS) i JavaScript-standardmoduler (ECMAScript-specifikation). JavaScript-modulinläsning fungerar på samma sätt i Blazor som för andra typer av webbappar, och du kan anpassa hur moduler definieras i din app. En guide om hur du använder JavaScript-moduler finns i MDN Web Docs: JavaScript-moduler.
JS isolering ger följande fördelar:
- Importerade JS förorenar inte längre det globala namnområdet.
- Användare av ett bibliotek och dess komponenter behöver inte importera den relaterade JS.
Mer information finns i Anropa JavaScript-funktioner från .NET-metoder i ASP.NET Core Blazor.
Dynamisk import med operatorn import() stöds med ASP.NET Core och Blazor:
if ({CONDITION}) import("/additionalModule.js");
I föregående exempel representerar platshållaren {CONDITION} en villkorlig kontroll för att avgöra om modulen ska laddas.
Information om webbläsarkompatibilitet finns i Kan jag använda: JavaScript-moduler: dynamisk import.
Undvik cirkelobjektreferenser
Objekt som innehåller cirkelreferenser kan inte serialiseras på klienten för något av följande:
- .NET-metodanrop.
- JavaScript-metoden anropar från C# när returtypen har cirkelreferenser.
Stöd för bytematris
Blazor stöder optimerad bytematris JavaScript (JS) interop som undviker kodning/avkodning av bytematriser till Base64. I följande exempel används JS interop för att skicka en bytematris till .NET.
Ange en sendByteArrayJS funktion. Funktionen kallas statiskt, med parametern för sammansättningsnamnet i invokeMethodAsync-anropet, via en knapp i komponenten, och returnerar inget värde.
CallDotnet8.razor.js:
export function sendByteArray() {
const data = new Uint8Array([0x45, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69,
0x6e, 0x67, 0x27, 0x73, 0x20, 0x73, 0x68, 0x69, 0x6e, 0x79, 0x2c,
0x20, 0x43, 0x61, 0x70, 0x74, 0x61, 0x69, 0x6e, 0x2e, 0x20, 0x4e,
0x6f, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x72, 0x65, 0x74, 0x2e]);
DotNet.invokeMethodAsync('BlazorSample', 'ReceiveByteArray', data)
.then(str => {
alert(str);
});
}
export function addHandlers() {
const btn = document.getElementById("btn");
btn.addEventListener("click", sendByteArray);
}
<script>
window.sendByteArray = () => {
const data = new Uint8Array([0x45,0x76,0x65,0x72,0x79,0x74,0x68,0x69,
0x6e,0x67,0x27,0x73,0x20,0x73,0x68,0x69,0x6e,0x79,0x2c,
0x20,0x43,0x61,0x70,0x74,0x61,0x69,0x6e,0x2e,0x20,0x4e,
0x6f,0x74,0x20,0x74,0x6f,0x20,0x66,0x72,0x65,0x74,0x2e]);
DotNet.invokeMethodAsync('BlazorSample', 'ReceiveByteArray', data)
.then(str => {
alert(str);
});
};
</script>
Anmärkning
Allmän vägledning om JS plats och våra rekommendationer för produktionsappar finns i JavaScript-plats i ASP.NET Core Blazor-appar.
CallDotnet8.razor:
@page "/call-dotnet-8"
@using System.Text
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 8</PageTitle>
<h1>Call .NET Example 8</h1>
<p>
<button id="btn">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet8.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes) =>
Task.FromResult(Encoding.UTF8.GetString(receivedBytes, 0,
receivedBytes.Length));
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
CallDotnet8.razor:
@page "/call-dotnet-8"
@using System.Text
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 8</PageTitle>
<h1>Call .NET Example 8</h1>
<p>
<button id="btn">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet8.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes) =>
Task.FromResult(Encoding.UTF8.GetString(receivedBytes, 0,
receivedBytes.Length));
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
CallDotNetExample8.razor:
@page "/call-dotnet-example-8"
@using System.Text
<PageTitle>Call .NET 8</PageTitle>
<h1>Call .NET Example 8</h1>
<p>
<button onclick="sendByteArray()">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes)
{
return Task.FromResult(
Encoding.UTF8.GetString(receivedBytes, 0, receivedBytes.Length));
}
}
CallDotNetExample8.razor:
@page "/call-dotnet-example-8"
@using System.Text
<h1>Call .NET Example 8</h1>
<p>
<button onclick="sendByteArray()">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes)
{
return Task.FromResult(
Encoding.UTF8.GetString(receivedBytes, 0, receivedBytes.Length));
}
}
Information om hur du använder en bytematris när du anropar JavaScript från .NET finns i Anropa JavaScript-funktioner från .NET-metoder i ASP.NET Core Blazor.
Strömma från JavaScript till .NET
Blazor stöder direktuppspelning av data från JavaScript till .NET. Strömmar begärs med hjälp av Microsoft.JSInterop.IJSStreamReference gränssnittet.
Microsoft.JSInterop.IJSStreamReference.OpenReadStreamAsync returnerar en Stream och använder följande parametrar:
-
maxAllowedSize: Maximalt antal byte som tillåts för läsåtgärden från JavaScript, som standard är 512 000 byte om det inte anges. -
cancellationToken: A CancellationToken för att avbryta läsningen.
I JavaScript:
function streamToDotNet() {
return new Uint8Array(10000000);
}
I C#-kod:
var dataReference =
await JS.InvokeAsync<IJSStreamReference>("streamToDotNet");
using var dataReferenceStream =
await dataReference.OpenReadStreamAsync(maxAllowedSize: 10_000_000);
var outputPath = Path.Combine(Path.GetTempPath(), "file.txt");
using var outputFileStream = File.OpenWrite(outputPath);
await dataReferenceStream.CopyToAsync(outputFileStream);
I föregående exempel:
-
JSär en inmatad IJSRuntime instans. IJSRuntime registreras av Blazor ramverket. -
dataReferenceStreamSkrivs till disken (file.txt) på den aktuella användarens temporära mappsökväg (GetTempPath).
Anropa JavaScript-funktioner från .NET-metoder i ASP.NET Core Blazor omfattar den omvända åtgärden, direktuppspelning från .NET till JavaScript med hjälp av en DotNetStreamReference.
ASP.NET Core-filuppladdningar Blazor beskriver hur du laddar upp en fil i Blazor. Ett formulärexempel som strömmar <textarea> data i en komponent på serversidan finns i Felsöka ASP.NET Core-formulärBlazor.
JavaScript-interop [JSImport]/[JSExport]
Det här avsnittet gäller komponenter på klientsidan.
Som ett alternativ till att interagera med JavaScript (JS) i komponenter på klientsidan med hjälp av BlazorJS interop-mekanism baserat på IJSRuntime-gränssnittet är ett JS[JSImport]/[JSExport] interop-API tillgängligt för appar som riktar sig till .NET 7 eller senare.
Mer information finns i JavaScript JSImport/JSExport interop med ASP.NET Core Blazor.
Borttagning av javascript-interopobjektreferenser
Exempel i interop-artiklarna i JavaScript (JS) visar typiska mönster för bortskaffande av objekt:
När du anropar .NET från JS, enligt beskrivningen i den här artikeln, gör du dig av med en skapad DotNetObjectReference från .NET eller från JS för att undvika att läcka .NET-minne.
När du anropar JS från .NET, enligt beskrivningen i Anropa JavaScript-funktioner från .NET-metoder i ASP.NET Core Blazor, ska du ta bort alla skapade IJSObjectReference/IJSInProcessObjectReference/
JSObjectReferenceantingen från .NET eller från JS för att undvika att läcka JS minne.
JS interop-objektreferenser implementeras som en karta där nyckeln är en identifierare på sidan av JS interop-anropet som skapar referensen. När bortskaffande av objekt initieras från antingen .NET- eller JS-sidan tar Blazor bort posten från kartan, och objektet kan bli föremål för avfallshantering så länge det inte finns någon annan stark referens till objektet.
Ta alltid bort objekt som skapats på .NET-sidan för att undvika att läcka .NET-hanterat minne.
DOM-rensningsuppgifter vid bortskaffande av komponenter
Mer information finns i ASP.NET Core Blazor JavaScript-samverkan (JS interop).
JavaScript-interopanrop utan krets
Mer information finns i ASP.NET Core Blazor JavaScript-samverkan (JS interop).
Ytterligare resurser
- Anropa JavaScript-funktioner från .NET-metoder i ASP.NET Core Blazor
-
InteropComponent.razorexempel (dotnet/AspNetCoreGitHub-lagringsplatsmaingren): Grenenmainrepresenterar produktenhetens aktuella utveckling för nästa version av ASP.NET Core. Om du vill välja grenen för en annan version (till exempelrelease/{VERSION}, där platshållaren{VERSION}är versionsnumret), använder du rullgardinsmenyn Växla grenar eller taggar för att välja grenen. För en gren som inte längre finns använder du fliken Taggar för att hitta API:et (till exempelv7.0.0). - Interaktion med DOM
-
Blazor exempel på GitHub-lagringsplats (
dotnet/blazor-samples) (hur du laddar ned) - Hantera fel i ASP.NET Core Blazor-appar (JavaScript-interop avsnitt)
- Hotreducering: .NET-metoder som anropas från webbläsaren
ASP.NET Core