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

Blazor WebAssembly集成ReactJS时blazorInterop未定义问题求助

问题背景

任务

现有一个C#编写的类库,需要让ReactJS调用其中的MdProcessor.ParseAndRender方法——传入字符串并获取返回的字符串结果。计划通过Blazor WebAssembly(BWASM)实现:将BWASM项目用dotnet publish发布后,在ReactJS中接入发布文件来调用目标函数。

现有实现代码

Blazor WebAssembly的Program.cs

using MarkdownProcessorWasm;
using MdPWASM;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.JSInterop;
using System;
using System.Threading.Tasks;
using MarkdownProcessor;
using MarkdownProcessor.Classes;
using MarkdownProcessor.Interfaces;
using MarkdownProcessor.Structs.Tags;

var builder = WebAssemblyHostBuilder.CreateDefault(args);

var host = builder.Build();

var jsRuntime = host.Services.GetRequiredService<IJSRuntime>();
await jsRuntime.InvokeVoidAsync("console.log", "Hello World from Blazor WebAssembly!");

var jsInterop = new MarkdownProcessorInterop();

await jsRuntime.InvokeVoidAsync("blazorInterop.registerProcessor", DotNetObjectReference.Create(jsInterop));

await host.RunAsync();

public class MarkdownProcessorInterop
{
    private MdProcessor _markdownProcessor;

    public MarkdownProcessorInterop()
    {
        var ital = new ItalicsTag();
        var bold = new BoldTag();
        var link = new Link();
        var header = new HeaderTag();
        var main = new MainTag();
        var list = new List<ITag> { bold, ital, link, header, main };

        _markdownProcessor = new MdProcessor(new StringParser(list), new ConsoleMdRenderer());
    }
        
    [JSInvokable]
    public string ParseMarkdown(string markdownText)
    {
        return _markdownProcessor.ParseAndRender(markdownText);
    }
}

Blazor WebAssembly的index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>MdPWASM</title>
    <base href="/" />
    <link rel="stylesheet" href="css/app.css" />
    <!-- If you add any scoped CSS files, uncomment the following to load them
    <link href="MdPWASM.styles.css" rel="stylesheet" /> -->
</head>

<body>
    <script>
        window.blazorInterop = {
            registerProcessor: function (processor) {
                window.processor = processor;
            },
            parseMarkdown: async function (markdownText) {
                if (!window.processor) {
                    throw new Error("WASM module is not ready yet.");
                }
                return await window.processor.invokeMethodAsync("ParseMarkdown", markdownText);
            }
        };
    </script>
    <script src="_framework/blazor.webassembly.js"></script>
    <script src="Interop.js"></script>
</body>

</html>

React客户端代码

useEffect(() => {
        const loadBlazor = async () => {
            try {
                await import('http://localhost:8080/_framework/blazor.webassembly.js');

                await window.Blazor.start({
                    loadBootResource: (type, name, defaultUri, integrity) => {
                        return `http://localhost:8080/_framework/${name}`;
                    }
                }).then(() => {
                    console.log('Blazor WebAssembly is initialized');
                }).catch(error => {
                    console.error('Blazor WebAssembly initialization error:', error);
                });
            } catch (error) {
                console.error('Error while fetching Blazor WebAssembly:', error);
            }
        };

        loadBlazor();
    }, []);

    const processMarkdown = async () => {
        try {
            if (window.processor) {
                const parsedHtml = await window.blazorInterop.parseMarkdown(markdownText);
                setHtmlOutput(parsedHtml);
            } else {
                console.error('Blazor WebAssembly is not loaded');
            }
        } catch (error) {
            console.error('Error while parsing Markdown:', error);
        }
    };

当前遇到的问题

通过localhost:8080获取发布文件,WebAssembly加载成功,Blazor的console.log能正常执行,但调用blazorInterop.registerProcessor时提示“blazorInterop未定义”。排查发现Blazor代码执行时,window上的blazorInterop属性还没创建;尝试延迟调用却陷入无限循环。需要解决两个核心问题:

  1. 如何确保blazorInterop正常声明?
  2. 如何将MdProcessor类库转为Wasm并保留ReactJS作为唯一前端框架?

解决方案建议

一、解决blazorInterop未定义的问题

问题核心是Blazor初始化时,blazorInterop还未挂载到window对象上,可通过以下两种方式修复:

1. 提前在React端声明blazorInterop

在React的Blazor加载逻辑中,先在window上定义blazorInterop的基础结构,再加载Blazor脚本,确保Blazor调用时该对象已存在:

useEffect(() => {
    const loadBlazor = async () => {
        try {
            // 提前初始化blazorInterop,避免Blazor调用时未定义
            window.blazorInterop = {
                processor: null,
                registerProcessor: function(processor) {
                    window.blazorInterop.processor = processor;
                },
                parseMarkdown: async function(markdownText) {
                    if (!window.blazorInterop.processor) {
                        throw new Error("WASM模块尚未准备就绪");
                    }
                    return await window.blazorInterop.processor.invokeMethodAsync("ParseMarkdown", markdownText);
                }
            };

            // 加载Blazor脚本
            await import('http://localhost:8080/_framework/blazor.webassembly.js');

            await window.Blazor.start({
                loadBootResource: (type, name, defaultUri, integrity) => {
                    return `http://localhost:8080/_framework/${name}`;
                }
            }).then(() => {
                console.log('Blazor WebAssembly初始化完成');
            }).catch(error => {
                console.error('Blazor WebAssembly初始化错误:', error);
            });
        } catch (error) {
            console.error('加载Blazor WebAssembly出错:', error);
        }
    };

    loadBlazor();
}, []);

同时删除Blazor index.html中的blazorInterop定义,避免重复或加载顺序冲突。

2. 利用Blazor初始化回调确保时机正确

Blazor提供了运行时就绪的回调机制,修改Program.cs,等待Blazor完全初始化后再执行JS互操作:

var builder = WebAssemblyHostBuilder.CreateDefault(args);
var host = builder.Build();

var jsRuntime = host.Services.GetRequiredService<IJSRuntime>();
// 等待Blazor运行时就绪后再执行互操作逻辑
await jsRuntime.InvokeAsync<IJSObjectReference>("import", "_framework/blazor.webassembly.js")
    .ContinueWith(async _ => {
        await jsRuntime.InvokeVoidAsync("console.log", "Hello World from Blazor WebAssembly!");
        var jsInterop = new MarkdownProcessorInterop();
        await jsRuntime.InvokeVoidAsync("blazorInterop.registerProcessor", DotNetObjectReference.Create(jsInterop));
    });

await host.RunAsync();

这种方式能确保Blazor环境完全准备好后,再去调用window上的blazorInterop方法。

二、将MdProcessor类库转为Wasm并保留React作为唯一前端

只需完成以下几步:

  1. 调整类库目标框架:将MdProcessor类库的目标框架改为.NET 7或更高版本(与Blazor Wasm项目一致),确保代码能编译为Wasm兼容的字节码。
  2. 正确引用类库:在Blazor Wasm项目中添加对MdProcessor类库的项目引用或NuGet引用,确保发布时类库代码被打包到Wasm资源中。
  3. 移除Blazor UI依赖:因为仅用Blazor作为Wasm运行时,不需要UI组件,删除Blazor项目中的App.razor、MainLayout.razor等UI文件,让Program.cs只负责初始化运行时和JS互操作逻辑。
  4. 发布与部署:执行dotnet publish -c Release生成发布文件,将_framework目录部署到静态资源服务器(如localhost:8080),React端通过该地址加载Wasm资源即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 23:42:08