我是微軟Dynamics 365 & Power Platform方面的工程師羅勇,也是2015年7月到2018年6月連續三年Dynamics CRM/Business Solutions方面的微軟最有價值專家(Microsoft MVP),歡迎關注我的微信公眾號 MSFTDynamics365erLuoYong ,回復380或者20191124可方便獲取本文,同時可以在第一間得到我發布的最新博文信息,follow me!
前面的博文講了些客戶端編程,但是對於重要的數據,一般需要服務器端再做一次校驗,常用的手段就是插件和實時工作流,今天我講一下插件,官方文檔請參考 Write a plug-in 和 Register a plug-in 等。
首先需要創建一個 .NET Framework 的 Class Library項目,記得 Framework選擇 .NET Framework 4.6.2 。當然,為不同版本的Dynamics 365 Customer Engagement選擇的Framework不盡相同,請根據官方文檔說明,我這個示例是為 V9.X 版本做的示例。
首先通過NuGet添加對Microsoft.CrmSdk.CoreAssemblies的引用,如下圖,當然也要選擇合適的版本。如果不能上網的話,就需要添加對 Microsoft.Xrm.Sdk.dll 和 Microsoft.Crm.Sdk.Proxy.dll 的引用。
一般我會刪除生成的Class1.cs文件,而是使用固定的命名方式來命名。比如我這個插件步驟將會注冊在ly_WorkOrder實體的Create消息的Pre階段,我就會新建一個 PreWorkOrderCreate.cs 的文件來撰寫業務邏輯,當然這個類必須繼承 Microsoft.Xrm.Sdk.IPlugin 接口,我使用的代碼如下:常見的是獲取組織服務和跟蹤服務,其中插件日志的使用請參考我的博文:Dynamics CRM 2015/2016新特性之三十四:有了插件日志,調試插件so easy! ,若要使用映像(Image),請參考我的博文:Dynamics 365 CE Update消息PostOperation階段Image的嘗試 和 Dynamics 365 CE在Pre Delete插件中應用Image 。記得若要拋出用戶可見可理解的異常文本,請使用throw new InvalidPluginExecutionException。
using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Query; using System; using System.ServiceModel; using System.Text; namespace PluginDemo { public class PreWorkOrderCreate : IPlugin { public void Execute(IServiceProvider serviceProvider) { //獲取日志服務 ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); //寫一些日志,方便跟蹤 tracingService.Trace($"Enter PreWorkOrderCreate on {DateTime.UtcNow.ToString()}"); IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity) { //插件針對的當前實體記錄,對於Pre Create來講,該對象包括了所有設置的字段值,若字段沒有設置值,在該對象中會不存在 Entity currentEntity = (Entity)context.InputParameters["Target"]; //獲取組織服務 IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService orgSvc = serviceFactory.CreateOrganizationService(context.UserId); int provinceValue = Int32.MaxValue; int cityValue = Int32.MaxValue; string buName = string.Empty; //首先獲取要做校驗的值 //記得先確認該屬性存在值再獲取其值,否則容易引發異常 if (currentEntity.Contains("ly_province")) { provinceValue = currentEntity.GetAttributeValue<OptionSetValue>("ly_province").Value; } if (currentEntity.Contains("ly_city")) { cityValue = currentEntity.GetAttributeValue<OptionSetValue>("ly_city").Value; } var userEntity = orgSvc.Retrieve("systemuser", context.UserId, new ColumnSet("businessunitid")); //每個系統用戶肯定都設置了業務部門,我這里只是例行檢查這個字段存在值 if (userEntity.Contains("businessunitid")) { buName = userEntity.GetAttributeValue<EntityReference>("businessunitid").Name; if(buName == "Demo") { //省份字段用戶選擇了值才校驗 if(provinceValue != Int32.MaxValue) { if(provinceValue != 430000) { throw new InvalidPluginExecutionException($"省份字段值選擇有誤!"); } else { //城市字段用戶選擇了值才做校驗 if(cityValue != Int32.MaxValue) { if (cityValue >= provinceValue && cityValue < provinceValue + 10000) { tracingService.Trace($"城市字段選擇了值,且屬於正確的省份!"); } else { throw new InvalidPluginExecutionException($"城市字段值選擇有誤!"); } } } } } else if(buName == "Sub Unit") { //省份字段用戶選擇了值才校驗 if (provinceValue != Int32.MaxValue) { if (provinceValue != 440000) { throw new InvalidPluginExecutionException($"省份字段值選擇有誤!"); } else { //城市字段用戶選擇了值才做校驗 if (cityValue != Int32.MaxValue) { if (cityValue >= provinceValue && cityValue < provinceValue + 10000) { tracingService.Trace($"城市字段選擇了值,且屬於正確的省份!"); } else { throw new InvalidPluginExecutionException($"城市字段值選擇有誤!"); } } } } } } else { throw new InvalidPluginExecutionException($"系統異常,當前用戶(userid={context.UserId})的業務部門沒有設置!"); } } tracingService.Trace($"Leave PreWorkOrderCreate on {DateTime.UtcNow.ToString()}"); } } }
記得一定要給該插件/自定義工作流活動程序集簽名,在Visual Studio中右擊該項目,選擇屬性(Properties) > 簽名(Signing),選中 Sign the assembly,我這里新建一個Key file。
Key file我的設置如下,為了簡便,我就不設置密碼保護了,保存后編譯插件項目,確定沒有編譯錯誤。
然后需要使用插件注冊工具將其注冊到Dynamics 365中,工具的下載請參考我的博文 下載Dynamics 365 Customer Engagement 工具 。雙擊其中的 PluginRegistration\PluginRegistration.exe 文件。點擊【CREATE NEW CONNECTION】,以便連接到Dynamics 365,下面這個截圖是連接到我自己的做了面向互聯網部署(IFD)的環境示例。
如果是連接到Dynamics 365 Customer Engagement Online,請參考下圖:
點擊【Register】 > 【Register New Assembly】。
選擇前面步驟編譯生成的插件程序集,Isolation Mode一般建議選擇Sandbox,而且Dynamics Customer Engagement Onine也只能選擇Sandbox,強烈建議選擇存儲到Database,點擊【Register Selected Plugins】按鈕,如果看不到該按鈕,是你的電腦分辨率太低所致,就用Tab鍵盤來輔助操作吧。
如果沒有錯誤的話會彈出類似如下對話框:
還需要右擊創建的Plugin,選擇【Register New Step】按鈕。
我這里設置如下,是注冊在lw_workorder的Create消息的PreOperation階段,其余的就不一一解釋了,請參考官方文檔,點擊【Register New Step】按鈕。
注冊成功后可以看到最終的結果類似如下:
剩下的工作就是測試了,使用InvalidPluginExecutionException拋出的異常信息在界面顯示效果如下: