.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
相关产品推荐
相关产品推荐

