获取 ASP.NET Core 中发生异常的行号

Posted

技术标签:

【中文标题】获取 ASP.NET Core 中发生异常的行号【英文标题】:Get line number where exception occurred in ASP.NET Core 【发布时间】:2016-11-14 15:10:18 【问题描述】:

我已经根据这篇博文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)的值。

【问题讨论】:

在优化代码中。发布版本,汇编代码/IL 代码可能不再匹配行号。 @Thomas 不匹配和完全为空是有区别的。 @Thomas 发布版本中没有行号 现在我对 DavidG 和 user3185569 的回答很感兴趣。 只要你有 PDB 文件,你应该可以得到行号。你确定你有正确的文件并且没有权限问题吗? 【参考方案1】:

看看DeveloperErrorPageMiddlewareimplementation:

    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;
    

【讨论】:

这对所提出的问题有何帮助? 无论如何都会有所帮助。我现在注意到我确实得到了 DeveloperExceptionPage 的行号。但是,查看源代码,它似乎是从堆栈跟踪中获取的,而我不是。

以上是关于获取 ASP.NET Core 中发生异常的行号的主要内容,如果未能解决你的问题,请参考以下文章

[Asp.Net Core]ExceptionFilter能捕捉到哪些异常

Angular 和 .Net Core 项目 VS 2022:发生未处理的异常:项目 'Leon\AppData\Roaming\ASP.NET\https\<projectName>.p

启用 ASP.NET 模拟时,异常堆栈跟踪中缺少行号

理解ASP.NET Core

非托管代码中的 ASP Net Core 1.1 和 EF 6 异常?

ASP.Net Core 2 错误处理:如何在 Http Response 中返回格式化的异常详细信息?