首页 > 代码库 > Dynamic CRM 2013学习笔记(二)插件基本用法及调试

Dynamic CRM 2013学习笔记(二)插件基本用法及调试

插件是可与 Microsoft Dynamics CRM 2013 和 Microsoft Dynamics CRM Online 集成的自定义业务逻辑(代码),用于修改或增加平台的标准行为。也可以将插件认为是针对 Microsoft Dynamics CRM 触发的事件的处理程序。您可以让插件订阅或注册已知事件集,以便在事件发生时运行您的代码。

 

一、基本用法

1. 要继承IPlugin,并实现Excute方法 ( 1- 3 行)

2. 从service provide 里获取执行上下文 ( 5行 )

3. 我们可以检查触发插件的实体名称 ( 7 – 11 行)

4. 还可以检查触发的事件,是create, update 还是delete (12 – 16行 )

5. 输入参数里获取触发的实体 ( 20 行 )

6. 通过service factory获取IOrganizationService,当CreateOrganizationService方法的参数为null时,表示的是系统用户,当参数为context.UserId 或Guid.Empty时,表示的是当前用户 ( 21 – 23行)

7. 最后是DoAction方法,插件的逻辑就可以在这里实现了。

  1: public class new_marketing_plan_updatePost : IPlugin
  2:     {
  3:         public void Execute(IServiceProvider serviceProvider)
  4:         {
  5:             IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
  6: 
  7:             //检查实体名称
  8:             if (context.PrimaryEntityName.ToLower() != "new_marketing_plan")
  9:             {
 10:                 throw new InvalidPluginExecutionException("Entity is not Marketing Plan");
 11:             }
 12:             // 检查消息是否正确
 13:             if (context.MessageName.ToLower() != "update")
 14:             {
 15:                 throw new InvalidPluginExecutionException("message is not Update");
 16:             }
 17: 
 18:             if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
 19:             {
 20:                 Entity entity = (Entity)context.InputParameters["Target"];
 21:                 IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
 22:                 IOrganizationService userService = serviceFactory.CreateOrganizationService(context.UserId);
 23:                 IOrganizationService adminSerivce = serviceFactory.CreateOrganizationService(null);
 24: 
 25:                 DoAction(adminSerivce, userService, entity);
 26:             }
 27:         }
 28:    }

 

二、删除插件

根据上面的介绍,获取当前实体的时是用的这种方式:

  1: Entity entity = (Entity)context.InputParameters["Target"];

但是对于删除事件,就不能这样获取了,这时应该通过下面的方式来获取:

  1: EntityReference er = context.InputParameters["Target"] as EntityReference;
  2: CurrentEntity = new Entity(er.LogicalName);
  3: CurrentEntity.Id = er.Id;
第一次写删除的插件,这个问题困扰了我好长时间。
 

三、用Unit Test调试插件

1. 下载Rhino.Mocks

2. 添加引用到unit test项目

Microsoft.Crm.sdk.proxy

Microsoft.Xrm.Client

Microsoft.Xrm.Sdk

Rhino.Mocks

System.Runtime.Serialization

以及要调试的项目,这里是MarketingManage

image

3. 初始化unit test

这里,我们用Rhino.Mocks来模拟IServiceProvider, IPluginExecutionContext, IOrganizationServiceFactory, IOrganizationService等变量。

(1)获取CRM连接 ( 12 – 14 行 )

(2)用Rhino.Mocks来模拟IServiceProvider, IPluginExecutionContext, IOrganizationServiceFactory, IOrganizationService ( 16 – 20 行 )

  1:         public IServiceProvider serviceProvider;
  2:         public IPluginExecutionContext context;
  3:         public IOrganizationServiceFactory factory;
  4:         public IOrganizationService service;
  5:         public String prefix = "new_";
  6:         public String customEntityName;
  7: 
  8:         [TestInitialize]
  9:         public void GetOrgService()
 10:         {
 11:             //跨域调试采用这个URL,同域用http://me-crm-01/crm即可
 12:             string server = "Url=http://crmdev:5555/CRM;Domain=xxx;Username=crmtest02;Password=abc-123";
 13: 
 14:             var myConnection = CrmConnection.Parse(server);
 15: 
 16:             serviceProvider = MockRepository.GenerateMock<IServiceProvider>();
 17:             context = MockRepository.GenerateMock<IPluginExecutionContext>();
 18:             factory = MockRepository.GenerateMock<IOrganizationServiceFactory>();
 19:             service = MockRepository.GenerateMock<IOrganizationService>();
 20:             service = new OrganizationService(myConnection);
 21:         }

 

4. 调试

下面就进入调试方法了:

(1)模拟一个Entity当作触发插件的实体 (4- 13行 )

(2)直接调试插件里的DoAction方法 (15-16 行 )

  1:         [TestMethod]
  2:         public void TestApproePaymentrequest()
  3:         {
  4:             ParameterCollection paramBag = new ParameterCollection();
  5: 
  6:             XRMHelper helper = new XRMHelper(service);
  7:             Entity currentent = helper.GetInfoByAttrValue("new_marketing_plan", "new_name", "20140910-000004")[0];  
  8:             paramBag.Add("Target", currentent);
  9: 
 10:             context.Stub(x => x.InputParameters).Return(paramBag);
 11:             serviceProvider.Stub(x => x.GetService(typeof(IPluginExecutionContext))).Return(context);
 12:             serviceProvider.Stub(x => x.GetService(typeof(IOrganizationServiceFactory))).Return(factory);
 13:             factory.Stub(x => x.CreateOrganizationService(null)).Return(service);
 14: 
 15:             new_marketing_plan_updatePost mp = new new_marketing_plan_updatePost();
 16:             mp.DoAction(service, service, currentent);
 17:         }
 

四、 日志记录和跟踪

有时插件写好了,Unit Test也通过了,但注册完插件,在真实环境里运行时,还是报错,比如像Dynamic CRM 2013学习笔记(-)插件输入实体参数解析里遇到的错误,这时我们就要用到跟踪功能。

跟踪功能可以提供运行时插件信息,以帮助诊断插件故障的原因,从而帮助开发人员解决插件问题。

此处所说的跟踪不同于 ASP.NET 跟踪。跟踪是在 Microsoft Dynamics CRM SDK 中通过使用跟踪服务 ITracingService 而实施的。开发人员在插件代码中添加 Trace 语句,然后构建并部署插件。在执行过程中,只有当插件在运行时向平台传回异常时,用户才会看到跟踪信息。对于同步注册插件,跟踪信息会显示在 Microsoft Dynamics CRM Web 应用程序的对话框中。对于异步注册插件,跟踪信息会显示在 Web 应用程序中“系统作业”窗体的“详细信息”区域中。此类信息的数量和特点将取决于开发人员为插件编写的代码。

实施此类型跟踪的主要原因是为了支持 Microsoft Dynamics CRM 中的隔离(沙盒)插件和自定义工作流活动功能。沙盒自定义代码无法将信息写入到系统事件日志或文件系统中。通过实施跟踪服务,就为沙盒插件和自定义工作流活动提供了一种在抛出异常时输出运行时信息的方法。此外,非沙盒插件也支持跟踪功能。

用法:

(1) 初始化

  1: ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
(2) 添加Trace语句
  1: tracingService.Trace("In DoAction method");
 
实际上,我们可以在每个方法里try catch一下,这下可以快速定位到是哪个方法报错,再通过Trace语句来精确定位。
例如:
  1:             catch (Exception ex)
  2:             {
  3:                 throw new InvalidPluginExecutionException("GetQueryExpression error : " + ex.Message);
  4:             }
下面是我的一个真实的case:
image 

Dynamic CRM 2013学习笔记(二)插件基本用法及调试