前言
在《EF Core使用Simple Logging輸出日志》中,我們介紹了查詢標記 TagWith
,它可以幫助我們快速定位到需要的日志:
而在 .NET 6 中,新增了另外一個查詢標記 TagWithCallSite
,它可以標記出代碼的位置:
var?user?=?await?new?DefaultDbContext().User.Where(p?=>?p.Name?==?"My?IO").TagWith("Find?My?IO").TagWithCallSite().FirstOrDefaultAsync();
那它是怎么做到的呢?
原理探究
查看 TagWithCallSite
的源代碼:
public?static?IQueryable<T>?TagWithCallSite<T>(this?IQueryable<T>?source,[NotParameterized]?[CallerFilePath]?string??filePath?=?null,[NotParameterized]?[CallerLineNumber]?int?lineNumber?=?0)
原來,它使用了 CallerFilePathAttribute
和 CallerLineNumberAttribute
來獲取包含調用方的源文件完整路徑和調用方法的行號。
原理利用
這讓我們想到了,在《.NET 6新特性試用 | ArgumentNullException衛語句》中發現的 CallerArgumentExpressionAttribute
,它可以獲取執行的表達式。
通過添加此 Attribute,我們可以創建自己的自定義查詢標記。實現代碼如下:
public?static?IQueryable<T>?TagWithCallInfo<T>(this?IQueryable<T>?source,string??tag?=?null,[NotParameterized][CallerArgumentExpression("source")]?string??argument?=?null,[NotParameterized][CallerMemberName]?string??memberName?=?null,[NotParameterized][CallerFilePath]?string??filePath?=?null,[NotParameterized][CallerLineNumber]?int?lineNumber?=?0)
{var?stringBuilder?=?new?StringBuilder();stringBuilder.AppendLine(tag);foreach?(var?str?in?argument.Split(Environment.NewLine,?StringSplitOptions.RemoveEmptyEntries)){stringBuilder.AppendLine(str);}stringBuilder.AppendLine($@"at?{memberName}");stringBuilder.AppendLine($@"File:?{filePath}:{lineNumber}");return?source.TagWith(stringBuilder.ToString());
}
該方法不僅包含自定義標記文本,還自動包括了被調用的 LINQ 查詢表達式、方法名稱、文件路徑、行號。
Demo
運行下列代碼進行驗證,完全滿足了我們的要求:
var?user?=?await?new?DefaultDbContext().User.Where(p?=>?p.Name?==?"My?IO")????.TagWithCallInfo("Find?My?IO").FirstOrDefaultAsync();
結論
今天,通過擴展 TagWithCallSite
,我們實現了自定義查詢標記。
添加微信號【MyIO666】,邀你加入技術交流群