ASP.NET Core Blazor で JavaScript 関数から .NET メソッドを呼び出す
注意
これは、この記事の最新バージョンではありません。 最新のバージョンに切り替えるには、目次の上部にある ASP.NET Core バージョン セレクターを使用します。
セレクターが狭いブラウザー ウィンドウに表示されない場合は、ウィンドウの幅を広げるか、垂直省略記号 ([⋮]) >[目次] の順に選択します。
この記事では、JavaScript (JS) から .NET メソッドを呼び出す方法について説明します。
.NET から JS 関数を呼び出す方法については、「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」をご覧ください。
静的 .NET メソッドの呼び出し
JavaScript (JS) から静的 .NET メソッドを呼び出すには、JS 関数を使用します。
DotNet.invokeMethodAsync
(推奨): Blazor Server と Blazor WebAssembly アプリの両方で非同期。DotNet.invokeMethod
: Blazor WebAssembly アプリのみで同期。
メソッドを含むアセンブリの名前、静的 .NET メソッドの識別子、および引数を渡します。
次に例を示します。
{ASSEMBLY NAME}
プレースホルダーは、アプリのアセンブリ名です。{.NET METHOD ID}
プレースホルダーは .NET メソッド識別子です。{ARGUMENTS}
プレースホルダーは、メソッドに渡す省略可能なコンマ区切りの引数であり、各引数は JSON シリアル化可能である必要があります。
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethodAsync
は、操作の結果を表す JS Promise
を返します。 DotNet.invokeMethod
(Blazor WebAssembly のみ) は操作の結果を返します。
重要
Blazor Server シナリオをサポートするには、非同期関数 (invokeMethodAsync
) が同期バージョン (invokeMethod
) より優先されます。
.NET メソッドはパブリックかつ静的であり、[JSInvokable]
属性を持つ必要があります。
次に例を示します。
{<T>}
プレースホルダーは戻り値の型を示します。これは、値を返すメソッドにのみ必要です。{.NET METHOD ID}
プレースホルダーはメソッド識別子です。
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
Note
オープン ジェネリック メソッドを呼び出すことは、静的な .NET メソッドではサポートされていませんが、インスタンス メソッドではサポートされています。 詳細については、「.NET ジェネリック クラス メソッドを呼び出す」のセクションを参照してください。
次の CallDotNetExample1
コンポーネントでは、ReturnArrayAsync
C# メソッドによって int
配列が返されます。 [JSInvokable]
属性 がメソッドに適用され、JS によってメソッドが呼び出し可能になります。
Pages/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 });
}
}
<button>
要素の onclick
HTML 属性は、 の @onclick
ディレクティブ属性ではなく、Blazorclick
イベントを処理するための JavaScript の onclick
イベント ハンドラー割り当てです。 returnArrayAsync
JS 関数はハンドラーとして割り当てられます。
次の returnArrayAsync
JS 関数では、前の CallDotNetExample1
コンポーネントの ReturnArrayAsync
.NET メソッドが呼び出され、その結果はブラウザーの Web 開発者ツール コンソールに記録されます。 BlazorSample
はアプリのアセンブリ名です。
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
注意
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
Trigger .NET static method
ボタンが選択されている場合は、ブラウザーの開発者ツール コンソールの出力に配列データが表示されます。 出力の形式はブラウザーによって若干異なります。 次の出力は、Microsoft Edge で使用される形式を示しています。
Array(3) [ 1, 2, 3 ]
データを引数として渡して invokeMethodAsync
関数を呼び出すときに、.NET メソッドにデータを渡します。
.NET にデータを渡す方法を示すには、関数が呼び出されたときに前の returnArrayAsync
JS 関数が開始位置を受け取り、その値を引数として invokeMethodAsync
関数に渡します。
<script>
window.returnArrayAsync = (startPosition) => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', startPosition)
.then(data => {
console.log(data);
});
};
</script>
CallDotNetExample1
コンポーネントで、関数呼び出しを変更して開始位置を含めます。 次の例では、5
の値を使用しています。
<button onclick="returnArrayAsync(5)">
...
</button>
コンポーネントの呼び出し可能 ReturnArrayAsync
メソッドは開始位置を受け取り、そこから配列を構築します。 コンソールにログするために、配列が返されます。
[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition)
{
return Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());
}
アプリが再コンパイルされ、ブラウザーが更新されると、ボタンが選択されたときに、ブラウザーのコンソールに次の出力が表示されます。
Array(3) [ 5, 6, 7 ]
既定では、JS 呼び出しの .NET メソッド識別子は .NET メソッド名ですが、[JSInvokable]
属性コンストラクターを使用して別の識別子を指定することもできます。 次の例では、DifferentMethodName
は ReturnArrayAsync
メソッドに割り当てられたメソッド識別子です。
[JSInvokable("DifferentMethodName")]
DotNet.invokeMethodAsync
または DotNet.invokeMethod
の呼び出し (Blazor WebAssembly のみ) で、DifferentMethodName
を呼び出して ReturnArrayAsync
.NET メソッドを実行します。
DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');
(Blazor WebAssembly のみ)
Note
このセクションの ReturnArrayAsync
メソッドの例では、明示的な C# async
および await
キーワードを使用せずに Task の結果を返します。 async
および await
を使用したメソッドのコーディングは、await
キーワードを使用して非同期操作の値を返す一般的なメソッドです。
async
および await
キーワードで構成される ReturnArrayAsync
メソッド:
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync()
{
return await Task.FromResult(new int[] { 1, 2, 3 });
}
詳細については、C# ガイドの「Async および Await を使用した非同期プログラミング」を参照してください。
.NET に渡す JavaScript オブジェクトとデータ参照を作成する
DotNet.createJSObjectReference(jsObject)
を呼び出して、.NET に渡すことができるように JS オブジェクト参照を構築します。jsObject
は JS オブジェクト参照の作成に使われる JS Object
です。 次の例では、シリアル化できない window
オブジェクトへの参照を .NET に渡します。これはその参照を ReceiveWindowObject
C# メソッドで IJSObjectReference として受け取ります。
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
前の例で、{ASSEMBLY NAME}
プレースホルダーはアプリの名前空間です。
Note
前の例では、window
オブジェクトへの参照が JS に保持されないため、JSObjectReference
の破棄は必要ありません。
JSObjectReference
への参照を維持したら、クライアントでの JS メモリのリークを避けるため、それを破棄する必要があります。 次の例では、前のコードをリファクタリングして JSObjectReference
への参照をキャプチャした後、DotNet.disposeJSObjectReference()
を呼び出して参照を破棄します。
var jsObjectReference = DotNet.createJSObjectReference(window);
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
前の例で、{ASSEMBLY NAME}
プレースホルダーはアプリの名前空間です。
DotNet.createJSStreamReference(streamReference)
を呼び出して JS ストリーム参照を構築し、.NET に渡すことができるようにします。streamReference
は、ArrayBuffer
、Blob
、または Uint8Array
や Float32Array
などの任意の型指定された配列であり、JS ストリーム参照を作成するために使用されます。
インスタンス .NET メソッドの呼び出し
JavaScript (JS) からインスタンス .NET メソッドを呼び出す場合:
インスタンスを DotNetObjectReference でラップし、その上で Create を呼び出すことにより、JS を参照して .NET インスタンスを渡します。
渡された DotNetObjectReference の
invokeMethodAsync
("推奨") またはinvokeMethod
(Blazor WebAssembly のみ) を使用して、JS から .NET インスタンス メソッドを呼び出します。 インスタンス .NET メソッドの識別子とすべての引数を渡します。 .NET インスタンスは、JS から他の .NET メソッドを呼び出すときに引数として渡すこともできます。次に例を示します。
dotNetHelper
が DotNetObjectReference です。{.NET METHOD ID}
プレースホルダーは .NET メソッド識別子です。{ARGUMENTS}
プレースホルダーは、メソッドに渡す省略可能なコンマ区切りの引数であり、各引数は JSON シリアル化可能である必要があります。
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});
Note
インスタンス メソッドを呼び出すときは、
invokeMethodAsync
とinvokeMethod
はアセンブリ名パラメーターを受け付けません。invokeMethodAsync
は、操作の結果を表す JSPromise
を返します。invokeMethod
(Blazor WebAssembly のみ) は操作の結果を返します。重要
Blazor Server シナリオをサポートするには、非同期関数 (
invokeMethodAsync
) が同期バージョン (invokeMethod
) より優先されます。
この記事の以降のセクションでは、インスタンス .NET メソッドを呼び出すさまざまな方法について説明します。
DotNetObjectReference
を個々の JavaScript 関数に渡す- 複数の JavaScript 関数を持つクラスに
DotNetObjectReference
を渡す - .NET ジェネリック クラス メソッドを呼び出す
- クラス インスタンスの例
- コンポーネント インスタンス .NET メソッド ヘルパー クラス
JavaScript で呼び出し可能な .NET メソッドのトリミングを回避する
"このセクションは、Ahead-Of-Time (AOT) コンパイルとランタイム再リンクが有効になっている Blazor WebAssembly アプリに適用されます。"
次のセクションに示すいくつかの例は、クラス インスタンスのアプローチに基づいています。ここで、[JSInvokable]
属性でマークされていて、JavaScript で呼び出し可能な .NET メソッドは、Razor コンポーネントではないクラスのメンバーです。 このような .NET メソッドがコンポーネント内にある Razor 場合、それらは、ランタイムの再リンクやトリミングから保護されます。 .NET メソッドが Razor コンポーネントの外部でトリミングされないようにするには、次の例に示すように、クラスのコンストラクターに DynamicDependency
属性を使用してメソッドを実装します。
using System.Diagnostics.CodeAnalysis;
using Microsoft.JSInterop;
public class ExampleClass {
[DynamicDependency(nameof(ExampleJSInvokableMethod))]
public ExampleClass()
{
}
[JSInvokable]
public string ExampleJSInvokableMethod()
{
...
}
}
詳細については、トリミング用に .NET ライブラリを準備する: DynamicDependency に関するページを参照してください。
DotNetObjectReference
を個々の JavaScript 関数に渡す
このセクションの例は、DotNetObjectReference を個々の JavaScript (JS) 関数に渡す方法を示しています。
次の sayHello1
JS 関数では DotNetObjectReference を受け取り、invokeMethodAsync
を呼び出してコンポーネントの GetHelloMessage
.NET メソッドを呼び出します。
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
注意
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
次の CallDotNetExample2
コンポーネントの場合:
- コンポーネントには、
GetHelloMessage
という名前の JS 呼び出し可能な .NET メソッドが含まれます。 Trigger .NET instance method
ボタンを選択すると、JS 関数sayHello1
が DotNetObjectReference と一緒に呼び出されます。sayHello1
:GetHelloMessage
を呼び出し、メッセージ結果を受信します。- メッセージの結果を呼び出し元の
TriggerDotNetInstanceMethod
メソッドに返します。
result
のsayHello1
から返されたメッセージがユーザーに表示されます。- メモリ リークを回避し、ガベージ コレクションを許可するには、DotNetObjectReference によって作成された .NET オブジェクト参照は
Dispose
メソッドで破棄されます。
Pages/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();
}
}
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
インスタンス メソッドに引数を渡すには:
.NET メソッドの呼び出しにパラメーターを追加します。 次の例では、名前がメソッドに渡されます。 必要に応じて、追加のパラメーターを一覧に追加します。
<script> window.sayHello2 = (dotNetHelper, name) => { return dotNetHelper.invokeMethodAsync('GetHelloMessage', name); }; </script>
前の例で、変数名
dotNetHelper
は任意であり、任意の希望する名前に変更できます。.NET メソッドにパラメーター リストを指定します。
Pages/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();
}
}
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
複数の JavaScript 関数を持つクラスに DotNetObjectReference
を渡す
このセクションの例は、DotNetObjectReference を複数の関数を持つ JavaScript (JS) クラスに渡す方法を示しています。
DotNetObjectReference を作成して OnAfterRenderAsync
ライフサイクル メソッド から JS クラスに渡して、複数の関数で使用できるようにします。 次の例に示すように、.NET コードで DotNetObjectReference が破棄されることを確認します。
次の CallDotNetExampleOneHelper
コンポーネントでは、[Trigger JS function
] ボタンは、Blazor の @onclick
ディレクティブ属性 "ではなく"JSonclick
プロパティを設定して JS を呼び出します。
Pages/CallDotNetExampleOneHelper.razor
:
@page "/call-dotnet-example-one-helper"
@implements IDisposable
@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 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();
}
}
前の例の場合:
JS
は、挿入された IJSRuntime インスタンスです。 IJSRuntime は Blazor フレームワークによって登録されます。- 変数名
dotNetHelper
は任意であり、任意の希望する名前に変更できます。 - コンポーネントは、ガベージ コレクションを許可し、メモリ リークを防ぐために、DotNetObjectReference を明示的に破棄する必要があります。
<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>
注意
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
前の例の場合:
GreetingHelpers
クラスは、window
オブジェクトに追加され、クラスをグローバルに定義します。これにより、Blazor が JS 相互運用のためにクラスを見つけることができます。- 変数名
dotNetHelper
は任意であり、任意の希望する名前に変更できます。
NET ジェネリック クラス メソッドを呼び出す
JavaScript (JS) 関数は .NET ジェネリック クラス メソッドを呼び出すことができ、ここで JS 関数はジェネリック クラスの .NET メソッドを呼び出します。
次のジェネリック型クラス (GenericType<TValue>
) で:
- クラスには、1 つのジェネリック
Value
プロパティを持つ 1 つの型パラメーター (TValue
) があります。 - クラスには、
[JSInvokable]
属性でマークされた 2 つの非ジェネリック メソッドがあり、それぞれにnewValue
という名前のジェネリック型パラメーターがあります。Update
はnewValue
からValue
の値を同期的に更新します。UpdateAsync
は、待ち受け時に現在のコンテキストに非同期的に戻す Task.Yield で待ち受け可能なタスクを作成した後newValue
からValue
の値を非同期的に更新します。
- クラスのメソッドはそれぞれ、
TValue
の型とValue
の値をコンソールに書き込みます。 コンソールへの書き込みは、デモンストレーションのみを目的とします。 通常、実稼働アプリでは、アプリのログのため、コンソールへの書き込みを回避します。 詳細については、「ASP.NET Core Blazor のログ」および「.NET Core および ASP.NET Core でのログ記録」を参照してください。
Note
"オープン ジェネリック型とメソッド" では、型プレースホルダーの型は指定されません。 逆に、"クローズド ジェネリック" では、すべての型プレースホルダーの型が指定されます。 このセクションの例は、クローズド ジェネリックを示していますが、オープン ジェネリックでの JS 相互運用 "インスタンス メソッド" の呼び出しは "サポートされています"。 オープン ジェネリックの使用はこの記事で前述した 静的 .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 void UpdateAsync(TValue newValue)
{
await Task.Yield();
Value = newValue;
Console.WriteLine($"UpdateAsync: GenericType<{typeof(TValue)}>: {Value}");
}
}
次の invokeMethodsAsync
関数では:
- ジェネリック型クラスの
Update
とUpdateAsync
のメソッドは、文字列と数値を表す引数で呼び出されます。 - Blazor WebAssembly アプリでは、
invokeMethod
との同期的な .NET メソッドの呼び出しがサポートされています。syncInterop
は、Blazor WebAssembly アプリで JS 相互運用が発生するかどうかを示すブール値を受け取ります。syncInterop
がtrue
の場合、invokeMethod
は安全に呼び出されます。syncInterop
の値がfalse
の場合、JS 相互運用が Blazor Server アプリで実行されているので、非同期関数invokeMethodAsync
だけが呼び出されます。 - デモンストレーションの目的で、DotNetObjectReference 関数呼び出し (
invokeMethod
またはinvokeMethodAsync
)、呼び出された .NET メソッド (Update
またはUpdateAsync
) およびおよび引数がコンソールに書き込まれます。 引数は乱数を使用して JS 関数呼び出しと .NET メソッド呼び出しの照合を許可します (.NET 側のコンソールにも書き込まれます)。 通常、実稼働コードは、クライアントまたはサーバー上でコンソールに書き込まれません。 実稼働アプリは通常、アプリの "ログ" に依存します。 詳細については、「ASP.NET Core Blazor のログ」および「.NET Core および 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
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
次の GenericsExample
コンポーネントでは、以下のことを行います。
Invoke Interop
ボタンを選択すると、JS 関数invokeMethodsAsync
が呼び出されます。- DotNetObjectReference 型のペアが作成され、
string
およびint
としてGenericType
のインスタンスの JS 関数に渡されます。
Pages/GenericsExample.razor
:
@page "/generics-example"
@using System.Runtime.InteropServices
@inject IJSRuntime JS
@implements IDisposable
<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 =
RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));
await JS.InvokeVoidAsync(
"invokeMethodsAsync", syncInterop, objRef1, objRef2);
}
public void Dispose()
{
objRef1?.Dispose();
objRef2?.Dispose();
}
}
前の例の JS
は、挿入された IJSRuntime インスタンスです。 IJSRuntime は Blazor フレームワークによって登録されます。
Blazor WebAssembly アプリで Invoke Interop
ボタンが選択されている場合の、前の例の一般的な出力を次に示します。
JS: invokeMethodAsync:Update('string 37802')
.NET: Update: GenericType<System.String>: string 37802
JS: invokeMethodAsync:UpdateAsync('string 53051')
JS: invokeMethod:Update('string 26784')
.NET: Update: GenericType<System.String>: string 26784
JS: invokeMethodAsync:Update(14107)
.NET: Update: GenericType<System.Int32>: 14107
JS: invokeMethodAsync:UpdateAsync(48995)
JS: invokeMethod:Update(12872)
.NET: Update: GenericType<System.Int32>: 12872
.NET: UpdateAsync: GenericType<System.String>: string 53051
.NET: UpdateAsync: GenericType<System.Int32>: 48995
前の例が Blazor Server アプリに実装されている場合、invokeMethod
を使用した同期呼び出しは回避されます。 Blazor Server のシナリオでは、非同期関数 (invokeMethodAsync
) が同期バージョン (invokeMethod
) より優先されます。
Blazor Server アプリの一般的な出力:
JS: invokeMethodAsync:Update('string 34809')
.NET: Update: GenericType<System.String>: string 34809
JS: invokeMethodAsync:UpdateAsync('string 93059')
JS: invokeMethodAsync:Update(41997)
.NET: Update: GenericType<System.Int32>: 41997
JS: invokeMethodAsync:UpdateAsync(24652)
.NET: UpdateAsync: GenericType<System.String>: string 93059
.NET: UpdateAsync: GenericType<System.Int32>: 24652
上記の出力例は、スレッドのスケジューリングやメソッドの実行速度など、いくつかの要因に応じて、非同期メソッドが "任意の順序で" 実行され、完了する例を示しています。 非同期メソッド呼び出しの完了順序は、確実には予測できません。
クラス インスタンスの例
次の sayHello1
JS 関数:
- 渡された DotNetObjectReference で
GetHelloMessage
.NET メソッドを呼び出します。 GetHelloMessage
からsayHello1
の呼び出し元にメッセージを返します。
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
注意
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
次の HelloHelper
クラスには、GetHelloMessage
という名前の JS 呼び出し可能な .NET メソッドが含まれます。 HelloHelper
が作成されると、Name
プロパティの名前が GetHelloMessage
からのメッセージを返すために使用されます。
HelloHelper.cs
:
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}!";
}
次の JsInteropClasses3
クラスの CallHelloHelperGetHelloMessage
メソッドでは、HelloHelper
の新しいインスタンスで JS 関数 sayHello1
を呼び出します。
JsInteropClasses3.cs
:
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);
}
}
メモリ リークを回避し、ガベージ コレクションを許可するため、DotNetObjectReference によって作成された .NET オブジェクト参照は、そのオブジェクト参照が using var
構文でスコープ外になったときに破棄されます。
次の CallDotNetExample4
コンポーネントで Trigger .NET instance method
ボタンを選択すると、name
の値で JsInteropClasses3.CallHelloHelperGetHelloMessage
が呼び出されます。
Pages/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);
}
}
}
次の図は、Name
フィールドに Amy Pond
という名前でレンダリングされたコンポーネントを示しています。 ボタンを選択すると、UI に Hello, Amy Pond!
が表示されます。
JsInteropClasses3
クラスに示されている上記のパターンは、完全にコンポーネントに実装することもできます。
Pages/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);
}
}
メモリ リークを回避し、ガベージ コレクションを許可するため、DotNetObjectReference によって作成された .NET オブジェクト参照は、そのオブジェクト参照が using var
構文でスコープ外になったときに破棄されます。
name
フィールドに名前 Amy Pond
が指定されている場合、CallDotNetExample5
コンポーネントによって表示される出力は Hello, Amy Pond!
です。
前の CallDotNetExample5
コンポーネントでは、.NET オブジェクト参照は破棄されます。 クラスまたはコンポーネントが DotNetObjectReference を破棄しない場合は、渡された DotNetObjectReference で dispose
を呼び出して、クライアントから破棄します。
window.{JS FUNCTION NAME} = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}');
dotNetHelper.dispose();
}
前の例の場合:
{JS FUNCTION NAME}
プレースホルダーは JS 関数の名前です。- 変数名
dotNetHelper
は任意であり、任意の希望する名前に変更できます。 {.NET METHOD ID}
プレースホルダーは .NET メソッド識別子です。
コンポーネント インスタンス .NET メソッド ヘルパー クラス
ヘルパー クラスでは、.NET インスタンス メソッドを Action として呼び出すことができます。 ヘルパー クラスは、次のシナリオで役立ちます。
- 同じ種類の複数のコンポーネントが同じページにレンダリングされる場合。
- Blazor Server アプリで、複数のユーザーが同じコンポーネントを同時に使用する場合。
次に例を示します。
CallDotNetExample6
コンポーネントには、アプリのShared
フォルダー内の共有コンポーネントであるいくつかのListItem1
コンポーネントが含まれています。- 各
ListItem1
コンポーネントは、メッセージとボタンで構成されます。 ListItem1
コンポーネント ボタンが選択されると、そのListItem1
のUpdateMessage
メソッドによってリスト項目のテキストが変更され、ボタンが非表示になります。
次の MessageUpdateInvokeHelper
クラスでは、クラスがインスタンス化されるときに指定された Action を呼び出すために、JS 呼び出し可能な .NET メソッド UpdateMessageCaller
が保持されます。
MessageUpdateInvokeHelper.cs
:
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
次の updateMessageCaller
JS 関数は、UpdateMessageCaller
.NET メソッドを呼び出します。
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
Note
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
次の ListItem1
コンポーネントは、親コンポーネントで何度でも使用できる共有コンポーネントであり、HTML リスト (<ul>...</ul>
または <ol>...</ol>
) のリスト項目 (<li>...</li>
) を作成します。 各 ListItem1
コンポーネント インスタンスは、Action がその UpdateMessage
メソッドに設定された MessageUpdateInvokeHelper
のインスタンスを確立します。
ListItem1
コンポーネントの InteropCall
ボタンが選択された場合、MessageUpdateInvokeHelper
インスタンス用に作成された DotNetObjectReference で updateMessageCaller
が呼び出されます。 これにより、フレームワークはその ListItem1
の MessageUpdateInvokeHelper
インスタンスで UpdateMessageCaller
を呼び出すことができます。 渡された DotNetObjectReference は JS (dotNetHelper.dispose()
) で破棄されます。
Shared/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();
}
}
message
が UpdateMessage
で設定されている場合、UI を更新するために StateHasChanged
が呼び出されます。 StateHasChanged
が呼び出されていない場合、Blazor には Action が呼び出されたときに UI を更新する必要があることを知る方法はありません。
次の CallDotNetExample6
親コンポーネントには、それぞれ ListItem1
コンポーネントのインスタンスである 4 つのリスト項目が含まれています。
Pages/CallDotNetExample6.razor
:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
次の図は、2 番目の InteropCall
ボタンが選択された後にレンダリングされた CallDotNetExample6
親コンポーネントを示しています。
- 2 番目の
ListItem1
コンポーネントによってUpdateMessage Called!
メッセージが表示されました。 - ボタンの CSS
display
プロパティがnone
に設定されているため、2 番目のListItem1
コンポーネントのInteropCall
ボタンは表示されません。
要素プロパティに割り当てられた DotNetObjectReference
から呼び出されるコンポーネント インスタンスの .NET メソッド
HTML 要素のプロパティに対する DotNetObjectReference の割り当てにより、コンポーネント インスタンスの .NET メソッドを呼び出すことができます。
- 要素の参照がキャプチャされます (ElementReference)。
- コンポーネントの
OnAfterRender{Async}
メソッドでは、要素の参照とコンポーネント インスタンスを DotNetObjectReference として、JavaScript (JS) 関数が呼び出されます。 この JS 関数は、DotNetObjectReference をプロパティ内の要素にアタッチします。 - JS で要素イベントが呼び出されると (たとえば
onclick
)、その要素のアタッチされた DotNetObjectReference が .NET メソッドの呼び出しに使用されます。
コンポーネント インスタンスの .NET メソッド ヘルパー クラスに関するセクションで説明されている方法と同様に、この方法は次のシナリオで役立ちます。
- 同じ種類の複数のコンポーネントが同じページにレンダリングされる場合。
- Blazor Server アプリで、複数のユーザーが同じコンポーネントを同時に使用する場合。
- .NET メソッドが、Blazor イベント (たとえば
@onclick
) からではなく、JS イベント (たとえばonclick
) から呼び出される場合。
次に例を示します。
CallDotNetExample7
コンポーネントには、アプリのShared
フォルダー内の共有コンポーネントであるいくつかのListItem2
コンポーネントが含まれています。- 各
ListItem2
コンポーネントは、リスト項目メッセージ<span>
と、display
CSS プロパティが表示用にinline-block
に設定された 2 つ目の<span>
で構成されています。 ListItem2
コンポーネントのリスト項目が選択されると、そのListItem2
のUpdateMessage
メソッドによって最初の<span>
のリスト項目テキストが変更され、そのdisplay
プロパティをnone
に設定することで 2 つ目の<span>
が非表示になります。
次の assignDotNetHelper
JS 関数は、dotNetHelper
という名前のプロパティの要素に DotNetObjectReference を割り当てます。
<script>
window.assignDotNetHelper = (element, dotNetHelper) => {
element.dotNetHelper = dotNetHelper;
}
</script>
次の interopCall
JS 関数では、渡される要素に DotNetObjectReference を使用して、UpdateMessage
という名前の .NET メソッドを呼び出します。
<script>
window.interopCall = async (element) => {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
</script>
注意
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
次の ListItem2
コンポーネントは、親コンポーネントで何度でも使用できる共有コンポーネントであり、HTML リスト (<ul>...</ul>
または <ol>...</ol>
) のリスト項目 (<li>...</li>
) を作成します。
各 ListItem2
コンポーネント インスタンスでは、要素の参照 (リスト項目の最初の <span>
要素) とコンポーネント インスタンスを DotNetObjectReference として、OnAfterRenderAsync
で assignDotNetHelper
JS 関数を呼び出します。
ListItem2
コンポーネントのメッセージ <span>
が選択されると、<span>
要素をパラメーター (this
) として渡して interopCall
が呼び出されます。これにより、UpdateMessage
.NET メソッドが呼び出されます。 UpdateMessage
では、message
が設定され、2 つ目の <span>
の display
プロパティが更新されると、StateHasChanged
が呼び出されて UI が更新されます。 StateHasChanged
が呼び出されないと、Blazor にはメソッドが呼び出されたときに UI を更新する必要があることを知る方法がありません。
DotNetObjectReference は、コンポーネントが破棄されるときに破棄されます。
Shared/ListItem2.razor
:
@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();
}
次の CallDotNetExample7
親コンポーネントには、それぞれ ListItem2
コンポーネントのインスタンスである 4 つのリスト項目が含まれています。
Pages/CallDotNetExample7.razor
:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
Blazor WebAssembly アプリでの同期 JS 相互運用
"このセクションは アプリにのみ適用されます。 "
JS 相互運用呼び出しは、呼び出されたコードが同期であるか非同期であるかに関係なく、既定で非同期となります。 Blazor ホスティング モデルの Blazor Server と Blazor WebAssembly の両方におけるコンポーネントの互換性を確保するため、既定では呼び出しは非同期です。 Blazor Server では、すべての JS 相互運用呼び出しは、ネットワーク接続を介して送信されるため、非同期である必要があります。
アプリが Blazor WebAssembly でのみ実行されることが確実である場合は、同期 JS 相互運用呼び出しを行うように選択できます。 これにより、非同期呼び出しを行う場合よりもオーバーヘッドがわずかに減少し、レンダリング サイクルが少なくなる可能性があります。これは、結果を待機する間の中間状態が存在しないためです。
Blazor WebAssembly アプリで JavaScript から .NET への同期呼び出しを行うには、DotNet.invokeMethodAsync
ではなく DotNet.invokeMethod
を使用します。
同期呼び出しは、次の場合に機能します。
- アプリが Blazor Server ではなく Blazor WebAssembly で実行されている。
- 呼び出された関数から同期的に値が返される。 この関数は
async
メソッドではなく、.NET Task や JavaScriptPromise
は返されません。
JavaScript の場所
JS 相互運用の概要に関する記事で説明されている方法のいずれかを使用して、JavaScript (JS) コードを読み込みます。
<head>
マークアップでスクリプトを読み込む ("通常は推奨されません")- マークアップでスクリプトを読み込む
- 外部 JavaScript ファイル (
.js
) からスクリプトを読み込む - Blazor の開始の前または後にスクリプトを挿入する
モジュールでのスクリプトの分離の詳細については、「JavaScript モジュールでの JavaScript の分離」セクションを参照してください。
警告
<script>
タグは動的に更新できないため、<script>
タグをコンポーネント ファイル (.razor
) 内に配置しないでください。
JavaScript モジュールでの JavaScript の分離
Blazor では、標準の Blazorに JavaScript (JS) を分離できます (JS)。 JavaScript モジュールの読み込みは、他の種類の Web アプリの場合と同じように Blazor で機能し、アプリでモジュールを定義する方法を自由にカスタマイズできます。 JavaScript モジュールの使用方法に関するガイドについては、MDN Web Docs の「JavaScript モジュール」を参照してください。
JS を分離すると、次のようなベネフィットがあります。
- インポートされる JS によって、グローバル名前空間が汚染されなくなります。
- ライブラリおよびコンポーネントのコンシューマーは、関連する JS をインポートする必要がありません。
詳しくは、「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」をご覧ください。
import()
演算子を使用した動的インポートは、ASP.NET Core と Blazorでサポートされています。
if ({CONDITION}) import("/additionalModule.js");
前述の例では、プレースホルダー {CONDITION}
は、モジュールを読み込む必要があるかどうかを判断するための条件付きチェックを表しています。
ブラウザーの互換性については、「Can I use: JavaScript modules: dynamic import (使用できるかどうか: JavaScript モジュール: dynamic import)」を参照してください。
循環オブジェクト参照の回避
循環参照を含むオブジェクトは、次のいずれに対しても、クライアントでシリアル化することはできません。
- .NET メソッドの呼び出し。
- 戻り値の型に循環参照がある場合の、C# からの JavaScript メソッドの呼び出し。
バイト配列のサポート
Blazor では、Base64 へのバイト配列のエンコードおよびデコードを回避する、最適化されたバイト配列 JavaScript (JS) 相互運用がサポートされています。 次の例では、JS 相互運用を使用してバイト配列を .NET に渡します。
sendByteArray
JS 関数を指定します。 この関数は、コンポーネント内のボタンによって静的に呼び出され (これには、invokeMethodAsync
の呼び出しのアセンブリ名パラメーターが含まれます)、値を返しません。
<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
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
Pages/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));
}
}
.NET から JavaScript を呼び出すときのバイト配列の使用については、「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」をご覧ください。
JavaScript から .NET へのストリーム
Blazor では、JavaScript から .NET に直接データをストリーミングすることがサポートされます。 ストリームは Microsoft.JSInterop.IJSStreamReference
インターフェイスを使用して要求されます。
Microsoft.JSInterop.IJSStreamReference.OpenReadStreamAsync
では Stream が返され、次のパラメーターが使用されます。
maxAllowedSize
: JavaScript からの読み取り操作に許可される最大バイト数。指定されていない場合、既定では 512,000 バイトになります。cancellationToken
: 読み取りをキャンセルするための CancellationToken。
JavaScript の場合:
function streamToDotNet() {
return new Uint8Array(10000000);
}
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);
前の例の場合:
JS
は、挿入された IJSRuntime インスタンスです。 IJSRuntime は Blazor フレームワークによって登録されます。dataReferenceStream
は、現在のユーザーの一時フォルダー パス (GetTempPath) でディスク (file.txt
) に書き込まれます。
「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」では、逆の動作である、DotNetStreamReference を使用した .NET から JavaScript へのストリーミングについて説明しています。
「ASP.NET Core Blazor ファイルのアップロード」では、Blazor でファイルをアップロードする方法を説明しています。
JavaScript 相互運用呼び出しのサイズ制限
"このセクションは Blazor Server アプリにのみ適用されます。 " Blazor WebAssembly では、フレームワークによって JavaScript (JS) 相互運用の入力と出力のサイズが制限されることはありません。
Blazor Server では、ハブ メソッドで許可される SignalR 受信メッセージの最大サイズによって、JS 相互運用呼び出しのサイズが制限されます。これは、HubOptions.MaximumReceiveMessageSize によって適用されます (既定値: 32 KB)。 JS から .NET への SignalR メッセージが MaximumReceiveMessageSize より大きい場合は、エラーがスローされます。 このフレームワークでは、ハブからクライアントへの SignalR メッセージのサイズが制限されることはありません。
SignalR のログがSignalR または Trace に設定されていない場合、メッセージ サイズのエラーはブラウザーの開発者ツール コンソールにのみ表示されます。
エラー :次のエラーで接続が切断されました。"エラー: サーバーが終了時にエラーを返しました:接続はエラーで終了しました。"
サーバー側のログ が Debug または Trace に設定されている場合、サーバー側のログには、メッセージ サイズ エラーの が表示されます。
appsettings.Development.json
:
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug"
}
}
}
エラー:
System.IO.InvalidDataException:メッセージの最大サイズ 32,768 B を超えました。 メッセージのサイズは、AddHubOptions で構成できます。
制限値を増やすには、Program.cs
で MaximumReceiveMessageSize を設定します。 次の例では、受信メッセージの最大サイズを 64 KB に設定します。
builder.Services.AddServerSideBlazor()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
SignalR 受信メッセージ サイズの制限値を増やすと、より多くのサーバー リソースが必要になり、悪意のあるユーザーからのより大きなリスクにサーバーがさらされます。 また、大量のコンテンツを文字列またはバイト配列としてメモリに読み取ると、ガベージ コレクターがうまく機能しない割り当てが発生する可能性もあり、その結果、パフォーマンスがさらに低下します。
Blazor Server アプリで JS と Blazor の間で大量のデータを転送するコードを開発するときは、次のガイダンスを考慮してください。
- SignalR 受信メッセージ サイズの制限を超えるデータを転送するには、ネイティブ ストリーミング相互運用サポートを利用します。
- ASP.NET Core で .NET メソッドから JavaScript 関数を呼び出す
- ASP.NET Core で JavaScript 関数から .NET メソッドを呼び出す
- 一般的なヒント:
- JS および C# コードで大きなオブジェクトを割り当てないでください。
- プロセスの完了時またはキャンセル時に、消費していたメモリを解放します。
- セキュリティ上の理由から、次の追加要件を適用します。
- 渡すことのできるファイルまたはデータの最大サイズを宣言します。
- クライアントからサーバーへの最小アップロード レートを宣言します。
- データがサーバーによって受信されたら、データは:
- すべてのセグメントが収集されるまで、一時的にメモリ バッファーに格納できます。
- 直ちに消費できます。 たとえば、データは、データベースに直ちに格納することも、セグメントを受信するたびにディスクに書き込むこともできます。
JavaScript [JSImport]
/[JSExport]
相互運用
このセクションは Blazor WebAssembly アプリに適用されます。
IJSRuntime インターフェイスに基づく Blazor の JS 相互運用メカニズムを使用して Blazor WebAssembly アプリで JavaScript (JS) と対話する代わりに、.NET 7 以降を対象とするアプリで JS[JSImport]
/[JSExport]
相互運用 API を使用できます。
詳細については、「ASP.NET Core Blazor WebAssembly を使用した JavaScript JSImport/JSExport 相互運用」を参照してください。
JavaScript 相互運用オブジェクト参照の破棄
JavaScript (JS) の相互運用に関する記事全体の例では、一般的なオブジェクト破棄パターンが示されています。
この記事で説明されているように、JS から .NET を呼び出すときは、.NET メモリのリークを避けるため、.NET または JS から、作成された DotNetObjectReference を破棄します。
「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」で説明されているように、.NET から JS を呼び出すときは、JS メモリのリークを避けるため、.NET または JS から、作成されたすべての IJSObjectReference/IJSInProcessObjectReference/
JSObjectReference
を破棄します。
JS 相互運用オブジェクト参照は、参照を作成する JS 相互運用呼び出しの側で識別子によってキー付けされたマップとして実装されます。 オブジェクトの破棄が .NET または JS の側から開始されると、Blazor はマップからエントリを削除し、オブジェクトへの強力な参照が他に存在しない限り、オブジェクトをガベージ コレクションできます。
.NET マネージド メモリのリークを回避するため、少なくとも、.NET 側で作成されたオブジェクトを常に破棄します。
コンポーネントの破棄中のドキュメント オブジェクト モデル (DOM) クリーンアップ タスク
コンポーネントの破棄の間に、DOM クリーンアップ タスクに対して JS 相互運用コードを実行しないでください。 次の理由から、代わりに、クライアントの JavaScript で MutationObserver
パターンを使います。
- クリーンアップ コードが
Dispose{Async}
で実行されるまでに、コンポーネントが DOM から削除されている可能性があります。 - Blazor Server アプリでは、クリーンアップ コードが
Dispose{Async}
で実行されるまでに、Blazor レンダラーがフレームワークによって破棄されている可能性があります。
MutationObserver
パターンを使うと、DOM から要素が削除されていても関数を実行できます。
回線を使用しない JavaScript 相互運用呼び出し
"このセクションは Blazor Server アプリにのみ適用されます。 "
JavaScript (JS) 相互運用呼び出しは、SignalR 回線が切断された後は発行できません。 コンポーネントの破棄中に回線がない、または回線が存在しないその他の時点で、次のメソッド呼び出しは失敗し、回線が切断されたというメッセージが JSDisconnectedException としてログされます。
- JS 相互運用メソッド呼び出し
- いずれかのIJSObjectReference での
Dispose
/DisposeAsync
呼び出し。
JSDisconnectedException のログを回避したり、カスタム情報をログしたりするには、try-catch
ステートメントで例外をキャッチします。
次のコンポーネント破棄の例で:
- コンポーネントでは IAsyncDisposable を実装します。
objInstance
は IJSObjectReference です。- JSDisconnectedException がキャッチされ、ログはされません。
- 必要に応じて、任意のログ レベルで
catch
ステートメントにカスタム情報をログできます。 次の例では、コンポーネントの破棄中にいつ、どこで回線が切断されるかを開発者が気にしないことを前提としているため、カスタム情報はログされません。
async ValueTask IAsyncDisposable.DisposeAsync()
{
try
{
if (objInstance is not null)
{
await objInstance.DisposeAsync();
}
}
catch (JSDisconnectedException)
{
}
}
回線が失われた後に、独自の JS オブジェクトをクリーンアップするか、クライアントで他の JS のコードを実行する必要がある場合は、クライアントの JS で MutationObserver
のパターンを使用します。 MutationObserver
パターンを使うと、DOM から要素が削除されていても関数を実行できます。
詳細については、次の記事を参照してください。
- ASP.NET Core Blazor アプリのエラーを処理する: "JavaScript 相互運用" のセクションでは、JS 相互運用シナリオでのエラー処理について説明しています。
- ASP.NET Core Razor コンポーネントのライフサイクル: 「
IDisposable
とIAsyncDisposable
を使用したコンポーネントの破棄」のセクションでは、Razor コンポーネントでの破棄パターンの実装方法について説明しています。
その他のリソース
- ASP.NET Core で .NET メソッドから JavaScript 関数を呼び出すBlazor
- の例 (dotnet/AspNetCore GitHub リポジトリの
main
ブランチ):main
ブランチは、ASP.NET Core の製品単位の現在の開発を表します。 別のリリース (release/5.0
) のブランチを選択するには、 [Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使用して、そのブランチを選択します。 - ドキュメント オブジェクト モデル (DOM) との対話
- Blazor サンプル GitHub リポジトリ (
dotnet/blazor-samples
) - ASP.NET Core Blazor アプリのエラーを処理する (「JavaScript 相互運用」のセクション)
- Blazor Server 脅威の緩和: ブラウザーから呼び出される .NET メソッド
.NET から JS 関数を呼び出す方法については、「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」をご覧ください。
静的 .NET メソッドの呼び出し
JavaScript (JS) から静的 .NET メソッドを呼び出すには、JS 関数を使用します。
DotNet.invokeMethodAsync
(推奨): Blazor Server と Blazor WebAssembly アプリの両方で非同期。DotNet.invokeMethod
: Blazor WebAssembly アプリのみで同期。
メソッドを含むアセンブリの名前、静的 .NET メソッドの識別子、および引数を渡します。
次に例を示します。
{ASSEMBLY NAME}
プレースホルダーは、アプリのアセンブリ名です。{.NET METHOD ID}
プレースホルダーは .NET メソッド識別子です。{ARGUMENTS}
プレースホルダーは、メソッドに渡す省略可能なコンマ区切りの引数であり、各引数は JSON シリアル化可能である必要があります。
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethodAsync
は、操作の結果を表す JS Promise
を返します。 DotNet.invokeMethod
(Blazor WebAssembly のみ) は操作の結果を返します。
重要
Blazor Server シナリオをサポートするには、非同期関数 (invokeMethodAsync
) が同期バージョン (invokeMethod
) より優先されます。
.NET メソッドはパブリックかつ静的であり、[JSInvokable]
属性を持つ必要があります。
次に例を示します。
{<T>}
プレースホルダーは戻り値の型を示します。これは、値を返すメソッドにのみ必要です。{.NET METHOD ID}
プレースホルダーはメソッド識別子です。
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
Note
オープン ジェネリック メソッドを呼び出すことは、静的な .NET メソッドではサポートされていませんが、インスタンス メソッドではサポートされています。 詳細については、「.NET ジェネリック クラス メソッドを呼び出す」のセクションを参照してください。
次の CallDotNetExample1
コンポーネントでは、ReturnArrayAsync
C# メソッドによって int
配列が返されます。 [JSInvokable]
属性 がメソッドに適用され、JS によってメソッドが呼び出し可能になります。
Pages/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 });
}
}
<button>
要素の onclick
HTML 属性は、 の @onclick
ディレクティブ属性ではなく、Blazorclick
イベントを処理するための JavaScript の onclick
イベント ハンドラー割り当てです。 returnArrayAsync
JS 関数はハンドラーとして割り当てられます。
次の returnArrayAsync
JS 関数では、前の CallDotNetExample1
コンポーネントの ReturnArrayAsync
.NET メソッドが呼び出され、その結果はブラウザーの Web 開発者ツール コンソールに記録されます。 BlazorSample
はアプリのアセンブリ名です。
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
注意
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
Trigger .NET static method
ボタンが選択されている場合は、ブラウザーの開発者ツール コンソールの出力に配列データが表示されます。 出力の形式はブラウザーによって若干異なります。 次の出力は、Microsoft Edge で使用される形式を示しています。
Array(3) [ 1, 2, 3 ]
データを引数として渡して invokeMethodAsync
関数を呼び出すときに、.NET メソッドにデータを渡します。
.NET にデータを渡す方法を示すには、関数が呼び出されたときに前の returnArrayAsync
JS 関数が開始位置を受け取り、その値を引数として invokeMethodAsync
関数に渡します。
<script>
window.returnArrayAsync = (startPosition) => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', startPosition)
.then(data => {
console.log(data);
});
};
</script>
CallDotNetExample1
コンポーネントで、関数呼び出しを変更して開始位置を含めます。 次の例では、5
の値を使用しています。
<button onclick="returnArrayAsync(5)">
...
</button>
コンポーネントの呼び出し可能 ReturnArrayAsync
メソッドは開始位置を受け取り、そこから配列を構築します。 コンソールにログするために、配列が返されます。
[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition)
{
return Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());
}
アプリが再コンパイルされ、ブラウザーが更新されると、ボタンが選択されたときに、ブラウザーのコンソールに次の出力が表示されます。
Array(3) [ 5, 6, 7 ]
既定では、JS 呼び出しの .NET メソッド識別子は .NET メソッド名ですが、[JSInvokable]
属性コンストラクターを使用して別の識別子を指定することもできます。 次の例では、DifferentMethodName
は ReturnArrayAsync
メソッドに割り当てられたメソッド識別子です。
[JSInvokable("DifferentMethodName")]
DotNet.invokeMethodAsync
または DotNet.invokeMethod
の呼び出し (Blazor WebAssembly のみ) で、DifferentMethodName
を呼び出して ReturnArrayAsync
.NET メソッドを実行します。
DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');
(Blazor WebAssembly のみ)
Note
このセクションの ReturnArrayAsync
メソッドの例では、明示的な C# async
および await
キーワードを使用せずに Task の結果を返します。 async
および await
を使用したメソッドのコーディングは、await
キーワードを使用して非同期操作の値を返す一般的なメソッドです。
async
および await
キーワードで構成される ReturnArrayAsync
メソッド:
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync()
{
return await Task.FromResult(new int[] { 1, 2, 3 });
}
詳細については、C# ガイドの「Async および Await を使用した非同期プログラミング」を参照してください。
.NET に渡す JavaScript オブジェクトとデータ参照を作成する
DotNet.createJSObjectReference(jsObject)
を呼び出して、.NET に渡すことができるように JS オブジェクト参照を構築します。jsObject
は JS オブジェクト参照の作成に使われる JS Object
です。 次の例では、シリアル化できない window
オブジェクトへの参照を .NET に渡します。これはその参照を ReceiveWindowObject
C# メソッドで IJSObjectReference として受け取ります。
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
前の例で、{ASSEMBLY NAME}
プレースホルダーはアプリの名前空間です。
Note
前の例では、window
オブジェクトへの参照が JS に保持されないため、JSObjectReference
の破棄は必要ありません。
JSObjectReference
への参照を維持したら、クライアントでの JS メモリのリークを避けるため、それを破棄する必要があります。 次の例では、前のコードをリファクタリングして JSObjectReference
への参照をキャプチャした後、DotNet.disposeJSObjectReference()
を呼び出して参照を破棄します。
var jsObjectReference = DotNet.createJSObjectReference(window);
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
前の例で、{ASSEMBLY NAME}
プレースホルダーはアプリの名前空間です。
DotNet.createJSStreamReference(streamReference)
を呼び出して JS ストリーム参照を構築し、.NET に渡すことができるようにします。streamReference
は、ArrayBuffer
、Blob
、または Uint8Array
や Float32Array
などの任意の型指定された配列であり、JS ストリーム参照を作成するために使用されます。
インスタンス .NET メソッドの呼び出し
JavaScript (JS) からインスタンス .NET メソッドを呼び出す場合:
インスタンスを DotNetObjectReference でラップし、その上で Create を呼び出すことにより、JS を参照して .NET インスタンスを渡します。
渡された DotNetObjectReference の
invokeMethodAsync
("推奨") またはinvokeMethod
(Blazor WebAssembly のみ) を使用して、JS から .NET インスタンス メソッドを呼び出します。 インスタンス .NET メソッドの識別子とすべての引数を渡します。 .NET インスタンスは、JS から他の .NET メソッドを呼び出すときに引数として渡すこともできます。次に例を示します。
dotNetHelper
が DotNetObjectReference です。{.NET METHOD ID}
プレースホルダーは .NET メソッド識別子です。{ARGUMENTS}
プレースホルダーは、メソッドに渡す省略可能なコンマ区切りの引数であり、各引数は JSON シリアル化可能である必要があります。
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});
Note
インスタンス メソッドを呼び出すときは、
invokeMethodAsync
とinvokeMethod
はアセンブリ名パラメーターを受け付けません。invokeMethodAsync
は、操作の結果を表す JSPromise
を返します。invokeMethod
(Blazor WebAssembly のみ) は操作の結果を返します。重要
Blazor Server シナリオをサポートするには、非同期関数 (
invokeMethodAsync
) が同期バージョン (invokeMethod
) より優先されます。
この記事の以降のセクションでは、インスタンス .NET メソッドを呼び出すさまざまな方法について説明します。
DotNetObjectReference
を個々の JavaScript 関数に渡す- 複数の JavaScript 関数を持つクラスに
DotNetObjectReference
を渡す - .NET ジェネリック クラス メソッドを呼び出す
- クラス インスタンスの例
- コンポーネント インスタンス .NET メソッド ヘルパー クラス
JavaScript で呼び出し可能な .NET メソッドのトリミングを回避する
"このセクションは、Ahead-Of-Time (AOT) コンパイルとランタイム再リンクが有効になっている Blazor WebAssembly アプリに適用されます。"
次のセクションに示すいくつかの例は、クラス インスタンスのアプローチに基づいています。ここで、[JSInvokable]
属性でマークされていて、JavaScript で呼び出し可能な .NET メソッドは、Razor コンポーネントではないクラスのメンバーです。 このような .NET メソッドがコンポーネント内にある Razor 場合、それらは、ランタイムの再リンクやトリミングから保護されます。 .NET メソッドが Razor コンポーネントの外部でトリミングされないようにするには、次の例に示すように、クラスのコンストラクターに DynamicDependency
属性を使用してメソッドを実装します。
using System.Diagnostics.CodeAnalysis;
using Microsoft.JSInterop;
public class ExampleClass {
[DynamicDependency(nameof(ExampleJSInvokableMethod))]
public ExampleClass()
{
}
[JSInvokable]
public string ExampleJSInvokableMethod()
{
...
}
}
DotNetObjectReference
を個々の JavaScript 関数に渡す
このセクションの例は、DotNetObjectReference を個々の JavaScript (JS) 関数に渡す方法を示しています。
次の sayHello1
JS 関数では DotNetObjectReference を受け取り、invokeMethodAsync
を呼び出してコンポーネントの GetHelloMessage
.NET メソッドを呼び出します。
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
注意
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
次の CallDotNetExample2
コンポーネントの場合:
- コンポーネントには、
GetHelloMessage
という名前の JS 呼び出し可能な .NET メソッドが含まれます。 Trigger .NET instance method
ボタンを選択すると、JS 関数sayHello1
が DotNetObjectReference と一緒に呼び出されます。sayHello1
:GetHelloMessage
を呼び出し、メッセージ結果を受信します。- メッセージの結果を呼び出し元の
TriggerDotNetInstanceMethod
メソッドに返します。
result
のsayHello1
から返されたメッセージがユーザーに表示されます。- メモリ リークを回避し、ガベージ コレクションを許可するには、DotNetObjectReference によって作成された .NET オブジェクト参照は
Dispose
メソッドで破棄されます。
Pages/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();
}
}
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
インスタンス メソッドに引数を渡すには:
.NET メソッドの呼び出しにパラメーターを追加します。 次の例では、名前がメソッドに渡されます。 必要に応じて、追加のパラメーターを一覧に追加します。
<script> window.sayHello2 = (dotNetHelper, name) => { return dotNetHelper.invokeMethodAsync('GetHelloMessage', name); }; </script>
前の例で、変数名
dotNetHelper
は任意であり、任意の希望する名前に変更できます。.NET メソッドにパラメーター リストを指定します。
Pages/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();
}
}
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
複数の JavaScript 関数を持つクラスに DotNetObjectReference
を渡す
このセクションの例は、DotNetObjectReference を複数の関数を持つ JavaScript (JS) クラスに渡す方法を示しています。
DotNetObjectReference を作成して OnAfterRenderAsync
ライフサイクル メソッド から JS クラスに渡して、複数の関数で使用できるようにします。 次の例に示すように、.NET コードで DotNetObjectReference が破棄されることを確認します。
次の CallDotNetExampleOneHelper
コンポーネントでは、[Trigger JS function
] ボタンは、Blazor の @onclick
ディレクティブ属性 "ではなく"JSonclick
プロパティを設定して JS を呼び出します。
Pages/CallDotNetExampleOneHelper.razor
:
@page "/call-dotnet-example-one-helper"
@implements IDisposable
@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 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();
}
}
前の例の場合:
JS
は、挿入された IJSRuntime インスタンスです。 IJSRuntime は Blazor フレームワークによって登録されます。- 変数名
dotNetHelper
は任意であり、任意の希望する名前に変更できます。 - コンポーネントは、ガベージ コレクションを許可し、メモリ リークを防ぐために、DotNetObjectReference を明示的に破棄する必要があります。
<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>
注意
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
前の例の場合:
GreetingHelpers
クラスは、window
オブジェクトに追加され、クラスをグローバルに定義します。これにより、Blazor が JS 相互運用のためにクラスを見つけることができます。- 変数名
dotNetHelper
は任意であり、任意の希望する名前に変更できます。
NET ジェネリック クラス メソッドを呼び出す
JavaScript (JS) 関数は .NET ジェネリック クラス メソッドを呼び出すことができ、ここで JS 関数はジェネリック クラスの .NET メソッドを呼び出します。
次のジェネリック型クラス (GenericType<TValue>
) で:
- クラスには、1 つのジェネリック
Value
プロパティを持つ 1 つの型パラメーター (TValue
) があります。 - クラスには、
[JSInvokable]
属性でマークされた 2 つの非ジェネリック メソッドがあり、それぞれにnewValue
という名前のジェネリック型パラメーターがあります。Update
はnewValue
からValue
の値を同期的に更新します。UpdateAsync
は、待ち受け時に現在のコンテキストに非同期的に戻す Task.Yield で待ち受け可能なタスクを作成した後newValue
からValue
の値を非同期的に更新します。
- クラスのメソッドはそれぞれ、
TValue
の型とValue
の値をコンソールに書き込みます。 コンソールへの書き込みは、デモンストレーションのみを目的とします。 通常、実稼働アプリでは、アプリのログのため、コンソールへの書き込みを回避します。 詳細については、「ASP.NET Core Blazor のログ」および「.NET Core および ASP.NET Core でのログ記録」を参照してください。
Note
"オープン ジェネリック型とメソッド" では、型プレースホルダーの型は指定されません。 逆に、"クローズド ジェネリック" では、すべての型プレースホルダーの型が指定されます。 このセクションの例は、クローズド ジェネリックを示していますが、オープン ジェネリックでの JS 相互運用 "インスタンス メソッド" の呼び出しは "サポートされています"。 オープン ジェネリックの使用はこの記事で前述した 静的 .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 void UpdateAsync(TValue newValue)
{
await Task.Yield();
Value = newValue;
Console.WriteLine($"UpdateAsync: GenericType<{typeof(TValue)}>: {Value}");
}
}
次の invokeMethodsAsync
関数では:
- ジェネリック型クラスの
Update
とUpdateAsync
のメソッドは、文字列と数値を表す引数で呼び出されます。 - Blazor WebAssembly アプリでは、
invokeMethod
との同期的な .NET メソッドの呼び出しがサポートされています。syncInterop
は、Blazor WebAssembly アプリで JS 相互運用が発生するかどうかを示すブール値を受け取ります。syncInterop
がtrue
の場合、invokeMethod
は安全に呼び出されます。syncInterop
の値がfalse
の場合、JS 相互運用が Blazor Server アプリで実行されているので、非同期関数invokeMethodAsync
だけが呼び出されます。 - デモンストレーションの目的で、DotNetObjectReference 関数呼び出し (
invokeMethod
またはinvokeMethodAsync
)、呼び出された .NET メソッド (Update
またはUpdateAsync
) およびおよび引数がコンソールに書き込まれます。 引数は乱数を使用して JS 関数呼び出しと .NET メソッド呼び出しの照合を許可します (.NET 側のコンソールにも書き込まれます)。 通常、実稼働コードは、クライアントまたはサーバー上でコンソールに書き込まれません。 実稼働アプリは通常、アプリの "ログ" に依存します。 詳細については、「ASP.NET Core Blazor のログ」および「.NET Core および 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
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
次の GenericsExample
コンポーネントでは、以下のことを行います。
Invoke Interop
ボタンを選択すると、JS 関数invokeMethodsAsync
が呼び出されます。- DotNetObjectReference 型のペアが作成され、
string
およびint
としてGenericType
のインスタンスの JS 関数に渡されます。
Pages/GenericsExample.razor
:
@page "/generics-example"
@using System.Runtime.InteropServices
@inject IJSRuntime JS
@implements IDisposable
<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 =
RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));
await JS.InvokeVoidAsync(
"invokeMethodsAsync", syncInterop, objRef1, objRef2);
}
public void Dispose()
{
objRef1?.Dispose();
objRef2?.Dispose();
}
}
前の例の JS
は、挿入された IJSRuntime インスタンスです。 IJSRuntime は Blazor フレームワークによって登録されます。
Blazor WebAssembly アプリで Invoke Interop
ボタンが選択されている場合の、前の例の一般的な出力を次に示します。
JS: invokeMethodAsync:Update('string 37802')
.NET: Update: GenericType<System.String>: string 37802
JS: invokeMethodAsync:UpdateAsync('string 53051')
JS: invokeMethod:Update('string 26784')
.NET: Update: GenericType<System.String>: string 26784
JS: invokeMethodAsync:Update(14107)
.NET: Update: GenericType<System.Int32>: 14107
JS: invokeMethodAsync:UpdateAsync(48995)
JS: invokeMethod:Update(12872)
.NET: Update: GenericType<System.Int32>: 12872
.NET: UpdateAsync: GenericType<System.String>: string 53051
.NET: UpdateAsync: GenericType<System.Int32>: 48995
前の例が Blazor Server アプリに実装されている場合、invokeMethod
を使用した同期呼び出しは回避されます。 Blazor Server のシナリオでは、非同期関数 (invokeMethodAsync
) が同期バージョン (invokeMethod
) より優先されます。
Blazor Server アプリの一般的な出力:
JS: invokeMethodAsync:Update('string 34809')
.NET: Update: GenericType<System.String>: string 34809
JS: invokeMethodAsync:UpdateAsync('string 93059')
JS: invokeMethodAsync:Update(41997)
.NET: Update: GenericType<System.Int32>: 41997
JS: invokeMethodAsync:UpdateAsync(24652)
.NET: UpdateAsync: GenericType<System.String>: string 93059
.NET: UpdateAsync: GenericType<System.Int32>: 24652
上記の出力例は、スレッドのスケジューリングやメソッドの実行速度など、いくつかの要因に応じて、非同期メソッドが "任意の順序で" 実行され、完了する例を示しています。 非同期メソッド呼び出しの完了順序は、確実には予測できません。
クラス インスタンスの例
次の sayHello1
JS 関数:
- 渡された DotNetObjectReference で
GetHelloMessage
.NET メソッドを呼び出します。 GetHelloMessage
からsayHello1
の呼び出し元にメッセージを返します。
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
注意
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
次の HelloHelper
クラスには、GetHelloMessage
という名前の JS 呼び出し可能な .NET メソッドが含まれます。 HelloHelper
が作成されると、Name
プロパティの名前が GetHelloMessage
からのメッセージを返すために使用されます。
HelloHelper.cs
:
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}!";
}
次の JsInteropClasses3
クラスの CallHelloHelperGetHelloMessage
メソッドでは、HelloHelper
の新しいインスタンスで JS 関数 sayHello1
を呼び出します。
JsInteropClasses3.cs
:
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);
}
}
メモリ リークを回避し、ガベージ コレクションを許可するため、DotNetObjectReference によって作成された .NET オブジェクト参照は、そのオブジェクト参照が using var
構文でスコープ外になったときに破棄されます。
次の CallDotNetExample4
コンポーネントで Trigger .NET instance method
ボタンを選択すると、name
の値で JsInteropClasses3.CallHelloHelperGetHelloMessage
が呼び出されます。
Pages/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);
}
}
}
次の図は、Name
フィールドに Amy Pond
という名前でレンダリングされたコンポーネントを示しています。 ボタンを選択すると、UI に Hello, Amy Pond!
が表示されます。
JsInteropClasses3
クラスに示されている上記のパターンは、完全にコンポーネントに実装することもできます。
Pages/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);
}
}
メモリ リークを回避し、ガベージ コレクションを許可するため、DotNetObjectReference によって作成された .NET オブジェクト参照は、そのオブジェクト参照が using var
構文でスコープ外になったときに破棄されます。
name
フィールドに名前 Amy Pond
が指定されている場合、CallDotNetExample5
コンポーネントによって表示される出力は Hello, Amy Pond!
です。
前の CallDotNetExample5
コンポーネントでは、.NET オブジェクト参照は破棄されます。 クラスまたはコンポーネントが DotNetObjectReference を破棄しない場合は、渡された DotNetObjectReference で dispose
を呼び出して、クライアントから破棄します。
window.{JS FUNCTION NAME} = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}');
dotNetHelper.dispose();
}
前の例の場合:
{JS FUNCTION NAME}
プレースホルダーは JS 関数の名前です。- 変数名
dotNetHelper
は任意であり、任意の希望する名前に変更できます。 {.NET METHOD ID}
プレースホルダーは .NET メソッド識別子です。
コンポーネント インスタンス .NET メソッド ヘルパー クラス
ヘルパー クラスでは、.NET インスタンス メソッドを Action として呼び出すことができます。 ヘルパー クラスは、次のシナリオで役立ちます。
- 同じ種類の複数のコンポーネントが同じページにレンダリングされる場合。
- Blazor Server アプリで、複数のユーザーが同じコンポーネントを同時に使用する場合。
次に例を示します。
CallDotNetExample6
コンポーネントには、アプリのShared
フォルダー内の共有コンポーネントであるいくつかのListItem1
コンポーネントが含まれています。- 各
ListItem1
コンポーネントは、メッセージとボタンで構成されます。 ListItem1
コンポーネント ボタンが選択されると、そのListItem1
のUpdateMessage
メソッドによってリスト項目のテキストが変更され、ボタンが非表示になります。
次の MessageUpdateInvokeHelper
クラスでは、クラスがインスタンス化されるときに指定された Action を呼び出すために、JS 呼び出し可能な .NET メソッド UpdateMessageCaller
が保持されます。
MessageUpdateInvokeHelper.cs
:
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
次の updateMessageCaller
JS 関数は、UpdateMessageCaller
.NET メソッドを呼び出します。
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
Note
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
次の ListItem1
コンポーネントは、親コンポーネントで何度でも使用できる共有コンポーネントであり、HTML リスト (<ul>...</ul>
または <ol>...</ol>
) のリスト項目 (<li>...</li>
) を作成します。 各 ListItem1
コンポーネント インスタンスは、Action がその UpdateMessage
メソッドに設定された MessageUpdateInvokeHelper
のインスタンスを確立します。
ListItem1
コンポーネントの InteropCall
ボタンが選択された場合、MessageUpdateInvokeHelper
インスタンス用に作成された DotNetObjectReference で updateMessageCaller
が呼び出されます。 これにより、フレームワークはその ListItem1
の MessageUpdateInvokeHelper
インスタンスで UpdateMessageCaller
を呼び出すことができます。 渡された DotNetObjectReference は JS (dotNetHelper.dispose()
) で破棄されます。
Shared/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();
}
}
message
が UpdateMessage
で設定されている場合、UI を更新するために StateHasChanged
が呼び出されます。 StateHasChanged
が呼び出されていない場合、Blazor には Action が呼び出されたときに UI を更新する必要があることを知る方法はありません。
次の CallDotNetExample6
親コンポーネントには、それぞれ ListItem1
コンポーネントのインスタンスである 4 つのリスト項目が含まれています。
Pages/CallDotNetExample6.razor
:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
次の図は、2 番目の InteropCall
ボタンが選択された後にレンダリングされた CallDotNetExample6
親コンポーネントを示しています。
- 2 番目の
ListItem1
コンポーネントによってUpdateMessage Called!
メッセージが表示されました。 - ボタンの CSS
display
プロパティがnone
に設定されているため、2 番目のListItem1
コンポーネントのInteropCall
ボタンは表示されません。
要素プロパティに割り当てられた DotNetObjectReference
から呼び出されるコンポーネント インスタンスの .NET メソッド
HTML 要素のプロパティに対する DotNetObjectReference の割り当てにより、コンポーネント インスタンスの .NET メソッドを呼び出すことができます。
- 要素の参照がキャプチャされます (ElementReference)。
- コンポーネントの
OnAfterRender{Async}
メソッドでは、要素の参照とコンポーネント インスタンスを DotNetObjectReference として、JavaScript (JS) 関数が呼び出されます。 この JS 関数は、DotNetObjectReference をプロパティ内の要素にアタッチします。 - JS で要素イベントが呼び出されると (たとえば
onclick
)、その要素のアタッチされた DotNetObjectReference が .NET メソッドの呼び出しに使用されます。
コンポーネント インスタンスの .NET メソッド ヘルパー クラスに関するセクションで説明されている方法と同様に、この方法は次のシナリオで役立ちます。
- 同じ種類の複数のコンポーネントが同じページにレンダリングされる場合。
- Blazor Server アプリで、複数のユーザーが同じコンポーネントを同時に使用する場合。
- .NET メソッドが、Blazor イベント (たとえば
@onclick
) からではなく、JS イベント (たとえばonclick
) から呼び出される場合。
次に例を示します。
CallDotNetExample7
コンポーネントには、アプリのShared
フォルダー内の共有コンポーネントであるいくつかのListItem2
コンポーネントが含まれています。- 各
ListItem2
コンポーネントは、リスト項目メッセージ<span>
と、display
CSS プロパティが表示用にinline-block
に設定された 2 つ目の<span>
で構成されています。 ListItem2
コンポーネントのリスト項目が選択されると、そのListItem2
のUpdateMessage
メソッドによって最初の<span>
のリスト項目テキストが変更され、そのdisplay
プロパティをnone
に設定することで 2 つ目の<span>
が非表示になります。
次の assignDotNetHelper
JS 関数は、dotNetHelper
という名前のプロパティの要素に DotNetObjectReference を割り当てます。
<script>
window.assignDotNetHelper = (element, dotNetHelper) => {
element.dotNetHelper = dotNetHelper;
}
</script>
次の interopCall
JS 関数では、渡される要素に DotNetObjectReference を使用して、UpdateMessage
という名前の .NET メソッドを呼び出します。
<script>
window.interopCall = async (element) => {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
</script>
注意
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
次の ListItem2
コンポーネントは、親コンポーネントで何度でも使用できる共有コンポーネントであり、HTML リスト (<ul>...</ul>
または <ol>...</ol>
) のリスト項目 (<li>...</li>
) を作成します。
各 ListItem2
コンポーネント インスタンスでは、要素の参照 (リスト項目の最初の <span>
要素) とコンポーネント インスタンスを DotNetObjectReference として、OnAfterRenderAsync
で assignDotNetHelper
JS 関数を呼び出します。
ListItem2
コンポーネントのメッセージ <span>
が選択されると、<span>
要素をパラメーター (this
) として渡して interopCall
が呼び出されます。これにより、UpdateMessage
.NET メソッドが呼び出されます。 UpdateMessage
では、message
が設定され、2 つ目の <span>
の display
プロパティが更新されると、StateHasChanged
が呼び出されて UI が更新されます。 StateHasChanged
が呼び出されないと、Blazor にはメソッドが呼び出されたときに UI を更新する必要があることを知る方法がありません。
DotNetObjectReference は、コンポーネントが破棄されるときに破棄されます。
Shared/ListItem2.razor
:
@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();
}
次の CallDotNetExample7
親コンポーネントには、それぞれ ListItem2
コンポーネントのインスタンスである 4 つのリスト項目が含まれています。
Pages/CallDotNetExample7.razor
:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
Blazor WebAssembly アプリでの同期 JS 相互運用
"このセクションは アプリにのみ適用されます。 "
JS 相互運用呼び出しは、呼び出されたコードが同期であるか非同期であるかに関係なく、既定で非同期となります。 Blazor ホスティング モデルの Blazor Server と Blazor WebAssembly の両方におけるコンポーネントの互換性を確保するため、既定では呼び出しは非同期です。 Blazor Server では、すべての JS 相互運用呼び出しは、ネットワーク接続を介して送信されるため、非同期である必要があります。
アプリが Blazor WebAssembly でのみ実行されることが確実である場合は、同期 JS 相互運用呼び出しを行うように選択できます。 これにより、非同期呼び出しを行う場合よりもオーバーヘッドがわずかに減少し、レンダリング サイクルが少なくなる可能性があります。これは、結果を待機する間の中間状態が存在しないためです。
Blazor WebAssembly アプリで JavaScript から .NET への同期呼び出しを行うには、DotNet.invokeMethodAsync
ではなく DotNet.invokeMethod
を使用します。
同期呼び出しは、次の場合に機能します。
- アプリが Blazor Server ではなく Blazor WebAssembly で実行されている。
- 呼び出された関数から同期的に値が返される。 この関数は
async
メソッドではなく、.NET Task や JavaScriptPromise
は返されません。
JavaScript の場所
JS 相互運用の概要に関する記事で説明されている方法のいずれかを使用して、JavaScript (JS) コードを読み込みます。
<head>
マークアップでスクリプトを読み込む ("通常は推奨されません")- マークアップでスクリプトを読み込む
- 外部 JavaScript ファイル (
.js
) からスクリプトを読み込む - Blazor の開始の前または後にスクリプトを挿入する
モジュールでのスクリプトの分離の詳細については、「JavaScript モジュールでの JavaScript の分離」セクションを参照してください。
警告
<script>
タグは動的に更新できないため、<script>
タグをコンポーネント ファイル (.razor
) 内に配置しないでください。
JavaScript モジュールでの JavaScript の分離
Blazor では、標準の Blazorに JavaScript (JS) を分離できます (JS)。 JavaScript モジュールの読み込みは、他の種類の Web アプリの場合と同じように Blazor で機能し、アプリでモジュールを定義する方法を自由にカスタマイズできます。 JavaScript モジュールの使用方法に関するガイドについては、MDN Web Docs の「JavaScript モジュール」を参照してください。
JS を分離すると、次のようなベネフィットがあります。
- インポートされる JS によって、グローバル名前空間が汚染されなくなります。
- ライブラリおよびコンポーネントのコンシューマーは、関連する JS をインポートする必要がありません。
詳しくは、「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」をご覧ください。
import()
演算子を使用した動的インポートは、ASP.NET Core と Blazorでサポートされています。
if ({CONDITION}) import("/additionalModule.js");
前述の例では、プレースホルダー {CONDITION}
は、モジュールを読み込む必要があるかどうかを判断するための条件付きチェックを表しています。
ブラウザーの互換性については、「Can I use: JavaScript modules: dynamic import (使用できるかどうか: JavaScript モジュール: dynamic import)」を参照してください。
循環オブジェクト参照の回避
循環参照を含むオブジェクトは、次のいずれに対しても、クライアントでシリアル化することはできません。
- .NET メソッドの呼び出し。
- 戻り値の型に循環参照がある場合の、C# からの JavaScript メソッドの呼び出し。
バイト配列のサポート
Blazor では、Base64 へのバイト配列のエンコードおよびデコードを回避する、最適化されたバイト配列 JavaScript (JS) 相互運用がサポートされています。 次の例では、JS 相互運用を使用してバイト配列を .NET に渡します。
sendByteArray
JS 関数を指定します。 この関数は、コンポーネント内のボタンによって静的に呼び出され (これには、invokeMethodAsync
の呼び出しのアセンブリ名パラメーターが含まれます)、値を返しません。
<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
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
Pages/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));
}
}
.NET から JavaScript を呼び出すときのバイト配列の使用については、「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」をご覧ください。
JavaScript から .NET へのストリーム
Blazor では、JavaScript から .NET に直接データをストリーミングすることがサポートされます。 ストリームは Microsoft.JSInterop.IJSStreamReference
インターフェイスを使用して要求されます。
Microsoft.JSInterop.IJSStreamReference.OpenReadStreamAsync
では Stream が返され、次のパラメーターが使用されます。
maxAllowedSize
: JavaScript からの読み取り操作に許可される最大バイト数。指定されていない場合、既定では 512,000 バイトになります。cancellationToken
: 読み取りをキャンセルするための CancellationToken。
JavaScript の場合:
function streamToDotNet() {
return new Uint8Array(10000000);
}
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);
前の例の場合:
JS
は、挿入された IJSRuntime インスタンスです。 IJSRuntime は Blazor フレームワークによって登録されます。dataReferenceStream
は、現在のユーザーの一時フォルダー パス (GetTempPath) でディスク (file.txt
) に書き込まれます。
「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」では、逆の動作である、DotNetStreamReference を使用した .NET から JavaScript へのストリーミングについて説明しています。
「ASP.NET Core Blazor ファイルのアップロード」では、Blazor でファイルをアップロードする方法を説明しています。
JavaScript 相互運用呼び出しのサイズ制限
"このセクションは Blazor Server アプリにのみ適用されます。 " Blazor WebAssembly では、フレームワークによって JavaScript (JS) 相互運用の入力と出力のサイズが制限されることはありません。
Blazor Server では、ハブ メソッドで許可される SignalR 受信メッセージの最大サイズによって、JS 相互運用呼び出しのサイズが制限されます。これは、HubOptions.MaximumReceiveMessageSize によって適用されます (既定値: 32 KB)。 JS から .NET への SignalR メッセージが MaximumReceiveMessageSize より大きい場合は、エラーがスローされます。 このフレームワークでは、ハブからクライアントへの SignalR メッセージのサイズが制限されることはありません。
SignalR のログがSignalR または Trace に設定されていない場合、メッセージ サイズのエラーはブラウザーの開発者ツール コンソールにのみ表示されます。
エラー :次のエラーで接続が切断されました。"エラー: サーバーが終了時にエラーを返しました:接続はエラーで終了しました。"
サーバー側のログ が Debug または Trace に設定されている場合、サーバー側のログには、メッセージ サイズ エラーの が表示されます。
appsettings.Development.json
:
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug"
}
}
}
エラー:
System.IO.InvalidDataException:メッセージの最大サイズ 32,768 B を超えました。 メッセージのサイズは、AddHubOptions で構成できます。
制限値を増やすには、Program.cs
で MaximumReceiveMessageSize を設定します。 次の例では、受信メッセージの最大サイズを 64 KB に設定します。
builder.Services.AddServerSideBlazor()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
SignalR 受信メッセージ サイズの制限値を増やすと、より多くのサーバー リソースが必要になり、悪意のあるユーザーからのより大きなリスクにサーバーがさらされます。 また、大量のコンテンツを文字列またはバイト配列としてメモリに読み取ると、ガベージ コレクターがうまく機能しない割り当てが発生する可能性もあり、その結果、パフォーマンスがさらに低下します。
Blazor Server アプリで JS と Blazor の間で大量のデータを転送するコードを開発するときは、次のガイダンスを考慮してください。
- SignalR 受信メッセージ サイズの制限を超えるデータを転送するには、ネイティブ ストリーミング相互運用サポートを利用します。
- ASP.NET Core で .NET メソッドから JavaScript 関数を呼び出す
- ASP.NET Core で JavaScript 関数から .NET メソッドを呼び出す
- 一般的なヒント:
- JS および C# コードで大きなオブジェクトを割り当てないでください。
- プロセスの完了時またはキャンセル時に、消費していたメモリを解放します。
- セキュリティ上の理由から、次の追加要件を適用します。
- 渡すことのできるファイルまたはデータの最大サイズを宣言します。
- クライアントからサーバーへの最小アップロード レートを宣言します。
- データがサーバーによって受信されたら、データは:
- すべてのセグメントが収集されるまで、一時的にメモリ バッファーに格納できます。
- 直ちに消費できます。 たとえば、データは、データベースに直ちに格納することも、セグメントを受信するたびにディスクに書き込むこともできます。
コンポーネントの破棄中のドキュメント オブジェクト モデル (DOM) クリーンアップ タスク
コンポーネントの破棄の間に、DOM クリーンアップ タスクに対して JS 相互運用コードを実行しないでください。 次の理由から、代わりに、クライアントの JavaScript で MutationObserver
パターンを使います。
- クリーンアップ コードが
Dispose{Async}
で実行されるまでに、コンポーネントが DOM から削除されている可能性があります。 - Blazor Server アプリでは、クリーンアップ コードが
Dispose{Async}
で実行されるまでに、Blazor レンダラーがフレームワークによって破棄されている可能性があります。
MutationObserver
パターンを使うと、DOM から要素が削除されていても関数を実行できます。
回線を使用しない JavaScript 相互運用呼び出し
"このセクションは Blazor Server アプリにのみ適用されます。 "
JavaScript (JS) 相互運用呼び出しは、SignalR 回線が切断された後は発行できません。 コンポーネントの破棄中に回線がない、または回線が存在しないその他の時点で、次のメソッド呼び出しは失敗し、回線が切断されたというメッセージが JSDisconnectedException としてログされます。
- JS 相互運用メソッド呼び出し
- いずれかのIJSObjectReference での
Dispose
/DisposeAsync
呼び出し。
JSDisconnectedException のログを回避したり、カスタム情報をログしたりするには、try-catch
ステートメントで例外をキャッチします。
次のコンポーネント破棄の例で:
- コンポーネントでは IAsyncDisposable を実装します。
objInstance
は IJSObjectReference です。- JSDisconnectedException がキャッチされ、ログはされません。
- 必要に応じて、任意のログ レベルで
catch
ステートメントにカスタム情報をログできます。 次の例では、コンポーネントの破棄中にいつ、どこで回線が切断されるかを開発者が気にしないことを前提としているため、カスタム情報はログされません。
async ValueTask IAsyncDisposable.DisposeAsync()
{
try
{
if (objInstance is not null)
{
await objInstance.DisposeAsync();
}
}
catch (JSDisconnectedException)
{
}
}
回線が失われた後に、独自の JS オブジェクトをクリーンアップするか、クライアントで他の JS のコードを実行する必要がある場合は、クライアントの JS で MutationObserver
のパターンを使用します。 MutationObserver
パターンを使うと、DOM から要素が削除されていても関数を実行できます。
詳細については、次の記事を参照してください。
- ASP.NET Core Blazor アプリのエラーを処理する: "JavaScript 相互運用" のセクションでは、JS 相互運用シナリオでのエラー処理について説明しています。
- ASP.NET Core Razor コンポーネントのライフサイクル: 「
IDisposable
とIAsyncDisposable
を使用したコンポーネントの破棄」のセクションでは、Razor コンポーネントでの破棄パターンの実装方法について説明しています。
その他のリソース
- ASP.NET Core で .NET メソッドから JavaScript 関数を呼び出すBlazor
- の例 (dotnet/AspNetCore GitHub リポジトリの
main
ブランチ):main
ブランチは、ASP.NET Core の製品単位の現在の開発を表します。 別のリリース (release/5.0
) のブランチを選択するには、 [Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使用して、そのブランチを選択します。 - ドキュメント オブジェクト モデル (DOM) との対話
- Blazor サンプル GitHub リポジトリ (
dotnet/blazor-samples
) - ASP.NET Core Blazor アプリのエラーを処理する (「JavaScript 相互運用」のセクション)
- Blazor Server 脅威の緩和: ブラウザーから呼び出される .NET メソッド
.NET から JS 関数を呼び出す方法については、「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」をご覧ください。
静的 .NET メソッドの呼び出し
JavaScript (JS) から静的 .NET メソッドを呼び出すには、JS 関数を使用します。
DotNet.invokeMethodAsync
(推奨): Blazor Server と Blazor WebAssembly アプリの両方で非同期。DotNet.invokeMethod
: Blazor WebAssembly アプリのみで同期。
次に例を示します。
{ASSEMBLY NAME}
プレースホルダーは、アプリのアセンブリ名です。{.NET METHOD ID}
プレースホルダーは .NET メソッド識別子です。{ARGUMENTS}
プレースホルダーは、メソッドに渡す省略可能なコンマ区切りの引数であり、各引数は JSON シリアル化可能である必要があります。
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethodAsync
は、操作の結果を表す JS Promise
を返します。 DotNet.invokeMethod
(Blazor WebAssembly のみ) は操作の結果を返します。
重要
Blazor Server シナリオをサポートするには、非同期関数 (invokeMethodAsync
) が同期バージョン (invokeMethod
) より優先されます。
.NET メソッドはパブリックかつ静的であり、[JSInvokable]
属性を持つ必要があります。
次に例を示します。
{<T>}
プレースホルダーは戻り値の型を示します。これは、値を返すメソッドにのみ必要です。{.NET METHOD ID}
プレースホルダーはメソッド識別子です。
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
Note
オープン ジェネリック メソッドを呼び出すことは、静的な .NET メソッドではサポートされていませんが、この記事で後述するインスタンス メソッドではサポートされています。
次の CallDotNetExample1
コンポーネントでは、ReturnArrayAsync
C# メソッドによって int
配列が返されます。 [JSInvokable]
属性 がメソッドに適用され、JS によってメソッドが呼び出し可能になります。
Pages/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 });
}
}
<button>
要素の onclick
HTML 属性は、 の @onclick
ディレクティブ属性ではなく、Blazorclick
イベントを処理するための JavaScript の onclick
イベント ハンドラー割り当てです。 returnArrayAsync
JS 関数はハンドラーとして割り当てられます。
次の returnArrayAsync
JS 関数では、前の CallDotNetExample1
コンポーネントの ReturnArrayAsync
.NET メソッドが呼び出され、その結果はブラウザーの Web 開発者ツール コンソールに記録されます。 BlazorSample
はアプリのアセンブリ名です。
wwwroot/index.html
(Blazor WebAssembly) または Pages/_Host.cshtml
(Blazor Server) の終了 </body>
タグの内部:
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
Trigger .NET static method
ボタンが選択されている場合は、ブラウザーの開発者ツール コンソールの出力に配列データが表示されます。 出力の形式はブラウザーによって若干異なります。 次の出力は、Microsoft Edge で使用される形式を示しています。
Array(3) [ 1, 2, 3 ]
データを引数として渡して invokeMethodAsync
関数を呼び出すときに、ReturnArrayAsync
.NET メソッドにデータを渡します。
.NET にデータを渡す方法を示すには、関数が呼び出されたときに前の returnArrayAsync
JS 関数が開始位置を受け取り、その値を引数として invokeMethodAsync
関数に渡します。
<script>
window.returnArrayAsync = (startPosition) => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', startPosition)
.then(data => {
console.log(data);
});
};
</script>
CallDotNetExample1
コンポーネントで、関数呼び出しを変更して開始位置を含めます。 次の例では、5
の値を使用しています。
<button onclick="returnArrayAsync(5)">
...
</button>
コンポーネントの呼び出し可能 ReturnArrayAsync
メソッドは開始位置を受け取り、そこから配列を構築します。 コンソールにログするために、配列が返されます。
[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition)
{
return Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());
}
アプリが再コンパイルされ、ブラウザーが更新されると、ボタンが選択されたときに、ブラウザーのコンソールに次の出力が表示されます。
Array(3) [ 5, 6, 7 ]
既定では、JS 呼び出しの .NET メソッド識別子は .NET メソッド名ですが、[JSInvokable]
属性コンストラクターを使用して別の識別子を指定することもできます。 次の例では、DifferentMethodName
は ReturnArrayAsync
メソッドに割り当てられたメソッド識別子です。
[JSInvokable("DifferentMethodName")]
DotNet.invokeMethodAsync
または DotNet.invokeMethod
の呼び出し (Blazor WebAssembly のみ) で、DifferentMethodName
を呼び出して ReturnArrayAsync
.NET メソッドを実行します。
DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');
(Blazor WebAssembly のみ)
Note
このセクションの ReturnArrayAsync
メソッドの例では、明示的な C# async
および await
キーワードを使用せずに Task の結果を返します。 async
および await
を使用したメソッドのコーディングは、await
キーワードを使用して非同期操作の値を返す一般的なメソッドです。
async
および await
キーワードで構成される ReturnArrayAsync
メソッド:
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync()
{
return await Task.FromResult(new int[] { 1, 2, 3 });
}
詳細については、C# ガイドの「Async および Await を使用した非同期プログラミング」を参照してください。
.NET に渡す JavaScript オブジェクトとデータ参照を作成する
DotNet.createJSObjectReference(jsObject)
を呼び出して、.NET に渡すことができるように JS オブジェクト参照を構築します。jsObject
は JS オブジェクト参照の作成に使われる JS Object
です。 次の例では、シリアル化できない window
オブジェクトへの参照を .NET に渡します。これはその参照を ReceiveWindowObject
C# メソッドで IJSObjectReference として受け取ります。
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
前の例で、{ASSEMBLY NAME}
プレースホルダーはアプリの名前空間です。
Note
前の例では、window
オブジェクトへの参照が JS に保持されないため、JSObjectReference
の破棄は必要ありません。
JSObjectReference
への参照を維持したら、クライアントでの JS メモリのリークを避けるため、それを破棄する必要があります。 次の例では、前のコードをリファクタリングして JSObjectReference
への参照をキャプチャした後、DotNet.disposeJSObjectReference()
を呼び出して参照を破棄します。
var jsObjectReference = DotNet.createJSObjectReference(window);
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
前の例で、{ASSEMBLY NAME}
プレースホルダーはアプリの名前空間です。
DotNet.createJSStreamReference(streamReference)
を呼び出して JS ストリーム参照を構築し、.NET に渡すことができるようにします。streamReference
は、ArrayBuffer
、Blob
、または Uint8Array
や Float32Array
などの任意の型指定された配列であり、JS ストリーム参照を作成するために使用されます。
インスタンス .NET メソッドの呼び出し
JavaScript (JS) からインスタンス .NET メソッドを呼び出す場合:
インスタンスを DotNetObjectReference でラップし、その上で Create を呼び出すことにより、JS を参照して .NET インスタンスを渡します。
渡された DotNetObjectReference の
invokeMethodAsync
("推奨") またはinvokeMethod
(Blazor WebAssembly のみ) を使用して、JS から .NET インスタンス メソッドを呼び出します。 インスタンス .NET メソッドの識別子とすべての引数を渡します。 .NET インスタンスは、JS から他の .NET メソッドを呼び出すときに引数として渡すこともできます。次に例を示します。
dotNetHelper
が DotNetObjectReference です。{.NET METHOD ID}
プレースホルダーは .NET メソッド識別子です。{ARGUMENTS}
プレースホルダーは、メソッドに渡す省略可能なコンマ区切りの引数であり、各引数は JSON シリアル化可能である必要があります。
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});
Note
インスタンス メソッドを呼び出すときは、
invokeMethodAsync
とinvokeMethod
はアセンブリ名パラメーターを受け付けません。invokeMethodAsync
は、操作の結果を表す JSPromise
を返します。invokeMethod
(Blazor WebAssembly のみ) は操作の結果を返します。重要
Blazor Server シナリオをサポートするには、非同期関数 (
invokeMethodAsync
) が同期バージョン (invokeMethod
) より優先されます。
この記事の以降のセクションでは、インスタンス .NET メソッドを呼び出すさまざまな方法について説明します。
コンポーネント インスタンスの例
次の sayHello1
JS 関数では DotNetObjectReference を受け取り、invokeMethodAsync
を呼び出してコンポーネントの GetHelloMessage
.NET メソッドを呼び出します。
wwwroot/index.html
(Blazor WebAssembly) または Pages/_Host.cshtml
(Blazor Server) の終了 </body>
タグの内部:
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
次の CallDotNetExample2
コンポーネントの場合:
- コンポーネントには、
GetHelloMessage
という名前の JS 呼び出し可能な .NET メソッドが含まれます。 Trigger .NET instance method
ボタンを選択すると、JS 関数sayHello1
が DotNetObjectReference と一緒に呼び出されます。sayHello1
:GetHelloMessage
を呼び出し、メッセージ結果を受信します。- メッセージの結果を呼び出し元の
TriggerDotNetInstanceMethod
メソッドに返します。
result
のsayHello1
から返されたメッセージがユーザーに表示されます。- メモリ リークを回避し、ガベージ コレクションを許可するには、DotNetObjectReference によって作成された .NET オブジェクト参照は
Dispose
メソッドで破棄されます。
Pages/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();
}
}
インスタンス メソッドに引数を渡すには:
.NET メソッドの呼び出しにパラメーターを追加します。 次の例では、名前がメソッドに渡されます。 必要に応じて、追加のパラメーターを一覧に追加します。
<script> window.sayHello2 = (dotNetHelper, name) => { return dotNetHelper.invokeMethodAsync('GetHelloMessage', name); }; </script>
.NET メソッドにパラメーター リストを指定します。
Pages/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();
}
}
クラス インスタンスの例
次の sayHello1
JS 関数:
- 渡された DotNetObjectReference で
GetHelloMessage
.NET メソッドを呼び出します。 GetHelloMessage
からsayHello1
の呼び出し元にメッセージを返します。
wwwroot/index.html
(Blazor WebAssembly) または Pages/_Host.cshtml
(Blazor Server) の終了 </body>
タグの内部:
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
次の HelloHelper
クラスには、GetHelloMessage
という名前の JS 呼び出し可能な .NET メソッドが含まれます。 HelloHelper
が作成されると、Name
プロパティの名前が GetHelloMessage
からのメッセージを返すために使用されます。
HelloHelper.cs
:
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string name)
{
Name = name;
}
public string Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
次の JsInteropClasses3
クラスの CallHelloHelperGetHelloMessage
メソッドでは、HelloHelper
の新しいインスタンスで JS 関数 sayHello1
を呼び出します。
JsInteropClasses3.cs
:
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);
}
}
メモリ リークを回避し、ガベージ コレクションを許可するため、DotNetObjectReference によって作成された .NET オブジェクト参照は、そのオブジェクト参照が using var
構文でスコープ外になったときに破棄されます。
次の CallDotNetExample4
コンポーネントで Trigger .NET instance method
ボタンを選択すると、name
の値で JsInteropClasses3.CallHelloHelperGetHelloMessage
が呼び出されます。
Pages/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);
}
}
次の図は、Name
フィールドに Amy Pond
という名前でレンダリングされたコンポーネントを示しています。 ボタンを選択すると、UI に Hello, Amy Pond!
が表示されます。
JsInteropClasses3
クラスに示されている上記のパターンは、完全にコンポーネントに実装することもできます。
Pages/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);
}
}
メモリ リークを回避し、ガベージ コレクションを許可するため、DotNetObjectReference によって作成された .NET オブジェクト参照は、そのオブジェクト参照が using var
構文でスコープ外になったときに破棄されます。
name
フィールドに名前 Amy Pond
が指定されている場合、CallDotNetExample5
コンポーネントによって表示される出力は Hello, Amy Pond!
です。
前の CallDotNetExample5
コンポーネントでは、.NET オブジェクト参照は破棄されます。 クラスまたはコンポーネントが DotNetObjectReference を破棄しない場合は、渡された DotNetObjectReference で dispose
を呼び出して、クライアントから破棄します。
window.{JS FUNCTION NAME} = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}');
dotNetHelper.dispose();
}
前の例の場合:
{JS FUNCTION NAME}
プレースホルダーは JS 関数の名前です。- 変数名
dotNetHelper
は任意であり、任意の希望する名前に変更できます。 {.NET METHOD ID}
プレースホルダーは .NET メソッド識別子です。
コンポーネント インスタンス .NET メソッド ヘルパー クラス
ヘルパー クラスでは、.NET インスタンス メソッドを Action として呼び出すことができます。 ヘルパー クラスは、次のシナリオで役立ちます。
- 同じ種類の複数のコンポーネントが同じページにレンダリングされる場合。
- Blazor Server アプリで、複数のユーザーが同じコンポーネントを同時に使用する場合。
次に例を示します。
CallDotNetExample6
コンポーネントには、アプリのShared
フォルダー内の共有コンポーネントであるいくつかのListItem1
コンポーネントが含まれています。- 各
ListItem1
コンポーネントは、メッセージとボタンで構成されます。 ListItem1
コンポーネント ボタンが選択されると、そのListItem1
のUpdateMessage
メソッドによってリスト項目のテキストが変更され、ボタンが非表示になります。
次の MessageUpdateInvokeHelper
クラスでは、クラスがインスタンス化されるときに指定された Action を呼び出すために、JS 呼び出し可能な .NET メソッド UpdateMessageCaller
が保持されます。
MessageUpdateInvokeHelper.cs
:
using System;
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
次の updateMessageCaller
JS 関数は、UpdateMessageCaller
.NET メソッドを呼び出します。
wwwroot/index.html
(Blazor WebAssembly) または Pages/_Host.cshtml
(Blazor Server) の終了 </body>
タグの内部:
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
次の ListItem1
コンポーネントは、親コンポーネントで何度でも使用できる共有コンポーネントであり、HTML リスト (<ul>...</ul>
または <ol>...</ol>
) のリスト項目 (<li>...</li>
) を作成します。 各 ListItem1
コンポーネント インスタンスは、Action がその UpdateMessage
メソッドに設定された MessageUpdateInvokeHelper
のインスタンスを確立します。
ListItem1
コンポーネントの InteropCall
ボタンが選択された場合、MessageUpdateInvokeHelper
インスタンス用に作成された DotNetObjectReference で updateMessageCaller
が呼び出されます。 これにより、フレームワークはその ListItem1
の MessageUpdateInvokeHelper
インスタンスで UpdateMessageCaller
を呼び出すことができます。 渡された DotNetObjectReference は JS (dotNetHelper.dispose()
) で破棄されます。
Shared/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()
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
message
が UpdateMessage
で設定されている場合、UI を更新するために StateHasChanged
が呼び出されます。 StateHasChanged
が呼び出されていない場合、Blazor には Action が呼び出されたときに UI を更新する必要があることを知る方法はありません。
次の CallDotNetExample6
親コンポーネントには、それぞれ ListItem1
コンポーネントのインスタンスである 4 つのリスト項目が含まれています。
Pages/CallDotNetExample6.razor
:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
次の図は、2 番目の InteropCall
ボタンが選択された後にレンダリングされた CallDotNetExample6
親コンポーネントを示しています。
- 2 番目の
ListItem1
コンポーネントによってUpdateMessage Called!
メッセージが表示されました。 - ボタンの CSS
display
プロパティがnone
に設定されているため、2 番目のListItem1
コンポーネントのInteropCall
ボタンは表示されません。
要素プロパティに割り当てられた DotNetObjectReference
から呼び出されるコンポーネント インスタンスの .NET メソッド
HTML 要素のプロパティに対する DotNetObjectReference の割り当てにより、コンポーネント インスタンスの .NET メソッドを呼び出すことができます。
- 要素の参照がキャプチャされます (ElementReference)。
- コンポーネントの
OnAfterRender{Async}
メソッドでは、要素の参照とコンポーネント インスタンスを DotNetObjectReference として、JavaScript (JS) 関数が呼び出されます。 この JS 関数は、DotNetObjectReference をプロパティ内の要素にアタッチします。 - JS で要素イベントが呼び出されると (たとえば
onclick
)、その要素のアタッチされた DotNetObjectReference が .NET メソッドの呼び出しに使用されます。
コンポーネント インスタンスの .NET メソッド ヘルパー クラスに関するセクションで説明されている方法と同様に、この方法は次のシナリオで役立ちます。
- 同じ種類の複数のコンポーネントが同じページにレンダリングされる場合。
- Blazor Server アプリで、複数のユーザーが同じコンポーネントを同時に使用する場合。
- .NET メソッドが、Blazor イベント (たとえば
@onclick
) からではなく、JS イベント (たとえばonclick
) から呼び出される場合。
次に例を示します。
CallDotNetExample7
コンポーネントには、アプリのShared
フォルダー内の共有コンポーネントであるいくつかのListItem2
コンポーネントが含まれています。- 各
ListItem2
コンポーネントは、リスト項目メッセージ<span>
と、display
CSS プロパティが表示用にinline-block
に設定された 2 つ目の<span>
で構成されています。 ListItem2
コンポーネントのリスト項目が選択されると、そのListItem2
のUpdateMessage
メソッドによって最初の<span>
のリスト項目テキストが変更され、そのdisplay
プロパティをnone
に設定することで 2 つ目の<span>
が非表示になります。
次の assignDotNetHelper
JS 関数は、dotNetHelper
という名前のプロパティの要素に DotNetObjectReference を割り当てます。
<script>
window.assignDotNetHelper = (element, dotNetHelper) => {
element.dotNetHelper = dotNetHelper;
}
</script>
次の interopCall
JS 関数では、渡される要素に DotNetObjectReference を使用して、UpdateMessage
という名前の .NET メソッドを呼び出します。
<script>
window.interopCall = async (element) => {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
</script>
注意
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
次の ListItem2
コンポーネントは、親コンポーネントで何度でも使用できる共有コンポーネントであり、HTML リスト (<ul>...</ul>
または <ol>...</ol>
) のリスト項目 (<li>...</li>
) を作成します。
各 ListItem2
コンポーネント インスタンスでは、要素の参照 (リスト項目の最初の <span>
要素) とコンポーネント インスタンスを DotNetObjectReference として、OnAfterRenderAsync
で assignDotNetHelper
JS 関数を呼び出します。
ListItem2
コンポーネントのメッセージ <span>
が選択されると、<span>
要素をパラメーター (this
) として渡して interopCall
が呼び出されます。これにより、UpdateMessage
.NET メソッドが呼び出されます。 UpdateMessage
では、message
が設定され、2 つ目の <span>
の display
プロパティが更新されると、StateHasChanged
が呼び出されて UI が更新されます。 StateHasChanged
が呼び出されないと、Blazor にはメソッドが呼び出されたときに UI を更新する必要があることを知る方法がありません。
DotNetObjectReference は、コンポーネントが破棄されるときに破棄されます。
Shared/ListItem2.razor
:
@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();
}
次の CallDotNetExample7
親コンポーネントには、それぞれ ListItem2
コンポーネントのインスタンスである 4 つのリスト項目が含まれています。
Pages/CallDotNetExample7.razor
:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
JavaScript の場所
JS 相互運用の概要に関する記事で説明されている方法のいずれかを使用して、JavaScript (JS) コードを読み込みます。
<head>
マークアップでスクリプトを読み込む ("通常は推奨されません")- マークアップでスクリプトを読み込む
- コンポーネントと同じ場所に存在する外部 JavaScript ファイル (
.js
) からスクリプトを読み込む - 外部 JavaScript ファイル (
.js
) からスクリプトを読み込む - の開始後にスクリプトを挿入する
モジュールでのスクリプトの分離の詳細については、「JavaScript モジュールでの JavaScript の分離」セクションを参照してください。
警告
<script>
タグは動的に更新できないため、<script>
タグをコンポーネント ファイル (.razor
) 内に配置しないでください。
循環オブジェクト参照の回避
循環参照を含むオブジェクトは、次のいずれに対しても、クライアントでシリアル化することはできません。
- .NET メソッドの呼び出し。
- 戻り値の型に循環参照がある場合の、C# からの JavaScript メソッドの呼び出し。
JavaScript 相互運用呼び出しのサイズ制限
"このセクションは Blazor Server アプリにのみ適用されます。 " Blazor WebAssembly では、フレームワークによって JavaScript (JS) 相互運用の入力と出力のサイズが制限されることはありません。
Blazor Server では、ハブ メソッドで許可される SignalR 受信メッセージの最大サイズによって、JS 相互運用呼び出しのサイズが制限されます。これは、HubOptions.MaximumReceiveMessageSize によって適用されます (既定値: 32 KB)。 JS から .NET への SignalR メッセージが MaximumReceiveMessageSize より大きい場合は、エラーがスローされます。 このフレームワークでは、ハブからクライアントへの SignalR メッセージのサイズが制限されることはありません。
SignalR のログがSignalR または Trace に設定されていない場合、メッセージ サイズのエラーはブラウザーの開発者ツール コンソールにのみ表示されます。
エラー :次のエラーで接続が切断されました。"エラー: サーバーが終了時にエラーを返しました:接続はエラーで終了しました。"
サーバー側のログ が Debug または Trace に設定されている場合、サーバー側のログには、メッセージ サイズ エラーの が表示されます。
appsettings.Development.json
:
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug"
}
}
}
エラー:
System.IO.InvalidDataException:メッセージの最大サイズ 32,768 B を超えました。 メッセージのサイズは、AddHubOptions で構成できます。
制限値を増やすには、Startup.ConfigureServices
で MaximumReceiveMessageSize を設定します。
services.AddServerSideBlazor()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
SignalR 受信メッセージ サイズの制限値を増やすと、より多くのサーバー リソースが必要になり、悪意のあるユーザーからのより大きなリスクにサーバーがさらされます。 また、大量のコンテンツを文字列またはバイト配列としてメモリに読み取ると、ガベージ コレクターがうまく機能しない割り当てが発生する可能性もあり、その結果、パフォーマンスがさらに低下します。
大きなペイロードを読み取るための 1 つの選択肢は、小さいチャンクでコンテンツを送信し、ペイロードを Stream として処理することです。 これは、大量の JSON ペイロードを読み取る場合、またはデータを JS で生バイトとして利用できる場合に使用できます。 Blazor Server で大規模なバイナリ ペイロードを送信する、Blazor Serverに似た手法を使用する方法の例については、InputFile
を参照してください。
Note
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。
Blazor Server アプリで JS と Blazor の間で大量のデータを転送するコードを開発するときは、次のガイダンスを考慮してください。
- データをより小さな部分にスライスし、すべてのデータがサーバーによって受信されるまでデータ セグメントを順番に送信します。
- JS および C# コードで大きなオブジェクトを割り当てないでください。
- データを送受信するときに、メイン UI スレッドを長時間ブロックしないでください。
- プロセスの完了時またはキャンセル時に、消費していたメモリを解放します。
- セキュリティ上の理由から、次の追加要件を適用します。
- 渡すことのできるファイルまたはデータの最大サイズを宣言します。
- クライアントからサーバーへの最小アップロード レートを宣言します。
- データがサーバーによって受信されたら、データは:
- すべてのセグメントが収集されるまで、一時的にメモリ バッファーに格納できます。
- 直ちに消費できます。 たとえば、データは、データベースに直ちに格納することも、セグメントを受信するたびにディスクに書き込むこともできます。
JavaScript モジュールでの JavaScript の分離
Blazor では、標準の Blazorに JavaScript (JS) を分離できます (JS)。 JavaScript モジュールの読み込みは、他の種類の Web アプリの場合と同じように Blazor で機能し、アプリでモジュールを定義する方法を自由にカスタマイズできます。 JavaScript モジュールの使用方法に関するガイドについては、MDN Web Docs の「JavaScript モジュール」を参照してください。
JS を分離すると、次のようなベネフィットがあります。
- インポートされる JS によって、グローバル名前空間が汚染されなくなります。
- ライブラリおよびコンポーネントのコンシューマーは、関連する JS をインポートする必要がありません。
詳しくは、「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」をご覧ください。
import()
演算子を使用した動的インポートは、ASP.NET Core と Blazorでサポートされています。
if ({CONDITION}) import("/additionalModule.js");
前述の例では、プレースホルダー {CONDITION}
は、モジュールを読み込む必要があるかどうかを判断するための条件付きチェックを表しています。
ブラウザーの互換性については、「Can I use: JavaScript modules: dynamic import (使用できるかどうか: JavaScript モジュール: dynamic import)」を参照してください。
コンポーネントの破棄中のドキュメント オブジェクト モデル (DOM) クリーンアップ タスク
コンポーネントの破棄の間に、DOM クリーンアップ タスクに対して JS 相互運用コードを実行しないでください。 次の理由から、代わりに、クライアントの JavaScript で MutationObserver
パターンを使います。
- クリーンアップ コードが
Dispose{Async}
で実行されるまでに、コンポーネントが DOM から削除されている可能性があります。 - Blazor Server アプリでは、クリーンアップ コードが
Dispose{Async}
で実行されるまでに、Blazor レンダラーがフレームワークによって破棄されている可能性があります。
MutationObserver
パターンを使うと、DOM から要素が削除されていても関数を実行できます。
回線を使用しない JavaScript 相互運用呼び出し
"このセクションは Blazor Server アプリにのみ適用されます。 "
JavaScript (JS) 相互運用呼び出しは、SignalR 回線が切断された後は発行できません。 コンポーネントの破棄中に回線がない、または回線が存在しないその他の時点で、次のメソッド呼び出しは失敗し、回線が切断されたというメッセージが JSDisconnectedException としてログされます。
- JS 相互運用メソッド呼び出し
- いずれかのIJSObjectReference での
Dispose
/DisposeAsync
呼び出し。
JSDisconnectedException のログを回避したり、カスタム情報をログしたりするには、try-catch
ステートメントで例外をキャッチします。
次のコンポーネント破棄の例で:
- コンポーネントでは IAsyncDisposable を実装します。
objInstance
は IJSObjectReference です。- JSDisconnectedException がキャッチされ、ログはされません。
- 必要に応じて、任意のログ レベルで
catch
ステートメントにカスタム情報をログできます。 次の例では、コンポーネントの破棄中にいつ、どこで回線が切断されるかを開発者が気にしないことを前提としているため、カスタム情報はログされません。
async ValueTask IAsyncDisposable.DisposeAsync()
{
try
{
if (objInstance is not null)
{
await objInstance.DisposeAsync();
}
}
catch (JSDisconnectedException)
{
}
}
回線が失われた後に、独自の JS オブジェクトをクリーンアップするか、クライアントで他の JS のコードを実行する必要がある場合は、クライアントの JS で MutationObserver
のパターンを使用します。 MutationObserver
パターンを使うと、DOM から要素が削除されていても関数を実行できます。
詳細については、次の記事を参照してください。
- ASP.NET Core Blazor アプリのエラーを処理する: "JavaScript 相互運用" のセクションでは、JS 相互運用シナリオでのエラー処理について説明しています。
- ASP.NET Core Razor コンポーネントのライフサイクル: 「
IDisposable
とIAsyncDisposable
を使用したコンポーネントの破棄」のセクションでは、Razor コンポーネントでの破棄パターンの実装方法について説明しています。
その他のリソース
- ASP.NET Core で .NET メソッドから JavaScript 関数を呼び出すBlazor
- の例 (dotnet/AspNetCore GitHub リポジトリの
main
ブランチ):main
ブランチは、ASP.NET Core の製品単位の現在の開発を表します。 別のリリース (release/5.0
) のブランチを選択するには、 [Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使用して、そのブランチを選択します。 - ドキュメント オブジェクト モデル (DOM) との対話
- Blazor サンプル GitHub リポジトリ (
dotnet/blazor-samples
) - ASP.NET Core Blazor アプリのエラーを処理する (「JavaScript 相互運用」のセクション)
- Blazor Server 脅威の緩和: ブラウザーから呼び出される .NET メソッド
.NET から JS 関数を呼び出す方法については、「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」をご覧ください。
静的 .NET メソッドの呼び出し
JavaScript (JS) から静的 .NET メソッドを呼び出すには、JS 関数を使用します。
DotNet.invokeMethodAsync
(推奨): Blazor Server と Blazor WebAssembly アプリの両方で非同期。DotNet.invokeMethod
: Blazor WebAssembly アプリのみで同期。
次に例を示します。
{ASSEMBLY NAME}
プレースホルダーは、アプリのアセンブリ名です。{.NET METHOD ID}
プレースホルダーは .NET メソッド識別子です。{ARGUMENTS}
プレースホルダーは、メソッドに渡す省略可能なコンマ区切りの引数であり、各引数は JSON シリアル化可能である必要があります。
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethodAsync
は、操作の結果を表す JS Promise
を返します。 DotNet.invokeMethod
(Blazor WebAssembly のみ) は操作の結果を返します。
重要
Blazor Server シナリオをサポートするには、非同期関数 (invokeMethodAsync
) が同期バージョン (invokeMethod
) より優先されます。
.NET メソッドはパブリックかつ静的であり、[JSInvokable]
属性を持つ必要があります。
次に例を示します。
{<T>}
プレースホルダーは戻り値の型を示します。これは、値を返すメソッドにのみ必要です。{.NET METHOD ID}
プレースホルダーはメソッド識別子です。
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
Note
オープン ジェネリック メソッドを呼び出すことは、静的な .NET メソッドではサポートされていませんが、この記事で後述するインスタンス メソッドではサポートされています。
次の CallDotNetExample1
コンポーネントでは、ReturnArrayAsync
C# メソッドによって int
配列が返されます。 [JSInvokable]
属性 がメソッドに適用され、JS によってメソッドが呼び出し可能になります。
Pages/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 });
}
}
<button>
要素の onclick
HTML 属性は、 の @onclick
ディレクティブ属性ではなく、Blazorclick
イベントを処理するための JavaScript の onclick
イベント ハンドラー割り当てです。 returnArrayAsync
JS 関数はハンドラーとして割り当てられます。
次の returnArrayAsync
JS 関数では、前の CallDotNetExample1
コンポーネントの ReturnArrayAsync
.NET メソッドが呼び出され、その結果はブラウザーの Web 開発者ツール コンソールに記録されます。 BlazorSample
はアプリのアセンブリ名です。
wwwroot/index.html
(Blazor WebAssembly) または Pages/_Host.cshtml
(Blazor Server) の終了 </body>
タグの内部:
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
Trigger .NET static method
ボタンが選択されている場合は、ブラウザーの開発者ツール コンソールの出力に配列データが表示されます。 出力の形式はブラウザーによって若干異なります。 次の出力は、Microsoft Edge で使用される形式を示しています。
Array(3) [ 1, 2, 3 ]
データを引数として渡して invokeMethodAsync
関数を呼び出すときに、.NET メソッドにデータを渡します。
.NET にデータを渡す方法を示すには、関数が呼び出されたときに前の returnArrayAsync
JS 関数が開始位置を受け取り、その値を引数として invokeMethodAsync
関数に渡します。
<script>
window.returnArrayAsync = (startPosition) => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', startPosition)
.then(data => {
console.log(data);
});
};
</script>
CallDotNetExample1
コンポーネントで、関数呼び出しを変更して開始位置を含めます。 次の例では、5
の値を使用しています。
<button onclick="returnArrayAsync(5)">
...
</button>
コンポーネントの呼び出し可能 ReturnArrayAsync
メソッドは開始位置を受け取り、そこから配列を構築します。 コンソールにログするために、配列が返されます。
[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition)
{
return Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());
}
アプリが再コンパイルされ、ブラウザーが更新されると、ボタンが選択されたときに、ブラウザーのコンソールに次の出力が表示されます。
Array(3) [ 5, 6, 7 ]
データを引数として渡して invokeMethodAsync
関数を呼び出すときに、.NET メソッドにデータを渡します。
.NET にデータを渡す方法を示すには、関数が呼び出されたときに前の returnArrayAsync
JS 関数が開始位置を受け取り、その値を引数として invokeMethodAsync
関数に渡します。
<script>
window.returnArrayAsync = (startPosition) => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', startPosition)
.then(data => {
console.log(data);
});
};
</script>
CallDotNetExample1
コンポーネントで、関数呼び出しを変更して開始位置を含めます。 次の例では、5
の値を使用しています。
<button onclick="returnArrayAsync(5)">
...
</button>
コンポーネントの呼び出し可能 ReturnArrayAsync
メソッドは開始位置を受け取り、そこから配列を構築します。 コンソールにログするために、配列が返されます。
[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition)
{
return Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());
}
アプリが再コンパイルされ、ブラウザーが更新されると、ボタンが選択されたときに、ブラウザーのコンソールに次の出力が表示されます。
Array(3) [ 5, 6, 7 ]
既定では、JS 呼び出しの .NET メソッド識別子は .NET メソッド名ですが、[JSInvokable]
属性コンストラクターを使用して別の識別子を指定することもできます。 次の例では、DifferentMethodName
は ReturnArrayAsync
メソッドに割り当てられたメソッド識別子です。
[JSInvokable("DifferentMethodName")]
DotNet.invokeMethodAsync
または DotNet.invokeMethod
の呼び出し (Blazor WebAssembly のみ) で、DifferentMethodName
を呼び出して ReturnArrayAsync
.NET メソッドを実行します。
DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');
(Blazor WebAssembly のみ)
Note
このセクションの ReturnArrayAsync
メソッドの例では、明示的な C# async
および await
キーワードを使用せずに Task の結果を返します。 async
および await
を使用したメソッドのコーディングは、await
キーワードを使用して非同期操作の値を返す一般的なメソッドです。
async
および await
キーワードで構成される ReturnArrayAsync
メソッド:
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync()
{
return await Task.FromResult(new int[] { 1, 2, 3 });
}
詳細については、C# ガイドの「Async および Await を使用した非同期プログラミング」を参照してください。
.NET に渡す JavaScript オブジェクトとデータ参照を作成する
DotNet.createJSObjectReference(jsObject)
を呼び出して、.NET に渡すことができるように JS オブジェクト参照を構築します。jsObject
は JS オブジェクト参照の作成に使われる JS Object
です。 次の例では、シリアル化できない window
オブジェクトへの参照を .NET に渡します。これはその参照を ReceiveWindowObject
C# メソッドで IJSObjectReference として受け取ります。
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
前の例で、{ASSEMBLY NAME}
プレースホルダーはアプリの名前空間です。
Note
前の例では、window
オブジェクトへの参照が JS に保持されないため、JSObjectReference
の破棄は必要ありません。
JSObjectReference
への参照を維持したら、クライアントでの JS メモリのリークを避けるため、それを破棄する必要があります。 次の例では、前のコードをリファクタリングして JSObjectReference
への参照をキャプチャした後、DotNet.disposeJSObjectReference()
を呼び出して参照を破棄します。
var jsObjectReference = DotNet.createJSObjectReference(window);
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
前の例で、{ASSEMBLY NAME}
プレースホルダーはアプリの名前空間です。
DotNet.createJSStreamReference(streamReference)
を呼び出して JS ストリーム参照を構築し、.NET に渡すことができるようにします。streamReference
は、ArrayBuffer
、Blob
、または Uint8Array
や Float32Array
などの任意の型指定された配列であり、JS ストリーム参照を作成するために使用されます。
インスタンス .NET メソッドの呼び出し
JavaScript (JS) からインスタンス .NET メソッドを呼び出す場合:
インスタンスを DotNetObjectReference でラップし、その上で Create を呼び出すことにより、JS を参照して .NET インスタンスを渡します。
渡された DotNetObjectReference の
invokeMethodAsync
("推奨") またはinvokeMethod
(Blazor WebAssembly のみ) を使用して、JS から .NET インスタンス メソッドを呼び出します。 インスタンス .NET メソッドの識別子とすべての引数を渡します。 .NET インスタンスは、JS から他の .NET メソッドを呼び出すときに引数として渡すこともできます。次に例を示します。
dotNetHelper
が DotNetObjectReference です。{.NET METHOD ID}
プレースホルダーは .NET メソッド識別子です。{ARGUMENTS}
プレースホルダーは、メソッドに渡す省略可能なコンマ区切りの引数であり、各引数は JSON シリアル化可能である必要があります。
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});
Note
インスタンス メソッドを呼び出すときは、
invokeMethodAsync
とinvokeMethod
はアセンブリ名パラメーターを受け付けません。invokeMethodAsync
は、操作の結果を表す JSPromise
を返します。invokeMethod
(Blazor WebAssembly のみ) は操作の結果を返します。重要
Blazor Server シナリオをサポートするには、非同期関数 (
invokeMethodAsync
) が同期バージョン (invokeMethod
) より優先されます。
この記事の以降のセクションでは、インスタンス .NET メソッドを呼び出すさまざまな方法について説明します。
コンポーネント インスタンスの例
次の sayHello1
JS 関数では DotNetObjectReference を受け取り、invokeMethodAsync
を呼び出してコンポーネントの GetHelloMessage
.NET メソッドを呼び出します。
wwwroot/index.html
(Blazor WebAssembly) または Pages/_Host.cshtml
(Blazor Server) の終了 </body>
タグの内部:
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
次の CallDotNetExample2
コンポーネントの場合:
- コンポーネントには、
GetHelloMessage
という名前の JS 呼び出し可能な .NET メソッドが含まれます。 Trigger .NET instance method
ボタンを選択すると、JS 関数sayHello1
が DotNetObjectReference と一緒に呼び出されます。sayHello1
:GetHelloMessage
を呼び出し、メッセージ結果を受信します。- メッセージの結果を呼び出し元の
TriggerDotNetInstanceMethod
メソッドに返します。
result
のsayHello1
から返されたメッセージがユーザーに表示されます。- メモリ リークを回避し、ガベージ コレクションを許可するには、DotNetObjectReference によって作成された .NET オブジェクト参照は
Dispose
メソッドで破棄されます。
Pages/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();
}
}
インスタンス メソッドに引数を渡すには:
.NET メソッドの呼び出しにパラメーターを追加します。 次の例では、名前がメソッドに渡されます。 必要に応じて、追加のパラメーターを一覧に追加します。
<script> window.sayHello2 = (dotNetHelper, name) => { return dotNetHelper.invokeMethodAsync('GetHelloMessage', name); }; </script>
.NET メソッドにパラメーター リストを指定します。
Pages/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();
}
}
クラス インスタンスの例
次の sayHello1
JS 関数:
- 渡された DotNetObjectReference で
GetHelloMessage
.NET メソッドを呼び出します。 GetHelloMessage
からsayHello1
の呼び出し元にメッセージを返します。
wwwroot/index.html
(Blazor WebAssembly) または Pages/_Host.cshtml
(Blazor Server) の終了 </body>
タグの内部:
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
次の HelloHelper
クラスには、GetHelloMessage
という名前の JS 呼び出し可能な .NET メソッドが含まれます。 HelloHelper
が作成されると、Name
プロパティの名前が GetHelloMessage
からのメッセージを返すために使用されます。
HelloHelper.cs
:
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string name)
{
Name = name;
}
public string Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
次の JsInteropClasses3
クラスの CallHelloHelperGetHelloMessage
メソッドでは、HelloHelper
の新しいインスタンスで JS 関数 sayHello1
を呼び出します。
JsInteropClasses3.cs
:
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);
}
}
メモリ リークを回避し、ガベージ コレクションを許可するため、DotNetObjectReference によって作成された .NET オブジェクト参照は、そのオブジェクト参照が using var
構文でスコープ外になったときに破棄されます。
次の CallDotNetExample4
コンポーネントで Trigger .NET instance method
ボタンを選択すると、name
の値で JsInteropClasses3.CallHelloHelperGetHelloMessage
が呼び出されます。
Pages/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);
}
}
次の図は、Name
フィールドに Amy Pond
という名前でレンダリングされたコンポーネントを示しています。 ボタンを選択すると、UI に Hello, Amy Pond!
が表示されます。
JsInteropClasses3
クラスに示されている上記のパターンは、完全にコンポーネントに実装することもできます。
Pages/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);
}
}
メモリ リークを回避し、ガベージ コレクションを許可するため、DotNetObjectReference によって作成された .NET オブジェクト参照は、そのオブジェクト参照が using var
構文でスコープ外になったときに破棄されます。
name
フィールドに名前 Amy Pond
が指定されている場合、CallDotNetExample5
コンポーネントによって表示される出力は Hello, Amy Pond!
です。
前の CallDotNetExample5
コンポーネントでは、.NET オブジェクト参照は破棄されます。 クラスまたはコンポーネントが DotNetObjectReference を破棄しない場合は、渡された DotNetObjectReference で dispose
を呼び出して、クライアントから破棄します。
window.{JS FUNCTION NAME} = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}');
dotNetHelper.dispose();
}
前の例の場合:
{JS FUNCTION NAME}
プレースホルダーは JS 関数の名前です。- 変数名
dotNetHelper
は任意であり、任意の希望する名前に変更できます。 {.NET METHOD ID}
プレースホルダーは .NET メソッド識別子です。
コンポーネント インスタンス .NET メソッド ヘルパー クラス
ヘルパー クラスでは、.NET インスタンス メソッドを Action として呼び出すことができます。 ヘルパー クラスは、次のシナリオで役立ちます。
- 同じ種類の複数のコンポーネントが同じページにレンダリングされる場合。
- Blazor Server アプリで、複数のユーザーが同じコンポーネントを同時に使用する場合。
次に例を示します。
CallDotNetExample6
コンポーネントには、アプリのShared
フォルダー内の共有コンポーネントであるいくつかのListItem1
コンポーネントが含まれています。- 各
ListItem1
コンポーネントは、メッセージとボタンで構成されます。 ListItem1
コンポーネント ボタンが選択されると、そのListItem1
のUpdateMessage
メソッドによってリスト項目のテキストが変更され、ボタンが非表示になります。
次の MessageUpdateInvokeHelper
クラスでは、クラスがインスタンス化されるときに指定された Action を呼び出すために、JS 呼び出し可能な .NET メソッド UpdateMessageCaller
が保持されます。
MessageUpdateInvokeHelper.cs
:
using System;
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
次の updateMessageCaller
JS 関数は、UpdateMessageCaller
.NET メソッドを呼び出します。
wwwroot/index.html
(Blazor WebAssembly) または Pages/_Host.cshtml
(Blazor Server) の終了 </body>
タグの内部:
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
次の ListItem1
コンポーネントは、親コンポーネントで何度でも使用できる共有コンポーネントであり、HTML リスト (<ul>...</ul>
または <ol>...</ol>
) のリスト項目 (<li>...</li>
) を作成します。 各 ListItem1
コンポーネント インスタンスは、Action がその UpdateMessage
メソッドに設定された MessageUpdateInvokeHelper
のインスタンスを確立します。
ListItem1
コンポーネントの InteropCall
ボタンが選択された場合、MessageUpdateInvokeHelper
インスタンス用に作成された DotNetObjectReference で updateMessageCaller
が呼び出されます。 これにより、フレームワークはその ListItem1
の MessageUpdateInvokeHelper
インスタンスで UpdateMessageCaller
を呼び出すことができます。 渡された DotNetObjectReference は JS (dotNetHelper.dispose()
) で破棄されます。
Shared/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()
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
message
が UpdateMessage
で設定されている場合、UI を更新するために StateHasChanged
が呼び出されます。 StateHasChanged
が呼び出されていない場合、Blazor には Action が呼び出されたときに UI を更新する必要があることを知る方法はありません。
次の CallDotNetExample6
親コンポーネントには、それぞれ ListItem1
コンポーネントのインスタンスである 4 つのリスト項目が含まれています。
Pages/CallDotNetExample6.razor
:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
次の図は、2 番目の InteropCall
ボタンが選択された後にレンダリングされた CallDotNetExample6
親コンポーネントを示しています。
- 2 番目の
ListItem1
コンポーネントによってUpdateMessage Called!
メッセージが表示されました。 - ボタンの CSS
display
プロパティがnone
に設定されているため、2 番目のListItem1
コンポーネントのInteropCall
ボタンは表示されません。
要素プロパティに割り当てられた DotNetObjectReference
から呼び出されるコンポーネント インスタンスの .NET メソッド
HTML 要素のプロパティに対する DotNetObjectReference の割り当てにより、コンポーネント インスタンスの .NET メソッドを呼び出すことができます。
- 要素の参照がキャプチャされます (ElementReference)。
- コンポーネントの
OnAfterRender{Async}
メソッドでは、要素の参照とコンポーネント インスタンスを DotNetObjectReference として、JavaScript (JS) 関数が呼び出されます。 この JS 関数は、DotNetObjectReference をプロパティ内の要素にアタッチします。 - JS で要素イベントが呼び出されると (たとえば
onclick
)、その要素のアタッチされた DotNetObjectReference が .NET メソッドの呼び出しに使用されます。
コンポーネント インスタンスの .NET メソッド ヘルパー クラスに関するセクションで説明されている方法と同様に、この方法は次のシナリオで役立ちます。
- 同じ種類の複数のコンポーネントが同じページにレンダリングされる場合。
- Blazor Server アプリで、複数のユーザーが同じコンポーネントを同時に使用する場合。
- .NET メソッドが、Blazor イベント (たとえば
@onclick
) からではなく、JS イベント (たとえばonclick
) から呼び出される場合。
次に例を示します。
CallDotNetExample7
コンポーネントには、アプリのShared
フォルダー内の共有コンポーネントであるいくつかのListItem2
コンポーネントが含まれています。- 各
ListItem2
コンポーネントは、リスト項目メッセージ<span>
と、display
CSS プロパティが表示用にinline-block
に設定された 2 つ目の<span>
で構成されています。 ListItem2
コンポーネントのリスト項目が選択されると、そのListItem2
のUpdateMessage
メソッドによって最初の<span>
のリスト項目テキストが変更され、そのdisplay
プロパティをnone
に設定することで 2 つ目の<span>
が非表示になります。
次の assignDotNetHelper
JS 関数は、dotNetHelper
という名前のプロパティの要素に DotNetObjectReference を割り当てます。
<script>
window.assignDotNetHelper = (element, dotNetHelper) => {
element.dotNetHelper = dotNetHelper;
}
</script>
次の interopCall
JS 関数では、渡される要素に DotNetObjectReference を使用して、UpdateMessage
という名前の .NET メソッドを呼び出します。
<script>
window.interopCall = async (element) => {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
</script>
注意
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」を参照してください。
前の例で、変数名 dotNetHelper
は任意であり、任意の希望する名前に変更できます。
次の ListItem2
コンポーネントは、親コンポーネントで何度でも使用できる共有コンポーネントであり、HTML リスト (<ul>...</ul>
または <ol>...</ol>
) のリスト項目 (<li>...</li>
) を作成します。
各 ListItem2
コンポーネント インスタンスでは、要素の参照 (リスト項目の最初の <span>
要素) とコンポーネント インスタンスを DotNetObjectReference として、OnAfterRenderAsync
で assignDotNetHelper
JS 関数を呼び出します。
ListItem2
コンポーネントのメッセージ <span>
が選択されると、<span>
要素をパラメーター (this
) として渡して interopCall
が呼び出されます。これにより、UpdateMessage
.NET メソッドが呼び出されます。 UpdateMessage
では、message
が設定され、2 つ目の <span>
の display
プロパティが更新されると、StateHasChanged
が呼び出されて UI が更新されます。 StateHasChanged
が呼び出されないと、Blazor にはメソッドが呼び出されたときに UI を更新する必要があることを知る方法がありません。
DotNetObjectReference は、コンポーネントが破棄されるときに破棄されます。
Shared/ListItem2.razor
:
@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();
}
次の CallDotNetExample7
親コンポーネントには、それぞれ ListItem2
コンポーネントのインスタンスである 4 つのリスト項目が含まれています。
Pages/CallDotNetExample7.razor
:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
JavaScript の場所
JS 相互運用の概要に関する記事で説明されている方法のいずれかを使用して、JavaScript (JS) コードを読み込みます。
<head>
マークアップでスクリプトを読み込む ("通常は推奨されません")- マークアップでスクリプトを読み込む
- 外部 JavaScript ファイル (
.js
) からスクリプトを読み込む - の開始後にスクリプトを挿入する
警告
<script>
タグは動的に更新できないため、<script>
タグをコンポーネント ファイル (.razor
) 内に配置しないでください。
循環オブジェクト参照の回避
循環参照を含むオブジェクトは、次のいずれに対しても、クライアントでシリアル化することはできません。
- .NET メソッドの呼び出し。
- 戻り値の型に循環参照がある場合の、C# からの JavaScript メソッドの呼び出し。
JavaScript 相互運用呼び出しのサイズ制限
"このセクションは Blazor Server アプリにのみ適用されます。 " Blazor WebAssembly では、フレームワークによって JavaScript (JS) 相互運用の入力と出力のサイズが制限されることはありません。
Blazor Server では、ハブ メソッドで許可される SignalR 受信メッセージの最大サイズによって、JS 相互運用呼び出しのサイズが制限されます。これは、HubOptions.MaximumReceiveMessageSize によって適用されます (既定値: 32 KB)。 JS から .NET への SignalR メッセージが MaximumReceiveMessageSize より大きい場合は、エラーがスローされます。 このフレームワークでは、ハブからクライアントへの SignalR メッセージのサイズが制限されることはありません。
SignalR のログがSignalR または Trace に設定されていない場合、メッセージ サイズのエラーはブラウザーの開発者ツール コンソールにのみ表示されます。
エラー :次のエラーで接続が切断されました。"エラー: サーバーが終了時にエラーを返しました:接続はエラーで終了しました。"
サーバー側のログ が Debug または Trace に設定されている場合、サーバー側のログには、メッセージ サイズ エラーの が表示されます。
appsettings.Development.json
:
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug"
}
}
}
エラー:
System.IO.InvalidDataException:メッセージの最大サイズ 32,768 B を超えました。 メッセージのサイズは、AddHubOptions で構成できます。
制限値を増やすには、Startup.ConfigureServices
で MaximumReceiveMessageSize を設定します。
services.AddServerSideBlazor()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
SignalR 受信メッセージ サイズの制限値を増やすと、より多くのサーバー リソースが必要になり、悪意のあるユーザーからのより大きなリスクにサーバーがさらされます。 また、大量のコンテンツを文字列またはバイト配列としてメモリに読み取ると、ガベージ コレクターがうまく機能しない割り当てが発生する可能性もあり、その結果、パフォーマンスがさらに低下します。
大きなペイロードを読み取るための 1 つの選択肢は、小さいチャンクでコンテンツを送信し、ペイロードを Stream として処理することです。 これは、大量の JSON ペイロードを読み取る場合、またはデータを JS で生バイトとして利用できる場合に使用できます。 Blazor Server で大規模なバイナリ ペイロードを送信する、Blazor Serverに似た手法を使用する方法の例については、InputFile
を参照してください。
Note
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。
Blazor Server アプリで JS と Blazor の間で大量のデータを転送するコードを開発するときは、次のガイダンスを考慮してください。
- データをより小さな部分にスライスし、すべてのデータがサーバーによって受信されるまでデータ セグメントを順番に送信します。
- JS および C# コードで大きなオブジェクトを割り当てないでください。
- データを送受信するときに、メイン UI スレッドを長時間ブロックしないでください。
- プロセスの完了時またはキャンセル時に、消費していたメモリを解放します。
- セキュリティ上の理由から、次の追加要件を適用します。
- 渡すことのできるファイルまたはデータの最大サイズを宣言します。
- クライアントからサーバーへの最小アップロード レートを宣言します。
- データがサーバーによって受信されたら、データは:
- すべてのセグメントが収集されるまで、一時的にメモリ バッファーに格納できます。
- 直ちに消費できます。 たとえば、データは、データベースに直ちに格納することも、セグメントを受信するたびにディスクに書き込むこともできます。
コンポーネントの破棄中のドキュメント オブジェクト モデル (DOM) クリーンアップ タスク
コンポーネントの破棄の間に、DOM クリーンアップ タスクに対して JS 相互運用コードを実行しないでください。 次の理由から、代わりに、クライアントの JavaScript で MutationObserver
パターンを使います。
- クリーンアップ コードが
Dispose{Async}
で実行されるまでに、コンポーネントが DOM から削除されている可能性があります。 - Blazor Server アプリでは、クリーンアップ コードが
Dispose{Async}
で実行されるまでに、Blazor レンダラーがフレームワークによって破棄されている可能性があります。
MutationObserver
パターンを使うと、DOM から要素が削除されていても関数を実行できます。
回線を使用しない JavaScript 相互運用呼び出し
"このセクションは Blazor Server アプリにのみ適用されます。 "
JavaScript (JS) 相互運用呼び出しは、SignalR 回線が切断された後は発行できません。 コンポーネントの破棄中に回線がない、または回線が存在しないその他の時点で、次のメソッド呼び出しは失敗し、回線が切断されたというメッセージが JSDisconnectedException としてログされます。
- JS 相互運用メソッド呼び出し
- いずれかのIJSObjectReference での
Dispose
/DisposeAsync
呼び出し。
JSDisconnectedException のログを回避したり、カスタム情報をログしたりするには、try-catch
ステートメントで例外をキャッチします。
次のコンポーネント破棄の例で:
- コンポーネントでは IAsyncDisposable を実装します。
objInstance
は IJSObjectReference です。- JSDisconnectedException がキャッチされ、ログはされません。
- 必要に応じて、任意のログ レベルで
catch
ステートメントにカスタム情報をログできます。 次の例では、コンポーネントの破棄中にいつ、どこで回線が切断されるかを開発者が気にしないことを前提としているため、カスタム情報はログされません。
async ValueTask IAsyncDisposable.DisposeAsync()
{
try
{
if (objInstance is not null)
{
await objInstance.DisposeAsync();
}
}
catch (JSDisconnectedException)
{
}
}
回線が失われた後に、独自の JS オブジェクトをクリーンアップするか、クライアントで他の JS のコードを実行する必要がある場合は、クライアントの JS で MutationObserver
のパターンを使用します。 MutationObserver
パターンを使うと、DOM から要素が削除されていても関数を実行できます。
詳細については、次の記事を参照してください。
- ASP.NET Core Blazor アプリのエラーを処理する: "JavaScript 相互運用" のセクションでは、JS 相互運用シナリオでのエラー処理について説明しています。
- ASP.NET Core Razor コンポーネントのライフサイクル: 「
IDisposable
とIAsyncDisposable
を使用したコンポーネントの破棄」のセクションでは、Razor コンポーネントでの破棄パターンの実装方法について説明しています。
その他のリソース
- ASP.NET Core で .NET メソッドから JavaScript 関数を呼び出すBlazor
- の例 (dotnet/AspNetCore GitHub リポジトリの
main
ブランチ):main
ブランチは、ASP.NET Core の製品単位の現在の開発を表します。 別のリリース (release/5.0
) のブランチを選択するには、 [Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使用して、そのブランチを選択します。 - ドキュメント オブジェクト モデル (DOM) との対話
- Blazor サンプル GitHub リポジトリ (
dotnet/blazor-samples
) - ASP.NET Core Blazor アプリのエラーを処理する (「JavaScript 相互運用」のセクション)
- Blazor Server 脅威の緩和: ブラウザーから呼び出される .NET メソッド