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 ve verzi .NET 10 tohoto článku.
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.
Note
Podporují se typy sjednocení jazyka C#.
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ě metoda ReturnArrayAsync C# vrací pole int. Atribut [JSInvokable] attribute se použije u metody, což umožňuje metodu vyvolat pomocí 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á k tlačítku událost click. Funkce returnArrayAsyncJS je přiřazena jako obslužná funkce.
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á k tlačítku událost click. 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 });
}
}
HTML atribut elementu <button>onclick je v JavaScriptu přiřazením obslužné rutiny události onclick pro zpracování událostí click, nikoli atributem direktivy @onclick v Blazor. Funkce returnArrayAsyncJS je přiřazena jako obslužná funkce.
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.
Když je vybráno tlačítko Trigger .NET static method, ve výstupu konzole nástrojů pro vývojáře v prohlížeči se zobrazí 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>
Vyvolatelná metoda ReturnArrayAsync komponenty přijímá počáteční pozici a sestaví z ní pole. Pole je vráceno k zaznamenání do konzole:
[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 (komponenty na straně serveru nebo na straně klienta) nebo DotNet.invokeMethod (pouze komponenty na straně klienta) volejte DifferentMethodName pro spuštění metody ReturnArrayAsync .NET:
DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');-
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');(pouze komponenty na straně klienta)
Note
Příklad metody ReturnArrayAsync v této části vrací výsledek Task bez použití explicitních klíčových slov jazyka C# async a await. Metody kódované pomocí async a await jsou typické pro metody, které používají klíčové slovo await k vrácení hodnoty asynchronních operací.
ReturnArrayAsync metoda složená z klíčových slov async a await:
[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ím DotNet.createJSObjectReference(jsObject) vytvoříte odkaz na objekt JS, aby jej bylo možné předat do .NET, kde jsObject je JS Object, který se používá k vytvoření odkazu na objekt JS. Následující příklad předá platformě .NET odkaz na neserializovatelný objekt window, který jej přijme v metodě jazyka C# ReceiveWindowObject 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 uvolnění objektu JSObjectReference, protože odkaz na objekt window není uchováván v JS.
Uchovávání odkazu na JSObjectReference vyžaduje jeho uvolnění, aby se zabránilo úniku paměti JS na 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.
Zavolejte DotNet.createJSStreamReference(streamReference), aby se vytvořil odkaz na stream JS, aby jej bylo možné předat do .NET, kde streamReference představuje ArrayBuffer, Blob nebo libovolné typované pole, například Uint8Array nebo Float32Array, použité k vytvoření odkazu na stream JS.
Vyvolání metody .NET instance
Vyvolání metody .NET instance z JavaScriptu (JS):
Předejte instanci .NET odkazem do JS tak, že instanci zabalíte do objektu DotNetObjectReference a zavoláte metodu Create.
Vyvolejte metodu instance .NET z JS pomocí
invokeMethodAsync(doporučeno) neboinvokeMethod(pouze pro 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).-
Zlikvidujte DotNetObjectReference.
Následující části tohoto článku ukazují různé přístupy k vyvolání metody .NET instance:
Vyhněte se odstraňování metod .NET volatelných z JavaScriptu
Tato část se vztahuje na klientské aplikace se zapnutou kompilací ahead-of-time (AOT) a opětovným linkování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.
Předejte DotNetObjectReference jednotlivé funkci JavaScriptu
Příklad v této části ukazuje, jak předat DotNetObjectReference individuální funkci JavaScriptu (JS).
Následující sayHello1JS funkce přijímá objekt DotNetObjectReference a volá invokeMethodAsync, aby zavolala metodu .NET GetHelloMessage komponenty:
<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. - Když je vybráno tlačítko
Trigger .NET instance method, je volána funkce JSsayHello1s parametrem 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 z
sayHello1vresultse zobrazí uživateli. - Aby se zabránilo úniku paměti a umožnilo uvolnění paměti, je reference na objekt .NET vytvořená pomocí DotNetObjectReference uvolněna v metodě
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.
Předat DotNetObjectReference do třídy s více funkcemi JavaScriptu
Příklad v této části ukazuje, jak předat DotNetObjectReference třídě JavaScriptu (JS) s více funkcemi.
Vytvořte a předejte DotNetObjectReference z metody životního cyklu OnAfterRenderAsync do třídy JS, aby ji mohlo používat více funkcí. Ujistěte se, že kód .NET odstraní DotNetObjectReference, jak ukazuje následující příklad.
V následující komponentě tlačítka Trigger JS function volají funkce JS pomocí nastavení vlastnosti JSonclick, nikoli atributu direktivy Blazor@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 injektovaná instance IJSRuntime. 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 se zachytí během likvidace modulu v případě, že dojde ke ztrátě obvodu SignalR zařízení Blazor. Pokud se předchozí kód použije v aplikaci Blazor WebAssembly, není zde žádné připojení SignalR, o které by bylo možné přijít, takže můžete odebrat blok
try-catcha ponechat řádek, který uvolní modul (await module.DisposeAsync();). Další informace najdete v tématu ASP.NET Core a interoperabilita jazyka JavaScript (JS interop).
CallDotNetExampleOneHelper.razor.js:
export class GreetingHelpers {
static dotNetHelper;
static setDotNetHelper(value) {
GreetingHelpers.dotNetHelper = value;
}
static async sayHello() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetHelloMessage');
alert(`Message from .NET: "${msg}"`);
}
static async welcomeVisitor() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetWelcomeMessage');
alert(`Message from .NET: "${msg}"`);
}
}
export function addHandlers() {
const sayHelloBtn = document.getElementById("sayHelloBtn");
sayHelloBtn.addEventListener("click", GreetingHelpers.sayHello);
const welcomeVisitorBtn = document.getElementById("welcomeVisitorBtn");
welcomeVisitorBtn.addEventListener("click", GreetingHelpers.welcomeVisitor);
}
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 injektovaná instance IJSRuntime. 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 metody obecné třídy .NET, kde funkce JS volá metodu obecné třídy .NET.
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 uzavřené generické typy poskytují typy pro všechny zástupné symboly pro typy. Příklady v této části ukazují uzavřené generické typy, ale volání JS metod instancí interopu s otevřenými obecnými typy je podporováno. 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í funkci invokeMethodsAsync:
- Metody
UpdateaUpdateAsynctřídy obecného typu 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.syncInteroppřijímá logickou hodnotu udávající, zda k interoperabilitě JS dochází na straně klienta. Když jesyncInteroptrue, lzeinvokeMethodbezpečně zavolat. Pokud je hodnotasyncInteropfalse, je volána pouze asynchronní funkceinvokeMethodAsync, protože rozhraní interoperability JS se spouští v komponentě na straně serveru. - Pro demonstrační účely se do konzole vypisují volání funkce DotNetObjectReference (
invokeMethodneboinvokeMethodAsync), volaná metoda .NET (UpdateneboUpdateAsync) a argument. Argumenty používají náhodné číslo k umožnění spárování volání funkce JS s voláním metody .NET (které se také vypisuje do konzole na straně .NET). Produkční kód obvykle nezapisuje do konzole, ať už na 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ž je vybráno tlačítkoInvoke Interop. - Vytvoří se dvojice typů DotNetObjectReference a předá se funkci JS pro instance
GenericTypejakostringaint.
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>: string 53051
.NET: UpdateAsync: GenericType<System.Int32>: 48995
Pokud je předchozí příklad implementován v komponentě na straně serveru, synchronním voláním s invokeMethod se lze vyhnout. 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>: string 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>: string 93059
.NET: UpdateAsync: GenericType<System.Int32>: 24652
Předchozí příklady výstupu ukazují, že asynchronní metody se spouštějí a dokončují v náhodném pořadí v závislosti na několika faktorech, včetně plánování vláken a rychlosti provedení metody. Není možné spolehlivě předpovědět pořadí dokončení asynchronních 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 z
GetHelloMessagevolajícímusayHello1.
<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 vytvoření HelloHelper se název ve vlastnosti Name 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 se zabránilo úniku paměti a umožnila se garbage collection, odkaz na objekt .NET vytvořený pomocí DotNetObjectReference se zruší, jakmile přestane být v rozsahu platnosti, a to pomocí syntaxe using var.
Když je v následující komponentě vybráno tlačítko Trigger .NET instance method, zavolá se JsInteropClasses3.CallHelloHelperGetHelloMessage 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 se zabránilo úniku paměti a umožnila se garbage collection, odkaz na objekt .NET vytvořený pomocí DotNetObjectReference se zruší, jakmile přestane být v rozsahu platnosti, a to pomocí syntaxe using var.
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 neuvolní DotNetObjectReference, uvolněte ho na straně klienta voláním dispose na předaném DotNetObjectReference:
window.{JS FUNCTION NAME} = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}');
dotNetHelper.dispose();
}
V předchozím příkladu:
- Zástupný symbol
{JS FUNCTION NAME}je název funkce JS. - 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 pro metodu .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í třída MessageUpdateInvokeHelper obsahuje metodu .NET JS, kterou lze vyvolat, UpdateMessageCaller, aby se vyvolal objekt 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á instance komponenty ListItem1 vytvoří instanci MessageUpdateInvokeHelper s Action nastaveným na svou metodu UpdateMessage.
Když je vybráno tlačítko InteropCall komponenty ListItem1, je updateMessageCaller vyvolána s vytvořeným DotNetObjectReference pro instanci MessageUpdateInvokeHelper. To umožňuje frameworku volat UpdateMessageCaller u instance MessageUpdateInvokeHelper objektu ListItem1. Předaný objekt DotNetObjectReference je odstraněn v 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 není volána funkce StateHasChanged, Blazor nemá jak vědět, že by se uživatelské rozhraní mělo aktualizovat, když je vyvoláno Action.
Následující nadřazená komponenta obsahuje čtyři položky seznamu, z nichž každá je instancí komponenty ListItem1.
CallDotnet6.razor:
@page "/call-dotnet-6"
<PageTitle>Call .NET 6</PageTitle>
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotnet6.razor:
@page "/call-dotnet-6"
<PageTitle>Call .NET 6</PageTitle>
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
Následující obrázek znázorňuje vykreslovanou nadřazenou komponentu po výběru druhého InteropCall tlačítka:
- Druhá
ListItem1komponenta zobrazila zprávuUpdateMessage Called!. - Tlačítko
InteropCallpro druhouListItem1komponentu není viditelné, protože vlastnost CSSdisplaytlačítka je nastavena nanone.
Metoda .NET instance komponenty volaná z DotNetObjectReference, přiřazená k vlastnosti elementu
Přiřazení DotNetObjectReference vlastnosti elementu HTML umožňuje volání metod .NET v instanci komponenty:
- Je zachycen odkaz na prvek (ElementReference).
- V metodě komponenty
OnAfterRender{Async}se volá funkce jazyka JavaScript (JS) s odkazem na prvek a instancí komponenty jako DotNetObjectReference. Funkce JS připojí DotNetObjectReference k prvku do 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á komponenta
ListItem2se skládá ze zprávy položky seznamu<span>a druhého prvku<span>s vlastností CSSdisplay, která je pro zobrazení nastavena nainline-block. - Když je vybrána položka seznamu součástí
ListItem2, metodaUpdateMessagedaného prvkuListItem2změní text položky seznamu v prvním prvku<span>a skryje druhý prvek<span>nastavením jeho vlastnostidisplaynanone.
Následující assignDotNetHelperJS funkce přiřadí DotNetObjectReference elementu ve vlastnosti s názvem dotNetHelper. Následující funkce interopCallJS používá DotNetObjectReference pro předaný prvek k vyvolání metody .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á instance komponenty ListItem2 volá funkci assignDotNetHelperJS v OnAfterRenderAsync s odkazem na prvek (první prvek <span> položky seznamu) a instancí komponenty jako DotNetObjectReference.
Když je vybrána zpráva <span> komponenty ListItem2, je vyvoláno interopCall a jako parametr je předán prvek <span> (this), což vyvolá metodu .NET UpdateMessage. V UpdateMessage se StateHasChanged volá za účelem aktualizace uživatelského rozhraní, když je nastaveno message a aktualizuje se vlastnost display druhé <span>. Pokud není volána funkce StateHasChanged, Blazor nemá jak poznat, že se má uživatelské rozhraní při volání metody aktualizovat.
Objekt DotNetObjectReference se odstraní, když se komponenta odstraní.
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, z nichž každá je instancí komponenty ListItem2.
CallDotnet7.razor:
@page "/call-dotnet-7"
<PageTitle>Call .NET 7</PageTitle>
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotnet7.razor:
@page "/call-dotnet-7"
<PageTitle>Call .NET 7</PageTitle>
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
Synchronní JS interoperabilita 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 volání JS interopu 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í modulů JS k načtení JS je popsáno v části Izolace JavaScriptu v modulech JavaScriptu tohoto článku.
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. Pokyny k používání modulů jazyka JavaScript naleznete v dokumentu MDN Web Docs: JavaScript modules.
Izolace JS poskytuje následující výhody:
- Importované JS už nezneč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é odkazy, nelze serializovat na straně klienta v žádném z těchto případů:
- Volání metod .NET
- Volání javascriptové metody z jazyka C#, pokud návratový typ obsahuje cyklický odkaz.
Podpora pole bajtů
Blazor podporuje propojení s JavaScriptem pro optimalizovaná bajtová pole (JS), které eliminuje nutnost kódovat a dekódovat bajtová pole do formátu Base64. Následující příklad používá interoperabilitu JS k předání pole bajtů do .NET.
sendByteArray
JS Zadejte funkci. Funkce je volána staticky pomocí tlačítka v komponentě; volání invokeMethodAsync přitom zahrnuje parametr názvu sestavení a funkce nevrací žádnou 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 vrátí Stream 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 injektovaná instance IJSRuntime. IJSRuntime je registrován v Blazor rámci. -
dataReferenceStreamse zapíše na disk (file.txt) do cesty dočasné složky aktuálního uživatele (GetTempPath).
Volání funkcí JavaScriptu z metod .NET v ASP.NET Core Blazor pojednává o opačném postupu, streamování z .NET do JavaScriptu pomocí DotNetStreamReference.
Nahrávání souborů v ASP.NET Core Blazor popisuje, jak nahrát soubor v Blazor. Příklad formuláře, který ve komponentě na straně serveru streamuje <textarea> data, najdete v tématu Řešení potíží s formuláři Blazor v 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 článku 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, uvolněte vytvořené DotNetObjectReference buď v .NET, nebo z JS, aby nedocházelo k únikům paměti .NET.
Při volání JS z .NET, jak je popsáno v Volání funkcí JavaScriptu z metod .NET v ASP.NET Core Blazor, uvolněte všechny vytvořené IJSObjectReference/IJSInProcessObjectReference/
JSObjectReferencebuď z .NET, nebo z JS, aby nedocházelo k únikům paměti JS.
JS reference na objekty interoperabilitní vrstvy jsou implementovány jako mapa indexovaná identifikátorem na straně JS interop volání, které tuto referenci vytváří. Když je uvolnění objektu zahájeno buď na straně .NET, nebo na straně JS, Blazor odebere položku z mapy a objekt může být uklizen garbage collectorem, pokud na něj neexistuje žádná jiná silná reference.
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 Core a interoperabilita jazyka JavaScript (JS interop).
Volání zprostředkovatele komunikace JavaScriptu bez okruhu
Další informace najdete v tématu ASP.NET Core a interoperabilita jazyka JavaScript (JS interop).
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. Chcete-li vybrat větev pro jinou verzi (napříkladrelease/{VERSION}, kde zástupný symbol{VERSION}představuje číslo verze), zvolte příslušnou 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 repozitář ukázek na GitHubu (
dotnet/blazor-samples) (jak stáhnout) - Zpracování chyb v aplikacích Blazor ASP.NET Core (část Interoperabilita JavaScriptu)
- Zmírnění hrozeb: Metody .NET vyvolané z prohlížeče