You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core发送不同类型邮件的最优架构选型咨询

ASP.NET Core 多邮件实现方案选择

现有代码结构

我在ASP.NET Core中定义了包含SendEmail方法的IEmailManager接口,邮件控制器通过构造函数依赖注入其实现类EmailManager来发送邮件,代码如下:

public interface IEmailManager
{
    void SendEmail();
}

public class EmailManager : IEmailManager
{
    private readonly SmtpCredentials _smtpCreds;

    public EmailManager(SmtpCredentials smtpCreds)
    {
        _smtpCreds = smtpCreds;
    }

    public void SendEmail()
    {
        // 原始邮件发送逻辑
    }
}

已通过.NET Core依赖注入完成该实现类的注册:

builder.Services.AddSingleton<IEmailManager, EmailManager>();

新增需求与实现

当前新增发送Summary类型邮件的需求,我创建了同样实现IEmailManager接口的SummaryEmailManager类:

public class SummaryEmailManager : IEmailManager
{
    private readonly SmtpCredentials _smtpCreds;

    public SummaryEmailManager(SmtpCredentials smtpCreds)
    {
        _smtpCreds = smtpCreds;
    }

    public void SendEmail()
    {
        // Summary邮件发送逻辑
    }
}

两种候选方案

目前我想到两种实现方案,恳请推荐最优方案或更合适的架构:

方案一:注入所有实现类集合

在Program.cs中为两个实现类注册单例服务,控制器注入IEnumerable<IEmailManager>:

builder.Services.AddSingleton(Configuration.GetSection("SmtpSettings").Get<SmtpCredentials>());
builder.Services.AddSingleton<IEmailManager, EmailManager>();
builder.Services.AddSingleton<IEmailManager, SummaryEmailManager>();

// 控制器构造函数
public EmailController(IEnumerable<IEmailManager> emailManagers)
{
    // 根据业务逻辑筛选对应的邮件管理器
}

方案二:工厂模式创建实例

创建IEmailManagerFactory工厂接口及其实现类EmailManagerFactory,通过条件判断返回对应IEmailManager实例,控制器注入该工厂:

public interface IEmailManagerFactory
{
    IEmailManager Create(string type);
}

public class EmailManagerFactory : IEmailManagerFactory
{
    private readonly SmtpCredentials _smtpCreds;

    // 通过DI注入SmtpCredentials,避免手动new
    public EmailManagerFactory(SmtpCredentials smtpCreds)
    {
        _smtpCreds = smtpCreds;
    }

    public IEmailManager Create(string type)
    {
        switch (type)
        {
            case "Summary":
                return new SummaryEmailManager(_smtpCreds);
            default:
                return new EmailManager(_smtpCreds);
        }
    }
}

注册工厂服务:

builder.Services.AddSingleton<IEmailManagerFactory, EmailManagerFactory>();

// 控制器构造函数
public EmailController(IEmailManagerFactory emailManagerFactory)
{
    // 根据类型获取对应实例
    var summaryEmailManager = emailManagerFactory.Create("Summary");
}

方案推荐与分析

方案一的优缺点

  • 优点:实现简单,无需额外代码,适合需要批量执行所有邮件发送逻辑的场景(比如一次性发送所有类型邮件)。
  • 缺点:控制器需要自行判断并筛选对应的邮件管理器,业务逻辑与实例选择耦合;新增邮件类型时,控制器代码可能需要修改,违反开闭原则。

方案二的优缺点

  • 优点:将实例创建逻辑封装在工厂中,控制器只负责业务调用,符合单一职责原则;新增邮件类型时,仅需修改工厂类(或结合配置扩展),控制器无需改动,扩展性更好。
  • 注意点:原工厂代码中手动new实例的方式不符合DI容器的设计原则,建议将依赖通过构造函数注入到工厂中(如上述修改后的工厂代码),确保所有依赖由容器管理。

更优扩展:策略模式+工厂

如果后续会新增更多邮件类型,可结合策略模式进一步优化:

  1. 为每种邮件类型定义标识(如枚举),在实现类上添加特性标记;
  2. 工厂通过DI容器获取所有IEmailManager实例,根据标识匹配返回对应实例,避免硬编码switch判断。

示例优化后的工厂:

public enum EmailType
{
    Default,
    Summary
}

// 为实现类添加特性
[AttributeUsage(AttributeTargets.Class)]
public class EmailTypeAttribute : Attribute
{
    public EmailType Type { get; }

    public EmailTypeAttribute(EmailType type)
    {
        Type = type;
    }
}

[EmailType(EmailType.Default)]
public class EmailManager : IEmailManager { /* ... */ }

[EmailType(EmailType.Summary)]
public class SummaryEmailManager : IEmailManager { /* ... */ }

// 优化后的工厂
public class EmailManagerFactory : IEmailManagerFactory
{
    private readonly IEnumerable<IEmailManager> _emailManagers;

    public EmailManagerFactory(IEnumerable<IEmailManager> emailManagers)
    {
        _emailManagers = emailManagers;
    }

    public IEmailManager Create(EmailType type)
    {
        var manager = _emailManagers.FirstOrDefault(m => 
            m.GetType().GetCustomAttribute<EmailTypeAttribute>()?.Type == type);
        
        return manager ?? throw new ArgumentException($"未找到类型为{type}的邮件管理器");
    }
}

这种方式彻底消除了硬编码的switch判断,新增邮件类型时只需添加带特性的实现类并注册,工厂和控制器都无需修改,扩展性和维护性更强。


内容的提问来源于stack exchange,提问作者Engr Umair

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 12:07:47