Interpreting ASP.NET 5 & MVC6 Series (12): Strongly Typed Routing Implementation Based on Lamda Expressions

Interpreting ASP.NET 5 & MVC6 Series (12): Strongly Typed Routing Implementation Based on Lamda Expressions

In the previous chapter, Understanding Routing, we talked about how, in MVC, in addition to using the default ASP.NET 5 routing registration method, you can also use Attribute-based features (Route and HttpXXX series methods) to define. In this chapter, we will talk about a strongly typed type based on Lambda expressions.

The following is a basic example of how to use this approach:

  1. services.Configure(opt => { opt.EnableTypedRouting(); opt.GetRoute( "homepage" , c => c.Action(x => x.Index())); opt.GetRoute( "aboutpage/{name}" , c => c.Action(x => x.About(Param.Any))); opt.PostRoute( "sendcontact" , c => c.Action(x => x.Contact())); });

As can be seen from the example, we can define the route through extension methods such as GetRoute or PostRoute, and then use Lambda expressions to define the type of Controller and the method of Action.

Note that obtaining the method name of the Action here is achieved by delegating the execution of the Action method (it is not actually executed, but the MethodInfo of the Action is obtained based on this).

Implementation principle

When configuring services in the ConfigureServices method of Stratup.cs, we can configure the core configuration file MvcOptions used by the MVC site, where this class has an ApplicationModelConventions property (List ) can save a collection of IApplicationModelConvention interfaces, which can pipeline the program model of the MVC program. The definition of this interface is as follows:

  1. public   interface IApplicationModelConvention
  2. {
  3. void Apply(ApplicationModel application);
  4. }

The parameter type received by the Apply method in the interface is ApplicationModel, and ApplicationModel has two extremely important contents for us to operate, one is the Controller model collection, and the other is the collection of various Filters. The definition of this class is as follows:

  1. public   class ApplicationModel
  2. {
  3. public ApplicationModel();
  4.  
  5. public IList Controllers { get; } public IList Filters { get; } }

The most important thing here is the ControllerModel class. The instance of this class stores a variety of important and operational information, such as the route definition data on this class and related Actions, API description information, route constraints, etc. All this information can be operated.

The new IApplicationModelConvention registration method is as follows:

  1. services.Configure(opt => { opts.ApplicationModelConventions.Add( new MyApplicationModelConvention()); });

Therefore, we can use this method to make responsive adjustments and modifications to the entire MVC program model at the appropriate time. The strongly typed routing in this chapter is implemented using this feature.

Implementation steps

First, define a strongly typed routing model TypedRouteModel class, which inherits from AttributeRouteModel. The AttributeRouteModel class is a basic model based on Attribute routing. The code of the TypedRouteModel class is as follows:

  1. public   class TypedRouteModel : AttributeRouteModel
  2. {
  3. public TypedRouteModel(string template)
  4. {
  5. Template = template;
  6. HttpMethods = new string[ 0 ];
  7. }
  8.  
  9. public TypeInfo ControllerType { get; private set; }
  10.  
  11. public MethodInfo ActionMember { get; private set; }
  12.  
  13. public IEnumerable HttpMethods { get; private set; } public TypedRouteModel Controller() { ControllerType = typeof(TController).GetTypeInfo(); return   this ; } public TypedRouteModel Action

The main functions of this class are: defining supported incoming Controller types and supporting chain calls.

Then define a TypedRoutingApplicationModelConvention class that inherits the IApplicationModelConvention interface. The code is as follows:

  1. public   class TypedRoutingApplicationModelConvention : IApplicationModelConvention
  2. {
  3. internal static readonly Dictionary

In this class, a static variable Routes is saved to save all routes declared in Lamda expression mode, and then search and modify them in the existing Controllers collection, replace the AttributeRouteModel property, and set the corresponding Http Method (if not set, all methods are allowed by default).

Here, we simply replace action.AttributeRouteModel, which may lead to some defects (for example, an Action can only support one routing path, the last one shall prevail). You can optimize it according to your own ability.

When optimizing, please note that the Route collection on the Controller is saved in the controller.Attributes property, and the Route collection on the Action is saved in the action.Attributes property, which can be optimized. Then, on MvcOptions, we add some extension methods to TypeRouteModel for easy use. The code is as follows:

  1. public   static   class MvcOptionsExtensions
  2. {
  3. public   static TypedRouteModel GetRoute( this MvcOptions opts, string template, Action configSetup) { return AddRoute(template, configSetup).ForHttpMethods( "GET" ); } public   static TypedRouteModel PostRoute( this MvcOptions opts, string template, Action configSetup) { return AddRoute(template, configSetup).ForHttpMethods( "POST" ); } public   static TypedRouteModel PutRoute( this MvcOptions opts, string template, Action configSetup) { return AddRoute(template, configSetup).ForHttpMethods( "PUT" ); } public   static TypedRouteModel DeleteRoute( this MvcOptions opts, string template, Action configSetup) { return AddRoute(template, configSetup).ForHttpMethods( "DELETE" ); } public   static TypedRouteModel TypedRoute( this MvcOptions opts, string template, Action configSetup) { return AddRoute(template, configSetup); } private   static TypedRouteModel AddRoute(string template, Action configSetup) { var route = new TypedRouteModel(template); configSetup(route); if (TypedRoutingApplicationModelConvention.Routes.ContainsKey(route.ControllerType)) { var controllerActions = TypedRoutingApplicationModelConvention.Routes[route.ControllerType]; controllerActions.Add(route); } else { var controllerActions = new List { route }; TypedRoutingApplicationModelConvention.Routes.Add(route.ControllerType, controllerActions); } return route; } public   static   void EnableTypedRouting( this MvcOptions opts) { opts.ApplicationModelConventions.Add( new TypedRoutingApplicationModelConvention()); } }

In the above code, we added an EnableTypedRouting extension method to add a new TypedRoutingApplicationModelConvention type instance to the MvcOptions.ApplicationModelConventions property.

Other extension methods are used to declare related routes. Please note that in the first example, we see that the method to obtain action information is to call the action method through delegation (but not actually call it), but some methods have parameters, what should we do? For this reason, we define a Param class that ignores parameters. The code is as follows:

  1. public   static   class Param { public   static TValue Any { get { return   default (TValue); } } }

In this way, when we define the route for the About method containing parameters, we can define it like this. The code is as follows:

opt.GetRoute("aboutpage/{name}", c => c.Action (x => x.About(Param .Any)));

In addition, since many methods in TypeRouteModel can be chained, we can also specify a name for the route in this way. The sample code is as follows:

opt.GetRoute("homepage", c => c.Action(x => x.Index())).WithName("foo");

At this point, the entire strongly typed routing function has been implemented, and everyone has one more choice when using it.

Disadvantages (or Bugs)

We can see that when implementing the IApplicationModelConvention interface above, we simply replace action.AttributeRouteModel. That is, if you have already set the Route attribute on the Action, it will overwrite your information, causing your route to fail. For example, if you define a custom route like this:

  1. public   class ProductsController : Controller
  2. {
  3. [Route( "index" )]
  4. public IActionResult Index()
  5. {
  6. return Content( "Index" );
  7. }
  8. }

Then, a strongly typed route is defined through Lamda expression. The code is as follows:

  1. opt.GetRoute( "homepage" , c => c.Action(x => x.Index()));

Then, you can only access it through /homepage, but not through /index, because it overwrites your Route.

However, the above Lamda expression method does not override the Route attribute definition defined on the Controller, so if you define the Route attribute on ProductsController, the two will be combined together, for example:

  1. [Route( "products" )]
  2. public   class ProductsController : Controller
  3. {
  4. public IActionResult Index()
  5. {
  6. return Content( "Index" );
  7. }
  8. }

Then your access URL should be /products/homepage, not /homepage. However, if your code in Lamda expression mode is as follows:

  1. opt.GetRoute( "/homepage" , c => c.Action(x => x.Index()));

Then your access URL should be /homepage, because the routing string is the absolute path /homepage, not homepage.

Reference: http://www.strathweb.com/2015/03/strongly-typed-routing-asp-net-mvc-6-iapplicationmodelconvention/

<<:  Interpreting ASP.NET 5 & MVC6 Series (11): Routing

>>:  Interpreting ASP.NET 5 & MVC6 Series (14): View Component

Recommend

iOS WeChat is updated again, and you can set video cover in Moments

[[417600]] Previously, iOS WeChat released the of...

9 Strategies for Optimizing E-Commerce Product Details Pages

Consider the following scenario: Let’s say you ar...

How to make a WeChat red envelope cover? WeChat Red Packet Cover Making Tutorial

How to make a WeChat red envelope cover? Tutorial...

my country lacks 4K TV standards: low-cost panels flood the market

As early as 2014, the China Household Electrical ...

With frequent volcanoes, will the next "Pompeii Doomsday" appear?

About two thousand years ago, on an afternoon of ...

YouTube's actual competitor is Facebook

Facebook said in its earnings report this week th...

When is the cheapest time to buy a mobile phone? Insiders say

Changing your phone during Double 11 is undoubted...

Analysis of mobile advertising in the skin care and beauty industry in Q1 2019

The first quarter of 2019 has passed. So what are...

A scientific guide to petting cats (full version)

Many of us may have encountered a cat that seemed...