6

Ich habe einen Dienst, der eine IMyDependency in seinem Konstruktor nimmt. IMyDependency, MyDependency und der Dienst befinden sich alle in derselben Assembly. MyDependency hat einen einzelnen, öffentlichen, parameterlosen Konstruktor.Servicestack mit Funq - Autowiring per Konvention

Zu meiner Überraschung, das hat nicht funktioniert:

container.RegisterAutoWired<IMyDependency>(); 

Es wirft einen "System.NullReferenceException".

Es funktioniert, wenn ich dies tun:

container.RegisterAutoWiredAs<MyDependency, IMyDependency>(); 

Aber dann, so tut dies:

container.RegisterAs<MyDependency, IMyDependency>(); 

Also, was ist der Unterschied? Wenn 'automatische Verdrahtung' keine konkrete Implementierung finden kann und es keinen Unterschied macht, ob Dienste, die die Abhängigkeit erfordern, gelöst werden können, was ist dann eine automatische Verdrahtung?

Soll Funq Ihre konkreten Implementierungen per Konvention finden können? Wenn ja, was ist diese Konvention, wenn nicht gleich genannt?

Danke.

Antwort

4

Für einfache Abfragen wie diese ist es am besten, nur die Quelle, z. hier ist der Quellcode für RegisterAutoWired:

public IRegistration<T> RegisterAutoWired<T>() 
{ 
    var serviceFactory = GenerateAutoWireFn<T>(); 
    return this.Register(serviceFactory); 
} 

Es hat eine Auto-Kabel Fabrik über einekonkrete Umsetzung erzeugt. Eine Schnittstelle hat keine Implementierung, sie muss eine konkrete Klasse sein.

und der Quellcode für RegisterAs:

public IRegistration<TAs> RegisterAs<T, TAs>() where T : TAs 
{ 
    return this.RegisterAutoWiredAs<T, TAs>(); 
} 

die nur eine kürzere alias ist man statt RegisterAutoWiredAs verwenden können.

+0

Also, wenn ich das richtig verstehe, soll ich tun: container.RegisterAutoWired (); Wenn ich dies jedoch nur zur Laufzeit (wenn ich den Dienst mit der Abhängigkeit aufrufen), bekomme ich "Erforderliche Abhängigkeit vom Typ IMyDependency konnte nicht aufgelöst werden". Daher ist mir der Zweck dieser Methode noch unklar, da der Container nicht in der Lage ist, die Schnittstelle zu finden, die dem registrierten Betontyp entspricht. –

+3

Es ist ziemlich einfach, es wird einfach injizieren, was Sie registrieren, wenn Sie 'MyDependency>' registrieren, dann wird es alle 'MyDependency'-Eigenschaften injizieren. Wenn Sie möchten, dass IMyDependency-Eigenschaften injiziert werden, müssen Sie 'RegisterAs ' aufrufen. – mythz

+1

In meinem Projekt habe ich ~ 200 Klassen nach Konvention: MyClass: IMyClass. Also entsprechend jedes Mal, wenn ich neue Klasse implementieren oder entfernen könnte Verkabelung für sie tun? Unity, Windsor und StructureMap haben eine Autowire-Konvention. – nerijus

8

Meinst du "Wie kann ich eine Lösung implementieren, um Baugruppen zu durchsuchen und automatisch Klassen in ServiceStack IOC basierend auf einer Konvention zu registrieren?"

Wenn ja, könnte ich eine Lösung für Sie:

  1. Erstellen Sie eine Schnittstelle, die Ihre Inject-able Klassen implementieren wird.
  2. Lassen Sie Ihre injizierbaren Klassen diese Schnittstelle implementieren.
  3. Verwenden Sie im Boot-Strapping-Code reflection, um Ihre Assemblys zu durchsuchen und eine Liste aller Klassen zu erhalten, die die inject-fähige Schnittstelle implementieren.
  4. Verwenden Sie Reflektion, um den Klassennamen und die Schnittstelle basierend auf Ihren Konventionen zu erhalten.
  5. Rufen Sie die ServiceStack IOC-Methode RegisterAutoWiredType und übergeben Sie die Klasse und die Schnittstelle, um sie zu registrieren.

Zum Beispiel, wenn unsere Namenskonvention ist Class iClassName:

private static void RegisterCustomTypes(Container container) 
{ 
    //Get the Assembly Where the injectable classes are located. 
    var assembly = Assembly.GetAssembly(typeof(IInjectable)); 

    //Get the injectable classes 
    var types =assembly.GetTypes() 
    .Where(m => m.IsClass && m.GetInterface("IInjectable") != null); 

    //loop through the injectable classes 
    foreach (var theType in types) 
    { 
    //set up the naming convention 
    var className = theType.Name; 
    var interfaceName = string.Concat("I", className); 
    //create the interface based on the naming convention 
    var theInterface = theType.GetInterface(interfaceName); 
    //register the type with the convention 
    container.RegisterAutoWiredType(theType, theInterface); 
    } 
} 

public interface IInjectable 
{ 

} 

//This class can be injected 
public interface ITestManager : IInjectable 
{ 
    void Execute(int id); 
} 

public class TestManager : ITestManager 
{ 
    public void Execute(int id) 
    { 
     throw new System.NotImplementedException(); 
    } 
} 
+0

Seit meinem ursprünglichen Beitrag habe ich verstanden, dass Func keine Assembly-Suche eingebaut hat. Wenn Sie Ihre eigene Reflektion implementieren, wie hier vorgeschlagen, denken Sie, dass ein Vorteil (z. B. die Leistung) bei der Verwendung von Func gegenüber einer anderen Lösung wie Ninject usw. bestehen bleibt? –

+0

Nicht sicher. Vielleicht hat Mythz eine Anleitung dazu? –

+1

@Saber, DI wird beim Start der Web-App nur einmal ausgeführt. Leistungsunterschiede können dort imo ignoriert werden. Windsor oder Ninject ... usw., sie sind alle gut. Der einzige Grund, warum ich Funq über andere verwende, ist, dass es mit SS kommt, ich bin zu faul, um einen anderen IoC zu unterhalten, der vom SS-Paket getrennt ist. – Tom