使用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类可以供开发者比较清楚地使用枚举类型的成员了。