Ho una catena di dipendenza che appare più o meno in questo modo:Ninject Bind Quando antenato del tipo T
public class CarSalesBatchJob
{
public CarSalesBatchJob(IFileProvider fileProvider)
{ ... }
}
public class MotorcycleSalesBatchJob
{
public MotorcycleSalesBatchJob(IFileProvider fileProvider)
{ ... }
}
public class FtpFileProvider : IFileProvider
{
public FtpFileProvider(IFtpSettings settings)
{ ... }
}
public class CarSalesFtpSettings : IFtpSettings { ... }
public class MotorcycleSalesFtpSettings : IFtpSettings { ... }
Fino ad ora, ho usato le convenzioni attacchi basati, ma che non è abbastanza buono più perché ho più di una implementazione per IFtpSettings
. Quindi ho deciso di utilizzare alcuni binding contestuali. A prima vista kernel.Bind<>().To<>().WhenInjectedInto<>()
sembrava promettente, ma che aiuta solo al primo livello, il che significa che se avessi una CarSalesFtpFileProvider
e MotorcycleSalesFtpProvider
ho potuto fare questo:
kernel.Bind<IFtpSettings>().To<CarSalesFtpSettings>()
.WhenInjectedInto<CarSalesFtpFileProvider>();
kernel.Bind<IFtpSettings>().To<MotorcycleSalesFtpSettings>()
.WhenInjectedInto<MotorcycleSalesFtpFileProvider>();
ma sembra abbastanza stupido per creare due implementazioni concrete di FtpFileProvider
in realtà differiscono solo su quali impostazioni voglio che usino. Ho visto che esiste un metodo chiamato WhenAnyAnchestorNamed(string name)
. Ma questa strada mi impone di inserire attributi e stringhe magiche nei miei lavori batch, di cui non sono entusiasta.
Ho anche notato che v'è una pianura .When(Func<IRequest, bool>)
vecchio metodo sulle dichiarazioni vincolanti, così mi si avvicinò con questo come le mie dichiarazioni rilegatura:
//at this point I've already ran the conventions based bindings code so I need to unbind
kernel.Unbind<IFtpSettings>();
kernel.Bind<IFtpSettings>().To<CarSalesFtpSettings>()
.When(r => HasAncestorOfType<CarSalesBatchJob>(r));
kernel.Bind<IFtpSettings>().To<MotorcycleSalesFtpSettings>()
.When(r => HasAncestorOfType<MotorcycleSalesBatchJob>(r));
// later on in the same class
private static bool HasAncestorOfType<T>(IRequest request)
{
if (request == null)
return false;
if (request.Service == typeof(T))
return true;
return HasAncestorOfType<T>(request.ParentRequest);
}
Quindi, se un costruttore chiede IFtpSettings, abbiamo recurse su richiesta albero per vedere se qualcuno dei servizi/tipi richiesti nella catena corrisponde al tipo fornito (CarSalesBatchJob o MotorcycleSalesBatchJob) e in tal caso restituisce true. Se arriviamo fino in cima alla catena, restituiamo false.
Ci scusiamo per la lunga spiegazione dello sfondo.
Ecco la mia domanda: c'è qualche ragione per cui non dovrei affrontare il problema in questo modo? È considerata una cattiva forma? C'è un modo migliore per trovare i tipi di richiesta degli antenati? Dovrei ristrutturare la mia classe/catena di dipendenza in modo più "gradevole"?
Credo che la soluzione che hai identificato nella tua domanda, per implementare due classi concrete che accoppiano un FtpFileProvider con un'implementazione di IFtpSettings, è la più facile da capire/leggere/debug/hand off. Altre soluzioni richiedono allo sviluppatore di saperne di più sul tuo strumento IOC specifico e su come lo hai configurato. Questa implementazione segue anche Convention over Configuration per Ninject. –