插件和工作流摘要 类

Abstract classes for plugins and workflows

我创建了以下两个摘要 类 我在我的插件和工作流程中使用:

/// <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!
    }
}

这似乎工作正常,有助于减少启动 IOrganizationServiceITracingService 实例时的样板代码。

但我注意到,在某些消息(即:invoicedetailUpdate)上,在第一次执行时会短暂延迟触发,public 的属性 BasePluginnull(这是预期的)然后在接下来的执行中,它们已经启动(??)。我注意到这是一个问题,因为我在基础 类 中有一个 Dispose 方法,它会在执行 ExecutePluginLogic 后将属性设置为空,然后其他线程会尝试使用 null特性。

因为我不会重用它们并重新启动它们(不管怎样,当你在 Execute 中实例化所有东西时会发生这种情况),我不知道这是否是一个问题,但我要反对此处的最佳做法?

仅仅因为它是基础 class 并不能消除 CRM 插件(和工作流程)中 class 级别变量的问题。

来自https://msdn.microsoft.com/en-us/library/gg328263.aspx#bkmk_writingbasic

For improved performance, Microsoft Dynamics CRM caches plug-in instances. The plug-in's Execute method should be written to be stateless because the constructor is not called for every invocation of the plug-in. Also, multiple system threads could execute the plug-in at the same time. All per invocation state information is stored in the context, so you should not use global variables or attempt to store any data in member variables for use during the next plug-in invocation unless that data was obtained from the configuration parameter provided to the constructor. Changes to a plug-ins registration will cause the plug-in to be re-initialized.

具有 class 级变量违反了此无状态要求。

我的建议是重写插件(然后对工作流执行相同的操作)以拥有一个对象来保存对 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/。在我描述的模型中,它不依赖于基础 class,而是使用在 Execute 方法的第一行实例化的 class 来完成相同的概念。我已经转向基本 class 模型 - 类似于此设计。如果有机会,我会在 GitHub.

上发布

此外,即使您将基础 class 设为通用(可能基于它检索的上下文类型),您也需要将 : IPlugin 接口添加到所有插件,即使基础 class 定义了它。