插件和工作流的抽象类

问题描述 投票:4回答:2

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

/// <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的实例。

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

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

c# .net dynamics-crm-2011 dynamics-crm-2016
2个回答
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上。


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.