【问题标题】:Dependency Injection in MS Dynamics CRMMS Dynamics CRM 中的依赖注入
【发布时间】:2014-02-04 02:46:54
【问题描述】:

我目前开始使用插件扩展 Microsoft Dynamics CRM。

是否可以向这些插件添加依赖注入(用于测试、松散耦合等目的)?我在哪里可以注册我的 IoC 容器,以便在所有相同类型的插件上使用它?

【问题讨论】:

标签: c# dynamics-crm-2011 dynamics-crm


【解决方案1】:

我们一直在尝试对 Dynamics CRM 应用程序进行单元测试和应用依赖注入。不幸的是,随着微软支持和顾问的确认,没有支持的方式来做到这一点。您可以将所有插件业务逻辑转移到另一个业务类并应用依赖注入或停止考虑它。

如果您选择使用 Dynamics CRM 进行反击,您需要在插件超类上定义一个静态字段,该类将成为您的 DI 容器。如下,

public abstract class SuperPlugin : IPlugin{
       public void Execute(IServiceProvider serviceProvider){
            // initialize a static container instance if not available
            var containerWrapper = new ContainerWrapper{
                Container = serviceProvider.GetService(typeof(IPluginExecutionContext)),
                Resolver = //static resolver instance of dependency container
            };
            OnExecution(containerWrapper);
       }
       public abstract void OnExecution(IDependencyResolver resolver);
}

我真的不明白为什么微软不简单地让我们将一些组件注册到他们在内部使用的 IServiceProvider 实现中。

附言。由于您的 SuperPlugin 类是 IPlugin,您可能忘记在子类上编写接口实现。但是我们在官方 Dynamics CRM SDK 附带的插件注册工具上遇到了一些错误。因此,如果您可能遇到同样的问题,您还应该按如下方式实现您的插件,

public class MyPlugin : SuperPlugin, IPlugin{
  public abstract void OnExecution(IDependencyResolver resolver){};
}

编辑:看一个解释https://github.com/nakahparis/DIForCRM概念的小例子

【讨论】:

  • 不错的解决方法。你将如何实例化依赖解析器?使用静态类还是单例结构?我有点担心使用静态解析器,因为您需要一个完全同步的依赖解析器(可以同时被多个线程访问),同时性能足以处理许多并发插件。对此有什么想法吗?
  • 是的,你是对的,但由于没有其他方法我更喜欢使用 Lazy :) 检查我创建的要点,gist.github.com/msusur/e34be94cbceac20ea364 但您还需要将 Setup 方法和 Factory 方法分开到其他类以应用单一职责。
  • 很好的解决方案!谢谢!
  • 您好 jrosseel,我有一个关于动态 crm 门户的案例,您可以投票要求微软添加此功能。 connect.microsoft.com/dynamicssuggestions/feedback/details/…
【解决方案2】:

CRM 中的插件是单元测试的祸根:

  • 非插件测试的问题
    • 无法暂时禁用
    • 很容易忘记它正在运行
  • 测试插件本身的问题
    • 无法进行单元测试并附加到进程
    • 有很多要模拟的东西、管道、服务提供商等
    • 多线程运行

这使我找到了以下测试插件的解决方案:

  • 尽快摆脱插件上下文,立即从中提取所需的所有对象和服务。
  • 创建一个ExecutePlugin 方法来挂钩单元测试,并在从插件上下文中提取对象后立即调用此方法。
  • 将尽可能多的代码推入业务层。

这导致插件看起来像这样(大量使用扩展方法以使其更简单):

public void Execute(IServiceProvider provider)
{
    var context = provider.GetContext();
    var service = provider.GetService(context);
    var target = GetTarget<Contact>(context);
    if (target == null || !target.ContainsAllNonNull(c => new
        {
            c.FirstName,
            c.LastName,
        }))
    {
        // Entity is of the wrong type, or doesn't contain all of the required attributes
        return;
    }

    ExecutePlugin(service, target);
}

public void ExecutePlugin(IOrganizationService service, Contact target){
    // Logic Goes Here
}

完成此操作后,您唯一需要对 ExceutePlugin 进行单元测试的就是您自己的 IOrganizationService,它会模拟所需的调用,然后您就完成了单元测试。我什至不费心对Execute 方法进行单元测试。要么它会起作用,要么它不会在 CRM 中首次使用时大吃一惊。

【讨论】:

  • 感谢 CRM 测试指南!我仍然想知道依赖注入,你知道吗?
  • @jrosseel 我假设这是用于单元测试?您希望模拟/存根哪些依赖项?
猜你喜欢
  • 2012-05-21
  • 2016-02-12
  • 1970-01-01
  • 2018-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多