Skip to content

Unlock RCL's potential by making view mapping extensible #26911

Open
@troyji

Description

@troyji

RCLs bring to the table a long sought-after set of functionality - a simple way to bundle views into sharable libraries. This functionality provides a way to simply implement complex application hierarchies that have been challenging to pull off in MVC in the past. Unfortunately, the current MVC implementation dramatically narrows the potential use cases through its assumptions about the view hierarchy across view assemblies.

Today, MVC assumes that view paths are unique across the main application and all of its referenced RCLs. When searching for a view, view priority is determined by searching the view assemblies in sequence and returns the first view that matches the requested path. The view assembly for the main application is always searched first.

Here are some of the characteristics that are enforced through this assumption:

  • The main application will always override views from the RCLs. You cannot choose to override a view in the main application with a view in the RCL.
  • The priority order between RCLs is arbitrary. There is no way to control this.
  • RCLs must be coordinated with the main application to make sure there are no path conflicts. This limits the share-ability of RCLs. For example, the standard approach is to have RCLs follow the Areas convention such that each RCL falls within its own area: /Areas/<RCL_Area>/Views/. This is an unreasonable assumption for a publicly shared RCL.
  • Controllers must be able to generate the unique view path required to find the correct view among all of the RCLs.

These assumptions are too restrictive for many desired applications of RCLs. For example, let's suppose you want to leverage RCLs to for a multi-tenant application with the following characteristics:

  • The main application will host the default views to be used by all tenants.
  • Tenants may override assets from the default application. Each tenant will have their own RCL with their view overrides.
  • When a controller requests a view, the view from the tenant RCL of the active tenant will be returned. If no override exists, the view from the application defaults should be returned.

To achieve this today, you might try to override all of the MVC components that depend on the view hierarchy assumption. One path forward would be:

  • For each precompiled view, capture the tenant context associated with it's originating RCL during startup.
  • If runtime compilation is enabled, capture the tenant associated with each project file provider during startup.
  • When a controller requests a view path, prepend the active tenant name.
  • During view selection in the view compiler, filter the set of precompiled views by their tenant context before searching by view path.
  • If runtime compilation is enabled, filter the project file system by tenant before searching by view path.
  • If the view is not found under the tenant context, search within the default views.

To implement this, you would minimally need to create custom implementations of IViewLocationExpander, IViewCompilerProvider, IViewCompiler, RazorCompiledItem, and IFileProvider. This level of override is complex and not well supported today (because of rampant internal modifiers).

I would like to see view selection logic become extensible. The main application should be allowed to filter which view assemblies are searched during each request based on the application's state. In the same way that MVC provides a robust routing system for URI -> Controller Action mapping, we need a similarly robust routing system for View Path -> Compiled View mappings now.

Metadata

Metadata

Assignees

No one assigned

    Labels

    affected-very-fewThis issue impacts very few customersarea-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesenhancementThis issue represents an ask for new feature or an enhancement to an existing onefeature-mvc-razor-viewsFeatures related to the Razor view engine for Razor pages and MVC viewsmulti-tenancyIssues based in multi-tenancyseverity-majorThis label is used by an internal tool

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions