我是微软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 != )
{
throw new InvalidPluginExecutionException($"省份字段值选择有误!");
}
else
{
//城市字段用户选择了值才做校验
if(cityValue != Int32.MaxValue)
{
if (cityValue >= provinceValue && cityValue < provinceValue + )
{
tracingService.Trace($"城市字段选择了值,且属于正确的省份!");
}
else
{
throw new InvalidPluginExecutionException($"城市字段值选择有误!");
}
}
}
}
}
else if(buName == "Sub Unit")
{
//省份字段用户选择了值才校验
if (provinceValue != Int32.MaxValue)
{
if (provinceValue != )
{
throw new InvalidPluginExecutionException($"省份字段值选择有误!");
}
else
{
//城市字段用户选择了值才做校验
if (cityValue != Int32.MaxValue)
{
if (cityValue >= provinceValue && cityValue < provinceValue + )
{
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抛出的异常信息在界面显示效果如下:

Dynamics 365中开发和注册插件介绍的更多相关文章

  1. Dynamics 365中的应用程序介绍

    本人微信和易信公众号:微软动态CRM专家罗勇 ,回复275或者20180630可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong.me ...

  2. Dynamics 365中自定义工作流活动获取的上下文分析及注意事项

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复244或者20170306可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...

  3. Dynamics 365 CRM 开发架构简介

    Dynamics 365 CRM提供了多种编程模型,你可以灵活地按需选用最佳模式. 本文是对Dynamics 365 CRM编程模型的综述. 概览 下图表明了Dynamics 365 CRM的主要可编 ...

  4. 自定义工作流活动报错:您无法登陆系统。原因可能是您的用户记录或您所属的业务部门在Microsoft Dynamics 365中已被禁用。

    本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复265或者20170926可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong.me ...

  5. 将Dynamics 365中的用户及其角色、角色导出到Excel中

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复240或者20161204可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...

  6. Dynamics 365中配置和使用文件夹级别的跟踪(folder-level tracking)

    本人微信和易信公众号:微软动态CRM专家罗勇 ,回复274或者20180630可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong.me ...

  7. Dynamics 365工作流报错:您无法登陆系统。原因可能是您的用户记录或您所属的业务部门在Microsoft Dynamics 365中已被禁用。

    本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复265或者20170926可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong.me ...

  8. Dynamics 365中的非交互式账号(Non-interactive User)介绍

    摘要: 本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复272或者20180616可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyon ...

  9. Dynamics 365中的事件框架与事件执行管道(Event execution pipeline)

    本文介绍了Microsoft Dynamics 365(以下简称D365)中的两个概念,事件框架(Event Framework)与事件执行管道(Event execution pipeline). ...

随机推荐

  1. es6 proxy浅析

    Proxy 使用proxy,你可以把老虎伪装成猫的外表,这有几个例子,希望能让你感受到proxy的威力. proxy 用来定义自定义的基本操作行为,比如查找.赋值.枚举性.函数调用等. proxy接受 ...

  2. openstack学习之neutron ml2初始化代码分析

    这里没有 去详细考虑neutron server怎么初始化的,而是直接从加载插件的地方开始分析.首先我们看下下面这个文件. Neutron/api/v2/router.py class APIRout ...

  3. BZOJ 1861书架

    小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引 ...

  4. HDU 6118 度度熊的交易计划(网络流-最小费用最大流)

    度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题: 喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区. 由于生产能力的区别,第i个片区能够花费a[i]元生产1个商品,但 ...

  5. hdu-4638

    There are n men ,every man has an ID(1..n).their ID is unique. Whose ID is i and i-1 are friends, Wh ...

  6. 《手把手教你》系列进阶篇之4-python+ selenium自动化测试 - python几种超神操作你都知道吗?(详细教程)

    1. 简介 今天分享和讲解的超神操作,对于菜鸟来说是超神的操作,对于大佬来说也就是几个简单方法的封装和调用.这里讲解和分享这部分主要是为了培养小伙伴们和童鞋们的面向对象的开发思维,对比这样做的好处让你 ...

  7. Python3 函数进阶2

    目录 迭代器 可迭代对象 迭代器对象 总结和补充 列表推导式 字典生成式 zip()函数 递归 迭代器 迭代器是访问容器类数据类型元素的一种方式 迭代器是一个可以记住遍历的位置的对象 迭代器对象从容器 ...

  8. 【Java Web开发学习】Spring4整合thymeleaf视图解析

    [Java Web开发学习]Spring4整合thymeleaf视图解析 目录 1.简单介绍2.简单例子 转载:https://www.cnblogs.com/yangchongxing/p/9111 ...

  9. selenium滑块操作

    from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains from ...

  10. Enumeration接口和Iterator接口的区别有哪些?

    Enumeration速度是Iterator的2倍,同时占用更少的内存.但是,Iterator远远比Enumeration安全,因为其他线程不能够修改正在被iterator遍历的集合里面的对象.同时, ...