How to Do Dependency Injection in a CRM Plugin

I first approached this because I thought it was ridiculous how our current mega-Plugins that handle all of our integrations were impossible to debug. I needed a way to separate the logic from the instantiation of the plugins inside of CRM. CRM introduces a ton of constraints as far as being able to code cleanly and take advantage of patterns that make the code maintainable and debuggable.

I usually use either the constructor or property injection patterns, as needed, from “Dependency Injection in .NET” by Mark Seemann http://www.manning.com/seemann/. So the first thing I did was separate out a logic layer from the Plugin. I couldn’t use constructor injection directly in the parent Plugin class because CRM caches the instantiation of Plugin classes to be used amongst the pool of messages triggering the plugin for performance.

Public Sub Execute(ByVal context As IPluginExecutionContext) Implements IPlugin.Execute

    If context.Depth > 1 Then
        Return
    End If

    Dim logWriter As ILogWriter = New LogWriter("...", "ON")
    Dim roiService As IROIService = New ROIService(_IsCRMTestServer)
    Dim crmService As ICrmService = context.CreateCrmService(True)
    Dim quoteStateUtils As IQuoteStateUtilities = New QuoteStateUtilities(crmService, logWriter)

    logWriter.WriteLine("*****************************************************************")
    logWriter.WriteLine("This plugin is on the " + IIf(_IsCRMTestServer = True, "test", "live") + " CRM server.")

    // CONSTRUCTOR DI...
    // THIS PREVENTS INSTANCE CACHING ISSUE IN CRM
    Dim quoteStateLogic As QuoteStateLogic = New QuoteStateLogic(logWriter, quoteStateUtils, roiService, crmService)

    quoteStateLogic.Execute(context)

End Sub

Public Class QuoteStateLogic

    Private ReadOnly _logWriter As ILogWriter
    Private ReadOnly _roiService As IROIService
    Private ReadOnly _crmService As ICrmService
    Private ReadOnly _quoteStateUtils As IQuoteStateUtilities

    Public Sub New(logWriter As ILogWriter, quoteStateUtils As IQuoteStateUtilities, roiService As IROIService, crmService As ICrmService)

        Me._logWriter = logWriter
        Me._quoteStateUtils = quoteStateUtils
        Me._roiService = roiService
        Me._crmService = crmService

    End Sub

Public Sub Execute(ByVal context As IPluginExecutionContext) {
...

With this, I’ve achieved the end goal, which was to remove the plugin logic’s dependency on concrete implementations. So the fact that the main Plugin.Execute() is now the composition root for the QuoteStateLogic class, I have complete control over the Plugin’s dependencies and I have taken away the responsibility of the logic-only class to instantiate its own dependencies. I was able to write a huge suite of unit tests and ignore my integration tests unless I absolutely needed them. I was also able to generate XML test fixtures using the CrmService’s Entity-serialization constructs.

Tweet
comments powered by Disqus