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

NLog自定义LimitedFrequencyEmailTarget同步调用疑问:IIS部署也会如此吗?

问题解答

这种同步调用的情况部署到IIS后依然会发生,和是否在Visual Studio调试无关——这是由NLog的目标执行机制决定的,和运行环境没有关系。

原因分析

NLog的MailTarget本身是同步目标,即使你重写了Write(AsyncLogEventInfo)方法,默认情况下NLog并不会自动将这个方法的执行放到后台线程。从你提供的堆栈跟踪可以看到,调用链是从logger.Error直接同步走到了你的Write方法,没有经过任何线程调度逻辑,这说明当前目标是同步执行的,和宿主环境(调试/IIS)无关。

实现异步执行的方案

如果你希望logger.Error()能立即返回,让邮件发送逻辑在后台线程执行,可以通过以下两种方式实现:

1. 使用NLog自带的AsyncTargetWrapper(推荐)

在NLog配置文件中,给你的LimitedFrequencyEmailTarget添加异步包装器,NLog会自动将日志事件放入队列,由后台线程处理,调用线程会立即返回。示例配置:

<targets>
  <target xsi:type="AsyncWrapper" name="asyncLimitedEmail">
    <target xsi:type="LimitedFrequencyEmailTarget" name="limitedEmail" 
            smtpServer="xxx" smtpPort="xxx" from="xxx" to="xxx" />
  </target>
</target>
<rules>
  <logger name="*" minlevel="Error" writeTo="asyncLimitedEmail" />
</rules>

2. 在派生类中手动实现异步逻辑

在你的Write方法里,手动将邮件发送逻辑放到后台线程执行,并正确调用异步完成回调:

protected override void Write(AsyncLogEventInfo logEvent)
{
    Task.Run(() =>
    {
        try
        {
            // 执行频率检查和邮件发送逻辑
            if (CheckIfTooManyEmails(DateTime.Now, 0))
            {
                // 频率超限,不发送邮件
                logEvent.Continuation(null);
                return;
            }
            base.Write(logEvent.LogEvent);
            logEvent.Continuation(null);
        }
        catch (Exception ex)
        {
            // 传递异常给NLog处理
            logEvent.Continuation(ex);
        }
    });
}

注意:手动实现需要自己处理线程安全、异常捕获和队列限流等问题,不如使用AsyncTargetWrapper可靠。

内容的提问来源于stack exchange,提问作者Zhijian Jim Luo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 05:26:11