Skip to content

BuildRenderTree Exceptions Missing Line Numbers in .NET SDK 8.0.300+ #11432

Open
@rsandbach

Description

@rsandbach

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area-compilerUmbrella for all compiler issues

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions