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
489 stars 190 forks source link

Razor views not existing after updating from .NET 5 to .NET 6 in Identity.UI #7251

Open Ben555555 opened 2 years ago

Ben555555 commented 2 years ago

Is there an existing issue for this?

Describe the bug

After migrating from .NET5 to .NET6 the razor views don't work anymore for Microsoft.AspNetCore.Identity.UI. We use scaffold to setup the identity server razor pages. When I open the Login page "https://localhost:44390/Identity/Account/Login" I get the following exception:

InvalidOperationException: The default Identity UI layout requires a partial view '_LoginPartial' usually located at '/Pages/_LoginPartial' or at '/Views/Shared/_LoginPartial' to work. Based on your configuration we have looked at it in the following locations: /Areas/Identity/Pages/Account/_LoginPartial.de-CH.cshtml /Areas/Identity/Pages/Account/_LoginPartial.de.cshtml /Areas/Identity/Pages/Account/_LoginPartial.cshtml /Areas/Identity/Pages/_LoginPartial.de-CH.cshtml /Areas/Identity/Pages/_LoginPartial.de.cshtml /Areas/Identity/Pages/_LoginPartial.cshtml /Areas/Identity/Pages/Shared/_LoginPartial.de-CH.cshtml /Areas/Identity/Pages/Shared/_LoginPartial.de.cshtml /Areas/Identity/Pages/Shared/_LoginPartial.cshtml /Areas/Identity/Views/Shared/_LoginPartial.de-CH.cshtml /Areas/Identity/Views/Shared/_LoginPartial.de.cshtml /Areas/Identity/Views/Shared/_LoginPartial.cshtml /Pages/Shared/_LoginPartial.de-CH.cshtml /Pages/Shared/_LoginPartial.de.cshtml /Pages/Shared/_LoginPartial.cshtml /Views/Shared/_LoginPartial.de-CH.cshtml /Views/Shared/_LoginPartial.de.cshtml /Views/Shared/_LoginPartial.cshtml. Microsoft.AspNetCore.Identity.UI.V5.Pages.Internal.Areas_Identity_Pages_V5Layout.b43_1()

The listed path "/Views/Shared/_LoginPartial.cshtml" clearly exists. It looks like the views are not even compiled, according to the size of the compiled Dlls.

When I turn on runtime compilation it seems to work. But this won't work after deployment. builder.AddRazorRuntimeCompilation();

I didn't change anything else, except the .NET version and the corresponding libraries from 5 to 6.

Also what I have noticed is that some routes are not mapped anymore which in the previous version were mapped: /Identity/Account/Login /Account/Login <= not mapped anymore

Expected Behavior

The pages razor pages should render as expected.

Steps To Reproduce

No response

Exceptions (if any)

InvalidOperationException: The default Identity UI layout requires a partial view '_LoginPartial' usually located at '/Pages/_LoginPartial' or at '/Views/Shared/_LoginPartial' to work. Based on your configuration we have looked at it in the following locations: /Areas/Identity/Pages/Account/_LoginPartial.de-CH.cshtml /Areas/Identity/Pages/Account/_LoginPartial.de.cshtml /Areas/Identity/Pages/Account/_LoginPartial.cshtml /Areas/Identity/Pages/_LoginPartial.de-CH.cshtml /Areas/Identity/Pages/_LoginPartial.de.cshtml /Areas/Identity/Pages/_LoginPartial.cshtml /Areas/Identity/Pages/Shared/_LoginPartial.de-CH.cshtml /Areas/Identity/Pages/Shared/_LoginPartial.de.cshtml /Areas/Identity/Pages/Shared/_LoginPartial.cshtml /Areas/Identity/Views/Shared/_LoginPartial.de-CH.cshtml /Areas/Identity/Views/Shared/_LoginPartial.de.cshtml /Areas/Identity/Views/Shared/_LoginPartial.cshtml /Pages/Shared/_LoginPartial.de-CH.cshtml /Pages/Shared/_LoginPartial.de.cshtml /Pages/Shared/_LoginPartial.cshtml /Views/Shared/_LoginPartial.de-CH.cshtml /Views/Shared/_LoginPartial.de.cshtml /Views/Shared/_LoginPartial.cshtml. Microsoft.AspNetCore.Identity.UI.V5.Pages.Internal.Areas_Identity_Pages_V5Layout.b43_1()

.NET Version

6.0.202

Anything else?

No response

javiercn commented 2 years ago

@Ben555555 thanks for contacting us.

Can you provide a minimal repro project that illustrates this issue?

Ben555555 commented 2 years ago

After digging for hours I found a possible solution or the root of the problem. While building the following message appears. Since it's only a warning I didn't quite give it any attention:

1>CSC : warning CS8785: Generator 'RazorSourceGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'NullReferenceException' with message 'Object reference not set to an instance of an object.'

From another source I found that you get more detailed information by adding the following to the csproj file:

  <PropertyGroup>
    <UseRazorSourceGenerator>false</UseRazorSourceGenerator>
  </PropertyGroup>

This didn't give me any additional information though, but suddenly the razor views were compiled and also all the route mappings were there!

@javiercn If this doesn't point out the problem, nor is a good solution I can provide a minimal repo though.

@javiercn Edit: I added the minimal repo: IdentityServer.zip

javiercn commented 2 years ago

@Ben555555 thanks, that is indeed useful information.

Seems that it is a razor-compiler issue, so I'm going to transfer it there.

javiercn commented 2 years ago

@jaredpar is there any way to get the callstack when a source generator fails with an exception?

jaredpar commented 2 years ago

@RikkiGibson, @chsienki

chsienki commented 2 years ago

@javiercn I can repro it and will take a deeper look later, it looks like there is a RazorCompiledItemMetadataAttribute with a null .Value. Here is the callstack if you also want to look into it

Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.CodeGeneration.CodeWriterExtensions.WriteStringLiteral(Microsoft.AspNetCore.Razor.Language.CodeGeneration.CodeWriter writer, string literal) Line 121
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/CodeWriterExtensions.cs(121)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.Extensions.MetadataAttributeTargetExtension.WriteRazorCompiledItemMetadataAttribute(Microsoft.AspNetCore.Razor.Language.CodeGeneration.CodeRenderingContext context, Microsoft.AspNetCore.Razor.Language.Extensions.RazorCompiledItemMetadataAttributeIntermediateNode node) Line 63
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/Extensions/MetadataAttributeTargetExtension.cs(63)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.Extensions.RazorCompiledItemMetadataAttributeIntermediateNode.WriteNode(Microsoft.AspNetCore.Razor.Language.CodeGeneration.CodeTarget target, Microsoft.AspNetCore.Razor.Language.CodeGeneration.CodeRenderingContext context) Line 59
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/Extensions/RazorCompiledItemMetadataAttributeIntermediateNode.cs(59)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.CodeGeneration.DefaultDocumentWriter.Visitor.VisitExtension(Microsoft.AspNetCore.Razor.Language.Intermediate.ExtensionIntermediateNode node) Line 223
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/DefaultDocumentWriter.cs(223)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.Intermediate.ExtensionIntermediateNode.AcceptExtensionNode<Microsoft.AspNetCore.Razor.Language.Extensions.RazorCompiledItemMetadataAttributeIntermediateNode>(Microsoft.AspNetCore.Razor.Language.Extensions.RazorCompiledItemMetadataAttributeIntermediateNode node, Microsoft.AspNetCore.Razor.Language.Intermediate.IntermediateNodeVisitor visitor) Line 27
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/Intermediate/ExtensionIntermediateNode.cs(27)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.Extensions.RazorCompiledItemMetadataAttributeIntermediateNode.Accept(Microsoft.AspNetCore.Razor.Language.Intermediate.IntermediateNodeVisitor visitor) Line 37
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/Extensions/RazorCompiledItemMetadataAttributeIntermediateNode.cs(37)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.Intermediate.IntermediateNodeVisitor.Visit(Microsoft.AspNetCore.Razor.Language.Intermediate.IntermediateNode node) Line 13
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/Intermediate/IntermediateNodeVisitor.cs(13)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.CodeGeneration.DefaultCodeRenderingContext.RenderChildren(Microsoft.AspNetCore.Razor.Language.Intermediate.IntermediateNode node) Line 146
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/DefaultCodeRenderingContext.cs(146)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.CodeGeneration.DefaultDocumentWriter.Visitor.VisitDefault(Microsoft.AspNetCore.Razor.Language.Intermediate.IntermediateNode node) Line 318
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/DefaultDocumentWriter.cs(318)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.CodeGeneration.DefaultDocumentWriter.Visitor.VisitNamespaceDeclaration(Microsoft.AspNetCore.Razor.Language.Intermediate.NamespaceDeclarationIntermediateNode node) Line 144
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/DefaultDocumentWriter.cs(144)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.Intermediate.NamespaceDeclarationIntermediateNode.Accept(Microsoft.AspNetCore.Razor.Language.Intermediate.IntermediateNodeVisitor visitor) Line 24
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/Intermediate/NamespaceDeclarationIntermediateNode.cs(24)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.Intermediate.IntermediateNodeVisitor.Visit(Microsoft.AspNetCore.Razor.Language.Intermediate.IntermediateNode node) Line 13
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/Intermediate/IntermediateNodeVisitor.cs(13)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.CodeGeneration.DefaultCodeRenderingContext.RenderChildren(Microsoft.AspNetCore.Razor.Language.Intermediate.IntermediateNode node) Line 146
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/DefaultCodeRenderingContext.cs(146)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.CodeGeneration.DefaultDocumentWriter.Visitor.VisitDefault(Microsoft.AspNetCore.Razor.Language.Intermediate.IntermediateNode node) Line 318
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/DefaultDocumentWriter.cs(318)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.CodeGeneration.DefaultDocumentWriter.Visitor.VisitDocument(Microsoft.AspNetCore.Razor.Language.Intermediate.DocumentIntermediateNode node) Line 131
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/DefaultDocumentWriter.cs(131)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.CodeGeneration.DefaultDocumentWriter.WriteDocument(Microsoft.AspNetCore.Razor.Language.RazorCodeDocument codeDocument, Microsoft.AspNetCore.Razor.Language.Intermediate.DocumentIntermediateNode documentNode) Line 46
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/DefaultDocumentWriter.cs(46)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.DefaultRazorCSharpLoweringPhase.ExecuteCore(Microsoft.AspNetCore.Razor.Language.RazorCodeDocument codeDocument) Line 29
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorCSharpLoweringPhase.cs(29)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.RazorEnginePhaseBase.Execute(Microsoft.AspNetCore.Razor.Language.RazorCodeDocument codeDocument) Line 43
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/RazorEnginePhaseBase.cs(43)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.DefaultRazorEngine.Process(Microsoft.AspNetCore.Razor.Language.RazorCodeDocument document) Line 50
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorEngine.cs(50)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.DefaultRazorProjectEngine.ProcessCore(Microsoft.AspNetCore.Razor.Language.RazorCodeDocument codeDocument) Line 268
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectEngine.cs(268)
Microsoft.AspNetCore.Razor.SourceGenerator.Tooling.Internal.dll!Microsoft.AspNetCore.Razor.Language.RazorProjectEngine.Process(Microsoft.AspNetCore.Razor.Language.RazorProjectItem projectItem) Line 37
    at /_/src/Microsoft.AspNetCore.Razor.Language/src/RazorProjectEngine.cs(37)
javiercn commented 2 years ago

@chsienki is the RazorCompiledItemMetadataAttribute with a null value inside the Microsoft.AspNetCore.Identity.UI assembly?

chsienki commented 2 years ago

Ah ok, I think I see what is going on. The crash happens because the razor files inside Templates don't have a target path (we should fix that, I'll open an issue).

They don't have a target path because it looks like they aren't supposed to be compiled at all. In the csproj we have

  <ItemGroup>
    <!-- Make sure razor email templates are not pre-compiled during build, only by MiniRazor -->
    <Compile Remove="Templates\Email\**" />
    <Content Remove="Templates\Email\**" />
    <EmbeddedResource Remove="Templates\Email\**" />
    <None Remove="Templates\Email\**" />
    <AdditionalFiles Include="Templates\Email\*.cshtml" IsRazorTemplate="true" />
  </ItemGroup>

Presumably that logic removed them from the pre-compilation pipeline, but they're still getting included in the source generator as they're additional files ending .cshtml

chsienki commented 2 years ago

@javiercn I'm not actually sure how we can fix this, the generator is always going to generate for every .cshtml and .razor file. In this case this files shouldn't be compiled by the razor generator; fixing the target path will just lead to build errors.

Either we need a way of allowing users to exclude files from the generator (a metadata value would be an easy way to do that) or say that you just can't do this and are required to use a different extension for the templates.

chsienki commented 2 years ago

Oh, actually, if we fix the target path issue, it might be as simple as just ignoring anything without a target path. Effectively that says 'the generator targets added this file', and anything else we just ignore.

chsienki commented 2 years ago

Filed https://github.com/dotnet/razor-tooling/issues/7236 to track not crashing when target path is empty

javiercn commented 2 years ago

@chsienki I've taken a look based on your comments and seems reasonable.