How to use pre-compiled razor views with the same name, but in different assemblies?
FlukeFan opened this issue · 5 comments
When using <Project Sdk="Microsoft.NET.Sdk.Razor">
, razor views are compiled into a .Views.dll
assembly. Each of the compiled views is decorated with a IRazorSourceChecksumMetadata
that contains an Identifier
that is unique to the assembly.
If you have a project where multiple independent libraries have views with the same Identifier
, is there a way to reference the correct view?
For example, consider the projects:
---- Web (references lib1 & lib2)
¦
---- Lib1 (contains precompiled /Index.cshtml
)
¦
---- Lib2 (contains precompiled /Index.cshtml
)
If a controller returns a ViewResult
for /Index.cshtml
, it will always return the view from Lib1. I think the second view is (silently) ignored.
An example project can be found here: https://github.com/FlukeFan/MultipleRazorLib
If a controller returns a ViewResult for /Index.cshtml, it will always return the view from Lib1. I think the second view is (silently) ignored.
It should in theory throw at startup stating views differing in case were discovered. In general, view lookup is treated as a bag and there isn't a way to good way to prefer a view from one class library over other.
That's dissapointing, but I understand. Perhaps a feature is required to give more control over the Identity
of the compiled pages if multiple assemblies are being used.
It should in theory throw at startup ...
... throws if there are two views with the same identity, but only in the same assembly. Multiple assemblies are added to the ViewDecriptors
after that without further checking for duplicates.
This means the 'error' found in the example project gets swallowed silently.
You're right, I misremembered how that works. The duplicate entries is to prevent having files with different casing from affecting runtime behavior since the lookup is case insensitive and we let the ordering of ApplicationParts
determine which view gets to win. This feature is used to allow replacing individual files from a referenced RCL (e.g. the Identity UI) from the main app, although admittedly the debugging experience isn't the greatest with conflicts in multiple class libraries. That said, it's pretty close to how the view engine's lookup from files on disk works - you're allowed to register multiple file providers and the nearest one with a successful result wins.
Perhaps a feature is required to give more control over the Identity of the compiled pages if multiple assemblies are being used.
I haven't tried this out, but you could register a feature provider for ViewsFeature
that mangles with the collection:
public class MangleViewsFeatureProvider : IApplicationFeatureProvider<ViewsFeature>
{
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ViewsFeature feature)
{
}
}
As long as the provider runs after RazorCompiledItemFeatureProvider
, you should have access to the list of view descriptors that were previously registered and re-order it or knock out entries.