【问题标题】:How can I use DI with Email and SMS classes如何将 DI 与电子邮件和 SMS 类一起使用
【发布时间】:2019-01-28 21:15:19
【问题描述】:

我有这个界面:

public interface IMessageSender
{
    Task SendMessageAsync(parameters);
}

还有这个类:

public class EmailSender : IMessageSender
{
}

public class SMSSender : IMessageSender
{
}

在我的控制器中,我是这样使用它们的:

public class MyController : Controller
{
    private readonly IMessageSender _messageSender;
    public MyController(IMessageSender messageSender)
    {
        _messageSender = messageSender;
    }
}

我在这个控制器中有两种方法:

public async Task<IActionResult> SendByEmail()
{ 
    await _messageSender.SendMessageAsync(parameters);
}

public async Task<IActionResult> SendBySMS()
{ 
    await _messageSender.SendMessageAsync(parameters);
}

在上述方法中,我如何告诉.net核心在SendByEmail方法中,我需要一个EmailSender类的实例,而在SendBySMS方法中,我需要一个SMSSender的实例班级。我已经将它添加到我的启动类中,但它显然总是创建一个 EmailSender 类的实例:

services.AddTransient<IMessageSender, EmailSender>();

【问题讨论】:

  • 不需要IMessageSender就不用注册了。仅当您需要“发送它,我不在乎如何”之类的抽象时。当您定义 IEmailSender 时,您的意思是“通过电子邮件发送”。您定义的每个接口背后都应该有具体的意图。在某个时间点 IEmailSender 可以接收其他参数并与 IMessageSender 完全分离。
  • 我建议这种方法的原因是很多人的诱惑是'这两个类做同样的事情,所以给他们一个公共接口'。但通常使用错误的方式思考它的接口。在考虑接口时,主要关注调用者。 调用者想要什么?如果来电者想发送电子邮件 - 给他们一个界面来做到这一点。如果他们想发送短信 - 给他们一个界面来做到这一点。他们不关心你的抽象——他们关心的是发送电子邮件或短信。

标签: c# asp.net-core dependency-injection .net-core


【解决方案1】:

目前你有:

public interface IMessageSender
{
    Task SendMessageAsync(parameters);
}

以及实现该接口的两个类。这确实有效,但我建议对这种方法稍作调整。保留IMessageSender,新增两个接口:

public interface IEmailSender : IMessageSender
{
}

public interface ISMSSender : IMessageSender
{
}

为什么要这样做?好吧,它现在允许您注入您感兴趣的特定发件人(该控制器想要发送电子邮件,该控制器想要发送短信)。

此外,由于它们都继承自 IMessageSender,使用一些 IoC 容器(例如 Autofac - 我还没有全部测试过),您还可以注入 IMessageSender 的集合(即 IEnumerable&lt;IMessageSender&gt;) - 这不是总是有用,但如果您想调用所有的消息发送者(即 SMS this 通过电子邮件发送),它会很有用。如果这没有用 - 没问题,请完全删除 IMessageSender(并将定义接口的方法移至 IEmailSenderISMSSender)。

现在,更改您的类以实现您的新接口:

public class EmailSender : IEmailSender
{
}

public class SMSSender : ISMSSender
{
}

并在容器的两个接口上注册您的类。 使用 Autofac 会类似于 AsImplementedInterfaces

查看您现有的代码,我建议以下解决方案:

services.AddTransient<IEmailSender, EmailSender>();
services.AddTransient<ISMSSender, SMSSender>();
services.AddTransient<IMessageSender, EmailSender>();
services.AddTransient<IMessageSender, SMSSender>();

然后将您的控制器更改为:

public MyController(IEmailSender emailSender, ISMSSender smsSender)

【讨论】:

  • 我认为services.AddTransient&lt;IMessageSender, EmailSender&gt;(); 是不正确的,因为以后如何区分它们以从它们创建实例?农夫在我看来更正确。不是吗?
  • 如果你想注入IEnumerable&lt;IMessageSender&gt;(比如stackoverflow.com/a/39569277/34092),这很有用。我怀疑你现在不需要它。在我的回答中阅读but it can be useful if
猜你喜欢
  • 2017-06-12
  • 1970-01-01
  • 2020-04-25
  • 1970-01-01
  • 2018-01-18
  • 2019-08-24
  • 2016-11-14
  • 1970-01-01
相关资源
最近更新 更多