Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Note
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 10 tohoto článku.
Warning
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Tento článek vysvětluje, jak vyvolat metody .NET z JavaScriptu (JS).
Informace o volání JS funkcí z .NET naleznete v tématu Volání javascriptových funkcí z metod .NET v ASP.NET Core Blazor.
Vyvolání statické metody .NET
Pokud chcete vyvolat statickou metodu .NET z JavaScriptu (JS), použijte JS tyto funkce:
-
DotNet.invokeMethodAsync(doporučeno): Asynchronní pro součásti na straně serveru i na straně klienta. -
DotNet.invokeMethod: Synchronní pouze pro komponenty na straně klienta.
Předejte název sestavení obsahující metodu, identifikátor statické metody .NET a všechny argumenty.
V následujícím příkladu:
- Zástupným
{PACKAGE ID/ASSEMBLY NAME}symbolem je ID balíčku projektu (<PackageId>v souboru projektu) pro knihovnu nebo název sestavení aplikace. - Zástupný
{.NET METHOD ID}symbol je identifikátor metody .NET. - Zástupný
{ARGUMENTS}symbol je volitelný argument oddělený čárkami, které se mají předat metodě, z nichž každý musí být serializovatelný ve formátu JSON.
DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethodAsync
JS Promise vrátí reprezentaci výsledku operace.
DotNet.invokeMethod (komponenty na straně klienta) vrátí výsledek operace.
Important
U komponent na straně serveru doporučujeme asynchronní funkci (invokeMethodAsync) nad synchronní verzí (invokeMethod).
Metoda .NET musí být veřejná, statická a musí mít [JSInvokable] atribut.
V následujícím příkladu:
- Zástupný
{<T>}symbol označuje návratový typ, který se vyžaduje pouze pro metody, které vracejí hodnotu. - Zástupný
{.NET METHOD ID}symbol je identifikátor metody.
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
Note
Volání otevřených obecných metod není podporováno u statických metod .NET, ale podporuje se metodami instance. Další informace naleznete v části Volání metod obecné třídy .NET.
V následující komponentě ReturnArrayAsync vrátí int metoda C# pole.
[JSInvokable]
se použije na metodu, která způsobí, že metoda vyvolá .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);
}
Funkce addHandlersJS přidá click do tlačítka událost. Funkce returnArrayAsyncJS je přiřazena jako obslužná rutina.
Funkce returnArrayAsyncJS volá metodu ReturnArrayAsync .NET komponenty, která zaprotokoluje výsledek do konzoly webových vývojářských nástrojů prohlížeče.
BlazorSample je název sestavení aplikace.
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);
}
Funkce addHandlersJS přidá click do tlačítka událost. Funkce returnArrayAsyncJS je přiřazena jako obslužná rutina.
Funkce returnArrayAsyncJS volá metodu ReturnArrayAsync .NET komponenty, která zaprotokoluje výsledek do konzoly webových vývojářských nástrojů prohlížeče.
BlazorSample je název sestavení aplikace.
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 });
}
}
Atribut <button> HTML elementu onclick je přiřazení obslužné rutiny události JavaScriptu onclick pro zpracování click událostí, nikoli Blazoratribut direktivy @onclick . Funkce returnArrayAsyncJS je přiřazena jako obslužná rutina.
Následující returnArrayAsyncJS funkce volá metodu ReturnArrayAsync .NET komponenty, která zaprotokoluje výsledek do konzoly webových vývojářských nástrojů prohlížeče.
BlazorSample je název sestavení aplikace.
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
Note
Obecné pokyny k JS umístění a doporučení pro produkční aplikace najdete v tématu o umístění JavaScriptu v aplikacích ASP.NET CoreBlazor.
Trigger .NET static method Po výběru tlačítka zobrazí výstup konzoly vývojářských nástrojů prohlížeče data pole. Formát výstupu se mírně liší mezi prohlížeči. Následující výstup ukazuje formát používaný aplikací Microsoft Edge:
Array(3) [ 11, 12, 13 ]
Při volání invokeMethodAsync funkce předejte data do metody .NET předáním dat jako argumentů.
Chcete-li předvést předávání dat do rozhraní .NET, předejte počáteční pozici ReturnArrayAsync metodě, ve které je metoda vyvolána: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>
Vyvolání ReturnArrayAsync metody komponenty obdrží počáteční pozici a vytvoří z ní pole. Pole se vrátí pro protokolování do konzoly:
[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition) =>
Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());
Po opětovném zkompilování aplikace a aktualizaci prohlížeče se po výběru tlačítka zobrazí v konzole prohlížeče následující výstup:
Array(3) [ 14, 15, 16 ]
Identifikátor metody .NET pro JS volání je název metody .NET, ale pomocí konstruktoru [JSInvokable] atributů můžete zadat jiný identifikátor. V následujícím příkladu DifferentMethodName je přiřazený identifikátor metody pro metodu ReturnArrayAsync :
[JSInvokable("DifferentMethodName")]
Při volání DotNet.invokeMethodAsync (součásti na straně serveru nebo na straně klienta) nebo DotNet.invokeMethod (pouze komponenty na straně klienta) volání DifferentMethodName metody ReturnArrayAsync .NET:
DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');-
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');(pouze komponenty na straně klienta)
Note
Příklad ReturnArrayAsync metody v této části vrátí výsledek Task bez použití explicitního jazyka C# async a await klíčových slov. Metody kódování a asyncawait jsou typické metody, které používají await klíčové slovo k vrácení hodnoty asynchronních operací.
ReturnArrayAsync metoda složená s async klíčovými await slovy:
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync() =>
await Task.FromResult(new int[] { 11, 12, 13 });
Další informace naleznete v tématu Asynchronní programování pomocí async a await v průvodci jazykem C#.
Vytvoření odkazů na javascriptový objekt a data pro předání do .NET
Volání DotNet.createJSObjectReference(jsObject) k JS vytvoření odkazu na objekt, aby bylo možné jej předat do .NET, kde jsObject se JS Object používá k vytvoření JS odkazu na objekt. Následující příklad předá odkaz na objekt, který není serializovatelný window objekt .NET, který ho přijímá v ReceiveWindowObject metodě C# jako IJSObjectReference:
DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
V předchozím příkladu zástupný symbol {PACKAGE ID/ASSEMBLY NAME} představuje ID balíčku projektu (<PackageId> v souboru projektu), který je určen pro název knihovny nebo sestavení pro aplikaci.
Note
Předchozí příklad nevyžaduje odstranění objektu JSObjectReference, jako odkaz na window objekt není uložen .JS
Udržování odkazu na objekt JSObjectReference vyžaduje, aby se zabránilo nevrácení JS paměti v klientovi. Následující příklad refaktoruje předchozí kód, aby zachytil odkaz na JSObjectReference, následovaný voláním DotNet.disposeJSObjectReference() pro odstranění odkazu:
var jsObjectReference = DotNet.createJSObjectReference(window);
DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
V předchozím příkladu zástupný symbol {PACKAGE ID/ASSEMBLY NAME} představuje ID balíčku projektu (<PackageId> v souboru projektu), který je určen pro název knihovny nebo sestavení pro aplikaci.
Volání DotNet.createJSStreamReference(streamReference) k JS vytvoření odkazu na datový proud tak, aby bylo možné jej předat do .NET, kde streamReference je ArrayBuffer, Blobnebo jakékoli typové pole, například Uint8Array nebo Float32Array, použité k vytvoření JS odkazu na datový proud.
Vyvolání metody .NET instance
Vyvolání metody .NET instance z JavaScriptu (JS):
Předejte instanci .NET odkazem tak, že JS zabalíte instanci do DotNetObjectReference a zavoláte Create na ni.
Vyvolání metody instance .NET pomocí JS (
invokeMethodAsyncdoporučeno) neboinvokeMethod(pouze komponenty na straně klienta) z předaného DotNetObjectReference. Předejte identifikátor metody .NET instance a všechny argumenty. Instanci .NET lze také předat jako argument při vyvolání jiných metod .NET z JS.V následujícím příkladu:
-
dotNetHelperje .DotNetObjectReference - Zástupný
{.NET METHOD ID}symbol je identifikátor metody .NET. - Zástupný
{ARGUMENTS}symbol je volitelný argument oddělený čárkami, které se mají předat metodě, z nichž každý musí být serializovatelný ve formátu JSON.
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});Note
invokeMethodAsyncainvokeMethodnepřijme parametr názvu sestavení při vyvolání metody instance.invokeMethodAsyncJSPromisevrátí reprezentaci výsledku operace.invokeMethod(pouze komponenty na straně klienta) vrátí výsledek operace.Important
U komponent na straně serveru doporučujeme asynchronní funkci (
invokeMethodAsync) nad synchronní verzí (invokeMethod).-
Likvidujte DotNetObjectReference.
Následující části tohoto článku ukazují různé přístupy k vyvolání metody .NET instance:
Vyhněte se oříznutí metod javascript-invokable .NET
Tato část se týká aplikací na straně klienta s povolenou kompilací AOT (Head-of-Time) a opětovným propojením za běhu.
Několik příkladů v následujících částech vychází z přístupu instance třídy, kde metoda JavaScript-invokable .NET označená atributem [JSInvokable] je členem třídy, která není Razor součástí. Pokud jsou takové metody .NET umístěné v komponentě Razor , jsou chráněné před opětovným propojením a oříznutím za běhu. Aby bylo možné chránit metody .NET před oříznutím mimo Razor komponenty, implementujte metody s atributem DynamicDependency v konstruktoru třídy, jak ukazuje následující příklad:
using System.Diagnostics.CodeAnalysis;
using Microsoft.JSInterop;
public class ExampleClass {
[DynamicDependency(nameof(ExampleJSInvokableMethod))]
public ExampleClass()
{
}
[JSInvokable]
public string ExampleJSInvokableMethod()
{
...
}
}
Další informace naleznete v tématu Příprava knihoven .NET pro oříznutí: DynamicDependency.
DotNetObjectReference Předání jednotlivé javascriptové funkce
Příklad v této části ukazuje, jak předat DotNetObjectReference individuální funkci JavaScriptu (JS).
Následující sayHello1JS funkce přijímá DotNetObjectReference volání metody .NET komponenty a volání invokeMethodAsyncGetHelloMessage :
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Note
Obecné pokyny k JS umístění a doporučení pro produkční aplikace najdete v tématu o umístění JavaScriptu v aplikacích ASP.NET CoreBlazor.
V předchozím příkladu je název dotNetHelper proměnné libovolný a lze ho změnit na libovolný preferovaný název.
Pro následující komponentu:
- Komponenta má metodu JS-invokable .NET s názvem
GetHelloMessage. -
Trigger .NET instance methodKdyž je tlačítko vybráno, JS funkcesayHello1je volána pomocí DotNetObjectReference. -
sayHello1:- Volání
GetHelloMessagea přijetí výsledku zprávy - Vrátí výsledek zprávy volající
TriggerDotNetInstanceMethodmetodě.
- Volání
- Vrácená zpráva od
sayHello1uživateleresultse zobrazí uživateli. - Aby nedocházelo k nevrácení paměti a povolte uvolňování paměti, je v metodě odstraněn odkaz na objekt .NET vytvořený DotNetObjectReference metodou
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();
}
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();
}
}
V předchozím příkladu je název dotNetHelper proměnné libovolný a lze ho změnit na libovolný preferovaný název.
K předání argumentů metodě instance použijte následující doprovodné materiály:
Přidejte parametry do vyvolání metody .NET. V následujícím příkladu se metodě předá název. Podle potřeby přidejte do seznamu další parametry.
<script>
window.sayHello2 = (dotNetHelper, name) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage', name);
};
</script>
V předchozím příkladu je název dotNetHelper proměnné libovolný a lze ho změnit na libovolný preferovaný název.
Zadejte seznam parametrů metodě .NET.
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();
}
}
V předchozím příkladu je název dotNetHelper proměnné libovolný a lze ho změnit na libovolný preferovaný název.
DotNetObjectReference Předání třídy s více javascriptovými funkcemi
Příklad v této části ukazuje, jak předat DotNetObjectReference javascriptovou třídu (JS) s více funkcemi.
Vytvořte a předejte DotNetObjectReference z OnAfterRenderAsync metodyJS životního cyklu do třídy více funkcí, které se mají použít. Ujistěte se, že kód .NET odstraní DotNetObjectReference, jak ukazuje následující příklad.
V následující komponentě tlačítka volají Trigger JS function funkce nastavenímJSJSvlastnosti, nikoli onclickatributu direktivyBlazor.@onclick
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();
}
}
V předchozím příkladu:
-
JSje vložená IJSRuntime instance. IJSRuntime je registrován v Blazor rámci. - Název
dotNetHelperproměnné je libovolný a lze ho změnit na libovolný preferovaný název. - Komponenta musí explicitně odstranit povolení uvolňování paměti a zabránit úniku DotNetObjectReference paměti.
-
JSDisconnectedException v případě Blazorztráty okruhu SignalR je zachycen během odstraňování modulu. Pokud se předchozí kód použije v Blazor WebAssembly aplikaci, nedojde ke ztrátě připojeníSignalR, takže můžete odebrat blok a nechat řádek, který modul odstraní
try-catch().await module.DisposeAsync();Další informace najdete v tématu ASP.NET Interoperabilita Core Blazor JavaScriptu (JSinteroperabilita).
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);
}
V předchozím příkladu je název dotNetHelper proměnné libovolný a lze ho změnit na libovolný preferovaný název.
@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();
}
}
V předchozím příkladu:
-
JSje vložená IJSRuntime instance. IJSRuntime je registrován v Blazor rámci. - Název
dotNetHelperproměnné je libovolný a lze ho změnit na libovolný preferovaný název. - Komponenta musí explicitně odstranit povolení uvolňování paměti a zabránit úniku DotNetObjectReference paměti.
<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>
V předchozím příkladu:
- Třída
GreetingHelpersse přidá do objektuwindow, který globálně definuje třídu, která umožňuje Blazor najít třídu pro JS interoperabilitu. - Název
dotNetHelperproměnné je libovolný a lze ho změnit na libovolný preferovaný název.
Note
Obecné pokyny k JS umístění a doporučení pro produkční aplikace najdete v tématu o umístění JavaScriptu v aplikacích ASP.NET CoreBlazor.
Volání metod obecné třídy .NET
Funkce Jazyka JavaScript (JS) mohou volat obecné metody třídy .NET, kde JS funkce volá metodu .NET obecné třídy.
V následující obecné třídě typu (GenericType<TValue>):
- Třída má jeden parametr typu (
TValue) s jedinou obecnouValuevlastností. - Třída má dvě negenerické metody označené atributem
[JSInvokable], z nichž každý má parametr obecného typu s názvemnewValue:-
Updatesynchronně aktualizuje hodnotuValueznewValue. -
UpdateAsyncasynchronně aktualizuje hodnotuValueznewValuepo vytvoření čekající úlohy s Task.Yield tím, že asynchronně vrátí zpět do aktuálního kontextu při očekávání.
-
- Každá z metod třídy zapisuje typ
TValuea hodnotuValuedo konzoly. Zápis do konzoly je určen pouze pro demonstrační účely. Produkční aplikace se obvykle vyhýbají zápisu do konzoly ve prospěch protokolování aplikací. Další informace najdete v tématu Blazor a Protokolování v .NET a ASP.NET Core.
Note
Otevřené obecné typy a metody nezadávají typy pro zástupné symboly typů. Naopak zavřené obecné typy poskytují typy pro všechny zástupné symboly typů. Příklady v této části ukazují uzavřené obecné typy, ale podporuje se vyvolání JS metod instance interopu s otevřenými obecnými typy. Použití otevřených obecných typů není podporováno pro vyvolání statických metod .NET, které byly popsány výše v tomto článku.
Další informace najdete v následujících článcích:
- Obecné třídy a metody (dokumentace k jazyku C#)
- Obecné třídy (Průvodce programováním v C#)
- Obecné typy v .NET (dokumentace k .NET)
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}");
}
}
V následující invokeMethodsAsync funkci:
- Třídy a
Updatemetody obecného typuUpdateAsyncjsou volány s argumenty představujícími řetězce a čísla. - Komponenty na straně klienta podporují synchronní volání metod .NET s
invokeMethod.syncInteropobdrží logickou hodnotu označující, jestli se v klientovi vyskytuje interoperabilita JS . KdysyncInteropjetrue,invokeMethodje bezpečně volána. Pokud jesyncInterophodnotafalse, volá se pouze asynchronní funkceinvokeMethodAsync, protože interoperabilita JS se spouští v komponentě na straně serveru. - Pro demonstrační účely DotNetObjectReference se volání funkce (
invokeMethodneboinvokeMethodAsync), volání metody .NET (UpdateneboUpdateAsync) a argument jsou zapsány do konzoly. Argumenty používají náhodné číslo k povolení shody JS volání metody .NET do volání metody .NET (také zapsáno do konzoly na straně .NET). Produkční kód obvykle nezapisuje do konzoly, a to buď v klientovi, nebo na serveru. Produkční aplikace se obvykle spoléhají na protokolování aplikací. Další informace najdete v tématu Blazor a Protokolování v .NET a 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>
Note
Obecné pokyny k JS umístění a doporučení pro produkční aplikace najdete v tématu o umístění JavaScriptu v aplikacích ASP.NET CoreBlazor.
V následující komponentě GenericsExample:
- Funkce JS
invokeMethodsAsyncse volá, kdyžInvoke Interopje tlačítko vybráno. - Vytvoří se dvojice DotNetObjectReference typů a předá funkci JS instance
GenericTypejakostringa .int
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();
}
}
V předchozím příkladu JS je vložená IJSRuntime instance.
IJSRuntime je registrován v Blazor rámci.
Následující příklad ukazuje typický výstup předchozího příkladu, když je tlačítko vybráno Invoke Interop v komponentě na straně klienta:
JS: invokeMethodAsync:Update('string 37802')
.NET: Aktualizace: GenericType<System.String>: řetězec 37802
JS: invokeMethodAsync:UpdateAsync('string 53051')
JS: invokeMethod:Update('string 26784')
.NET: Aktualizace: GenericType<System.String>: řetězec 26784
JS: invokeMethodAsync:Update(14107)
.NET: Aktualizace: GenericType<System.Int32>: 14107
JS: invokeMethodAsync:UpdateAsync(48995)
JS: invokeMethod:Update(12872)
.NET: Aktualizace: GenericType<System.Int32>: 12872
.NET: UpdateAsync: GenericType<System.String>: řetězec 53051
.NET: UpdateAsync: GenericType<System.Int32>: 48995
Pokud je předchozí příklad implementován v komponentě na straně serveru, synchronní volání se invokeMethod vyhnete. U komponent na straně serveru doporučujeme asynchronní funkci (invokeMethodAsync) nad synchronní verzí (invokeMethod).
Typický výstup součásti na straně serveru:
JS: invokeMethodAsync:Update('string 34809')
.NET: Aktualizace: GenericType<System.String>: řetězec 34809
JS: invokeMethodAsync:UpdateAsync('string 93059')
JS: invokeMethodAsync:Update(41997)
.NET: Aktualizace: GenericType<System.Int32>: 41997
JS: invokeMethodAsync:UpdateAsync(24652)
.NET: UpdateAsync: GenericType<System.String>: řetězec 93059
.NET: UpdateAsync: GenericType<System.Int32>: 24652
Předchozí příklady výstupu ukazují, že asynchronní metody se provádějí a provádějí v libovolném pořadí v závislosti na několika faktorech, včetně plánování vláken a rychlosti provádění metody. Není možné spolehlivě předpovědět pořadí dokončení pro asynchronní volání metod.
Příklady instancí třídy
sayHello1
JS Následující funkce:
- Volá metodu
GetHelloMessage.NET na předaném DotNetObjectReference. - Vrátí zprávu od
GetHelloMessagevolajícíhosayHello1.
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Note
Obecné pokyny k JS umístění a doporučení pro produkční aplikace najdete v tématu o umístění JavaScriptu v aplikacích ASP.NET CoreBlazor.
V předchozím příkladu je název dotNetHelper proměnné libovolný a lze ho změnit na libovolný preferovaný název.
Následující HelloHelper třída má metodu JS-invokable .NET s názvem GetHelloMessage. Při HelloHelper vytváření se název ve Name vlastnosti použije k vrácení zprávy z 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}!";
}
Metoda CallHelloHelperGetHelloMessage v následující JsInteropClasses3 třídě vyvolá JS funkci sayHello1 s novou instancí 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);
}
}
Aby nedošlo k nevrácení paměti a umožnilo uvolňování paměti, je odkaz na objekt .NET vytvořený DotNetObjectReference odstraněn, když odkaz na objekt přejde mimo rozsah se using var syntaxí.
Trigger .NET instance method Když je tlačítko vybráno v následující komponentě, JsInteropClasses3.CallHelloHelperGetHelloMessage je volána s hodnotou 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);
}
}
Následující obrázek znázorňuje vykreslovanou komponentu s názvem Amy Pond v Name poli. Po výběru Hello, Amy Pond! tlačítka se zobrazí v uživatelském rozhraní:
Předchozí vzor zobrazený ve JsInteropClasses3 třídě lze také implementovat zcela v 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);
}
}
Aby nedošlo k nevrácení paměti a umožnilo uvolňování paměti, je odkaz na objekt .NET vytvořený DotNetObjectReference odstraněn, když odkaz na objekt přejde mimo rozsah se using var syntaxí.
Výstup zobrazený komponentou je Hello, Amy Pond! , když Amy Pond je název zadaný v name poli.
V předchozí komponentě je odkaz na objekt .NET uvolněn. Pokud třída nebo komponenta nelikviduje , vyřaďte DotNetObjectReferenceji od klienta voláním dispose předaného DotNetObjectReference:
window.{JS FUNCTION NAME} = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}');
dotNetHelper.dispose();
}
V předchozím příkladu:
- Zástupný
{JS FUNCTION NAME}symbol je JS název funkce. - Název
dotNetHelperproměnné je libovolný a lze ho změnit na libovolný preferovaný název. - Zástupný
{.NET METHOD ID}symbol je identifikátor metody .NET.
Pomocná třída metody .NET instance komponenty
Pomocná třída může vyvolat metodu instance .NET jako .Action Pomocné třídy jsou užitečné ve scénářích, kdy použití statických metod .NET neplatí:
- Pokud se na stejné stránce vykreslí několik součástí stejného typu.
- V aplikacích na straně serveru s více uživateli současně používajících stejnou komponentu.
V následujícím příkladu:
- Komponenta obsahuje několik
ListItem1komponent. - Každá
ListItem1komponenta se skládá ze zprávy a tlačítka. -
ListItem1Když je vybráno tlačítko komponenty, tatoListItem1UpdateMessagemetoda změní text položky seznamu a tlačítko skryje.
Následující MessageUpdateInvokeHelper třída udržuje JS-invokable .NET metoda , UpdateMessageCallervyvolat Action zadané při vytvoření instance třídy.
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();
}
}
Následující updateMessageCallerJS funkce vyvolá metodu UpdateMessageCaller .NET.
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
Note
Obecné pokyny k JS umístění a doporučení pro produkční aplikace najdete v tématu o umístění JavaScriptu v aplikacích ASP.NET CoreBlazor.
V předchozím příkladu je název dotNetHelper proměnné libovolný a lze ho změnit na libovolný preferovaný název.
Následující ListItem1 komponenta je sdílená komponenta, která se dá použít libovolný početkrát v nadřazené komponentě a vytvoří položky seznamu (<li>...</li>) pro seznam HTML (<ul>...</ul> nebo <ol>...</ol>). Každá ListItem1 instance komponenty vytvoří instanci MessageUpdateInvokeHelper s nastavenou metodou ActionUpdateMessage .
ListItem1 Když je vybráno tlačítko komponentyInteropCall, updateMessageCaller vyvolá se s vytvořenou DotNetObjectReferenceMessageUpdateInvokeHelper instancí. To umožňuje rozhraní volat UpdateMessageCallerListItem1MessageUpdateInvokeHelper tuto instanci. Předaný DotNetObjectReference se vyřadí do 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 je volána k aktualizaci uživatelského rozhraní, pokud message je nastavena v UpdateMessage. Pokud StateHasChanged není volána, neexistuje způsob, jak zjistit, Blazor že by se uživatelské rozhraní mělo aktualizovat při Action vyvolání.
Následující nadřazená komponenta obsahuje čtyři položky seznamu, každou instanci ListItem1 komponenty.
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>
Následující obrázek znázorňuje vykreslovanou nadřazenou komponentu po výběru druhého InteropCall tlačítka:
-
ListItem1Druhá komponenta zobrazilaUpdateMessage Called!zprávu. - Tlačítko
InteropCallpro druhouListItem1komponentu není viditelné, protože vlastnost CSSdisplaytlačítka je nastavena nanone.
Metoda .NET instance komponenty volaná z DotNetObjectReference přiřazené vlastnosti elementu
Přiřazení DotNetObjectReference vlastnosti elementu HTML umožňuje volání metod .NET v instanci komponenty:
- Zachytává se odkaz na element (ElementReference).
- V metodě
OnAfterRender{Async}je vyvolána funkce JavaScript (JS) s odkazem elementu a instance komponenty jako DotNetObjectReference. Funkce JS připojí DotNetObjectReference prvek ve vlastnosti. - Při vyvolání JS události elementu (například
onclick) se k volání metody .NET použije připojený DotNetObjectReference prvek.
Tento přístup je užitečný ve scénářích, kdy použití statických metod .NET není možné použít, podobně jako přístup popsaný v části pomocné třídy metody instance komponenty .NET:
- Pokud se na stejné stránce vykreslí několik součástí stejného typu.
- V aplikacích na straně serveru s více uživateli současně používajících stejnou komponentu.
- Metoda .NET je vyvolána z JS události (například
onclick), ne z Blazor události (například@onclick).
V následujícím příkladu:
- Komponenta obsahuje několik
ListItem2komponent, což je sdílená komponenta. - Každá
ListItem2komponenta se skládá ze zprávy<span>položky seznamu a sekundy<span>s vlastností CSS nastavenoudisplaynainline-blockzobrazení. -
ListItem2Pokud je vybrána položka seznamu součástí, tatoListItem2UpdateMessagemetoda změní text položky seznamu v první<span>a skryje sekundu<span>nastavením jehodisplayvlastnosti nanone.
Následující assignDotNetHelperJS funkce přiřadí DotNetObjectReference elementu ve vlastnosti s názvem dotNetHelper. Následující interopCallJS funkce používá DotNetObjectReference pro předaný prvek vyvolá metodu .NET s názvem 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>
Note
Obecné pokyny k JS umístění a doporučení pro produkční aplikace najdete v tématu o umístění JavaScriptu v aplikacích ASP.NET CoreBlazor.
V předchozím příkladu je název dotNetHelper proměnné libovolný a lze ho změnit na libovolný preferovaný název.
Následující ListItem2 komponenta je sdílená komponenta, která se dá použít libovolný početkrát v nadřazené komponentě a vytvoří položky seznamu (<li>...</li>) pro seznam HTML (<ul>...</ul> nebo <ol>...</ol>).
Každá ListItem2 instance komponenty vyvolá assignDotNetHelperJS funkci OnAfterRenderAsync pomocí odkazu prvku (první <span> prvek položky seznamu) a instance komponenty jako DotNetObjectReference.
ListItem2 Když je vybrána zpráva <span> komponenty, interopCall vyvolá se předání <span> elementu jako parametru (this), který vyvolá metodu UpdateMessage .NET. V UpdateMessage, StateHasChanged je volána k aktualizaci uživatelského rozhraní při message nastavení a display vlastnost druhé <span> se aktualizuje. Pokud StateHasChanged není volána, nemá žádný způsob, jak zjistit, Blazor že uživatelské rozhraní by mělo být aktualizováno při vyvolání metody.
Tato komponenta DotNetObjectReference je uvolněna, když je komponenta uvolněna.
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();
}
Následující nadřazená komponenta obsahuje čtyři položky seznamu, každou instanci ListItem2 komponenty.
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>
Synchronní JS spolupráce v komponentách na straně klienta
Tato část se týká pouze komponent na straně klienta.
JS interop volání jsou asynchronní, bez ohledu na to, zda je volaný kód synchronní nebo asynchronní. Volání jsou asynchronní, aby se zajistilo, že komponenty jsou kompatibilní napříč režimy vykreslování na straně serveru a na straně klienta. Na serveru musí být všechna JS volání zprostředkovatele komunikace asynchronní, protože se odesílají přes síťové připojení.
Pokud víte, že vaše komponenta běží jenom na WebAssembly, můžete se rozhodnout provádět synchronní JS volání interopu. To má o něco menší režii než provádění asynchronních volání a může vést k menšímu počtu cyklů vykreslování, protože při čekání na výsledky neexistuje žádný přechodný stav.
Pokud chcete v komponentě na straně klienta provést synchronní volání z JavaScriptu do .NET, použijte DotNet.invokeMethod místo DotNet.invokeMethodAsync.
Synchronní volání fungují v následujících případech:
Umístění JavaScriptu
Načtěte kód JavaScriptu (JS) pomocí některého z přístupů popsaných v článku o umístění JavaScriptu:
Použití JS modulů k načtení JS je popsáno v tomto článku v izolací JavaScriptu v části moduly JavaScriptu.
Warning
Značku umístěte <script> do souboru komponenty (.razor) pouze v případě, že je zaručeno přijetí statického vykreslování na straně serveru (statické SSR), protože <script> značku nelze dynamicky aktualizovat.
Warning
Neumisťujte <script> značku do souboru komponenty (.razor), protože <script> značku nejde dynamicky aktualizovat.
Izolace JavaScriptu v modulech JavaScriptu
Blazor umožňuje izolaci JavaScriptu (JS) ve standardních modulech JavaScriptu (specifikace ECMAScript). Načítání modulu JavaScriptu funguje stejně jako Blazor u jiných typů webových aplikací a můžete si přizpůsobit, jak se moduly definují ve vaší aplikaci. Průvodce používáním modulů JavaScriptu najdete v tématu MDN Web Docs: Moduly JavaScriptu.
Izolace JS poskytuje následující výhody:
- Import JS už znečišťuje globální obor názvů.
- Uživatelé knihovny a komponent už nemusí importovat související JS.
Další informace najdete v tématu Volání funkcí JavaScriptu z metod .NET v ASP.NET Core Blazor.
Dynamický import s operátorem import() se podporuje s ASP.NET Core aBlazor:
if ({CONDITION}) import("/additionalModule.js");
V předchozím příkladu {CONDITION} zástupný symbol představuje podmíněnou kontrolu, která určuje, jestli se má modul načíst.
Informace o kompatibilitě prohlížeče najdete v tématu Je možné použít: moduly JavaScriptu: dynamický import.
Vyhněte se cyklických odkazům na objekty.
Objekty, které obsahují cyklický odkaz, nelze serializovat v klientovi pro:
- Volání metody .NET
- Volání javascriptové metody z jazyka C#, pokud návratový typ obsahuje cyklický odkaz.
Podpora bajtového pole
Blazor podporuje optimalizovanou bajtůovou matici JavaScriptu (JS), která zabraňuje kódování a dekódování bajtových polí do Base64. Následující příklad používá JS zprostředkovatele komunikace k předání bajtového pole do .NET.
sendByteArray
JS Zadejte funkci. Funkce se volá staticky, která zahrnuje parametr názvu sestavení ve invokeMethodAsync volání, tlačítkem v komponentě a nevrací hodnotu:
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>
Note
Obecné pokyny k JS umístění a doporučení pro produkční aplikace najdete v tématu o umístění JavaScriptu v aplikacích ASP.NET CoreBlazor.
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));
}
}
Informace o použití bajtového pole při volání JavaScriptu z .NET naleznete v tématu Volání javascriptových funkcí z metod .NET v ASP.NET Core Blazor.
Streamování z JavaScriptu do .NET
Blazor podporuje streamování dat přímo z JavaScriptu do .NET. Datové proudy se požadují pomocí Microsoft.JSInterop.IJSStreamReference rozhraní.
Microsoft.JSInterop.IJSStreamReference.OpenReadStreamAsync
Stream vrátí a používá následující parametry:
-
maxAllowedSize: Maximální počet bajtů povolených pro operaci čtení z JavaScriptu, který je ve výchozím nastavení 512 000 bajtů, pokud není zadaný. -
cancellationToken: A CancellationToken pro zrušení čtení.
V JavaScriptu:
function streamToDotNet() {
return new Uint8Array(10000000);
}
V kódu jazyka C#:
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);
V předchozím příkladu:
-
JSje vložená IJSRuntime instance. IJSRuntime je registrován v Blazor rámci. - Zapíše se
dataReferenceStreamna disk (file.txt) v cestě k dočasné složce aktuálního uživatele (GetTempPath).
Volání funkcí JavaScriptu z metod .NET v ASP.NET Core Blazor pokrývá zpětnou operaci streamování z .NET do JavaScriptu DotNetStreamReferencepomocí .
ASP.NET nahrání Blazor základního souboru popisuje, jak nahrát soubor do Blazorsouboru . Příklad formulářů, který streamuje <textarea> data v komponentě na straně serveru, najdete v tématu Blazor ASP.NET Core.
Interoperabilita JavaScriptu [JSImport]/[JSExport]
Tato část se týká komponent na straně klienta.
Jako alternativu k interakci s JavaScriptem (JS) v komponentách na straně klienta pomocí BlazorJSmechanismu vzájemné spolupráce založeného na IJSRuntime rozhraníJS[JSImport]/[JSExport] je k dispozici rozhraní API vzájemné spolupráce pro aplikace, které cílí na .NET 7 nebo novější.
Další informace naleznete v tématu JavaScript JSImport/JSExport interop s ASP.NET Core Blazor.
Vyřazení odkazů na objekty zprostředkovatele komunikace JavaScriptu
Příklady v článcích interoperability JavaScriptu (JS) ukazují typické vzory odstranění objektů:
Při volání rozhraní .NET z JS, jak je popsáno v tomto článku, odstraňte vytvořené DotNetObjectReference z .NET nebo JS z důvodu zabránění úniku paměti .NET.
Při volání JS z .NET, jak je popsáno v volání javascriptových funkcí z metod .NET v ASP.NET Core Blazor, odstraňte všechny vytvořenéIJSObjectReference/IJSInProcessObjectReference/
JSObjectReferencez .NET nebo z JS důvodu zabránění úniku JS paměti.
JS odkazy na objekty vzájemné spolupráce jsou implementovány jako mapované pomocí identifikátoru na straně JS volání zprostředkovatele komunikace, který vytvoří odkaz. Když je odstranění objektu inicializováno z rozhraní .NET nebo JS ze strany, Blazor odebere položku z mapy a objekt může být uvolněn z paměti, pokud neexistuje žádný jiný silný odkaz na objekt.
Minimálně vždy odstraňte objekty vytvořené na straně .NET, aby nedošlo k úniku spravované paměti .NET.
Úlohy čištění DOM během odstraňování komponent
Další informace najdete v tématu ASP.NET Interoperabilita Core Blazor JavaScriptu (JSinteroperabilita).
Volání zprostředkovatele komunikace JavaScriptu bez okruhu
Další informace najdete v tématu ASP.NET Interoperabilita Core Blazor JavaScriptu (JSinteroperabilita).
Dodatečné zdroje
- Volání funkcí JavaScriptu z metod .NET v ASP.NET Core Blazor
-
InteropComponent.razorexample (dotnet/AspNetCoreGitHub repositorymainbranch): Větevmainpředstavuje aktuální vývoj produktové jednotky pro příští verzi ASP.NET Core. Pokud chcete vybrat větev pro jinou verzi (napříkladrelease/{VERSION}, kde{VERSION}zástupný symbol je verze verze), vyberte větev pomocí rozevíracího seznamu Přepnout větve nebo značky . Pro větev, která již neexistuje, pomocí karty Značky vyhledejte rozhraní API (napříkladv7.0.0). - Interakce s nástrojem DOM
-
Blazor (
dotnet/blazor-samplespostup stažení) - Blazor ASP.NET Core (oddíl interoperability JavaScriptu)
- Zmírnění hrozeb: Metody .NET vyvolané z prohlížeče