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

Blazor Server调用JavaScript函数saveFile提示未定义问题求助

解决Blazor调用JS函数saveFile提示未定义的问题

问题描述

在Blazor Razor页面后台调用saveFile JavaScript函数时,持续抛出函数未定义的错误,具体报错信息如下:

[2023-11-14T15:49:45.869Z] Error: Microsoft.JSInterop.JSException: Could not find 'saveFile' ('saveFile' was undefined).
findFunction/<@https://localhost:7261/_framework/blazor.server.js:1:497
findFunction@https://localhost:7261/_framework/blazor.server.js:1:465
E@https://localhost:7261/_framework/blazor.server.js:1:2606
beginInvokeJSFromDotNet/s<@https://localhost:7261/_framework/blazor.server.js:1:3494
beginInvokeJSFromDotNet@https://localhost:7261/_framework/blazor.server.js:1:3475
_invokeClientMethod/<@https://localhost:7261/_framework/blazor.server.js:1:72077
_invokeClientMethod@https://localhost:7261/_framework/blazor.server.js:1:72063
_processIncomingData@https://localhost:7261/_framework/blazor.server.js:1:70105
kt/this.connection.onreceive@https://localhost:7261/_framework/blazor.server.js:1:64508
connect/</o.onmessage@https://localhost:7261/_framework/blazor.server.js:1:48842


   at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)

   at HR_Taxonomy_Change_Management.Pages.Administration.GetSpreadsheet() in C:\Users\v-reedchris\source\repos\HR Taxonomy Change Management\HR Taxonomy Change Management\Pages\Administration.razor.cs:line 169

   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)

   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState) blazor.server.js:1:116297

已尝试的操作:

  • 将JS文件放置在wwwroot/js/saveFile.js及项目根目录
  • 调整_Layout页面中的JS加载顺序
  • 浏览器调试器可定位到对应的JS文件,但问题仍未解决

相关代码

C# 触发下载代码(Razor后台)

private async Task GetSpreadsheet()
{
    IBinaryWorkbookFormatProvider formatProvider = new Telerik.Windows.Documents.Spreadsheet.FormatProviders.OpenXml.Xlsx.XlsxFormatProvider();

    var docService = await AdminDomain.GetReportAsync().ConfigureAwait(false);
    byte[] bytesFromWorkbook = formatProvider.Export(docService);

    await JSRuntime.InvokeAsync<object>("saveFile", "test.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", bytesFromWorkbook);
}

JavaScript 原函数代码

function saveFile(file, contentType, content) {
    // Create the URL
    const file = new File([content], filename, { type: contentType });
    const exportUrl = URL.createObjectURL(file);

    // Create the <a> element and click on it
    const a = document.createElement("a");
    document.body.appendChild(a);
    a.href = exportUrl;
    a.download = filename;
    a.target = "_self";
    a.click();

    // We don't need to keep the object URL, let's release the memory
    // On older versions of Safari, it seems you need to comment this line...
    URL.revokeObjectURL(exportUrl);
}

解决方案

1. 将JS函数挂载到全局window对象

Blazor的JSInterop只能访问全局作用域的函数,必须把saveFile绑定到window上,同时修正原函数的参数名错误:

window.saveFile = function(filename, contentType, content) {
    // 修正:原函数参数名错误,第一个参数应为filename,且函数内使用的filename变量未定义
    const file = new File([content], filename, { type: contentType });
    const exportUrl = URL.createObjectURL(file);

    const a = document.createElement("a");
    document.body.appendChild(a);
    a.href = exportUrl;
    a.download = filename;
    a.target = "_self";
    a.click();

    URL.revokeObjectURL(exportUrl);
    document.body.removeChild(a); // 清理创建的DOM元素,避免内存泄漏
}

2. 确保JS文件正确加载

在_Layout.cshtml(Blazor Server场景)中,按以下方式加载JS文件:

<!-- 放在<body>末尾,在blazor.server.js之前加载,或添加defer属性保证DOM加载完成后执行 -->
<script src="~/js/saveFile.js" defer></script>
<script src="_framework/blazor.server.js"></script>

如果是单个Razor组件单独引用JS,可在组件内添加:

@inject IJSRuntime JSRuntime
@implements IAsyncDisposable

<script src="~/js/saveFile.js"></script>

3. 验证函数是否全局注册

打开浏览器控制台,执行window.saveFile:

  • 如果返回函数体,说明已成功全局注册
  • 如果返回undefined,检查:
    • JS文件路径是否正确,查看浏览器Network标签确认文件是否成功加载(状态码200)
    • JS文件是否存在语法错误,查看Console标签的报错信息

4. 处理Byte数组的传递

Blazor传递byte[]到JS时会自动转换为Uint8Array,如果出现文件损坏问题,可显式转换为ArrayBuffer:

window.saveFile = function(filename, contentType, content) {
    const arrayBuffer = content instanceof Uint8Array ? content.buffer : content;
    const file = new File([arrayBuffer], filename, { type: contentType });
    // 后续逻辑不变
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 11:31:09