Learn Forge 系列:Forge 雲端自動化設計服務 - 網路app部分

梁曉冬發表於2019-05-06

上一篇文章中,我們講解了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雲端自動化全過程。

相關文章