dotnet / razor

Compiler and tooling experience for Razor ASP.NET Core apps in Visual Studio, Visual Studio for Mac, and VS Code.
https://asp.net
MIT License
500 stars 191 forks source link

Generated Document inconsistent on project start #7942

Closed ryanbrandenburg closed 1 year ago

ryanbrandenburg commented 1 year ago

Repro

  1. Create a BlazorServer app in VS and navigate to the "Counter.razor" file. Close the VS instance.
  2. Delete the bin/obj directories of that project.
  3. Launch VS and open the above project. It should open straight to Counter.razor.
  4. Once the code-folding loads in notice that there is (probably, this is a timing issue so no guarantees) no fold item for "IncrementCount".
  5. Make a single non-functional edit (I add a space at the end of the file) and notice that the folding for IncrementCount appears and remains.

Analysis

On investigating this issue I find that when it happens the document is in a particular state, with "namespace _GeneratedComponent" instead of "namespace BlazorAppX" and "public partial class AspNetCore_0752594c7e14f0368c47d153dcf3b33238202539" intead of "public partial class Counter". On investigating the Compiler I found that this is a case that happens when no namespace can be determined. But in the default Blazor templates the namespace is always set in the "_Layout.cshtml" file. But I also don't see any evidence that the _Layout.cshtml file has been processed yet, it does not appear to have the special loading provided for Import files.

My hypothesis

I believe that on VS-launch there is a race condition which can cause the compiler to provide inconsistent generated CSharp results depending on whether certain dependencies (_Layout.cshtml in this case by hypothetically it could be more/others) have been loaded.

Suggested Fix

It seems to me that we should have a system similar to IImportProjectFeature for ensuring _Layout and other dependencies are loaded before returning the CodeDocument and allowing C# code generation (possibly this system should replace imports?)

jjonescz commented 1 year ago

@ryanbrandenburg I've looked into this and noticed two things while debugging:

  1. This is reproducible even without obj deleted, where it seems the root namespace should be loaded from obj\Debug\net7.0\project.razor.vs.json, right?

  2. More importantly, namespace for Counter.razor isn't picked up from _Layout.cshtml (or _Host.cshtml). The @namespace directive there is used only for the generated layout class. So it seems the compiler behaves properly, just root namespace isn't set correctly when Visual Studio starts.

ryanbrandenburg commented 1 year ago

WRT number 2 it seems that the answer is yes and no. _Layout.cshtml and _Host.cshtml don't seem to have relevance, but in the absence of a namespace directive the importSyntaxTree seems to be used I suspect that little detail was what confounded me the last time I looked at this. But something you said rattled my brain and I think got me pointed in the right direction with https://github.com/dotnet/razor/pull/8298. I'm gonna give this a look with a fresh brain next week but I think that PR (or something like it) could solve the issue from our end like you suggested, so I'll take it off your hands if you don't mind.