Description
I've been troubleshooting an issue that I have noticed when compiling razor in .NET SDK 8.0.206
vs .NET SDK 8.0.300+
that appears to have started with #10006 (8dafe2f). Changes were made to ComponentRuntimeNodeWriter.cs
that affect how debug symbols are generated.
Prior to 8.0.300, an exception thrown in BuildRenderTree, during runtime and debugging, would include the line number of the razor file.
Consider this razor component:
Home.razor
@page "/"
@test.Name
<button @onclick="ThrowInRenderTree">Render Tree</button>
<button @onclick="ThrowInCodeBlock">Code Block</button>
@code {
TestClass test = new() { Name = "Hello" };
class TestClass {
public required string Name { get; set; }
}
void ThrowInRenderTree() {
test = null;
}
void ThrowInCodeBlock(){
throw new NullReferenceException("Code Block");
}
}
After clicking the 'RenderTree' button (8.0.206)
warn: Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer[100]
Unhandled exception rendering component: Object reference not set to an instance of an object.
System.NullReferenceException: Object reference not set to an instance of an object.
at test_debug_symbols.Components.Pages.Home.BuildRenderTree(RenderTreeBuilder __builder)
in C:\Users\source\repos\test-debug-symbols\Components\Pages\Home.razor:line 2
at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment, Exception& renderFragmentException)
After clicking the 'RenderTree' button (8.0.300)
warn: Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer[100]
Unhandled exception rendering component: Object reference not set to an instance of an object.
System.NullReferenceException: Object reference not set to an instance of an object.
at test_debug_symbols.Components.Pages.Home.BuildRenderTree(RenderTreeBuilder __builder)
at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment, Exception& renderFragmentException)
Home_razor.g.cs Snippet (8.0.206)
The enhanced line directive is not nested in AddContent.
#line hidden
#nullable disable
[global::Microsoft.AspNetCore.Components.RouteAttribute("/")]
public partial class Home : global::Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 1998
protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
#nullable restore
#line (2,2)-(2,11) 24 "C:\Users\source\repos\test-debug-symbols\Components\Pages\Home.razor"
__builder.AddContent(0, test.Name);
Home_razor.g.cs Snippet (8.0.300)
The line directive is nested within the method parameter.
#line hidden
#nullable disable
)]
#nullable restore
public partial class Home : global::Microsoft.AspNetCore.Components.ComponentBase
#nullable disable
{
#pragma warning disable 1998
protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__builder.AddContent(0,
#nullable restore
#line (2,2)-(2,11) "C:\Users\source\repos\test-debug-symbols\Components\Pages\Home.razor"
test.Name
#line default
#line hidden
#nullable disable
);
This creates issues during debugging, as visual studio has to decompile the assembly vs being able to locate the source file when the exception is thrown. It also prevents runtime exceptions from including line numbers, as the PDB does not include the hidden lines.
Console Application to demonstrate the impact of moving the #line directive
#line hidden
using test_cmd;
var x = new MockBuilder();
Test test = null;
#line (2,2)-(2,11) 2 "C:\Users\source\repos\test-debug-symbols\Components\Pages\Home.razor"
x.AddContent(0, test.Name);
#line default
class Test
{
public string Name { get; set; }
}
Stack Trace shows the correct line number:
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
at Program.<Main>$(String[] args) in C:\Users\source\repos\test-debug-symbols\Components\Pages\Home.razor:line 2
#line hidden
using test_cmd;
var x = new MockBuilder();
Test test = null;
x.AddContent(0,
#line (2, 2) - (2, 11) 2 "C:\Users\source\repos\test-debug-symbols\Components\Pages\Home.razor"
test.Name
#line default
);
class Test
{
public string Name { get; set; }
}
The stack trace is missing the line number.
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
at Program.<Main>$(String[] args)
Activity