Posso passare i parametri di costruttore di Unità Risolvere() metodo?
-
16-09-2019 - |
Domanda
Sto usando Microsoft Unità per l'iniezione di dipendenza e voglio fare qualcosa di simile a questo:
IDataContext context = _unityContainer.Resolve<IDataContext>();
var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context
IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2);
RepositoryA
e RepositoryB
entrambi hanno un costruttore che prende un IDataContext
parametro, e voglio Unità per inizializzare il repository con il contesto che lo passo.Anche notare che IDataContext
non è registrato con l'Unità (non voglio 3 istanze di IDataContext
).
Soluzione
Ad oggi hanno aggiunto questa funzionalità:
E 'nella sua ultima goccia qui:
http://unity.codeplex.com/SourceControl/changeset/view/33899
Discussione su di esso qui:
http://unity.codeplex.com/Thread/View.aspx? ThreadId = 66434
Esempio:
container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"
Altri suggerimenti
< 2 cents>
Cosa succede se in un secondo momento decidere di utilizzare un altro servizio che richiede più o meno che proprio contesto?
Il problema con i parametri del costruttore e Cio è che i parametri sono, in definitiva, legata al tipo di calcestruzzo utilizzato, invece di essere parte del contratto che l'interfaccia del servizio definisce.
Il mio suggerimento è che si sia risolto il contesto, e credo che l'Unità deve avere un modo per evitare la costruzione di 3 istanze di esso, o si dovrebbe prendere in considerazione un servizio di fabbrica che è un modo per costruire l'oggetto.
Per esempio, se in un secondo momento decidere di costruire un repository che non si basa su un database di tipo tradizionale, ma invece di utilizzare un file XML per produrre dummy-i dati per il test?Come si va su di alimentazione il contenuto XML per costruttore?
Cio è basato intorno disaccoppiamento codice, legando il tipo e la semantica degli argomenti per i calcestruzzi, davvero non hanno fatto il disaccoppiamento correttamente, c'è ancora una dipendenza.
"Questo codice può parlare di qualsiasi tipo di repository forse, come lungo come si implementa questa interfaccia....Oh, e utilizza un contesto di dati".
Ora, so che altri IoC container dispone di supporto per questo, e l'ho avuto nella mia prima versione del mio bene, ma a mio parere, non appartiene con la risoluzione passo.
< /2 cents>
Grazie ragazzi ... il mio è simile al post di "Exist". Vedi sotto:
IUnityContainer container = new UnityContainer();
container.LoadConfiguration();
_activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
{
new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
});
È possibile utilizzare InjectionConstructor / InjectionProperty / InjectionMethod a seconda della architettura di iniezione all'interno del ResolvedParameter
Nel tuo caso l'oggetto deve essere registrato con un nome, e per lo stesso insance è necessario ContainerControlledLifeTimeManager () come LifeTimeManager.
_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager());
_unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB");
var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));
var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextB")));
La risposta molto breve è: no. Unità attualmente non ha modo di passare parametri al costruttore che non sono costanti o iniettato, che ho potuto trovare. IMHO questa è la cosa più grande che manca, ma penso che è di progettazione, piuttosto che per omissione.
Come osserva Jeff Fritz, in teoria è possibile creare un gestore di vita personalizzato che sa quale istanza di contesto per iniettare in varie tipologie, ma questo è un livello di hard-codifica che sembra ovviare lo scopo di utilizzare l'unità o DI nel primo posto.
Si potrebbe fare un piccolo passo indietro dalla piena DI ed effettuare le implementazioni repository responsabile di stabilire i propri contesti di dati. Il contesto istanza può ancora essere risolta dal contenitore, ma la logica per decidere quale usare avrebbe dovuto andare in attuazione del repository. Non è così puro, certamente, ma sarebbe sbarazzarsi del problema.
Un'altra alternativa è possibile utilizzare (non so davvero se si tratta di una buona pratica o no) è la creazione di due contenitori e registrazione un'istanza per ogni:
IDataContext context = _unityContainer.Resolve<IDataContext>();
_unityContainer.RegisterInstance(context);
var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context
//declare _unityContainer2
IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance
_unityContainer2.RegisterInstance(context2);
var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance
Spero che questo aiuti anche
NotDan, penso che si può avere risposto alla tua domanda nei commenti a lassevk.
In primo luogo, vorrei utilizzare un LifetimeManager per gestire il ciclo di vita e il numero di istanze di IDataContext che l'unità crea.
http://msdn.microsoft.com/en-us/library/cc440953. aspx
Sembra che l'oggetto ContainerControlledLifetimeManager
vi darà la gestione delle istanze di cui avete bisogno. Con questo LifetimeManager in atto, Unità dovrebbe aggiungere la stessa istanza del IDataContext a tutti gli oggetti che richiedono una dipendenza IDataContext.