Frage

Obwohl diese Frage ist im Zusammenhang mit StructureMap, meine Allgemeine Frage:

Wenn die Verkabelung von Komponenten mit einem IoC container in code (im Gegensatz der Konfiguration über xml) Sie müssen in der Regel expliziten project/build Referenzen zu allen Baugruppen?

Warum die separate Komponenten?Denn:


"Abstrakte Klassen, die sich in einem getrennte Montage von Ihrer konkreten Implementierungen sind eine großartige Möglichkeit, um eine solche Trennung." -Rahmen Design Guidelines p.91


Beispiel:

Sagen wir, ich habe PersonBase.dll und Bob.dll

Bob erbt von der abstrakten Klasse PersonBase.Sie sind beide in dem Person namespace. Aber in der verschiedenen Baugruppen.

Ich bin Programmierung PersonBase, nicht Bob.

Zurück in meinem Haupt-code, ich brauche eine person.StructureMap können die scan-Baugruppen.Toll, ich werde Fragen, StructureMap für einen!

Nun, in meinem Haupt-code, freue ich mich natürlich nur mit Bezug auf die PersonBase, nicht zu Bob.Ich wirklich nicht wollen, dass mein code wissen alles über Bob.Keine Referenzen, keine nuthin.Das ist der springende Punkt.

So möchte ich sagen:

//Reference: PersonBase.dll (only)
using Person;  
...

//this is as much as we'll ever be specific about Bob:
Scan( x=> { x.Assembly("Bob.dll"); }

//Ok, I should now have something that's a PersonBase (Bob). But no ?
ObjectFactory.GetAllInstances<PersonBase>().Count == 0

Kein Glück.Was funktioniert, wird ausdrücklich darauf hingewiesen, dass ich will Bob:

//Reference: PersonBase.dll and Bob.dll
using Person; 
...
Scan( x => {x.Assembly("Bob.dll"); }

//If I'm explicit, it works. But Bob's just a PersonBase, what gives?
ObjectFactory.GetAllInstances<Bob>().Count == 1 //there he is!

Aber jetzt ich habe die Referenz Bob.dll in meinem Projekt, die genau das ist, was ich nicht wollte.

Kann ich diese situation vermeiden, mit Spring + Xml-Konfiguration.Aber dann bin ich wieder auf den Frühling + Xml configuration ...!

Bin ich etwas fehlt mit StructureMap, oder auch als Allgemeine Prinzip (fließend) IoC Konfigurationen benötigen, explizite Referenzen alle Baugruppen?

Möglicherweise Verwandte Frage: StructureMap-und scan-Baugruppen

War es hilfreich?

Lösung

Ich habe endlich dieses aussortiert.Es sieht aus wie diese:

IoC-Uml http://img396.imageshack.us/img396/1343/iocuml.jpg

mit der Baugruppen

  • Core.exe
  • PersonBase.dll (verwiesen compile time von Core.exe)
  • Bob.dll (Laufzeit geladen über StructureMap-Scan)
  • Betty.dll (Laufzeit geladen über StructureMap-Scan)

Um es mit StructureMap, brauchte ich eine benutzerdefinierte "ITypeScanner" zu unterstützen-Scannen von Baugruppen:

public class MyScanner : ITypeScanner {
  public void Process(Type type, PluginGraph graph) {

    if(type.BaseType == null) return;

    if(type.BaseType.Equals(typeof(PersonBase))) {
      graph.Configure(x => 
        x.ForRequestedType<PersonBase>()
        .TheDefault.Is.OfConcreteType(type));
    }
  }
} 

Also mein Haupt-code sieht wie folgt aus:

ObjectFactory.Configure(x => x.Scan (
  scan =>
  {
    scan.AssembliesFromPath(Environment.CurrentDirectory 
    /*, filter=>filter.You.Could.Filter.Here*/);

    //scan.WithDefaultConventions(); //doesn't do it

    scan.With<MyScanner>();
  }
));

ObjectFactory.GetAllInstances<PersonBase>()
 .ToList()
  .ForEach(p => 
  { Console.WriteLine(p.FirstName); } );

Andere Tipps

Sie können tun xml-Konfiguration mit StructureMap als gut.Sie können sogar mischen Sie Sie, wenn Sie möchten.

Es gibt auch "StructureMap" Attribute könnten Sie in Ihre Bob-Klasse zu erzählen, StructureMap, wie um die assembly zu laden.DefaultConstructor ist eine, die ich am Ende mit von Zeit zu Zeit.

Die automatische scan-option funktioniert nur, wenn Sie halten die Namensgebung, assembly und namespace-Konventionen.Sie können Sie manuell konfigurieren structuremap mit einem fluent interface.Beispiel:

ObjectFactory.Initialize(initialization => 
   initialization.ForRequestedType<PersonBase>()
    .TheDefault.Is.OfConcreteType<Bob>());

Was wir tun, auf meinem aktuellen Projekt (welches AutoFac, nicht StructureMap, aber ich glaube, es sollte keinen Unterschied machen):

Wir haben die Schnittstellen definieren externen Dienste, die die Anwendung verwendet, die in einen Kern-Baugruppe, lassen Sie uns sagen, App.Core (wie Ihr PersonBase).

Dann haben wir die Implementierungen dieser Schnittstellen, die in Services.Real (wie Bob.dll).

In unserem Fall haben wir auch Service.Fake,, die verwendet werden, zur Erleichterung der UI-Tests mit Abhängigkeiten von anderen enterprise-services und Datenbanken, usw.

Die front-end - "client" - Anwendung selbst (in unserem Fall, ASP.NET MVC-app) Referenzen App.Core.

Wenn die app gestartet wird, verwenden wir Assembly.Load laden Sie die entsprechende "Dienstleistungen" Umsetzung DLL, basierend auf einer config-Einstellung.

Jede dieser DLLs, die eine Implementierung von IServiceRegistry, dass gibt eine Liste der services, die es implementiert:

public enum LifestyleType { Singleton, Transient, PerRequest}

public class ServiceInfo {
    public Type InterfaceType {get;set;}
    public Type ImplementationType {get;set;}
    // this might or might not be useful for your app, 
    // depending on the types of services, etc.
    public LifestyleType Lifestyle {get;set;} 
}

public interface IServiceRegistry {
    IEnumerable<ServiceInfo> GetServices();
}

...die Anwendung findet diese ServiceRegistry über Reflexion und listet diese ServiceInfo Instanzen und registriert Sie auf dem Behälter.Für uns, dieses zu registrieren-alle-services Leben in der Web-Anwendung, aber es ist möglich (und wünschenswert in vielen Fällen) haben es in einer separaten assembly.

Auf diese Weise können wir isolieren die domain-Logik von der Infrastruktur-code, und verhindern, dass "nur-einmal" Workarounds, wo die Anwendung beendet sich je auf eine direkte Bezugnahme auf den Infrastruktur-code.Wir auch vermeiden, dass einen Verweis auf den container, in jedem Services-Implementierung.

Eine wirklich wichtige Sache, wenn Sie, dies zu tun:machen sicher Sie haben tests, die bestätigen, dass Sie können erstellen jeder "top-level" - Typ (in unserem Fall, ASP.NET MVC-Controller) mit jeder möglichen Konfiguration der IOC-container.

Ansonsten ist es ziemlich leicht, zu vergessen, zu implementieren einer Schnittstelle und brechen Sie große Bereiche Ihrer Anwendung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top