【问题标题】:Best Design Pattern for writing CRM 2011 Plugins编写 CRM 2011 插件的最佳设计模式
【发布时间】:2012-06-21 06:42:03
【问题描述】:

由于客户提供的复杂请求,有时我的代码会变得杂乱无章。 我花时间阅读和理解自上次工作以来我所写的内容,但这需要时间。

我想知道是否有人实现了一种很好的设计模式,可以节省时间并使代码更有条理和可读性等等。

【问题讨论】:

  • 您认为代码的哪一部分变得最无组织/不可读?

标签: c# dynamics-crm-2011


【解决方案1】:

拥有一个实现 IPlugin 的基础插件是朝着正确方向迈出的一大步。它的 Execute 函数可以将 IServiceProvider 以及您的 dataContext 或 OrganizationService 传递到抽象的 onExecute 方法中,该方法包含在带有虚拟错误处理程序方法的 try catch 中。这将消除大量重复的样板代码...

编辑 1

添加了显示抽象 OnExecute 和虚拟错误处理程序的代码示例:

public abstract class PluginBase : IPlugin
{

    public void Execute(IServiceProvider serviceProvider)
    {
        try
        {
            OnExecute(serviceProvider);
        }
        catch (Exception ex)
        {
            bool rethrow = false;
            try
            {
                OnError(ex);
            }
            catch
            {
                rethrow = true;
            }

            if (rethrow)
            {
                throw;
            }
        }
        finally
        {
            OnCleanup();
        }
    }

    // method is marked as abstract, all inheriting class must implement it
    protected abstract void OnExecute(IServiceProvider serviceProvider);

    // method is virtual so if an inheriting class wishes to do something different, they can
    protected virtual void OnError(Exception ex){
        // Perform logging how ever you log:
        Logger.Write(ex);
    }

    /// <summary>
    /// Cleanup resources.
    /// </summary>
    protected virtual void OnCleanup()
    {
        // Allows inheriting class to perform any cleaup after the plugin has executed and any exceptions have been handled
    }
}

编辑 2

我在 DLaB.Xrm.Plugin 命名空间的 DLaB.Xrm(在 Nuget 上)中定义了一个插件库,可以为您处理很多很棒的事情。 Here 是一个示例插件类,向您展示如何使用它。

【讨论】:

  • Daryl,您能否说明一下您的想法,因为我没有得到“抽象的 onExecute 方法”和“虚拟错误处理程序”。
  • 基本同意BasePlugin的想法。它允许您减少重复代码,例如SetState 请求,Association 请求这种事情。您甚至可以包含一个 ObjectTypeCode 枚举。而是取决于您的要求(有多少插件?他们在做什么?)。还要考虑您的目标安装位置 - 如果将插件安装到数据库,则必须在服务器 GAC 中安装额外的 DLL。
  • 请在下面找到更新的链接:github.com/daryllabar/XrmUnitTest/blob/…
【解决方案2】:

我的工作基于 2 个类:

第一个叫PluginContext

using System;

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;

/// <summary>
/// The plugin context.
/// </summary>
public class PluginContext
{
    #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="PluginContext"/> class.
        /// </summary>
        /// <param name="serviceProvider">
        /// The service provider.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// </exception>
        public PluginContext(IServiceProvider serviceProvider)
        {
            if (serviceProvider == null)
            {
                throw new ArgumentNullException("serviceProvider");
            }

            // Obtain the execution context service from the service provider.
            this.PluginExecutionContext =
                (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            // Obtain the tracing service from the service provider.
            this.TracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            // Obtain the Organization Service factory service from the service provider
            var factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

            // Use the factory to generate the Organization Service.
            this.OrganizationService = factory.CreateOrganizationService(this.PluginExecutionContext.UserId);

            this.OrganizationServiceContext = new OrganizationServiceContext(this.OrganizationService);
        }

        #endregion

    #region Properties

        /// <summary>
        /// Gets the organization service.
        /// </summary>
        /// <value>
        /// The organization service.
        /// </value>
        public IOrganizationService OrganizationService { get; private set; }

        /// <summary>
        /// Gets the plugin execution context.
        /// </summary>
        /// <value>
        /// The plugin execution context.
        /// </value>
        public IPluginExecutionContext PluginExecutionContext { get; private set; }

        /// <summary>
        /// Gets the service provider.
        /// </summary>
        /// <value>
        /// The service provider.
        /// </value>
        public IServiceProvider ServiceProvider { get; private set; }

        /// <summary>
        /// Gets the tracing service.
        /// </summary>
        /// <value>
        /// The tracing service.
        /// </value>
        public ITracingService TracingService { get; private set; }

        /// <summary>
        /// Gets the organization service context.
        /// </summary>
        /// <value>
        /// The organization service context.
        /// </value>
        public OrganizationServiceContext OrganizationServiceContext { get; private set; }

        #endregion

    #region Methods

        /// <summary>
        /// The trace.
        /// </summary>
        /// <param name="message">
        /// The message.
        /// </param>
        public void Trace(string message)
        {
            if (string.IsNullOrWhiteSpace(message) || this.TracingService == null)
            {
                return;
            }

            if (this.PluginExecutionContext == null)
            {
                this.TracingService.Trace(message);
            }
            else
            {
                this.TracingService.Trace(
                    "{0}, Correlation Id: {1}, Initiating User: {2}", 
                    message, 
                    this.PluginExecutionContext.CorrelationId, 
                    this.PluginExecutionContext.InitiatingUserId);
            }
        }

        #endregion
}

第二个叫PluginBase

using System;

using Microsoft.Xrm.Sdk;

/// <summary>
///     Base class for all Plugins.
/// </summary>
public abstract class PluginBase : IPlugin
{
    #region Public Properties

    /// <summary>
    ///     Gets the entity reference.
    /// </summary>
    /// <value>
    ///     The entity reference.
    /// </value>    
    public EntityReference EntityReference { get; private set; }

    /// <summary>
    ///     Gets the plugin context.
    /// </summary>
    /// <value>
    ///     The plugin context.
    /// </value>    
    public PluginContext LocalContext { get; private set; }

    #endregion

    #region Properties

    /// <summary>
    ///     Gets a value indicating whether [ignore plugin].
    /// </summary>
    /// <value>
    ///     <c>true</c> if [ignore plugin]; otherwise, <c>false</c>.
    /// </value>
    /// <created>1/5/2014</created>
    protected virtual bool IgnorePlugin
    {
        get
        {
            return false;
        }
    }

    #endregion

    #region Public Methods and Operators

    /// <summary>
    /// Executes the specified service provider.
    /// </summary>
    /// <param name="serviceProvider">
    /// The service provider.
    /// </param>    
    public void Execute(IServiceProvider serviceProvider)
    {
        if (this.IgnorePlugin)
        {
            return;
        }

        this.LocalContext = new PluginContext(serviceProvider);

        if (!this.LocalContext.PluginExecutionContext.InputParameters.Contains("Target"))
        {
            return;
        }

        var entity = this.LocalContext.PluginExecutionContext.InputParameters["Target"] as Entity;
        if (entity != null)
        {
            this.EntityReference = entity.ToEntityReference();
        }
        else
        {
            this.EntityReference =
                this.LocalContext.PluginExecutionContext.InputParameters["Target"] as EntityReference;
            if (this.EntityReference == null)
            {
                return;
            }
        }

        this.Execute();
    }

    /// <summary>
    ///     Executes this instance.
    /// </summary>    
    public abstract void Execute();

    #endregion
}

插件类应该是这样的:

public class SamplePlugin : PluginBase
{
    // If don't want the plugin to be executed then override the IgnorePlugin property

    protected override bool IgnorePlugin
    {
        get
        {
            return true;
        }
    }

    public override void Execute()
    {
        var query = LocalContext
            .OrganizationServiceContext
            .CreateQuery("account")
            .Where(a => (string)a["accountname"] == "test accounts")
            .ToList();
    }
}

【讨论】:

  • 我使用了一个类似的概念——随着我的框架的发展,我已经实现了更多的逻辑。其中之一是添加“跟踪日志”-> 跟踪调用列表,并且当调试设置为 true 作为其他地方的标志时-它将抛出它在执行插件期间收到的跟踪的联合列表。
【解决方案3】:

我知道我可能迟到了,但是...

有几个 Visual Studio 插件模板,这些示例将让您了解什么是最好的。

我最喜欢的一个是:http://pogo69.wordpress.com/2011/04/15/crm-2011-visual-studio-plugin-templates/

无论如何,你必须知道,最终你的逻辑设计会改进并变得更好,你所需要的只是练习。

问候!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    • 2011-09-30
    相关资源
    最近更新 更多