在上一篇文章中,我们讲解了Forge Design Automation的基本原理和样例代码的插件部分。本文继续前篇,当插件包准备就绪后,转向forgesample,基本框架流程是:
1 . app的Configure首先检测本地可用的bundle压缩包,即上篇文章编译好的结果。选择压缩包,并选择云端Forge执行的引擎。显然,Revit插件的要Revit引擎。注意选择合适的版本
2 . 点击【Create/Update】,app将从本地上传bundle压缩包到服务端,再通过Forge的云端自动化服务端口创建自动化App,提交插件包,创建Activity。所有这些准备好后,您的Forge账户中就含有了对应的Activity,而Activity连接到自动化App,知道使用哪个插件执行接下来的任务。
/// <summary>
/// 创建云端自动化app,上载插件bundle
/// </summary>
[HttpPost]
[Route("api/forge/designautomation/appbundles")]
public async Task<IActionResult> CreateAppBundle([FromBody]JObject appBundleSpecs)
{
//......
/// <summary>
/// 创建 activity
/// </summary>
[HttpPost]
[Route("api/forge/designautomation/activities")]
public async Task<IActionResult> CreateActivity([FromBody]JObject activitySpecs)
{
//......
3 . 退出Configure窗口,程序会通过云端自动化服务获取Activity列表。在【Existing activities】选择到需要的Activity
/// <summary>
/// 获取该Forge账户下所有可用Activity列表
/// </summary>
[HttpGet]
[Route("api/forge/designautomation/activities")]
public async Task<List<string>> GetDefinedActivities()
{
Page<string> activities = await _designAutomation.GetActivitiesAsync();
//......
4 . 【Input File】选择到本地的Revit文件,可使用本例samples文件夹下提供的样例文件。
5 . 输入需要改变的长和宽,点击[Start Workitem]. 将执行StartWorkitem
[HttpPost]
[Route("api/forge/designautomation/workitems")]
public async Task<IActionResult> StartWorkitem([FromForm]StartWorkitemInput input)
{
**StartWorkitem**首先把本地Revit上传到后端,并通过Forge的Data Management API将文件传到某个bucket,和我们通常为了测试Forge Viewer上传文件到bucket一样。因为Forge的云端自动化服务的输入文件只能从云存储而来,所以此案例利用Forge的bucket存储。您也可以改造为从其它数据存储。
``
//....
// 确保bucket存在,否则创建之
try
{
PostBucketsPayload bucketPayload = new PostBucketsPayload(bucketKey, null, PostBucketsPayload.PolicyKeyEnum.Transient);
await buckets.CreateBucketAsync(bucketPayload, "US");
}
catch { };
//.......
//上载文件到bucket
using (StreamReader streamReader = new StreamReader(fileSavePath))
await objects.UploadObjectAsync(bucketKey, inputFileNameOSS, (int)streamReader.BaseStream.Length, streamReader.BaseStream, "application/octet-stream");
System.IO.File.Delete(fileSavePath);
当这些准备好以后,配置云端自动化WorkItem的参数:
1) 输入参数:一个是原始Revit文件,通过配置access token来拿到
XrefTreeArgument inputFileArgument = new XrefTreeArgument()
{
Url = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", bucketKey, inputFileNameOSS),
Headers = new Dictionary<string, string>()
{
{ "Authorization", "Bearer " + oauth.access_token }
}
};
```
2) 需要更改的几何数据(长宽),通过配置一个json文件。长宽从客户端提交的输入而来。
dynamic inputJson = new JObject();
inputJson.Width = widthParam;
inputJson.Height = heigthParam;
XrefTreeArgument inputJsonArgument = new XrefTreeArgument()
{
Url = "data:application/json, " + ((JObject)inputJson).ToString(Formatting.None).Replace("\"", "'")
};
3) 再配置更新后的Revit文件放置的位置,同样,本例将把结果文件放回到bucket中。同样,需要access token。
```
string outputFileNameOSS = string.Format("{0}_output_{1}",
DateTime.Now.ToString("yyyyMMddhhmmss"),
Path.GetFileName(input.inputFile.FileName));
XrefTreeArgument outputFileArgument = new XrefTreeArgument()
{
Url = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}",
bucketKey, outputFileNameOSS),
Verb = Verb.Put,
Headers = new Dictionary<string, string>()
{
{"Authorization", "Bearer " + oauth.access_token }
}
};
```
4) 最后就是提交任务WorkItem,传入前面配置好的参数,开启云端自动化的过程。
string callbackUrl = string.Format("{0}/api/forge/callback/designautomation?id={1}&outputFileName={2}",
OAuthController.GetAppSetting("FORGE_WEBHOOK_URL"), browerConnectionId,
outputFileNameOSS);
WorkItem workItemSpec = new WorkItem()
{
ActivityId = activityName,
Arguments = new Dictionary<string, IArgument>()
{
{ "inputFile", inputFileArgument },
{ "inputJson", inputJsonArgument },
{ "outputFile", outputFileArgument },
//回调函数
{ "onComplete", new XrefTreeArgument { Verb = Verb.Post, Url = callbackUrl } }
}
};
WorkItemStatus workItemStatus = await _designAutomation.CreateWorkItemsAsync(workItemSpec);
云端自动化开启后,需要一个过程才结束,可以通过主动查询来获取状态,而本例采取回调函数的方式,即onComplete。当WorkItem结束后,无论什么情况,都自动通知callbackUrl, 带上WorkItem执行的日志(log)文件内容。而callbackUrl定义如下:
[HttpPost]
[Route("/api/forge/callback/designautomation")]
public async Task<IActionResult> OnCallback(string id, string outputFileName, [FromBody]dynamic body)
{
由于默认是本地测试(localhost),回调函数要得到响应,采取了ngrok做重定向。
但这只是通知了网络应用的后端,但怎么自动通知前端浏览器呢?本例采用了SignalR. SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信。此部分内容略过,请查阅本例的前后端相关代码。
当WorkItem成功执行,结果文件导出到Forge的bucket,还会提供一个签名下载url,出现在客户端面板,用户就能把更改后的文件下载来查看了。
运行forgesample,按照Readme要求填写Forge的client id,client secret,本网络应用的host,以及用于获取Design Automation回调结果状态的ngrok 重定向链接。本文就不再赘述了。
本例可以作为研究其它方案的模板框架,只需要对前端用户界面做一定修改,提供核心插件模块,易于调试和诊断Forge云端自动化全过程。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。