2009-06-26 11 views
0

Heute habe ich diese Klasse haben:Abhängigkeitsinjektion - Logik im überladenen Konstruktor platzieren?

public class SmtpClientWrapper 
{ 
    private readonly SmtpClient _smtpClient; 

    public SmtpClientWrapper(SmtpClient smtpClient) 
    { 
     _smtpClient = smtpClient; 
    } 

    public virtual void Send(MailMessage msg) 
    { 
     if (_smtpClient == null) throw new InvalidOperationException("SmtpClient must be passed to the constructor before calling Send."); 

     _smtpClient.Send(msg); 
    } 
} 

Im Moment habe ich dies die SmtpEmailProvider initiieren können:

public class SmtpEmailProvider : IMessageProvider 
{ 
    private readonly SmtpClientWrapper _smtpClientWrapper; 

    public SmtpEmailProvider(SmtpClientWrapper smtpClientWrapper) 
    { 
     _smtpClientWrapper = smtpClientWrapper; 
    } 

Um in der Lage sein, die SmtpClient zu verspotten, habe ich es so gewickelt Klasse, und legen Sie die SmtpClient Logik gibt:

public IMessageProvider LocateProviderByName(string providerName) 
{ 
    var client = new SmtpClient 
        { 
         Host = "127.0.0.1", 
         Port = 25 
        }; 
    client.Credentials = new NetworkCredential("...", "..."); 
    return new SmtpEmailProvider(new SmtpClientWrapper(client)); 
} 

Aber ich möchte ersetzen, dass mit:

public IMessageProvider LocateProviderByName(string providerName) 
{ 
    return IoC.Resolve<IMessageProvider>(providerName); 
} 

Dann muss ich die Logik im Konstruktor ohne Parameter platzieren. Aber ich habe das Gefühl, dass ich im Konstruktor viel zu tun habe.

Gibt es einen anderen Weg, es zu tun?

Antwort

2

Ich bin ein wenig verwirrt darüber, was genau Sie versuchen zu erreichen. Wenn ich annehmen soll, dass Sie Smtp-E-Mail-Anbieter bereitstellen müssen und IoC verwenden, sollten Sie Ihren gesamten Objekt-Graphen mit dem IoC-Framework erstellen und verkabeln. Damit meine ich, dass Sie Ihr IoC-Framework so konfigurieren würden, dass es den SmtpClient erstellt, mit dem es den SmtpClientWrapper erstellt, und schließlich den SmtpEmailProvider mit erstellt. Sie sollten keine Abhängigkeitserstellungslogik im SmtpEmailProvider-Konstruktor einfügen müssen. Hier

ist ein Beispiel mit Schloss Windsor, angesichts der Code, den Sie zur Verfügung gestellt:

<configuration> 
    <component id="smtpClient" type="System.Net.Mail.SmtpClient, System"> 
    <parameters> 
     <Host>127.0.0.1</Host> 
     <Port>25</Port> 
    </parameters> 
    </component> 
    <component id="smtpClientWrapper" type="Naespace.SmtpClientWrapper, Assembly"> 
    <parameters> 
     <smtpClient>${smtpClient}</smtpClient> 
    </parameters> 
    </component> 
    <component id="smtpProvider" service="Namespace.IMessageProvider, Assembly" type="Namespace.SmtpEmailProvider, Assembly"> 
    <parameters> 
     <smtpClientWrapper>${smtpClientWrapper}</smtpClientWrapper> 
    </parameters> 
    </component> 
</configuration> 

Mit der obigen Windsor Konfiguration, können Sie einfach Ihre IMessageProvider erstellen wie folgt:

public IMessageProvider LocateProviderByName(string providerName) 
{ 
    return IoC.Resolve<IMessageProvider>(providerName); 
} 

var messageProvider = LocateProviderByName("smtpProvider"); 

Der entscheidende Punkt Hier ist die Verwendung des IoC-Containers für das, was es ist: ein Abhängigkeitserzeugungs- und -verwaltungssystem, das vollständige Objektdiagramme für Sie erstellen kann und sollte. Dies verringert das Problem, das Sie mit zu viel Abhängigkeitsverwaltungslogik in einem Konstruktor haben.

+0

+ 1 für neue Ideen, wie man Dinge macht. Aber sagen, dass die Logik dort ist nicht nur etwas, das mit IoC angegeben werden kann. So muss ich zum Beispiel in der Lage sein, Host/Port von einem anderen Einstellungsrepository abhängig von einigen Parametern abzurufen. Wo wäre der richtige Ort, um die Logik zu setzen? – Allrameest

+1

Wenn Sie diese Art von Fähigkeit benötigen, würde ich einen anderen Anbieter oder eine Fabrik erstellen, die injiziert werden kann, als eine Instanz von dem, was Sie brauchen. Zum Beispiel scheint es so, als müssten Sie dem SmtpClient einen Host, Port und Credential dynamisch zuweisen. Ich würde eine SmtpClientFactory erstellen, die dann in den SmtpClientWrapper eingefügt wird. Der SmtpClientWrapper kann dann intern seine interne Instanz des SmtpClients erstellen (und bei Bedarf zwischenspeichern). Um hier Mockability zu erhalten, müssen Sie sicherstellen, dass Ihre SmtpClientFactory über virtuelle Methoden verfügt. – jrista

+0

Ok! Eine Fabrik war eine Sache, die mir vorschwebte. Ich werde damit gehen! :) – Allrameest

Verwandte Themen