Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Discussion] Razor compiler no longer produces a Views assembly #7577

Open
captainsafia opened this issue Apr 6, 2021 · 22 comments
Open

[Discussion] Razor compiler no longer produces a Views assembly #7577

captainsafia opened this issue Apr 6, 2021 · 22 comments
Labels
area-compiler Umbrella for all compiler issues untriaged

Comments

@captainsafia
Copy link
Member

Discussion post for the the change made in .NET 6 Preview 3 to remove two-step compilation from the Razor compiler.

@Mike-E-angelo
Copy link

Thank you for making a discussion post. 😁 I wanted to share my appreciation for this decision and for all the work being done to improve this part of the razor development process. It is very much appreciated. 🙏

@stefanloerwald
Copy link

I'm very happy to see the Blazor team tackle this big effort early on in the development of .NET 6. Thank you so much!

I would love to read the source code, but searching for the source generator wasn't successful (github's search isn't exactly the best). Could you please point me towards the SG code for razor?

Thanks
Stefan

Side note: I suspect the announcement post contains a minor error saying that the new behavior is to generate a dll called AppName.Views.dll, where it probably should say AppName.dll.

@watfordgnf
Copy link

@stefanloerwald
Copy link

@stefanloerwald it looks like https://github.com/dotnet/sdk/tree/main/src/RazorSdk/SourceGenerators has most of the work to take the language from https://github.com/dotnet/aspnetcore/tree/main/src/Razor/Microsoft.AspNetCore.Razor.Language and tie it into a source generator.

Thank you so much! I didn't think to look in any of the sister repos.

@theCuriousOne
Copy link

Does this also means the hot reload for Razor Views will no longer be available/supported?

@captainsafia
Copy link
Member Author

Side note: I suspect the announcement post contains a minor error saying that the new behavior is to generate a dll called AppName.Views.dll, where it probably should say AppName.dll.

Oof! Yes, it does. Shouldn't have written that post so quickly. Too many typos. 😲

Does this also means the hot reload for Razor Views will no longer be available/supported?

So, hot reload is a new feature that we're shipping in .NET 6 Preview 3, the same release that this feature is being shipped alongside so this doesn't really change anything about the way things used to work (e.g. the "no longer" part) since hot reload is new.

In fact, this work helps enable hot-reload scenarios. The hot reload feature that we are shipping works by communicating deltas of IL code to the running application. The running app then applies those deltas to the app as part of the update. The feature currently only supports communicating deltas for a single assembly for the work we did here was necessary to get things working correctly for hot reload.

@stefanloerwald it looks like https://github.com/dotnet/sdk/tree/main/src/RazorSdk/SourceGenerators has most of the work to take the language from https://github.com/dotnet/aspnetcore/tree/main/src/Razor/Microsoft.AspNetCore.Razor.Language and tie it into a source generator.

@stefanloerwald @watfordgnf Thanks for digging up the code. We lifted and shifted the SDKs from the aspnetcore repo to the sdk repo for .NET 6.

A quick note: you might spot that we leverage static members to do some "caching" in the RSG. This is temporary workaround that we will be replacing with the work outlined dotnet/aspnetcore#31244. Depending on when folks come across this thread, I would recommend using the API mentioned in the issue above for your RSG instead of using the temporary workaround we've employed here.

@pranavkm
Copy link
Contributor

pranavkm commented Apr 7, 2021

@theCuriousOne to add to @captainsafia's comment - starting in preview3, hot reload will be enabled for MVC apps including Razor views. Our goal is to make is compelling enough to replace runtime compilation with hot reload as the default dev workflow by the end of 6.0. At this point, hot reload for .cshtml files is a little crummy - the code that cshtml generates doesn't play very well with hot reload forcing it do a full rebuild more often than we'd like to and we're looking to tackle it.

@drdamour
Copy link

drdamour commented May 2, 2021

@captainsafia i suspect when @theCuriousOne said razor hot reload, really what was beign asked about is razor runtime compilation. https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-compilation?view=aspnetcore-5.0&tabs=visual-studio#enable-runtime-compilation-in-an-existing-project is that now deprecated in favour of hot reload?

@theCuriousOne
Copy link

@drdamour Thank you. I had no idea it was called differently. I know that in .net framework I used to change a razor page -> save the file -> changes are visible in browser (without the need to rebuild project/solution).

@soundaranbu
Copy link

Hi @captainsafia , Good day!
I'm working on a library Razor.Templating.Core which helps to render string out of .cshtml files in all kinds of workloads(Web, Console, Worker Service, etc). This library is already being used in many projects which are in production right now.

For apps that targets SDKs other than Microsoft.NET.Sdk.Web, to load the Application Parts, I used to discover the RCL assemblies using RelatedAssemblyAttribute which was added to the main RCL assembly. This was the only work around for me because ApplicationPartAttribute was not added to the main entry assembly for SDKs that don't target the web sdk.

Now with this change RelatedAssemblyAttribute is no longer getting added to the RCL assemblies which removes the only work around to discover the RCL assemblies and the precompiled view assemblies for non-web sdk.
Reference to affected method: https://github.com/soundaranbu/RazorTemplating/blob/e6ff3dbbbc807e075ce7a1173096e941a7e747b4/src/Razor.Templating.Core/RazorViewToStringRendererFactory.cs#L138-L177

My Request:

  • Please add a way to discover the RCL assemblies in non-web projects by adding an attribute that tells that this is RCL assembly
  • Or add ApplicationPart attribute to the entry assembly of non-web sdk projects as well
  • Or if there's a way already, kindly let me know how.

@chrfin
Copy link

chrfin commented May 14, 2021

@soundaranbu If I get this whole thing correctly there is no *.Views.dll anymore and thus no RelatedAssembly. The views are part of the main DLL in .NET 6 any you do not need to load parts from any other assembly anymore - all are in the main DLL.

@soundaranbu
Copy link

@soundaranbu If I get this whole thing correctly there is no *.Views.dll anymore and thus no RelatedAssembly.

This is correct.

The views are part of the main DLL in .NET 6 any you do not need to load parts from any other assembly anymore - all are in the main DLL.

This is also correct only when there are no references to external Razor Class Libraries(RCL)

But my library use case is to support razor templating(.cshtml to string) not just for web application but also out of web apps like console, worker service, azure functions, etc).
The way web applications discover application parts is by looking at the ApplicationPartAttribute in the main dll when you add reference to one or more Razor Class Library projects.

Hence, I need a mechanism to discover the application parts for non web apps as the existing mechanism got removed by this change. Please go over my request again

My Request:

  • Please add a way to discover the RCL assemblies in non-web projects by adding an attribute that tells that this is RCL assembly
  • Or add ApplicationPart attribute to the entry assembly of non-web sdk projects as well
  • Or if there's a way already, kindly let me know how.

@soundaranbu
Copy link

I think I found a way to solve this by looking at the SDK code. Thanks to Open Source!
https://github.com/dotnet/sdk/blob/main/src/RazorSdk/Targets/Microsoft.NET.Sdk.Razor.MvcApplicationPartsDiscovery.targets
It looks like the RCL libraries are identified by checking if they have any reference to any MVC assemblies.

@ghost
Copy link

ghost commented Jul 15, 2021

Thank you for contacting us. Due to a lack of activity on this discussion issue we're closing it in an effort to keep our backlog clean. If you believe there is a concern related to the ASP.NET Core framework, which hasn't been addressed yet, please file a new issue.

This issue will be locked after 30 more days of inactivity. If you still wish to discuss this subject after then, please create a new issue!

@ghost ghost closed this as completed Jul 15, 2021
@captainsafia
Copy link
Member Author

Re-opening to provide space for further convo.

@captainsafia captainsafia reopened this Jul 15, 2021
@ebicoglu
Copy link

after migrating to .NET6 preview we have a little problem with obfuscation step of our devops pipeline.
I guess the team changed the access modifier of the page inherited classes from public to internal seal class.
as this is not public anymore the Razor Page names are being obfuscated now.
how can I revert this to public?

The following screenshot shows an obfuscated binary with .NET6 and .NET5
image

@pranavkm
Copy link
Contributor

@ebicoglu could you elaborate on why it's important to not obfuscate view types? Views are typically looked up by paths and aren't meant to be directly referenced by app code, so the fact that they're well-formed doesn't seem like an issue.

@nfplee
Copy link

nfplee commented Nov 17, 2021

@pranavkm this has led to an issue you helped me out with a few years back. I have upgraded the samples to show a working ASP.NET Core 5 application and an almost identical app targetting ASP.NET Core 6 which does not work. To test run the applications and click on the "MyLibrary" link.

AspNetCore5.zip
AspNetCore6.zip

I understand the reason why this is no longer working but is there a way to get this to work for .NET 6?

Update:

When I compare .NET 5 which produces the following attribute with the fix:

[RazorSourceChecksum("SHA1", "xxx", "/MyLibrary/Views/Home/Index.cshtml")]

I notice that in .NET 6 it produces:

[RazorCompiledItemMetadata("Identifier", "/Areas/MyLibrary/Views/Home/Index.cshtml")]

Therefore from my understanding I need to override the identifier produced in the RazorCompiledItemMetadataAttribute. Searching for that led me to the CreateNewOnMetadataUpdateAttributePass class. It seems the indentifier's value is generated by the following code:

var identifierFeature = Engine.Features.OfType<IMetadataIdentifierFeature>().First();
var identifier = identifierFeature.GetIdentifier(codeDocument, codeDocument.Source);

I'm guessing I need to implement my own IMetadataIdentifierFeature and register it first in the list of features. This is where I get lost as I can't see how I can inject my own feature. I'll keep looking but if you could help point me in the right direction or let me know if I'm going down the wrong path that would be appreciated.

@ebicoglu
Copy link

ebicoglu commented Nov 18, 2021

@pranavkm when it's obfuscated we get an error like the view cannot be found (in .NET6).
I don't know how it works internally but it searches for the Page name and it's being encrypted.
So I prefer to not obfuscate these page names.
I have some workarounds like skipping the razor page obfuscation but just to let you know that this "behavior change" affects somethings in the prod apps.

@ghost
Copy link

ghost commented Jan 17, 2022

Thank you for contacting us. Due to a lack of activity on this discussion issue we're closing it in an effort to keep our backlog clean. If you believe there is a concern related to the ASP.NET Core framework, which hasn't been addressed yet, please file a new issue.

This issue will be locked after 30 more days of inactivity. If you still wish to discuss this subject after then, please create a new issue!

@ghost ghost closed this as completed Jan 17, 2022
@captainsafia captainsafia reopened this Jan 18, 2022
@drdamour
Copy link

I maintain a lib for my company that glues razor views to azure functions. When moving to .net 6 for inprocess functions i'm now getting all types of errors in app insights like:

Method overloads are not supported. There are multiple methods with the name 'JRS.Agvance.Client.ITMaint.AzF.FuncAgvanceClientITMaint.FetchSystemInfo'.

i've traced this down to the fact that i am adding the assembly as a razor part with code like this:

public static IMvcCoreBuilder AddPrioritizedRazorAssembly(
            this IMvcCoreBuilder builder,
            Assembly razorAssembly
        )
        {
            return builder
                .ConfigureApplicationPartManager(
                    m =>
                    {
                        m.ApplicationParts.Insert(
                            0,
                            new CompiledRazorAssemblyPart(
                                razorAssembly
                            )
                        );
                    }
                );
        }

where i'm passing in my Az Function assembly (which now has the razor views in it). this was working find in .net 3.1. Is there a better way to register the razor parts of my unified assembly with the Application Parts?

@Pilchie Pilchie added the area-compiler Umbrella for all compiler issues label Apr 8, 2022
@mkArtakMSFT mkArtakMSFT transferred this issue from dotnet/aspnetcore Apr 12, 2022
@drdamour
Copy link

I maintain a lib for my company that glues razor views to azure functions. When moving to .net 6 for inprocess functions i'm now getting all types of errors in app insights like:

Method overloads are not supported. There are multiple methods with the name 'JRS.Agvance.Client.ITMaint.AzF.FuncAgvanceClientITMaint.FetchSystemInfo'.

i've traced this down to the fact that i am adding the assembly as a razor part with code like this:

public static IMvcCoreBuilder AddPrioritizedRazorAssembly(
            this IMvcCoreBuilder builder,
            Assembly razorAssembly
        )
        {
            return builder
                .ConfigureApplicationPartManager(
                    m =>
                    {
                        m.ApplicationParts.Insert(
                            0,
                            new CompiledRazorAssemblyPart(
                                razorAssembly
                            )
                        );
                    }
                );
        }

where i'm passing in my Az Function assembly (which now has the razor views in it). this was working find in .net 3.1. Is there a better way to register the razor parts of my unified assembly with the Application Parts?

this turned out to be a bug in az function host runtime that was addressed Azure/azure-functions-host#8248

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-compiler Umbrella for all compiler issues untriaged
Projects
None yet
Development

No branches or pull requests