插件和工作流的抽象类

时间:2016-06-13 14:14:18

标签: c# .net dynamics-crm-2011 dynamics-crm-2016

我已经在我的插件和工作流程中创建了以下两个抽象类:

/// <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的实例时减少锅炉板代码。

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

因为我没有重复使用它们并且无论如何重新启动它们(这是当你在null中实现所有内容时会发生的事情),我不知道这是否是一个问题,但我是否反对最好在这里练习?

2 个答案:

答案 0 :(得分:6)

仅仅因为它是一个基类并没有消除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上。

答案 1 :(得分:0)

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