C#查看堆棧通常是在異常處理中,出現異常之后通過異常的堆棧可以很方便的得到出現這個錯誤的代碼調用路徑。這個很有用,是否可以在沒有異常出現時使用這種方法排查一些非異常錯誤呢?答案是肯定的。
起因:
論壇發帖子有幾個途徑,有可能是新聞系統直接導入的帖子,也有可能是抓取的帖子,還有可能是用戶通過正常途徑發表。但是這兩天出了一個問題,有些帖子的HasImage屬性不對。通過幾種方法做調試都不能重現問題,沒有辦法,只有在程序中添加回復的地方添加日志程序來記錄堆棧,從而追蹤到是哪個途徑發帖出現了問題。
代碼:
[PostProviderExtension] public class HasImageErrorCheckerPostExtension : IPostProviderExtension { public void BindEvents(PostProviderBase postProvider) { postProvider.Added += new PostChanged(postProvider_Added); } void postProvider_Added(Model.PostInfo post) { try { StackFrame[] stacks = new StackTrace().GetFrames(); if (post.Content.IndexOf("IMG") > -1 && post.HasImage == false) { StringBuilder sb = new StringBuilder(); sb.AppendLine("問題出現"); sb.AppendLine("stack is:"); sb.Append(ToString(stacks)); sb.Append("content="); sb.AppendLine(post.Content); sb.Append("HasImage="); sb.AppendLine(UserPostContentProcessor.HasImage(post.Content).ToString()); sb.Append("createUserID="); sb.AppendLine(post.CreateUserID.ToString()); sb.AppendLine(string.Format("LoginUser={0},Level={1}",PageBase.GetLoginUser().ID,PageBase.GetLoginUser().LevelNo)); TextLogWriter.NamedInstance("\\log\\HasImageErrorCheckerPostExtension\\").Write(sb.ToString()); } } catch (Exception ex) { TextLogWriter.NamedInstance("\\log\\HasImageErrorCheckerPostExtension\\").Write(ex); } } private string ToString(StackFrame[] stacks) { string result = string.Empty; foreach (StackFrame stack in stacks) { result += string.Format("{0} {1} {2} {3}\r\n", stack.GetFileName(), stack.GetFileLineNumber(), stack.GetFileColumnNumber(), stack.GetMethod().ToString()); } return result; } }
上面類HasImageErrorCheckerPostExtension繼承自IPostProviderExtension並且有PostProviderExtension屬性修飾,系統會自動調用它並在發帖時觸發這里綁定的事件。這里的核心代碼是new StackTrace().GetFrames()通過這個方法可以得到當前程序執行時的堆棧信息。在Release模式下可以得到調用的方法名,在Debug模式下可以得到具體的文件行號,列號。
這個方法是調試中不能重現問題時的一種查找問題的選擇方案。