如何在ASP.NET后台事件中立即触发Forge Viewer模型销毁?
问题描述
当前开发Autodesk Forge IDA,现有代码可实现Viewer中模型的销毁与显示:首次点击按钮时从Bucket获取文件并转换为SVF后显示;后续点击时先销毁旧模型再加载新模型。但从Bucket取文件转SVF耗时45-60秒,且当前销毁和显示操作都要等后端Button1_Click事件完全执行完才触发。需求是点击按钮后立即销毁旧模型,让Viewer保持空白,直到后端处理完成再加载新模型。
问题根源
后端Button1_Click是同步执行的方法,Page.ClientScript.RegisterStartupScript会把JS脚本放在页面回发后的响应里,只有当整个后端方法(包括耗时的文件获取、转换)执行完毕,前端才会收到响应并执行销毁和显示的脚本,所以销毁操作被延迟了。
解决方案
把后端的文件处理逻辑改成异步调用,让前端先执行销毁操作,再通过AJAX请求后端处理文件,后端处理完成后返回新模型的URN,前端再加载新模型。具体步骤:
- 将服务器端按钮替换为HTML按钮,前端点击时先调用
destroyModel()销毁旧模型 - 后端编写异步接口(WebMethod)处理文件获取与SVF转换,返回模型URN
- 前端通过AJAX调用该接口,等待返回结果后调用
showModel()加载新模型
修改后的代码示例
前端页面(default.aspx)
<!-- 替换原服务器按钮为HTML按钮 --> <button id="loadModelBtn">加载模型</button> <div id="forgeViewer"></div> <script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js"></script> <link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css"> <script src="viewer.js"></script> <script> let counter = 1; // 记录点击次数,可根据实际情况调整初始值 document.getElementById('loadModelBtn').addEventListener('click', async function() { if (counter !== 1) { // 立即销毁旧模型 destroyModel(); } try { // 异步调用后端接口处理文件并获取URN const response = await fetch('default.aspx/ProcessModel', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ counter: counter }) }); const result = await response.json(); const objectIdBase64 = result.d; // 加载新模型 showModel(objectIdBase64); counter++; } catch (error) { console.error('模型处理失败:', error); } }); </script>
后端代码(default.aspx.cs)
using System.Web.Services; using System.Web.Script.Serialization; public partial class _Default : System.Web.UI.Page { [WebMethod] public static string ProcessModel(int counter) { string objectIdBase64 = string.Empty; if (counter == 1) { // 首次点击:从Bucket获取文件并转换为SVF的代码 // ... 你的原有逻辑 ... // 处理完成后设置objectIdBase64 } else { // 后续点击:从Bucket获取文件并转换为SVF的代码 // ... 你的原有逻辑 ... // 处理完成后设置objectIdBase64 } return objectIdBase64; } }
viewer.js 优化(增强鲁棒性)
let viewer = null; function showModel(urn) { const options = { env: 'AutodeskProduction', getAccessToken: getForgeToken }; Autodesk.Viewing.Initializer(options, () => { viewer = new Autodesk.Viewing.GuiViewer3D(document.getElementById('forgeViewer')); viewer.start(); const documentId = 'urn:' + urn; Autodesk.Viewing.endpoint.HTTP_REQUEST_HEADERS['If-Modified-Since'] = "Sat, 29 Oct 1994 19:43:31 GMT"; Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure); }); } function onDocumentLoadSuccess(doc) { const defaultModel = doc.getRoot().getDefaultGeometry(); viewer.loadDocumentNode(doc, defaultModel); } function onDocumentLoadFailure(viewerErrorCode) { console.error('模型加载失败 - 错误码:' + viewerErrorCode); } function destroyModel() { if (viewer) { viewer.finish(); viewer = null; } Autodesk.Viewing.shutdown(); // 清空Viewer容器(可选) document.getElementById('forgeViewer').innerHTML = ''; } // 实现你的getForgeToken方法 function getForgeToken(callback) { // ... 你的令牌获取逻辑 ... }
关键说明
- 前端点击按钮后立即执行
destroyModel(),无需等待后端处理,Viewer会立刻空白 - 后端
ProcessModel是异步WebMethod,处理耗时的文件操作,完成后返回URN - 前端通过
async/await等待后端响应,收到URN后再加载新模型
内容的提问来源于stack exchange,提问作者Siddhesh Nikam
相关产品推荐
相关产品推荐

