首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >插件和工作流的抽象类

插件和工作流的抽象类
EN

Stack Overflow用户
提问于 2016-06-13 14:14:18
回答 2查看 2.4K关注 0票数 5

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

代码语言:javascript
复制
/// <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();
    }
}

代码语言:javascript
复制
/// <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();
    }     
}

下面是我如何创建一个插件:

代码语言:javascript
复制
public class CalculateTaxesOnUpdate : BasePlugin
{

    public override void ExecutePluginLogic()
    {
        //From there I don't need to instanciate anything...neat!
    }
}

当涉及到启动IOrganizationServiceITracingService的实例时,这似乎很好,并且有助于减少锅炉板代码。

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

由于我不会重用它们并以任何方式重新启动它们(这是在Execute中实例化所有东西时会发生的情况),所以我不知道这是否是一个问题,但我是否违背了这里的最佳实践?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-06-13 17:37:41

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

来自writingbasic

为了提高性能,Microsoft Dynamics缓存插件实例。插件的执行方法应该是无状态的,因为并不是每次插件调用都会调用构造函数。此外,多个系统线程可以同时执行插件.每个调用状态信息都存储在上下文中,因此不应使用全局变量或尝试将任何数据存储在成员变量中,以便在下一次插件调用期间使用,除非该数据是从提供给构造函数的配置参数中获取的。对插件注册的更改将导致重新初始化插件。

类级变量违反了这种无状态需求。

我的建议是重写插件(然后对工作流执行同样的操作),使对象能够保存对Execute的每次调用的引用,从而允许代码满足无状态需求。

代码语言:javascript
复制
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上。

票数 7
EN

Stack Overflow用户

发布于 2018-03-01 15:12:34

此外,即使您曾经使基类泛化(可能基于它检索的上下文类型),您仍然需要将: IPlugin接口添加到所有插件中,即使基类定义了它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37792030

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档