使用CrmSvcUtil.exe創建代碼生成工具擴展選項集的代碼生成,並解決UnknownLabel命名的問題
關於CrmSvcUtil.exe工具
我們知道CrmSvcUtil.exe 是用於 Microsoft Dynamics 365(在線或本地) 的一個命令行代碼生成工具。 該工具可生成表示 Microsoft Dynamics 365 使用的實體數據模型的前期綁定 .NET Framework 類。
下載方法:Download tools from NuGet
- 在內部部署版本里可以使用以下命令生成代碼
CrmSvcUtil.exe /url:http://d365opServer:5555/Dynamics365/XRMServices/2011/Organization.svc /out:AllEntitiesOP.cs /username:simonsh /password:XXXXXX /domain:d365op.net /namespace:net.mymuch
隨即會生成所有Entity的早期類。導入到VS解決方案中即可使用。
- 在Online版本里可以使用以下命令生成代碼
CrmSvcUtil.exe /url:https://XXX.api.crm.dynamics.com/XRMServices/2011/Organization.svc /out:AllEntitiesOnline.cs /username:simonsh@XXXX.com /password:XXXXX /namespace:net.mymuch
Dynamics365 Online版本加載的功能如果比較多的話,這個cs文件會比較大。
創建用於代碼生成工具的擴展
以上操作雖然可以生成所有Entity的早期類,但是當遇到一些特殊情況,無法滿足編程的需求,這個時候就要對Entity以外的內容進行擴展。CrmSvcUtil.exe工具還有另外一部分擴展參數可以使用。
參數名稱 | 接口名稱 | 說明 |
---|---|---|
/codecustomization | ICustomizeCodeDomService | 在 CodeDOM 生成完成後調用,假定爲 ICodeGenerationService 的默認實例。 這對生成其他類(如選擇列表中的常量)很有用。 |
/codewriterfilter | ICodeWriterFilterService | 在 CodeDOM 生成過程中調用(假定爲 ICodeGenerationService 的默認實例),以確定是否應生成特定對象或屬性。 |
/codewritermessagefilter | ICodeWriterMessageFilterService | 在 CodeDOM 生成過程中調用(假定爲 ICodeGenerationService 的默認實例),以確定是否應生成特定消息。 由於 Microsoft.Crm.Sdk.Proxy.dll 和 Microsoft.Xrm.Sdk.dll 中已生成消息,因此不應將其用於請求/響應。 |
/metadataproviderservice | IMetadataProviderService | 調用以從服務器中檢索元數據。 在生成過程中可能多次調用此參數,所以應緩存數據。 |
/codegenerationservice | ICodeGenerationService | CodeDOM 生成的核心實現。 如果發生更改,其他擴展可能無法按所述方式工作。 |
/namingservice | INamingService | 在 CodeDOM 生成過程中調用,以確定對象的名稱(假定爲默認實現)。 |
通過指定以上這些命令行參數和參數值,可以擴展代碼生成工具的功能。 若要指定參數,請向命令行中添加以下內容:/<參數名稱>:<類名稱>,<程序集名稱>。 請注意,程序集名稱不包括 .dll 擴展名。 作爲替代方式,也可以採用""的格式向配置文件中添加等效值。
詳見官方說明:Create extensions for the code generation tool
- 生成擴展的準備工作
以下我們以生成選項集的cs類爲例,首先需要找到Dynamics 365 CRM SDK 8.X版本下載,然後找到SampleCode\CS\CrmSvcUtilExtensions,裏面有兩個工程進行編譯。因爲是8.X的版本,如果要適用到9.X的CRM中,需要對工程的引用進行更新後再編譯。
- 編譯完後,把兩個DLL文件拷貝到跟CrmSvcUtil.exe工具同級目錄下
- CMD中執行以下命令,具體參數可以根據自己的需要進行修改。
CrmSvcUtil.exe /codewriterfilter:"Microsoft.Crm.Sdk.Samples.FilteringService,GeneratePicklistEnums" /codecustomization:"Microsoft.Crm.Sdk.Samples.CodeCustomizationService,GeneratePicklistEnums" /namingservice:"Microsoft.Crm.Sdk.Samples.NamingService,GeneratePicklistEnums" /url:https://XXXX.api.crm.dynamics.com/XRMServices/2011/Organization.svc /out:OptionSets.cs /username:simonsh@XXXX.com /password:XXXXXX /namespace:net.mymuch
-
生成的代碼
-
找到自定義的選項集
-
這裏發現了問題,自動生成的名字是UnknownLable開頭的,這就有點不爽了。
我的選項集定義是這樣的:
如果選項集的內容是英文的,會是正常的。
那麼對於中文定義的選項集內容就沒有辦法了嗎?
解決命名爲UnknownLabel的問題
-
首先導致這個UnknownLabel的原因是因爲CrmSvcUtil.exe工具裏引用到的方法不支持中文等Unicode字符爲命名的變量,當然當下不管是C#還是java雖然都已經支持了中文的變量,但是這樣做不合規矩。
-
解決的思路有下面的幾種:
一, 如果你的多語言支持中有英文的,可以切換dynamics365 的語言爲英文,定義的選項集自然爲英文,這個時候可以正常輸出變量。當然沒有英文支持的就悲劇了。
二,可以藉助第三方工具DDL,把取到的label的中文值轉換成拼音。
三,統一自定義選項集的命名規則,可以填寫外部值來命令對應的英文。 -
這裏我們選擇使用第三種思路,先修改自定義選項集的外部值,爲什麼選擇外部值這個屬性,我在最後會作說明。
-
修改官方sample代碼,如果名字中包含UnknownLabel字符並且外部值被定義的話,則用外部值代替。編譯好後,複製DLL到CrmSvcUtil.exe的同級目錄。
/// <summary>
/// Handles building the name for an Option of an OptionSet.
/// </summary>
public string GetNameForOption(OptionSetMetadataBase optionSetMetadata,
OptionMetadata optionMetadata, IServiceProvider services)
{
var name = DefaultNamingService.GetNameForOption(optionSetMetadata,
optionMetadata, services);
// 如果名字中包含UnknownLabel字符的
if (name.Contains("UnknownLabel"))
{
// 如果外部值不爲空
if (optionMetadata.ExternalValue != null && !optionMetadata.ExternalValue.Equals(""))
{
// Name設置爲外部值
name = optionMetadata.ExternalValue;
}
}
Trace.TraceInformation(String.Format("The name of this option is {0}",
name));
name = EnsureValidIdentifier(name);
name = EnsureUniqueOptionName(optionSetMetadata, name);
return name;
}
- 執行剛纔的命令
- 這是自動生成代碼中的這個選項名字就用外部值替換了。
- 另外,爲什麼選擇這個屬性,我查了一下官方文檔,沒有對這個外部值屬性做任何說明。可能是一種擴展屬性。至此,生成的cs類可以供開發者比較清楚地使用枚舉類型的成員了。