Volání metod .NET z funkcí JavaScriptu v ASP.NET Core Blazor
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Upozorňující
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.
Důležité
Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
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ý
{ASSEMBLY NAME}
symbol je 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('{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.
Důležité
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}()
{
...
}
}
Poznámka:
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. Atribut [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 addHandlers
JS přidá click
do tlačítka událost. Funkce returnArrayAsync
JS je přiřazena jako obslužná rutina.
Funkce returnArrayAsync
JS 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 addHandlers
JS přidá click
do tlačítka událost. Funkce returnArrayAsync
JS je přiřazena jako obslužná rutina.
Funkce returnArrayAsync
JS 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 returnArrayAsync
JS je přiřazena jako obslužná rutina.
Následující returnArrayAsync
JS 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>
Poznámka:
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)
Poznámka:
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 async
await
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('{ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
V předchozím příkladu {ASSEMBLY NAME}
je zástupný symbol obor názvů aplikace.
Poznámka:
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('{ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
V předchozím příkladu {ASSEMBLY NAME}
je zástupný symbol obor názvů aplikace.
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
, Blob
nebo 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 (
invokeMethodAsync
doporuč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:
dotNetHelper
je .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});
Poznámka:
invokeMethodAsync
ainvokeMethod
nepřijme parametr názvu sestavení při vyvolání metody instance.invokeMethodAsync
JSPromise
vrátí reprezentaci výsledku operace.invokeMethod
(pouze komponenty na straně klienta) vrátí výsledek operace.Důležité
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í sayHello1
JS funkce přijímá DotNetObjectReference volání metody .NET komponenty a volání invokeMethodAsync
GetHelloMessage
:
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Poznámka:
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 method
Když je tlačítko vybráno, JS funkcesayHello1
je volána pomocí DotNetObjectReference.sayHello1
:- Volání
GetHelloMessage
a přijetí výsledku zprávy - Vrátí výsledek zprávy volající
TriggerDotNetInstanceMethod
metodě.
- Volání
- Vrácená zpráva od
sayHello1
uživateleresult
se 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
metody JS ž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í JS funkce nastavenímonclick
JSvlastnosti, nikoli Blazoratributu direktivy@onclick
.Trigger JS function
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:
JS
je vložená IJSRuntime instance. IJSRuntime je registrován v Blazor rámci.- Název
dotNetHelper
promě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í
catch
try
-().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:
JS
je vložená IJSRuntime instance. IJSRuntime je registrován v Blazor rámci.- Název
dotNetHelper
promě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
GreetingHelpers
se přidá do objektuwindow
, který globálně definuje třídu, která umožňuje Blazor najít třídu pro JS interoperabilitu. - Název
dotNetHelper
proměnné je libovolný a lze ho změnit na libovolný preferovaný název.
Poznámka:
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 obecnouValue
vlastností. - Třída má dvě negenerické metody označené atributem
[JSInvokable]
, z nichž každý má parametr obecného typu s názvemnewValue
:Update
synchronně aktualizuje hodnotuValue
znewValue
.UpdateAsync
asynchronně aktualizuje hodnotuValue
znewValue
po 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
TValue
a hodnotuValue
do 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 ASP.NET Blazor Protokolování a protokolování v .NET Core a ASP.NET Core.
Poznámka:
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
UpdateAsync
metody obecného typuUpdate
jsou volány s argumenty představujícími řetězce a čísla. - Komponenty na straně klienta podporují synchronní volání metod .NET s
invokeMethod
.syncInterop
obdrží logickou hodnotu označující, jestli se v klientovi vyskytuje interoperabilita JS . KdysyncInterop
jetrue
,invokeMethod
je bezpečně volána. Pokud jefalse
hodnotasyncInterop
, 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 (
invokeMethod
neboinvokeMethodAsync
), volání metody .NET (Update
neboUpdateAsync
) 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 ASP.NET Blazor Protokolování a protokolování v .NET Core 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>
Poznámka:
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
invokeMethodsAsync
se volá, kdyžInvoke Interop
je tlačítko vybráno. - Vytvoří se dvojice DotNetObjectReference typů a předá funkci JS instance
GenericType
jakostring
a .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
GetHelloMessage
volajícíhosayHello1
.
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Poznámka:
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
dotNetHelper
promě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
ListItem1
komponent. - Každá
ListItem1
komponenta se skládá ze zprávy a tlačítka. ListItem1
Když je vybráno tlačítko komponenty, tatoListItem1
UpdateMessage
metoda změní text položky seznamu a tlačítko skryje.
Následující MessageUpdateInvokeHelper
třída udržuje JS-invokable .NET metoda , UpdateMessageCaller
vyvolat 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í updateMessageCaller
JS funkce vyvolá metodu UpdateMessageCaller
.NET.
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
Poznámka:
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 Action UpdateMessage
.
ListItem1
Když je vybráno tlačítko komponentyInteropCall
, updateMessageCaller
vyvolá se s vytvořenou DotNetObjectReference MessageUpdateInvokeHelper
instancí. To umožňuje rozhraní volat UpdateMessageCaller
ListItem1
MessageUpdateInvokeHelper
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:
ListItem1
Druhá komponenta zobrazilaUpdateMessage Called!
zprávu.- Tlačítko
InteropCall
pro druhouListItem1
komponentu není viditelné, protože vlastnost CSSdisplay
tlačí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ě komponenty
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
ListItem2
komponent, což je sdílená komponenta. - Každá
ListItem2
komponenta se skládá ze zprávy<span>
položky seznamu a sekundy<span>
s vlastností CSS nastavenoudisplay
nainline-block
zobrazení. ListItem2
Pokud je vybrána položka seznamu součástí, tatoListItem2
UpdateMessage
metoda změní text položky seznamu v první<span>
a skryje sekundu<span>
nastavením jehodisplay
vlastnosti nanone
.
Následující assignDotNetHelper
JS funkce přiřadí DotNetObjectReference elementu ve vlastnosti s názvem dotNetHelper
. Následující interopCall
JS 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>
Poznámka:
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á assignDotNetHelper
JS 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.
Upozorňující
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.
Upozorňující
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>
Poznámka:
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:
JS
je vložená IJSRuntime instance. IJSRuntime je registrován v Blazor rámci.- Zapíše se
dataReferenceStream
na 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 Řešení potíží s formuláři ASP.NET CoreBlazor.
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í JS Blazormechanismu 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éIJSInProcessObjectReference//
JSObjectReference
IJSObjectReferencez .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).
Další materiály
- Volání funkcí JavaScriptu z metod .NET v ASP.NET Core Blazor
InteropComponent.razor
example (dotnet/AspNetCore
GitHub repositorymain
branch): Větevmain
př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
- Blazorukázky úložiště GitHub () (
dotnet/blazor-samples
postup stažení) - Zpracování chyb v aplikacích ASP.NET Core Blazor (oddíl interoperability JavaScriptu)
- Zmírnění hrozeb: Metody .NET vyvolané z prohlížeče