You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Net MAUI (Blazor)如何在C#类中注入IJSRuntime并调用JS?

在Razor页面外的C#类中注入IJSRuntime调用JavaScript

问题场景

我想在Razor页面之外的C#类中处理JavaScript逻辑,尝试通过注入IJSRuntime实现,相关代码如下:

自定义服务类

public class InvokeJavaScriptService 
{
    private IJSRuntime js;
    public InvokeJavaScriptService(IJSRuntime js)
    {
        this.js = js; 
    }

    public async Task CallJsFromCSharp()
    {
        try
        {
            await js.InvokeAsync<object>("invokeJSfromCS");
        }
        catch(Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
       
    }
}

服务注册

builder.Services.AddScoped<InvokeJavaScriptService>();

前端JavaScript(index.html)

<script>
    async function invokeJSfromCS() {
        var value = "C# Method called from JavaScript with parameter";
        // 调用C#方法
        DotNet.invokeMethodAsync ('MauiBlazorTestApp', 'JStoCSCall', value);
    }
</script>

Razor页面回调方法(index.razor)

@page "/"
<div>
</div>

@code{
    private static string content { get; set; }

    [JSInvokable] // 接收JavaScript回调的C#方法
    public static void JStoCSCall(string value)
    {
        content = value;
    }
}

调用CallJsFromCSharp()时出现错误,但预期是触发index.html中的invokeJSfromCS函数并回调到Razor页面的方法。既然Razor页面可以通过@inject注入IJSRuntime,那C#类中应该也可以实现,请问该怎么做?


解决方案

1. 确认上下文有效性

IJSRuntime仅在Blazor渲染上下文内有效,你的InvokeJavaScriptService必须在Blazor组件的生命周期内被注入和调用,不能在非Blazor上下文(比如后台服务、应用启动阶段)直接调用,否则会因JS运行时上下文缺失报错。

2. 在Razor组件中正确调用服务

在需要触发JS逻辑的Razor组件中注入服务,选择合适的生命周期方法(推荐OnAfterRenderAsync,确保组件渲染完成、JS环境就绪)调用服务方法:

@page "/"
@inject InvokeJavaScriptService JsService

<div>
</div>

@code{
    private static string content { get; set; }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            // 组件首次渲染完成后触发JS调用
            await JsService.CallJsFromCSharp();
        }
    }

    [JSInvokable]
    public static void JStoCSCall(string value)
    {
        content = value;
    }
}

3. 修复JS调用C#的潜在问题

  • 确保DotNet.invokeMethodAsync中的程序集名称'MauiBlazorTestApp'与项目实际程序集名称完全一致(可通过右键项目→属性查看)。
  • 静态回调方法无法直接更新组件UI,若需要更新UI,建议改为实例方法并传递组件引用:

修改Razor页面代码:

@page "/"
@inject InvokeJavaScriptService JsService
@implements IAsyncDisposable

<div>@content</div>

@code{
    private string content { get; set; }
    private DotNetObjectReference<Index>? _objRef;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            _objRef = DotNetObjectReference.Create(this);
            // 传递组件引用给JS
            await JsService.CallJsFromCSharp(_objRef);
        }
    }

    [JSInvokable]
    public void JStoCSCall(string value)
    {
        content = value;
        StateHasChanged(); // 触发UI更新
    }

    public async ValueTask DisposeAsync()
    {
        _objRef?.Dispose();
    }
}

修改服务类和JS代码:

public class InvokeJavaScriptService 
{
    private readonly IJSRuntime _js;
    public InvokeJavaScriptService(IJSRuntime js)
    {
        _js = js; 
    }

    public async Task CallJsFromCSharp(DotNetObjectReference<Index> objRef)
    {
        try
        {
            await _js.InvokeAsync<object>("invokeJSfromCS", objRef);
        }
        catch(Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }
}
<script>
    async function invokeJSfromCS(dotNetRef) {
        var value = "C# Method called from JavaScript with parameter";
        // 调用组件实例方法
        await dotNetRef.invokeMethodAsync('JStoCSCall', value);
    }
</script>

4. 确认服务注册范围

IJSRuntime本身是Scoped服务,因此你的InvokeJavaScriptService注册为Scoped是正确的,不要注册为Singleton,否则会导致上下文不一致问题。


内容的提问来源于stack exchange,提问作者Razvan Emil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 07:51:12