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

A pair of energy "catchers" make the invisible visible!

"Welcome to the Micro Energy Capture Laborat...

Tik Tok Promotion: How to Make Money Through Tik Tok?

1. How to make money from short videos on Douyin ...

How to attract new customers?

This article mainly focuses on how to achieve gro...

This Chinese Valentine's Day, I am only impressed by these 7 marketing plans!

First of all, I have a bad news to tell you. Yes,...

Apple, just acquire ARM!

The tech industry's M&A season has arrive...

The neglected "egg beater" - the life of Darrieus wind turbine

Author: Cheng Mingchen The article comes from the...

The Essential Guide to App Store ASO: 3 Steps to ASO Optimization

ASO provides free, high-quality users to your And...

What is open source? Where did it come from and where is it going?

Many domestic software companies or research inst...

How to acquire a large number of accurate users at low cost?

In 2017, the operation method of increasing fans ...