简体   繁体   中英

Dependency Injection in MS Dynamics CRM

I am currently getting started with the extending of Microsoft Dynamics CRM using Plugins.

Is it possible to add Dependency injection to these plugins (for testing, loose coupling, etc. purposes)? Where can I register my IoC-container so that it's used over all the plugins of the same type?

Plugins in CRM are the Bane of Unit Testing:

  • Issues with non-plugin test
    • No way to temporarily disable
    • Easy to forget it is running
  • Issues with testing plugins themselves
    • Unable to unit test and attach to process
    • A lot to mock out, Pipeline, Service Provider etc
    • Runs multi-threaded

This has led me to the following solution for testing plugins:

  • Get rid of the plugin context as quickly as possible, extracting out all objects and service required from it right away.
  • Create an ExecutePlugin method to hook unit tests into, and immediately call this method after extracting the objects from the plugin context.
  • Push as much code as possible into the business layer.

This results in plugins that look like this (with a heavy use of extension methods to make this simpler):

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
}

Once this is done, the only thing you need to unit test the ExceutePlugin is your own IOrganizationService that mocks out the required calls and you have your unit testing done. I don't even bother unit testing the Execute method. Either it'll work, or it won't and blow chow on the first use from within CRM.

We've been trying to unit test and apply dependency injection on our Dynamics CRM application. Unfortunately, as Microsoft support and consultants are confirmed, there is no supported way to do it. You may either transfer all of your plugin business logic to an another business class and apply dependency injection or stop thinking about it.

If you choose to fight back with Dynamics CRM, you need to define a static field on a plugin super class which will be your DI Container. As follows,

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);
}

I really cannot understand why Microsoft doesn't simply let us register some components to the IServiceProvider implementation that they are using internally.

Ps. Since your SuperPlugin class is an IPlugin, you may forget to write the interface implementation on the sub class. But we encountered some bugs on Plugin Registration tool that is shipped with official Dynamics CRM SDK. So in case you may have the same problem you should also implement your plugins as follows,

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

Edit: See a small example that explains the concept https://github.com/nakahparis/DIForCRM

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM