
在《C# 開發 BIMFACE 系列文章》中介紹了模型轉換、模型對比接口。這2個功能接口比較特殊,發起請求后,邏輯處理是在BIMFACE雲端進行的,通常需要5~10分鍾。當邏輯處理完成后,BIMFACE通過回調機制通知對比結果。
BIMFACE支持回調機制。在調用方發起模型轉換、模型集成、模型對比、生成離線數據包、圖紙拆分等接口操作時,可以通過傳入參數callback的方式來啟用回調機制。 在BIMFACE處理完相應操作后,根據調用方傳入的回調地址通知調用方相應操作的結果。
URL參數:
signature(簽名):為了確保回調消息是由BIMFACE發出的,調用方在收到回調消息后,須驗證簽名。簽名的計算方式:MD5(``appKey:appSecret:compareId:status:nonce''),如果調用方計算的簽名與BIMFACE返回的簽名一致,則證明該消息是安全可靠的。
應用收到回調后,須向BIMFace發送回執,回執消息:HTTP STATUS 200
Callbak示例:
* 調用方對文件1685236328506848發起了模型轉換,並且傳入的回調地址是:https://my.app.com/callback。
* BIMFACE在模型轉換任務處理完成后,會發送一個get請求到調用方的callback地址:
https://my.app.com/callback?fileId=1685236328506848&status=success&thumbnail=38044a282f55cb26e3704643dccd2b55/thumbnail/96.png,38044a282f55cb26e3704643dccd2b55/thumbnail/256.png&reason=&signature=99a6fccb1894dfdb4cce48fd5ec58110&nonce=123abc
* 調用方接收到這條請求后,可以進行signature的驗證,並發送回執消息。
特別說明
BIMFACE的回調機制與微信公眾號或者小程序開發類似,需要開發者提供開發者服務器,且有正式合法域名或者外網IP,對外公布一個地址,BIMFACE服務器能訪問到該地址才可以。
如果無法提供有效的回調地址,則只能通過手動調用 模型轉換、模型集成、模型對比、生成離線數據包等操作的其他API來獲取對應的處理結果。
在.NET平台下實現該功能可以使用 WebService、一般處理程序、WebAPI等技術方式實現。下面介紹在一般處理程序中實現的思路與步驟。
1、配置BIMACE開發者賬號信息。
在web.config 或者 app.config 文件中配置開發者賬號信息,供驗證消息簽名時使用。
2、獲取BIMFace服務器發送的回調請求參數。
1 long fileId = context.Request.QueryString["fileId"].ToLong(); // 文件ID 2 string status = context.Request.QueryString["status"]; // 轉換的結果 3 string reason = context.Request.QueryString["reason"]; // 若轉換失敗,則返回失敗原因 4 string thumbnail = context.Request.QueryString["thumbnail"]; // 縮略圖地址 5 string nonce = context.Request.QueryString["nonce"]; // 回調隨機數 6 string signature = context.Request.QueryString["signature"]; // BIMFACE的加密簽名
3、根據請求參數計算簽名。
簽名的計算方式:MD5(``appKey:appSecret:compareId:status:nonce'')
1 /// <summary> 2 /// 根據回調的參數計算簽名 3 /// </summary> 4 /// <param name="appKey">開發者秘鑰</param> 5 /// <param name="appSecret">開發者密碼</param> 6 /// <param name="fileId">BIMFace發出的回調信息:文件ID</param> 7 /// <param name="status">BIMFace發出的回調信息:轉換的結果</param> 8 /// <param name="nonce">BIMFace發出的回調信息:回調隨機數</param> 9 /// <returns></returns> 10 public static string GetCallbackSignature(string appKey, string appSecret, long fileId, string status, string nonce) 11 { 12 return string.Format("{0}:{1}:{2}:{3}:{4}", appKey, appSecret, fileId, status, nonce).EncryptByMD5(); 13 }
其中使用到的擴展方法 EncryptByMD5() 實現如下:

1 /// <summary> 2 /// 自定義擴展方法:使用 MD5(不可逆加密) 算法加密字符串。返回二進制形式的字符串。字符串的編碼方式為UTF8。 3 /// </summary> 4 /// <param name="this">擴展對象。字符串。編碼方式為UTF8</param> 5 /// <param name="caseType">字符串大小寫。默認小寫</param> 6 /// <returns></returns> 7 public static string EncryptByMD5(this string @this, CaseType caseType = CaseType.Lower) 8 { 9 using (MD5 md5 = MD5.Create()) 10 { 11 var sb = new StringBuilder(); 12 byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(@this)); 13 foreach (byte bytes in hashBytes) 14 { 15 sb.Append(bytes.ToString("X2"));//X2 表示二進制 16 } 17 18 return caseType == CaseType.Upper ? sb.ToString() : sb.ToString().ToLower(); 19 } 20 }
4、驗證簽名。
將步驟3中的計算結果與BIMFace發出的回調消息簽名做對比,如果簽名一直則證明該消息是安全可靠的。
1 /// <summary> 2 /// 驗證BIMFace發出的回調消息簽名信息是否安全可靠 3 /// </summary> 4 /// <param name="appKey">開發者秘鑰</param> 5 /// <param name="appSecret">開發者密碼</param> 6 /// <param name="fileId">BIMFace發出的回調信息:文件ID</param> 7 /// <param name="status">BIMFace發出的回調信息:轉換的結果</param> 8 /// <param name="nonce">BIMFace發出的回調信息:回調隨機數</param> 9 /// <param name="signature">BIMFace發出的回調信息:簽名</param> 10 /// <param name="custCalcSignature">輸出參數:根據BIMFACE平台的加密規則計算出來的簽名信息</param> 11 /// <returns></returns> 12 public static bool CheckCallbackSignature(string appKey, string appSecret, long fileId, string status, string nonce, string signature, out string custCalcSignature) 13 { 14 /* signature(簽名):為了確保回調消息是由BIMFace發出的,應用在收到回調消息后,須驗證簽名。 15 * 簽名的計算方式:MD5("appKey:appSecret:fileId:status:nonce"),如果應用計算的簽名與BIMFace返回的簽名一致,則證明該消息是安全可靠的。 16 */ 17 custCalcSignature = GetCallbackSignature(appKey, appSecret, fileId, status, nonce); 18 19 return custCalcSignature == signature; 20 }
5、根據簽名驗證結果做出回執響應消息。
如果驗證簽名成功則可以將模型轉換、模型集成、模型對比、生成離線數據包等操作的處理結果寫入數據庫保存供后續其他業務邏輯使用。
簽名成功后,須向BIMFace發送回執,回執消息:HTTP STATUS 200。
1 bool checkSignature = CallbackUtils.CheckCallbackSignature(appKey, appSecret, fileId, status, nonce, signature, out custCalcSignature); 2 if (checkSignature) 3 { 4 tip = "[BIMFace發出的回調信息簽名驗證成功!]" 5 + Environment.NewLine 6 + callbackResponse; 7 LogUtility.Info(tip); 8 9 //Todo 此處可以根據fileId把相關的信息寫入數據庫中 10 11 // 回執消息:應用收到回調后,須向BIMFace發送回執,回執消息:HTTP STATUS 200 12 context.Response.Write("HTTP STATUS 200"); 13 } 14 else 15 { 16 tip = "[BIMFace發出的回調信息簽名驗證不通過!]" 17 + Environment.NewLine 18 + callbackResponse 19 + Environment.NewLine 20 + "自定義計算簽名 custCalcSignature:" + custCalcSignature; 21 22 LogUtility.Error(tip); 23 24 context.Response.Write(tip); 25 }
如果簽名驗證失敗,則需要將簽名信息寫入文本日志供分析原因使用。此時通過編碼方式實現郵件、短信、微信消息等方式通知開發者回調程序處理結果不正確,使其及時知道業務系統的運行狀況。
6、發布程序並使用該回調地址。
程序完成后發布到開發者服務器。在模型轉換、模型集成、模型對比、生成離線數據包等操作的API接口參數中使用該回調地址。
完整的代碼如下:
1 /// <summary> 2 /// BimFace回調處理 3 /// </summary> 4 public class BimFaceHandler : IHttpHandler 5 { 6 public void ProcessRequest(HttpContext context) 7 { 8 context.Response.ContentType = "text/plain"; 9 context.Response.ContentEncoding = Encoding.UTF8; 10 11 string appKey = ConfigUtility.GetAppSettingValue("BIMFACE_AppKey"); 12 string appSecret = ConfigUtility.GetAppSettingValue("BIMFACE_AppSecret"); 13 string uid = context.Request.QueryString["uid"]; // SparkBimFace 14 15 #region 校驗 16 if (appKey.IsNullOrWhiteSpace()) 17 { 18 LogUtility.Error("BIMFace appKey 配置項沒有配置!"); 19 20 return; 21 } 22 23 if (appSecret.IsNullOrWhiteSpace()) 24 { 25 LogUtility.Error("BIMFace appSecret 配置項沒有配置!"); 26 27 return; 28 } 29 30 if (uid.IsNullOrWhiteSpace()) 31 { 32 LogUtility.Error("[非法請求]回調地址Url鏈接中的參數 uid 沒有配置或者配置的值為空!"); 33 34 return; 35 } 36 #endregion 37 38 long fileId = context.Request.QueryString["fileId"].ToLong(); // 文件ID 39 string status = context.Request.QueryString["status"]; // 轉換的結果 40 string reason = context.Request.QueryString["reason"]; // 若轉換失敗,則返回失敗原因 41 string thumbnail = context.Request.QueryString["thumbnail"]; // 縮略圖地址 42 string nonce = context.Request.QueryString["nonce"]; // 回調隨機數 43 string signature = context.Request.QueryString["signature"]; // BIMFACE的加密簽名 44 45 string callbackResponse = string.Format("fileId:{0},\r\nstatus:{1},\r\nreason:{2},\r\nthumbnail:{3},\r\nnonce:{4},\r\nsignature:{5}", 46 fileId, status, reason, thumbnail, nonce, signature); 47 string tip; 48 string custCalcSignature; 49 50 bool checkSignature = CallbackUtils.CheckCallbackSignature(appKey, appSecret, fileId, status, nonce, signature, out custCalcSignature); 51 if (checkSignature) 52 { 53 tip = "[BIMFace發出的回調信息簽名驗證成功!]" 54 + Environment.NewLine 55 + callbackResponse; 56 LogUtility.Info(tip); 57 58 //Todo 此處可以根據fileId把相關的信息寫入數據庫中 59 60 // 回執消息:應用收到回調后,須向BIMFace發送回執,回執消息:HTTP STATUS 200 61 context.Response.Write("HTTP STATUS 200"); 62 } 63 else 64 { 65 tip = "[BIMFace發出的回調信息簽名驗證不通過!]" 66 + Environment.NewLine 67 + callbackResponse 68 + Environment.NewLine 69 + "自定義計算簽名 custCalcSignature:" + custCalcSignature; 70 71 LogUtility.Error(tip); 72 73 context.Response.Write(tip); 74 } 75 76 context.Response.End(); 77 } 78 79 /// <summary> 80 /// 該屬性獲得一個布爾值,指示另一個請求是否可以使用該HTTP處理程序的實例。 81 /// <para>如果設置為true,能提高性能,但要注意線程之間安全性問題。如果設置為false,則線程是安全的</para> 82 /// </summary> 83 public bool IsReusable 84 { 85 get 86 { 87 return false; 88 } 89 } 90 }
BIMFACE服務器端的回調機制非常友好,在BIMFACE服務器與開發者服務器之間自動架起了通訊橋梁。每當BIMFACE服務器上的耗時操作處理結束后(不一定每次都是成功的,也有可能是失敗的結果),BIMFACE服務器會及時的將結果推送給開發者服務器,開發者接收到處理結果后進行相應處理即可與業務關聯起來。但是使用該回調機制也是有條件限制的,要求開發者服務器以及開發者應用程序是365x24小時運行,中間不能暫停運行,如果遇到以下情況,BIMFACE回調機制將無法推送消息,導致模型的相關狀態信息丟失,與開發者的預期不符。
1、開發者服務器網絡不穩定。可能導致BIMFACE服務器請求回調地址(開發者服務器)不成功。
2、不定時間的維護開發者服務器、重啟服務器等情況。可能導致BIMFACE服務器請求回調地址(開發者服務器)不成功。
3、開發者應用程序不定時間的暫停或停止運行(升級應用程序、維護服務器等原因)。可能導致BIMFACE服務器請求回調地址(開發者服務器)不成功。
4、開發者服務器回調地址中的應用程序處理邏輯不正確。可能導致BIMFACE服務器請求回調地址(開發者服務器)不成功。
5、其他情況···
在開發者發起模型轉換、模型集成、模型對比、生成離線數據包等耗時操作的API之后,使用模型之前,需要判斷操作結果的狀態,然后才能進行其他的業務操作。比如發起模型轉換這個動作,開發者調用模型轉換API之后,BIMFACE服務器開始對模型進行轉換,但是轉換需要一個過程,並不能立刻轉換完成,至少需要等待幾秒。如果此時開發者想立刻預覽該模型,那么第一步就需要判斷模型是否已經轉換成功,因為只有轉換成功的模型才能預覽。所以開發者第一次就需要手動調用【獲取轉換狀態】接口來查詢該模型的轉換狀態,轉換狀態有三種值:processing、 success、failed。
(1)如果【獲取轉換狀態】接口返回結果是 processing,則開發者需要在UI端以友好的提示告知當前操作者:模型正在轉換中,暫時無法預覽。等待轉換完成后再預覽。
(2)如果【獲取轉換狀態】接口返回結果是 failed,則開發者需要在UI端以友好的提示告知當前操作者:模型轉換失敗,暫時無法預覽。開發者需要去排查轉換失敗的原因並解決。轉換失敗有可能是圖紙的問題,或者網絡的問題等。
(3)如果【獲取轉換狀態】接口返回結果是 success,則應用程序直接跳轉到預覽界面即可進行查看。
以上三種狀態,無論返回哪種狀態,都需要把狀態值保存到數據庫中。供后續使用。
第二次及以后操作(預覽等),開發者需要到數據庫中查找該模型的狀態,如果是 processing 或者 failed, 則需要開發者再次調用【獲取轉換狀態】接口,並將獲取到的狀態值更新到數據庫中。重復該操作,直到查詢返回的狀態是 success 才可以進行后續的操作。
總結:不建議使用BIMFACE服務器端API的回調機制。
最穩妥的方式就是直接調用各個耗時操作對應的查詢操作結果的接口。
