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

.NET 5中Serilog依赖注入Logger无法发送邮件问题

问题:依赖注入的Serilog Logger无法发送邮件,直接使用Log类可正常发送

我正在为C# .NET 5 Web应用及API集成Serilog,已配置Email和MS SQL接收器且均可正常工作,但发现仅直接使用Log类时能发送邮件,依赖注入的ILogger<T>无法发送邮件。

相关代码

Program.cs

public static void Main(string[] args)
{
    var builder = new ConfigurationBuilder();
    BuildConfig(builder);
    Log.Logger = CreateLogger(builder);

    try
    {
        CreateHostBuilder(args).Build().Run();
    }
    catch (Exception e)
    {
        Log.Fatal(e, "Host terminated unexpectedly");
    }
    finally
    {
        Log.CloseAndFlush();
    }
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseSerilog()
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

public static Serilog.ILogger CreateLogger(ConfigurationBuilder builder)
{
    var emailSettings = Configuration.GetSection("Serilog").GetSection("WriteTo").GetSection("0").GetSection("Args");
    var emailInfo = CreateEmailInformation(emailSettings);

    return new LoggerConfiguration()
               .ReadFrom.Configuration(Configuration)
               .Enrich.FromLogContext()
               .WriteTo.Email(emailInfo)
               .CreateLogger();
}

API服务代码(CollectionRepository)

private readonly AppDbContext _context;
private readonly ILogger<CollectionRepository> _logger;

public CollectionRepository(AppDbContext appDbContext, ILogger<CollectionRepository> logger)
{
    _context = appDbContext;
    _logger = logger;
}

public async Task<List<amp.collection>> GetCollections()
{
    var result = new List<amp.collection>();
    try
    {
        result = await db.GetCollections();
    }
    catch (Exception e)
    {
        _logger.LogError(e, "Exception occurred in GetCollections()");
    }
    return result;
}

更新测试发现

在_logger.LogError()后立即添加Log.CloseAndFlush(),邮件即可发送,推测问题与邮件的异步特性有关。


原因及解决方案

核心原因

Serilog的Email接收器默认采用异步批量投递策略:日志会先缓存,等待达到批量阈值或指定周期后才实际发送邮件。直接使用Log.Fatal()时,程序后续进入finally块执行了Log.CloseAndFlush(),强制等待所有异步日志任务完成,所以邮件能发送成功;而依赖注入的ILogger<T>写入日志后,没有触发刷新操作,异步投递任务还没执行就继续后续流程,导致邮件未发送。

解决方法

  1. 修改Email接收器配置,关闭批量异步投递
    在代码配置或配置文件中,设置batchPostingLimit: 1和period: TimeSpan.Zero,让日志立即发送(注意:此方式会同步阻塞线程,影响高并发场景性能,仅适合对实时性要求极高的场景)。
    代码示例:

    .WriteTo.Email(emailInfo, batchPostingLimit: 1, period: TimeSpan.Zero)
    
  2. 在合适时机触发日志刷新

    • 全局层面:Web应用正常关闭时,Serilog会自动执行刷新,但如果需要在请求过程中确保邮件立即发送,可以注入Serilog原生的Serilog.ILogger(而非微软的ILogger<T>),调用其Flush()方法;
    • 临时处理:在需要立即发送邮件的日志调用后,手动调用Log.Flush()(注意全局调用的线程安全)。
  3. 统一使用Serilog原生Logger注入
    放弃微软的ILogger<T>抽象层,直接注入Serilog的Serilog.ILogger,它提供了Flush()方法可手动触发日志投递,更贴合Serilog的原生特性。

额外注意点

你的CreateLogger方法同时使用了ReadFrom.Configuration()和手动添加WriteTo.Email(),可能导致重复配置Email接收器,建议统一通过配置文件或代码完成配置,避免潜在冲突。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 00:27:05