6

Ho un servizio che prende un'IMyDependency nel suo costruttore. IMyDependency, MyDependency e il servizio vivono tutti nello stesso assembly. MyDependency ha un costruttore singolo, pubblico, senza parametri.servicestack con funq - autowiring per convenzione

Con mia grande sorpresa, questo non ha funzionato:

container.RegisterAutoWired<IMyDependency>(); 

getta un "System.NullReferenceException".

Funziona se faccio questo:

container.RegisterAutoWiredAs<MyDependency, IMyDependency>(); 

Ma poi, così fa questo:

container.RegisterAs<MyDependency, IMyDependency>(); 

Allora, qual è la differenza? Se il "cablaggio automatico" non riesce a trovare un'implementazione concreta e non fa alcuna differenza se i servizi che richiedono la dipendenza possono essere risolti, qual è il cablaggio automatico?

Funq dovrebbe essere in grado di trovare le implementazioni concrete per convenzione? In tal caso, qual è questa convenzione, se non lo stesso nome?

Grazie.

risposta

4

Per query semplici come questa è meglio contattare la fonte, ad es. qui è il codice sorgente per RegisterAutoWired:

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

Esso genera una fabbrica di auto-wired nel corso di un Concrete implementazione. Un'interfaccia non ha implementazione, deve essere una classe concreta.

E il codice sorgente per RegisterAs:

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

che è solo un alias più brevi è possibile utilizzare al posto di RegisterAutoWiredAs.

+0

Quindi, se ho capito bene, dovrei fare: container.RegisterAutoWired (); Tuttavia, se faccio solo questo, in fase di esecuzione (quando chiamo il servizio con la dipendenza), ottengo "La dipendenza richiesta di tipo IMyDependency non può essere risolta". Quindi non sono ancora chiaro sullo scopo di questo metodo, in quanto il contenitore non sembra in grado di trovare l'interfaccia corrispondente al tipo di calcestruzzo registrato. –

+3

È piuttosto semplice, semplicemente si inietterà ciò che si registra, se si 'Register ' di quanto verrà iniettare tutte le proprietà 'MyDependency'. Se si desidera iniettare proprietà 'IMyDependency' piuttosto che chiamare' RegisterAs '. – mythz

+1

Nel mio progetto mi piacciono ~ 200 classi per convenzione: MyClass: IMyClass. Quindi, in base a questo ogni volta che implemento una nuova classe o rimuovo, potrei fare il cablaggio per questo? Unity, Windsor e StructureMap hanno un'autowire per convenzione. – nerijus

8

Intendi "come posso implementare una soluzione per cercare tra gli assembly e registrare automaticamente le classi in IOC di ServiceStack in base a una convenzione?"

Se è così, potrei avere una soluzione per voi:

  1. creare un'interfaccia che le vostre classi Iniettare-grado attueranno.
  2. Le classi iniettabili possono implementare tale interfaccia.
  3. Nel codice di avvio utilizza la riflessione per cercare gli assiemi e ottenere un elenco di tutte le classi che implementano l'interfaccia iniettabile.
  4. Utilizzare la riflessione per ottenere il nome classe e l'interfaccia in base alle convenzioni.
  5. Chiamare il metodo IOC ServiceStack RegisterAutoWiredType e passare la classe e l'interfaccia per registrarli.

Per esempio se la nostra convenzione di denominazione è NomeClasse 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

Dal mio post originale, ho capito che Func non ha una ricerca assembly integrata. Se implementate la vostra riflessione come suggerito qui, pensate che qualsiasi vantaggio (come le prestazioni) rimarrebbe nell'uso di Func, su un'altra soluzione come Ninject, ecc.? –

+0

Non sicuro. Forse il mythz ha delle indicazioni su questo? –

+1

@Saber, DI viene eseguito solo all'avvio dell'applicazione Web. La differenza di prestazioni può essere ignorata qui. Windsor o Ninject ... ecc., Sono tutti buoni. L'unico motivo per cui utilizzo Funq rispetto ad altri è perché viene fornito con SS, sono troppo pigro per mantenere un altro IoC separato dal pacchetto SS. – Tom