尝试通过 Serilog 上下文、using 语句和一些 try/catch 块来理解最佳实践。当我在一些方法中记录任何内容时,我试图在 Serilog 上下文中包含一些数据的 ID。
所有这些方法都被简单的 try/catch 块包围,我正在尝试找出插入
using
语句的最佳方法。
第一个方法对我来说是正确的,因为我知道它将在方法结束时被处置 - 但如果
try
块内出现错误,它仍然会处置我的ctxId
对象吗?我的直觉告诉我不行,但我似乎找不到答案。
[Route("method")]
public async Task<IActionResult> Method(Parameters params) {
using var ctxId = Serilog.Context.LogContext.PushProperty("Id", params.Id.ToString());
try {
// do stuff
_logger.LogInformation("info...");
}
catch (Exception ex) {
_logger.LogError("error...", ex);
}
}
理想情况下,我不想做这样的事情(如下)并重复这些行。
[Route("method")]
public async Task<IActionResult> Method(Parameters params) {
try {
// do stuff
using var ctxId = Serilog.Context.LogContext.PushProperty("Id", params.Id.ToString());
_logger.LogInformation("info...");
}
catch (Exception ex) {
using var ctxId = Serilog.Context.LogContext.PushProperty("Id", params.Id.ToString());
_logger.LogError("error...", ex);
}
}
但是如果 try 块内出现错误,它仍然会处置我的 ctxId 对象吗?
是的。
using
仍然只是 try/finally 的“语法糖”。所以你的方法被重写为:
ContextId ctxId = null;
try{
ctxId = Serilog.Context.LogContext.PushProperty("Id", params.Id.ToString());
try {
// do stuff
_logger.LogInformation("info...");
}
catch (Exception ex) {
_logger.LogError("error...", ex);
}
}
finally{
ctxId?.Dispose();
}
无论
//do stuff
中发生什么*,ctxId?.Dispose()
仍然会运行。一般来说,最佳实践是尽可能缩小变量的范围。 (在合理范围内,使用精细范围也会损害可读性)。如果这就是整个方法,就像您的情况一样,那就完全没问题了。
[ * ] 有一些异常是无法捕获的,例如 StackOverflowException。那时您必须依靠操作系统来进行任何清理。