2014-01-15 28 views
8

Ich bin derzeit mit der Erweiterung von Microsoft Dynamics CRM mit Plugins begonnen.Dependency Injection in MS Dynamics CRM

Ist es möglich, diesen Plugins Dependency Injection hinzuzufügen (für Tests, lose Kopplung usw.)? Wo kann ich meinen IoC-Container registrieren, so dass er über alle Plugins desselben Typs verwendet wird?

+0

Sie erklärt für diese Funktion auf https abstimmen: //ideas.dynamics.com/ideas/dynamics-crm/814208 –

Antwort

5

Wir haben versucht, Einheit-Test und Anwendung Abhängigkeitseinspeisung für unsere Dynamics CRM-Anwendung. Da Microsoft Support und Berater bestätigt sind, gibt es leider keinen unterstützten Weg. Sie können entweder Ihre gesamte Plugin-Geschäftslogik in eine andere Business-Klasse übertragen und die Abhängigkeitsinjektion anwenden oder aufhören, darüber nachzudenken.

Wenn Sie sich entscheiden, mit Dynamics CRM zu kämpfen, müssen Sie ein statisches Feld in einer Superklasse des Plugins definieren, die Ihr DI-Container sein wird. Wie folgt,

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

Ich kann wirklich nicht verstehen, warum Microsoft nicht einfach lassen Sie uns einige Komponenten der IServiceProvider Implementierung registrieren, die sie intern verwenden.

Ps.Da Ihre SuperPlugin-Klasse ein IP-Plugin ist, vergessen Sie möglicherweise, die Schnittstellenimplementierung für die Subklasse zu schreiben. Wir haben jedoch einige Fehler im Plugin-Registrierungstool festgestellt, das mit dem offiziellen Dynamics CRM SDK ausgeliefert wird. So im Falle können Sie das gleiche Problem haben, sollten Sie auch Ihre Plugins wie folgt implementieren,

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

Edit: ein kleines Beispiel sehen, dass das Konzept https://github.com/nakahparis/DIForCRM

+0

Schöne Workaround. Wie würden Sie den Dependency Resolver instanziieren? Verwenden Sie eine statische Klasse oder eine Singleton-Struktur? Ich bin ein bisschen besorgt über die Verwendung eines statischen Resolvers, da Sie einen Dependency Resolver benötigen, der vollständig synchronisiert ist (auf den mehrere Threads gleichzeitig zugreifen können) und gleichzeitig so leistungsfähig ist, dass viele gleichzeitige Plugins gehandhabt werden können. Irgendwelche Gedanken dazu? –

+1

Yeah, du hast Recht, aber da es keinen anderen Weg gibt, verwende ich lieber Lazy <> :) überprüfe den von mir erstellten Sinn, https://gist.github.com/msusur/e34be94cbceac20ea364, aber du musst auch die Setup-Methode trennen und Factory-Methode für andere Klassen, um die Einzelverantwortung anzuwenden. –

+0

Große Lösung! Vielen Dank! –

5

Plugins in CRM sind die Bane of Unit Testing:

  • Probleme mit nicht-Plugin Test
    • No way vorübergehend
    • Leicht zu deaktivieren, zu vergessen es läuft
  • Probleme mit dem Testen von Plugins selbst
    • Nicht in der Lage, Unit Test und befestigen
    • viel zu verarbeiten, um zu verspotten, Pipeline, Dienstleister etc.
    • Läuft multi-threaded

Das hat mich zum Testen Plugins zu folgenden Lösung führt:

  • Löschen Sie den Plugin-Kontext so schnell wie möglich und extrahieren Sie sofort alle benötigten Objekte und Dienste.
  • Erstellen Sie eine ExecutePlugin Methode, um Komponententests anzuhängen, und rufen Sie diese Methode sofort nach dem Extrahieren der Objekte aus dem Kontext des Plugins auf.
  • Schieben Sie so viel Code wie möglich in die Business-Schicht.

Dies führt zu Plugins, die wie folgt aussehen (mit einem schweren Einsatz von Erweiterungsmethoden dies einfacher zu machen):

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 
} 

Sobald dies geschehen ist, ist die einzige Sache, die Sie Unit-Test müssen die ExceutePlugin ist Ihre eigene IOrganizationService, die die erforderlichen Anrufe verspottet und Sie Ihre Unit-Tests durchgeführt haben. Ich störe nicht einmal Unit-Tests der Execute Methode. Entweder wird es funktionieren, oder es wird nicht funktionieren und blasen Chow bei der ersten Verwendung aus CRM heraus.

+0

Vielen Dank für diese nette Anleitung zum Testen in CRM! Ich wundere mich immer noch über Dependency Injection, weißt du etwas darüber? –

+0

@jrosseel Ich gehe davon aus, dass dies für Unit-Tests ist? Welche Abhängigkeiten wolltest du verspotten? – Daryl