我已根据此博文https://blog.kloud.com.au/2016/03/23/aspnet-core-tips-and-tricks-global-exception-handling/实现了自定义异常过滤器。
我现在注意到我无法从StackFrame获取发生异常的文件名或行号;方法GetFileLineNumber的值始终为0.
我尝试过的一个简单示例:
StackTrace trace = new StackTrace(exception, true);
StackFrame[] stackFrames = trace.GetFrames();
if (stackFrames != null) {
foreach (StackFrame traceFrame in stackFrames) {
sourceFile = traceFrame.GetFileName();
sourceLineNumber = traceFrame.GetFileLineNumber();
}
}
提一下:GetFileName也返回null,但我可以从不同的位置获取命名空间和类名,所以这不是问题。
在某个地方注意到我应该在文件夹上有PDB文件才能工作,我检查了我已经拥有它。即使它起作用,它也应该在生产环境中起作用。
还尝试使用来电者信息(https://msdn.microsoft.com/en-us/library/mt653988.aspx),但有一些不同的问题。异常过滤器必须实现IExceptionFilter接口并使用它的方法。因此,即使属性是可选的,我也无法添加属性。
以下是Startup.cs的代码部分:
public void ConfigureServices(IServiceCollection services) {
...
services.AddMvc(config => {
config.Filters.Add(new ApplicationExceptionFilter());
});
}
这是自定义过滤器
public class ApplicationExceptionFilter : IExceptionFilter {
public void OnException(ExceptionContext context) {
ApplicationExceptionHandler.handleException(context.HttpContext, context.Exception);
}
}
我尝试获取来电者信息的原因是:
public void OnException(ExceptionContext context,
[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) {
但由于它不再实现接口,因此无效。
如何在一个地方处理异常时获取行号?
假设我的问题是我没有从堆栈跟踪中获取行号并重现问题:
public ActionResult ServerError() {
Int32 x = 0;
try {
return Content((1 / x).ToString());
} catch (Exception ex) {
StackTrace trace = new StackTrace(ex, true);
StackFrame[] stackFrames = trace.GetFrames();
if (stackFrames != null) {
foreach (StackFrame traceFrame in stackFrames) {
String sourceFile = traceFrame.GetFileName();
int sourceLineNumber = traceFrame.GetFileLineNumber();
}
}
}
return Content("");
}
仍未获取sourceFile(它为null)或sourceLineNumber(它为0)的值。
答案 0 :(得分:-1)
查看DeveloperErrorPageMiddleware
implementation:
private IEnumerable<ErrorDetails> GetErrorDetails(Exception ex)
{
for (var scan = ex; scan != null; scan = scan.InnerException)
{
var stackTrace = ex.StackTrace;
yield return new ErrorDetails
{
Error = scan,
StackFrames = StackTraceHelper.GetFrames(ex)
.Select(frame => GetStackFrame(frame.MethodDisplayInfo.ToString(), frame.FilePath, frame.LineNumber))
};
};
}
// make it internal to enable unit testing
internal StackFrame GetStackFrame(string method, string filePath, int lineNumber)
{
var stackFrame = new StackFrame
{
Function = method,
File = filePath,
Line = lineNumber
};
if (string.IsNullOrEmpty(stackFrame.File))
{
return stackFrame;
}
IEnumerable<string> lines = null;
if (File.Exists(stackFrame.File))
{
lines = File.ReadLines(stackFrame.File);
}
else
{
// Handle relative paths and embedded files
var fileInfo = _fileProvider.GetFileInfo(stackFrame.File);
if (fileInfo.Exists)
{
// ReadLines doesn't accept a stream. Use ReadLines as its more efficient
// relative to reading lines via stream reader
if (!string.IsNullOrEmpty(fileInfo.PhysicalPath))
{
lines = File.ReadLines(fileInfo.PhysicalPath);
}
else
{
lines = ReadLines(fileInfo);
}
}
}
if (lines != null)
{
ReadFrameContent(stackFrame, lines, stackFrame.Line, stackFrame.Line);
}
return stackFrame;
}