Expanding Razor View Location And Sub Areas In ASP.NET Core

Introduction

In this article, we'll learn sub area, using IViewLocationExpander. IViewLocationExpander takes care to modify view locations, how the view engine searches for the path.

The source code is available @ Github https://github.com/nemi-chand/SubArea.ASPNetCoreMVC 

Areas are ASP.NET MVC Core features, which are used to organize the functionality into the groups. Read more about areas here.

IViewLocationExpander Methods:

  1. ExpandViewLocations(ViewLocationExpanderContext, IEnumerable<String>)
    This is invoked by Razor view engine to determine the possible view locations. View engine searches the path in order; it adds in view locations, so the order of view location matters.
  1. PopulateValues(ViewLocationExpanderContext) 
    This is called each time to populate the route values.

Sub area in MVC

Steps to create the Sub area in MVC are given below.

  1. Sub area folder structure.
  2. SubArea RouteValueAttribute.
  3. SubAreaViewLocationExpander.
  4. Configure Razor View Engine option in startup class.
  5. Attribute usages.
  6. SubArea Routes.

Folder structure

Area refers to MVC features, which are used to restructure or group the functionality, separate the Controller and Views of each area. In ASP.NET Core MVC, we can create n-level of sub areas under an area.

Create the folder structure, as shown below.

  
Sub area folder structure

SubArea Attribute

It is a key-value pair RouteValueAttribute, which specifies the containing Controller or an action. This is a must to decorate the Controller with this attribute.

This is similar to an area attribute. To more about it, click here.

The route key is fixed for subarea routes and route value changes as sub area is requested. This attribute usage is restricted to a class and a method.

  1. /// <summary>  
  2.     /// this is simillar to this https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Core/AreaAttribute.cs  
  3.     /// </summary>  
  4.     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]  
  5.     public class SubAreaAttribute : RouteValueAttribute  
  6.     {  
  7.         public SubAreaAttribute(string subAreaName)  
  8.             : base("subarea", subAreaName)  
  9.         {  
  10.             if (string.IsNullOrEmpty(subAreaName))  
  11.             {  
  12.                 throw new ArgumentException("Sub area name cannot be null or empty", nameof(subAreaName));  
  13.             }  
  14.         }  
  15.     }  

Sub Area View location Expander

This is implementing the IViewLocationExpander interface to expand the sub area view location. You can set view location. The route key is set to subarea and gets the same key value from RazorviewEngine, which routes to place in runtime location path. View engine string format follows as {0} --> action Name , {1} --> Controller name and {2} --> name of the area, if it exists. The order of view locations matters because the engine search for the path is added into the order.

  1. /// <summary>  
  2.     /// sub area view location expander  
  3.     /// </summary>  
  4.     public class SubAreaViewLocationExpander : IViewLocationExpander  
  5.     {  
  6.         private const string _subArea = "subarea";  
  7.   
  8.         public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, 
  9.             IEnumerable<string> viewLocations)  
  10.         {  
  11.             //check if subarea key contain  
  12.             if (context.ActionContext.RouteData.Values.ContainsKey(_subArea))  
  13.             {  
  14.                 string subArea = RazorViewEngine.GetNormalizedRouteValue(context.ActionContext, _subArea);  
  15.                 IEnumerable<string> subAreaViewLocation = new string[]  
  16.                 {  
  17.                 "/Areas/{2}/SubAreas/"+subArea+"/Views/{1}/{0}.cshtml"  
  18.                 };  
  19.   
  20.                 viewLocations = subAreaViewLocation.Concat(viewLocations);  
  21.   
  22.             }  
  23.   
  24.             return viewLocations;  
  25.         }  
  26.   
  27.         public void PopulateValues(ViewLocationExpanderContext context)  
  28.         {  
  29.             string subArea = string.Empty;  
  30.             context.ActionContext.ActionDescriptor.RouteValues.TryGetValue(_subArea, out subArea);  
  31.   
  32.             context.Values[_subArea] = subArea;  
  33.         }  

Configure Razor View Options

In the startup class, you have to configure Razor view engine options in Configure Services method.

  1. services.Configure<RazorViewEngineOptions>(o => 
  2. {  
  3.     o.ViewLocationExpanders.Add(new SubAreaViewLocationExpander());  
  4. });  
Attribute usages in Controller

Just decorate your Controller with an area and subarea attribute.

  1. [Area("Department")]  
  2. [SubArea("IT")]  
  3. public class HomeController: Controller {  
  4.     /// <summary>    
  5.     /// GET /Department/IT/Home/Index    
  6.     /// </summary>    
  7.     /// <returns></returns>    
  8.     public IActionResult Index() {  
  9.         return View();  
  10.     }  
  11. }  

 

Routes

Route key is for sub area, which is similar to an area route. Sub area route key will be same in view location expander.  

  1. app.UseMvc(routes =>    
  2.             {    
  3.                 routes.MapRoute(    
  4.                     name: "subAreaRoute",    
  5.                     template: "{area:exists}/{subarea:exists}/{controller=Home}/{action=Index}/{id?}");    
  6.                 routes.MapRoute(    
  7.                     name: "areaRoute",    
  8.                     template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");    
  9.                 routes.MapRoute(    
  10.                     name: "default",    
  11.                     template: "{controller=Home}/{action=Index}/{id?}");    
  12.   
  13.             });    
Department Area screen 
  1. //GET Deparment/Home/Index   
 
IT Sub-Area screen
  1. //GET Deparment/IT/Home/Index 

Marketing Sub-Area screen
  1. //GET Deparment/Marketing/Home/Index

 
The source code is available @ GitHub.

In this article you have learned how you can create a sub area under the area with n-level. IViewLocationExpander helps to modify the view location paths.