📌

Blazor から JavaScript のクラスのコンストラクタを呼びたい

2022/12/29に公開

Blazor には JavaScirpt の相互運用機能があります。

https://learn.microsoft.com/ja-jp/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-7.0

.NET から JavaScript の処理を呼び出したり…

https://learn.microsoft.com/ja-jp/aspnet/core/blazor/javascript-interoperability/call-javascript-from-dotnet?view=aspnetcore-7.0

JavaScript から .NET の処理を呼び出すことが出来ます。

https://learn.microsoft.com/ja-jp/aspnet/core/blazor/javascript-interoperability/call-dotnet-from-javascript?view=aspnetcore-7.0

ということは、JavaScript じゃないと出来ないことは JavaScript に書いて C# から呼び出してしまえば何でも出来る!!ということで JavaScript で適当なクラスを定義したとしましょう。このオブジェクトを作るためにはコンストラクタを呼び出さないといけないのですが、残念ながら .NET 7 時点ではできません。これは .NET 8 で実装が予定されているためおとなしく待ちましょう…。実装されるといいな。

詳細は以下の Issue で確認できます。この Issue が .NET 8 の時点でクローズされていれば実装されたということですね!

https://github.com/dotnet/aspnetcore/issues/31151

回避方法

ということで .NET 6, .NET 7 の時点では以下のようにインスタンスを生成するための静的メソッドや関数を定義してお茶を濁す感じになります。

試してみましょう。wwwrootscripts.js という名前で以下のような JavaScript ファイルを作ります。

scripts.js
export class Sample {
    constructor(name) {
        this.name = name;
    }

    alert() {
        window.alert(`Hello ${this.name}`);
    }

    // インスタンス作るためのメソッド
    static create(name) {
        return new Sample(name);
    }
}

そして Index.razor あたりで以下のようなコードを書いて Sample.create メソッドを呼んで Sample クラスのインスタンスを作って alert メソッドを呼び出してみます。

Index.razor
@page "/"
@inject IJSRuntime _js
@implements IAsyncDisposable

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

<button @onclick="OnClick">Click me</button>


@code {
    private IJSObjectReference? _module;
    private IJSObjectReference? _class;

    private async Task OnClick()
    {
        if (_class is null) return;

        await _class.InvokeVoidAsync("alert");
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            _module = await _js.InvokeAsync<IJSObjectReference>(
                "import", "./scripts.js"
            );
            _class = await _module.InvokeAsync<IJSObjectReference>("Sample.create", "okazuki");
        }
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (_module is not null) 
            try { await _module.DisposeAsync(); } catch { }
        if (_class is not null)
            try { await _class.DisposeAsync(); } catch { }
    }
}

実行してボタンを押すと以下のように表示されます。ちゃんと JavaScript のクラスのインスタンスを作ってメソッドを呼べてますね!!

まとめ

.NET 8 で実装されますように。

Microsoft (有志)

Discussion