0

Aujourd'hui, j'ai cette classe:Injection de dépendances - Place la logique dans le constructeur surchargé?

public class SmtpEmailProvider : IMessageProvider 
{ 
    private readonly SmtpClientWrapper _smtpClientWrapper; 

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

Pour pouvoir se moquer de la SmtpClient, je l'ai enveloppé comme ceci:

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); 
    } 
} 

En ce moment, je peux le faire pour lancer le SmtpEmailProvider classe, et placez-le là logique SmtpClient:

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)); 
} 

Mais je veux le remplacer par:

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

Ensuite, j'ai besoin de placer la logique dans le constructeur sans paramètres. Mais j'ai l'impression que je fais beaucoup dans le contructor alors.

Existe-t-il un autre moyen de le faire?

Répondre

2

Je suis un peu confus au sujet de ce que vous essayez d'accomplir. Si je dois supposer que vous devez fournir des courriers électroniques Smtp, et que vous utilisez IoC, alors vous devriez créer et câbler votre graphique objet entier avec le framework IoC. Par cela, je veux dire que vous devez configurer votre infrastructure IoC pour créer le SmtpClient, avec lequel il crée ensuite le SmtpClientWrapper, créant finalement le SmtpEmailProvider avec. Vous ne devriez pas avoir besoin de mettre une logique de création de dépendances dans le constructeur SmtpEmailProvider.

Voici un exemple avec le château de Windsor, étant donné le code que vous avez fourni:

<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> 

Avec la configuration ci-dessus Windsor, vous pouvez simplement créer votre IMessageProvider comme ceci:

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

var messageProvider = LocateProviderByName("smtpProvider"); 

Le point clé voici comment utiliser le conteneur IoC pour ce qu'il est: un système de création et de gestion de dépendances qui peut, et devrait, créer des graphiques d'objets complets pour vous. Cela atténue le problème que vous avez avec trop de logique de gestion des dépendances dans un constructeur.

+0

+ 1 pour me donner de nouvelles idées de comment faire les choses. Mais dites que la logique n'est pas seulement quelque chose qui peut être spécifié avec IoC. Comme ça, je dois par exemple être capable de récupérer un hôte/port à partir d'un autre référentiel de paramètres en fonction de certains paramètres. Où serait le bon endroit pour mettre la logique? – Allrameest

+1

Si vous avez besoin de ce type de fonctionnalités, je créerais un autre fournisseur ou une autre usine pouvant être injectée plutôt qu'une instance de ce dont vous avez besoin. Par exemple, il semble que vous deviez assigner dynamiquement un hôte, un port et des informations d'identification à SmtpClient. Je voudrais créer un SmtpClientFactory qui est ensuite injecté dans le SmtpClientWrapper. Le SmtpClientWrapper peut alors créer son instance interne du SmtpClient en interne (et la mettre en cache si nécessaire). La chose clé ici, pour maintenir la similitude, est de s'assurer que votre SmtpClientFactory a des méthodes virtuelles. – jrista

+0

Ok! Une usine était une chose que j'avais en tête. Je vais aller avec ça! :) – Allrameest

Questions connexes