我在我的插件和工作流中创建了以下两个抽象类:
/// <summary>
/// Base plugin class. Provides access to most often used Xrm resources.
/// </summary>
public abstract class BasePlugin : IPlugin
{
public IServiceProvider ServiceProvider { get; set; }
public ITracingService TracingService { get; set; }
public IPluginExecutionContext PluginContext { get; set; }
public IOrganizationService Service { get; set; }
public void Execute(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
TracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
PluginContext = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
Service = serviceFactory.CreateOrganizationService(PluginContext.UserId);
ExecutePluginLogic();
}
public virtual void ExecutePluginLogic()
{
throw new NotImplementedException();
}
}
和
/// <summary>
/// Base workflow class. Provides access to most often used Xrm resources.
/// </summary>
public abstract class BaseWorkflow : CodeActivity
{
public CodeActivityContext CodeActivityContext { get; set; }
public IWorkflowContext WorkflowContext { get; set; }
public ITracingService TracingService { get; set; }
public IOrganizationService Service { get; set; }
protected override void Execute(CodeActivityContext context)
{
IOrganizationServiceFactory serviceFactory = context.GetExtension<IOrganizationServiceFactory>();
CodeActivityContext = context;
TracingService = context.GetExtension<ITracingService>();
WorkflowContext = context.GetExtension<IWorkflowContext>();
Service = serviceFactory.CreateOrganizationService(WorkflowContext.UserId);
ExecuteWorkflowLogic();
}
public virtual void ExecuteWorkflowLogic()
{
throw new NotImplementedException();
}
}
这是我如何创建一个插件:
public class CalculateTaxesOnUpdate : BasePlugin
{
public override void ExecutePluginLogic()
{
//From there I don't need to instanciate anything...neat!
}
}
这似乎工作得很好,有助于减少锅炉板代码,即启动IOrganizationService
和ITracingService
的实例。
但我注意到在短暂延迟触发的一些消息(即:Update
的invoicedetail
)上,在第一次执行时,BasePlugin
的公共属性是null
(预期)然后在接下来的执行中,它们已经启动( ??)。我注意到这是一个问题,因为我在基类中有一个Dispose
方法,它会在执行ExecutePluginLogic
后将属性设置为null,然后其他线程会尝试使用null
属性。
因为我不会重复使用它们并且无论如何重新启动它们(这是当你在Execute
中实现所有内容时会发生的事情),我不知道这是否是一个问题,但我是否反对这里的最佳做法?
仅仅因为它是一个基类并没有消除CRM插件(和工作流程)中类级别变量的问题。
来自https://msdn.microsoft.com/en-us/library/gg328263.aspx#bkmk_writingbasic:
为了提高性能,Microsoft Dynamics CRM缓存插件实例。应该将插件的Execute方法编写为无状态,因为每次调用插件时都不会调用构造函数。此外,多个系统线程可以同时执行插件。所有每个调用状态信息都存储在上下文中,因此您不应使用全局变量或尝试将任何数据存储在成员变量中,以便在下一个插件调用期间使用,除非该数据是从提供给构造函数的配置参数中获取的。对插件注册的更改将导致插件重新初始化。
具有类级别变量违反了此无状态要求。
我的建议是重写插件(然后为工作流做同样的事情),让对象保存每次调用Execute
的引用,从而允许代码满足无状态要求。
public class CrmObjects
{
public IServiceProvider ServiceProvider { get; set; }
public ITracingService TracingService { get; set; }
public IPluginExecutionContext PluginContext { get; set; }
public IOrganizationService Service { get; set; }
}
public abstract class BasePlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var crmObjects = new CrmObjects();
crmObjects.ServiceProvider = serviceProvider;
crmObjects.TracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
crmObjects.PluginContext = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
crmObjects.Service = serviceFactory.CreateOrganizationService(crmObjects.PluginContext.UserId);
ExecutePluginLogic(crmObjects);
}
public virtual void ExecutePluginLogic(CrmObjects crmObjects)
{
throw new NotImplementedException();
}
}
几年前,我写了一篇关于做类似事情的博客文章http://nicknow.net/dynamics-crm-2011-abstracting-plugin-setup/。在我描述的模型中,它不依赖于基类,而是使用在Execute
方法的第一行上实例化的类来实现相同的概念。我已经转移到基类模型 - 类似于这个设计。当我有机会时,我会把它放在GitHub上。
此外,即使您使基类具有通用性(可能基于它检索的上下文类型),您也需要将: IPlugin
接口添加到所有插件中,即使基类定义它也是如此。