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

.NET 6 WebAPI 中Serilog日志消息模板存放的最佳实践咨询

业内通用的三种标准实现方案

方案1:公共静态常量类存储(最常用,无性能损耗)

你觉得静态类不规范其实是认知误区,这是.NET生态里存储全局常量的标准做法,编译期就可以做校验,维护成本极低,适合全项目通用的日志模板。
示例代码:

// 全局统一存放日志模板的静态类
public static class LogTemplates
{
    public const string InvalidModelMessageTemplate = "Model is null or invalid: {Model}";
    public const string NotFoundMessageTemplate = "Could not find {Entity} with id: {Id}";
    public const string UnhandledExceptionMessageTemplate = "Unexpected exception in {Controller}: {Message}";
}

调用的时候直接引用静态类即可:

catch (Exception ex)
{
    _logger.LogError(LogTemplates.UnhandledExceptionMessageTemplate, nameof(TmpController), ex.Message);
    return StatusCode(StatusCodes.Status500InternalServerError);
}

方案2:控制器基类封装(适合控制器层专属日志逻辑)

如果日志模板仅在控制器层使用,可以直接把模板和日志调用逻辑都封装到自定义的控制器基类里,进一步减少重复代码:

// 自定义控制器基类
[ApiController]
[Route("api/[controller]")]
public class CustomControllerBase : ControllerBase
{
    protected readonly ILogger<CustomControllerBase> _logger;
    // 模板直接作为基类的常量,或者引用上面的静态常量类都可以
    private const string UnhandledExceptionMessageTemplate = "Unexpected exception in {Controller}: {Message}";

    public CustomControllerBase(ILogger<CustomControllerBase> logger)
    {
        _logger = logger;
    }

    // 封装统一的异常日志方法,不需要每个控制器重复写模板和参数
    protected void LogUnhandledException(Exception ex)
    {
        _logger.LogError(UnhandledExceptionMessageTemplate, GetType().Name, ex.Message);
    }
}

子类控制器继承后直接调用封装好的方法即可:

public class TmpController : CustomControllerBase
{
    public TmpController(ILogger<CustomControllerBase> logger) : base(logger)
    {
    }

    // 业务方法里的异常处理
    catch (Exception ex)
    {
        LogUnhandledException(ex);
        return StatusCode(StatusCodes.Status500InternalServerError);
    }
}

方案3:ILogger扩展方法封装(最灵活,全场景通用)

可以直接给ILogger写扩展方法,把模板和参数传递都封装到扩展里,不仅控制器能用,业务服务、仓储层等所有需要打日志的地方都可以直接调用:

public static class LoggerExtensions
{
    private const string UnhandledExceptionMessageTemplate = "Unexpected exception in {ServiceName}: {Message}";
    private const string NotFoundMessageTemplate = "Could not find {Entity} with id: {Id}";

    public static void LogUnhandledException(this ILogger logger, string serviceName, Exception ex)
    {
        logger.LogError(UnhandledExceptionMessageTemplate, serviceName, ex.Message);
    }

    public static void LogEntityNotFound<T>(this ILogger logger, object id)
    {
        logger.LogWarning(NotFoundMessageTemplate, typeof(T).Name, id);
    }
}

调用示例:

// 控制器里调用
catch (Exception ex)
{
    _logger.LogUnhandledException(nameof(TmpController), ex);
    return StatusCode(StatusCodes.Status500InternalServerError);
}

// 服务层调用
var user = _userRepo.GetById(id);
if (user == null)
{
    _logger.LogEntityNotFound<User>(id);
    return default;
}

补充说明

Serilog本身没有提供专门存储日志模板的内置功能,它的设计思路是模板属于业务定义的部分,由开发者根据自己的项目架构选择管理方式。上面三种都是业内成熟项目普遍采用的方案,你可以根据自己的项目规模选择:

  • 小型项目直接用方案1即可,维护成本最低
  • 中大型项目推荐方案1+方案3结合,全项目统一日志规范
  • 如果只有控制器层需要统一日志模板,选方案2即可

内容的提问来源于stack exchange,提问作者M-Expunged

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 19:15:03