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

Blazor组件JS互操作JSON反序列化问题求助

问题分析与解决方案

错误根源

第一种方法的序列化错误

querySelectorAll返回的是NodeList(类数组对象),并非标准JS数组,Blazor无法将其反序列化为IJSObjectReference[]——因为NodeList没有实现数组的序列化协议,无法被自动转换为C#的数组类型。

第二种方法的"找不到get方法"错误

getElementsByTagName返回的是HTMLCollection,JS中访问其长度是直接取length属性,获取元素是用item(index)或直接索引(collection[index]),不存在名为get的方法,因此调用InvokeAsync("get", ...)会触发异常。


推荐解决方案:让JS直接返回结构化数据

最简洁高效的方式是让JS完成DOM数据提取并整理为JSON数组,直接传给C#,避免频繁的JS互操作调用,同时彻底解决序列化问题。

1. 修改JavaScript代码

将原JS函数改为返回整理好的数据数组:

window.storeAndCallCSharpMethod = () => {
    const dataArray = [];
    const tableBody = document.getElementById('table-body');
    const rows = tableBody.getElementsByTagName('tr');

    for (let i = 0; i < rows.length; i++) {
        const row = rows[i];
        const inputs = row.getElementsByTagName('input');

        const rowData = {
            Name: inputs[1].value,
            Quantity: inputs[2].value,
            UOM: inputs[3].value,
            RequiredBy: inputs[4].value
        };

        dataArray.push(rowData);
    }

    return dataArray;
}

2. 修改C#方法

直接接收JS返回的数组,Blazor会自动反序列化为List<Item>:

@code {
    List<Item> dataArray = new List<Item>();

    private async Task StoreAndCallCSharpMethod()
    {
        // 直接获取JS返回的结构化数据
        dataArray = await JSRuntime.InvokeAsync<List<Item>>("storeAndCallCSharpMethod");

        // 处理数据(插入SQL等操作)
        foreach (var data in dataArray)
        {
            await insert.PRInsert(data.Name, data.Quantity, data.UOM, DateTime.Parse(data.RequiredBy));
            Console.WriteLine($"{data.Name}, {data.Quantity}, {data.UOM}, {data.RequiredBy}");
        }
    }
}

备选方案:修正DOM元素的JS互操作(不推荐)

如果必须在C#中逐个操作DOM元素,需按照JS对象的正确访问方式修正代码:

private async Task StoreAndCallCSharpMethod()
{
    var tableBody = await JSRuntime.InvokeAsync<IJSObjectReference>("eval", "document.getElementById('table-body')");
    var rows = await tableBody.InvokeAsync<IJSObjectReference>("getElementsByTagName", "tr");
    
    // 获取HTMLCollection的长度
    int rowCount = await JSRuntime.InvokeAsync<int>("eval", "arguments[0].length", rows);

    for (int i = 0; i < rowCount; i++)
    {
        // 通过item方法获取指定索引的行元素
        var row = await rows.InvokeAsync<IJSObjectReference>("item", i);
        var inputs = await row.InvokeAsync<IJSObjectReference>("getElementsByTagName", "input");
        
        // 直接通过JS eval获取输入框的值
        var name = await JSRuntime.InvokeAsync<string>("eval", "arguments[0][1].value", inputs);
        var quantity = await JSRuntime.InvokeAsync<string>("eval", "arguments[0][2].value", inputs);
        var uom = await JSRuntime.InvokeAsync<string>("eval", "arguments[0][3].value", inputs);
        var requiredByStr = await JSRuntime.InvokeAsync<string>("eval", "arguments[0][4].value", inputs);

        var rowData = new Item
        {
            Name = name,
            Quantity = quantity,
            UOM = uom,
            RequiredBy = DateTime.Parse(requiredByStr)
        };

        dataArray.Add(rowData);
    }

    foreach (var data in dataArray)
    {
        Console.WriteLine($"{data.Name}, {data.Quantity}, {data.UOM}, {data.RequiredBy}");
    }
}

注意事项

  • 确保Item类的属性名与JS对象的键名完全匹配(大小写敏感),若需适配不同命名风格,可使用[JsonPropertyName]特性指定映射关系。
  • 日期字符串解析:JS的input[type="date"]返回ISO格式字符串(如2024-05-20),可直接用DateTime.Parse解析。
  • Razor类库中的JS引用:需在宿主项目(Blazor Server的_Host.cshtml或MAUI Blazor的index.html)中正确引用包含该JS函数的脚本文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:02:10