异常堆栈跟踪中不包含行号(使用 Roslyn 动态编译的代码)

Line Number is not included in Exception Stacktrace (Code Dynamically Compiled with Roslyn)

我使用roslyn编译器按需编译代码

现在,当编译代码中出现异常时(示例:除以零异常),我进入 Visual Studio 显示的行号:

但是当我执行 stacktrace.ToString() 时,行信息不包括在内。 在 frame.GetLineNumber 中,行号也是 0。

异常处理代码:

    try
     {
        int i = 0;
        int iiii = 5 / i; 
     }
     catch (Exception ex)
     {
        var stackTrace = new StackTrace(ex, true);
        var frame = stackTrace.GetFrame(0);

        Console.WriteLine("Exception message: {0}", ex.Message);
        Console.WriteLine("Exception in file: {0}", frame.GetFileName());
        Console.WriteLine("Exception in method: {0}", frame.GetMethod());
        Console.WriteLine("Exception at line numer: {0}", frame.GetFileLineNumber());
     }

按需编译我的代码

 CSharpParseOptions po = new CSharpParseOptions(LanguageVersion.CSharp7, DocumentationMode.Parse, SourceCodeKind.Regular);
     SyntaxTree parsedSyntaxTree = SyntaxFactory.ParseSyntaxTree(code, po);

     List<string> defaultNamespaces = GetUsings(parsedSyntaxTree);

     //// Referenzen über Kommentare heraussuchen:
     List<MetadataReference> defaultReferences = GetReferences(parsedSyntaxTree, rootPfad);

     var encoding = Encoding.UTF8;

     var assemblyName = Path.GetRandomFileName();
     var symbolsName = Path.ChangeExtension(assemblyName, "pdb");
     var sourceCodePath = "generated.cs";

     var buffer = encoding.GetBytes(code);
     var sourceText = SourceText.From(buffer, buffer.Length, encoding, canBeEmbedded: true);

     var syntaxTree = CSharpSyntaxTree.ParseText(
         sourceText,
         new CSharpParseOptions(),
         path: sourceCodePath);

     var syntaxRootNode = syntaxTree.GetRoot() as CSharpSyntaxNode;
     var encoded = CSharpSyntaxTree.Create(syntaxRootNode, null, sourceCodePath, encoding);


     CSharpCompilationOptions defaultCompilationOptions =
           new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
                   .WithOverflowChecks(true).WithOptimizationLevel(OptimizationLevel.Debug).WithPlatform(Platform.AnyCpu)
                   .WithUsings(defaultNamespaces);

     CSharpCompilation compilation = CSharpCompilation.Create(
         assemblyName,
         syntaxTrees: new[] { encoded },
         references: defaultReferences,

         options: defaultCompilationOptions
     );

     using (var assemblyStream = new MemoryStream())
     using (var symbolsStream = new MemoryStream())
     {
        var emitOptions = new EmitOptions(
                debugInformationFormat: DebugInformationFormat.PortablePdb,
                pdbFilePath: symbolsName);

        var embeddedTexts = new List<EmbeddedText> { EmbeddedText.FromSource(sourceCodePath, sourceText) };

        EmitResult result = compilation.Emit(
            peStream: assemblyStream,
            pdbStream: symbolsStream,
            embeddedTexts: embeddedTexts,
            options: emitOptions);


        if (result.Success)
        {
           Console.WriteLine("Kompilierung erfolgreich!");
           try
           {
              var assembly = Assembly.Load(assemblyStream.ToArray(), symbolsStream.ToArray());
              var parsedCodeInfo = new IM3ParsedCodeInfo() { Assembly = assembly, Erfolgreich = true };

              return parsedCodeInfo;
           }
           catch (Exception ex)
           {
              Console.WriteLine("Ausnahme aufgetreten:");
              Console.WriteLine(ex);

              var parsedCodeInfo = new IM3ParsedCodeInfo() { ErrorException = ex, Erfolgreich = false };
              return parsedCodeInfo;
           }
        }
        else
        {
           Console.WriteLine("Kompilierung nicht erfolgreich!");
           foreach (var diagnostic in result.Diagnostics)
           {
              Console.WriteLine(diagnostic.ToString());
           }

           var parsedCodeInfo = new IM3ParsedCodeInfo() { ErrorDiagnostics = result.Diagnostics, Erfolgreich = false };
           return parsedCodeInfo;
        }
     }

提供的解决方案建议图片:

更新: 根据 Hans Passant 评论:

If you are running in .NET Core you'll need PortablePDB files; for .NET Framework you'll need PDB files

根据 MSDN StackTrace.GetFrame(0) returns 最近的函数调用,即 IEnumerator<T>.MoveNext() 并且您需要 .NET Framework 的 PDB 文件或 .NET 的 PortablePDB。 NET Core(但你没有)。

您应该将 StackFrames0 迭代到 StackTrace.FrameCount - 1,在第一个 StackFrame.GetFileLineNumber() > 0:

处停止
var stack = new StackFrame(ex, true);
StackFrame frame = null;
for (int i = 0; i < stack.FrameCount; i++)
{
    frame = stack.GetFrame(i);
    if (frame.GetFileLineNumber() > 0) break;
}

Console.WriteLine("Exception message: {0}", ex.Message);
Console.WriteLine("Exception in file: {0}", frame.GetFileName());
Console.WriteLine("Exception in method: {0}", frame.GetMethod());
Console.WriteLine("Exception at line number: {0}", frame.GetFileLineNumber());

这会正确打印

Exception message: Sequence contains no elements

Exception in file: [FilePath]\Root.cs

Exception in method: System.Object GetModuleDescription(System.Object[])

Exception at line number: 70

您还必须在脚本选项中提供源文件。

在我的例子中是这样的:

var options = ScriptOptions.Default
                           .WithReferences(references)
                           .WithFilePath(sourceFile)
                           .WithFileEncoding(sourceFileEncoding)
                           .WithEmitDebugInformation(true)
                           .WithImports(imports);

注意 WithFilePath(sourceFile)

在我的例子中,我将使用创建脚本:

CSharpScript.Create(this.Content, options, globalType);

然后获取程序集:

script.Compile();
var stream = new MemoryStream();
using (stream)
{
  var emitResult = script.GetCompilation().Emit(stream);

  if (emitResult.Success)
    return Assembly.Load(stream.ToArray());
}

我刚刚检查过,它在堆栈跟踪中显示了行号。如果您需要更多信息,请回复。