异常堆栈跟踪中不包含行号(使用 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(但你没有)。
您应该将 StackFrames
从 0
迭代到 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());
}
我刚刚检查过,它在堆栈跟踪中显示了行号。如果您需要更多信息,请回复。