BlazorアプリケーションでC#のコードからJavaScriptを呼び出す

BlazorアプリケーションでC#のコードからJavaScriptを呼び出すコードを紹介します。

概要

BlazorアプリケーションでJavaScriptの処理をC#のコードから呼び出したい場合のコードを紹介します。C#のコードからJavaScriptを呼び出す場合には、IJSRuntime クラスのInvokeAsync()メソッドを利用します。

プログラム1 : シンプルな実装

プロジェクトの作成

ASP.NET Core Webアプリケーションを作成します。手順はこちらの記事を参照して下さい。

Blazorアプリケーションのファイル作成

Blazorアプリケーションで必要なファイルを作成します。
App.Razor
<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" />
    </Found>
    <NotFound>
        <LayoutView>
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>
_Imports.razor
@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace ExecJavaScript
{
  public class Startup
  {
    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
      services.AddRazorPages();
      services.AddServerSideBlazor();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
      if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
      }

      app.UseStaticFiles();
      app.UseRouting();

      app.UseEndpoints(endpoints =>
      {
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
      });
    }
  }
}

フォールバックページの作成

Pagesフォルダ内にフォールバックページを作成します。
フォールバックページ内のheadタグ内にJavaScriptの関数を実装します。今回は myfunc という関数を作成します。関数が実行されるとalert関数を実行しダイアログを表示します。ダイアログのメッセージには「myfunc関数が呼び出されました」の文字列と、myfunc関数を呼び出した際の引数を表示します。
_Host.cshtml
@page
@model ExecJavaScript.Pages._HostModel
@namespace ExecJavaScript.Pages
<!DOCTYPE html>
<html lang="ja">
<head>
    <script>
        function myfunc(text) {
            alert('myfunc関数が呼び出されました:' + text);
        }
    </script>
</head>
<body>
    <app>
        @(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
    </app>
    <script src="_framework/blazor.server.js"></script>
</body>
</html>

@{
}

ページの作成

ページを作成します。Pagesフォルダ内に Index.razor ファイルを作成します。コードは下記になります。
@inject IJSRuntime JsRuntime; を記述します。@inject ディレクティブによりIJSRuntimeのサービスを要求します。ページでは、buttonタグでボタンを配置します。@onclick属性に"ButtonClick"を指定しボタンがクリックされた際には@codeセクションのButtonClick()関数を呼び出します。
ButtonClick()関数では、IJSRuntimeのサービスインスタンスである JsRuntime オブジェクトの InvokeVoidAsync メソッドを呼び出します。InvokeVoidAsync の第一引数には呼び出すJavaScritptの関数名を与えます。第二引数以降に関数の引数を与えます。今回、myfunc関数は一つしか引数が無いため、InvokeVoidAsync に与える引数は呼び出す関数名とパラメーター一つの合計2つになります。
Index.razor
@page "/Index"
@inject IJSRuntime JsRuntime;
<h3>Index</h3>
<p></p>
<button type="button" @onclick="ButtonClick">Button1</button>

@code {
    void ButtonClick()
    {
        string param = "penguin";
        JsRuntime.InvokeVoidAsync("myfunc", param);
        StateHasChanged();
    }
}

実装完了後のソリューションエクスプローラーの状態です。

実行結果

プロジェクトを実行します。Webブラウザで(アプリケーションルートURL)/Index URLにアクセスします。下図のページが表示されます。


[Button1]をクリックします。アラートダイアログが表示され「myfunc関数が呼び出されました」のメッセージが表示されます。またメッセージの後にC#コードからmyfunc関数に与えた引数の"penguin" の値も表示されています。


C#のコードからJavaScriptの関数の呼び出しができました。

プログラム2 : ページのrazorコンポーネントの基底のC#コードからの呼び出し

先のプログラムはrazorファイル内の@codeセクションからJavaScriptの関数を呼び出しました。このセクションでは、razorファイルの基底クラスのC#のコードからJavaScript関数を呼び出すコードを紹介します。
先ほどのプログラムのPagesフォルダに Index_cb.razor ファイルとIndex_cb.razor.cs ファイルを追加します。コードは下記になります。
Index_cb.razorでは@inheritsディレクティブを記述しIndex_cb.razor.cs ファイルで実装されているIndex_cbModelクラスの派生クラスとします。また、ページ内にはbuttonタグを記述しボタンを配置します。@onclick属性には "ButtonClick" を指定します。ボタンのクリックにより、Index_cbModelクラスに実装した、ButtonClickメソッドを呼び出す処理になります。実装の詳細に関してはこちらの記事を参照してください。
Index_cb.razor
@page "/Index_cb"
@namespace ExecJavaScript.Pages
@inherits Index_cbModel
<h3>Index_cb</h3>
<button type="button" @onclick="ButtonClick">Button1</button>

C#のコードでは、[Inject]属性を利用し IJSRuntimeオブジェクトを参照します。IJSRuntimeオブジェクトのインスタンスオブジェクトが JsRuntime になります。また、ボタンがクリックされた際に呼び出される、ButtonClickメソッドを実装します。ボタンのクリックにより、IJSRuntimeオブジェクトのInvokeAsyncオブジェクトを呼び出します。第一引数に呼び出す関数名を与えます。第二引数にパラメーターを与えます。
Index_cb.razor.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace ExecJavaScript.Pages
{
  public class Index_cbModel : ComponentBase
  {
    [Inject]
    private IJSRuntime JsRuntime { get; set; }

    public void ButtonClick()
    {
      string param = "Duck";
      JsRuntime.InvokeVoidAsync("myfunc", param);
      StateHasChanged();
    }
  }
}

実装完了後のソリューションエクスプローラーの状態です。

実行結果

プロジェクトを実行します。Webブラウザで(アプリケーションルートURL)/Index_cb URLにアクセスします。下図のページが表示されます。


[Button1]をクリックします。アラートダイアログが表示され「myfunc関数が呼び出されました」のメッセージが表示されます。またメッセージの後にC#コードからmyfunc関数に与えた引数の"Duck" の値も表示されています。

プログラム3 : 戻り値がある場合の例

戻り値がある場合の実装コードを紹介します。
フォールバックページの_Host.cshtml ファイルにJavaScriptの関数を追加します。mycalc の名称で関数を実装します。2つの引数を受け取り数値に変換して2つの引数を足し、「計算結果は(合計値)です。」の文字列を巻子の戻り値として返します。
_Host.cshtml
@page
@model ExecJavaScript.Pages._HostModel
@namespace ExecJavaScript.Pages
<!DOCTYPE html>
<html lang="ja">
<head>
    <script>
        function myfunc(text) {
            alert('myfunc関数が呼び出されました:' + text);
        }

        function mycalc(a, b) {
            var c = Number(a) + Number(b);
            return "計算結果は" + String(c) + "です。";
        }

    </script>
</head>
<body>
    <app>
        @(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
    </app>
    <script src="_framework/blazor.server.js"></script>
</body>
</html>

ページを追加します。Index_return.razor ファイルと Index_return.razor.cs ファイルを追加します。コードは下記です。
Index_return.razor は@Inheritsディレクティブの記述により、Index_return.razor.csファイルのクラスIndex_returnModelの派生クラスとします。ページにはbuttonタグを記述しボタンを配置します。クリック時にはIndex_returnModelクラスのButtonClickメソッドを呼び出します。
また、ボタンの下部の段落で returnText変数の内容を表示します。reutnTextにはJavaScriptの関数の戻り値を代入するため、ボタンクリックでJavaScriptを実行したときの戻り値の値がページに表示される動作になります。
Index_return.razor
@page "/Index_return"
@namespace ExecJavaScript.Pages
@inherits Index_returnModel
<h3>Index_return</h3>
<button type="button" @onclick="ButtonClick">Button1</button>
<p>@retuenText</p>

C#のコードでは、IJSRuntime をInject属性を付けて呼び出しサービスが利用できる状態にします。今回は戻り値があるため、 InvokeVoidAsync メソッドではなくInvokeAsync メソッドを呼び出します。InvokeAsyncメソッドは非同期メソッドのため、await を付けてメソッドを呼び出し、メソッドの結果が戻るまで待機します。awaitを利用するため、ButtonClickメソッドも非同期にする必要があるため、メソッドの識別子にasyncを記述します。
InvokeAsyncメソッドのタイプ部分のTValueには戻り値の型を記述します。今回のJavaScriptの戻り値の型は文字列なので、stringを記述します。InvokeAsyncの第一引数には呼び出すJavaScriptの関数名を与えるため"mycalc"を与えます。mycalc関数は2つの引数があるため、第二引数と第三引数はmycalc関数の引数を記述します。
JavaScript関数の戻り値はreturnText変数に代入します。
Index_return.razor.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace ExecJavaScript.Pages
{
  public class Index_returnModel:ComponentBase
  {
    [Inject]
    private IJSRuntime JsRuntime { get; set; }

    protected string retuenText;

    public async void ButtonClick()
    {
      int param1 = 8;
      int param2 = 4;
      retuenText = await JsRuntime.InvokeAsync<string>("mycalc", param1, param2);

      StateHasChanged();
    }
  }
}

実行結果

プロジェクトを実行します。Webブラウザで(アプリケーションルートURL)/Index_return URLにアクセスします。下図のページが表示されます。


[Button1]をクリックします。ページに「計算結果は12です。」の文字列が表示されます。JavaScriptの関数を呼び出し、計算結果と戻り値の取得ができていることが確認できます。


BlazorアプリケーションでC#のコードからJavaScriptの呼び出しができました。

このページのキーワード
  • BlazorアプリケーションでC#のコードからJSを呼び出す
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2019-11-10
iPentec all rights reserverd.