Ninject / DI: come passare correttamente i dati di inizializzazione al tipo iniettato in fase di esecuzione

1

Ho le seguenti due classi:

public class StoreService : IStoreService
{
    private IEmailService _emailService;

    public StoreService(IEmailService emailService)
    {
        _emailService = emailService;
    }
}

public class EmailService : IEmailService
{
}

Usando Ninject I puoi impostare i binding senza problemi per farlo iniettare un'implementazione concreta di IEmailService nel costruttore StoreService. StoreService viene effettivamente inserito nel codice sottostante di un WebForm ASP.NET in questo modo:

[Ninject.Inject]
public IStoreService StoreService { get; set; }

Ma ora ho bisogno di cambiare EmailService per accettare un oggetto che contiene le impostazioni relative a SMTP (che vengono estratte da ApplicationSettings di Web.config). Così ho cambiato EmailService ora come questo:

public class EmailService : IEmailService
{
    private SMTPSettings _smtpSettings;

    public void SetSMTPSettings(SMTPSettings smtpSettings)
    {
        _smtpSettings = smtpSettings;
    }
}

L'impostazione di SMTPSettings in questo modo richiede anche che venga passata in StoreService (tramite un altro metodo pubblico). Questo deve essere fatto nel metodo Page_Load nel codice WebForms (ho solo accesso alla classe Settings nel livello UI).

Con DI manuale / povero potrei passare SMTPSettings direttamente nel costruttore di EmailService e quindi inserire EmailService nel costruttore di StoreService. Con Ninject I non ho accesso alle istanze di tipi iniettati al di fuori degli oggetti a cui sono iniettati, quindi devo impostare i loro dati AFTER Ninject li ha già iniettati tramite un metodo di setter pubblico separato. Questo a me sembra sbagliato.

Come dovrei davvero risolvere questo scenario?

    
posta MrLane 20.08.2014 - 05:23
fonte

1 risposta

0

With manual/poor mans DI I could pass SMTPSettings directly into the constructor of EmailService and then inject EmailService into the StoreService constructor.

Questo è anche ciò che deve accadere quando si usa Ninject, eccetto che tu non hai bisogno di iniettare questi valori nei costruttori, Ninject lo farà per te - risolverà ricorsivamente tutte le dipendenze di cui hai bisogno per ottenere un StoreService.

Se dichiari il tuo EmailService proprio come avresti quando utilizzi DI di poveri, come questo:

public class EmailService : IEmailService
{
    private SMTPSettings _smtpSettings;

    public EmailService(SMTPSettings smtpSettings)
    {
        _smtpSettings = smtpSettings;
    }
}

Ora, quando si chiede a Ninject un IStoreService, si vuole creare un'istanza di StoreService. Un StoreService richiede un IEmailService, quindi vorrà istanziare un EmailService. Un EmailService richiede un'istanza SMTPSettings ... se a Ninject si può dire come ottenere una tale istanza Ninject è in grado di produrre un'istanza StoreService completamente inizializzata.

Non ho mai usato Ninject (ma ho usato altri framework .NET DI), ma da quello che posso raccogliere dai documenti di Ninject un modo per farlo è registrare un metodo factory che produrrà un'istanza SMTPSettings ( link ):

using (IKernel kernel = new StandardKernel())
{
    kernel.Bind<SMTPSettings>()
          .ToMethod(context => new SMTPSettings() /* or any other expression that returns an SMTPSettings instance */);           
}

Con questo binding in atto, Ninject dovrebbe essere in grado di produrre un'istanza StoreService completamente inizializzata.

NB. Ho usato link per vedere Ninject in azione, forse contiene alcune informazioni utili anche per te.

    
risposta data 22.08.2014 - 17:32
fonte

Leggi altre domande sui tag