Interpreting the ASP. 5 & MVC6 Series (12): implementation of strongly typed routing based on LAMDA expression

Source: Internet
Author: User

Original: Interpretation of ASP. 5 & MVC6 Series (12): implementation of strongly typed routing based on LAMDA expression

In the previous in-depth understanding of the routing chapter, we talked about the use of attribute-based features (route and Httpxxx series methods) in MVC, in addition to the default method of routing registration with ASP. NET 5. In this chapter, we will describe a strongly typed type based on a lambda expression.

The basic usage examples of this approach are as follows:

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

As can be seen from the example, we can define the route through extension methods such as Getroute or Postroute, and later use lambda expressions to set the type of controller and the method of action.

Note that the method name of the action is obtained here by delegating execution of the action method (not actually executed, but rather based on the methodinfo of the action).

Implementation principle

Stratup.cs ConfigureServices When configuring services in the method, we can configure the core configuration file used by the MVC site, MvcOptions where the class has a ApplicationModelConventions property ( List<IApplicationModelConvention >) that can hold a IApplicationModelConvention collection of interfaces. Interface can be used to process the program model of the MVC program, the interface is defined as follows:

public interface IApplicationModelConvention{   void Apply(ApplicationModel application);}

The types of Apply parameters received by the methods in the interface are ApplicationModel , and ApplicationModel there are two extremely important things for us to manipulate, one is the controller model collection, and the other is a collection of various filter types, defined as follows:

public class ApplicationModel{    public ApplicationModel();    public IList<ControllerModel> Controllers { get; }    public IList<IFilter> Filters { get; }}

The most important thing here is the ControllerModel class, which holds a variety of important and actionable information, such as routing definition data on the class and related actions, API description information, routing constraints, and so on, all of which can be manipulated.

The new Iapplicationmodelconvention registration method is as follows:

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

So we can use this method to adapt and modify the entire MVC program model at the right time, and the strong-type routing in this section is implemented using this feature.

Implementation steps

First, define a strongly typed routing model TypedRouteModel class, which inherits from the AttributeRouteModel AttributeRouteModel Basic model of the attribute route, and the code for the TypedRouteModel class is as follows:

public class Typedroutemodel:attributeroutemodel{Public Typedroutemodel (string template) {Template = Temp        Late;    Httpmethods = new String[0];    Public TypeInfo Controllertype {get; private set;}    Public MethodInfo Actionmember {get; private set;}    Public ienumerable<string> httpmethods {get; private set;} Public Typedroutemodel controller<tcontroller> () {controllertype = typeof (Tcontroller).        GetTypeInfo ();    return this; } public Typedroutemodel action<t, u> (expression<func<t, u>> Expression) {actionmember = G        etmethodinfointernal (expression);        Controllertype = ActionMember.DeclaringType.GetTypeInfo ();    return this; } public Typedroutemodel action<t> (expression<action<t>> Expression) {actionmember = GetMe        thodinfointernal (expression);        Controllertype = ActionMember.DeclaringType.GetTypeInfo ();    return this; } private StatiC MethodInfo getmethodinfointernal (dynamic expression) {var method = expression.        Body as Methodcallexpression; if (Method! = NULL) return method.        Method;    throw new ArgumentException ("Expression is incorrect!");        } Public Typedroutemodel Withname (string name) {name = name;    return this;        } public Typedroutemodel Forhttpmethods (params string[] methods) {Httpmethods = methods;    return this; }}

The primary function of this class is to define support for incoming controller types and to support chained calls.

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

public class typedroutingapplicationmodelconvention:iapplicationmodelconvention{internal static readonly Dictionary <typeinfo, list<typedroutemodel>> Routes = new Dictionary<typeinfo, list<typedroutemodel>> ()    ; public void Apply (Applicationmodel application) {foreach (var controller in application. Controllers) {if (Routes.containskey) (controller. Controllertype)) {var typedroutes = Routes[controller.                Controllertype]; foreach (var route in Typedroutes) {var action = controller. Actions.firstordefault (x = X.actionmethod = = route.                    Actionmember); if (action! = null) {action.                        Attributeroutemodel = route; Note Here is the direct substitution, which affects the route attribute definition of the routing foreach (Var method in route) on the existing controller. Httpmethods) {action. HttpmeThods.                        Add (method); }                    }                }            }        }    }}

In this class, a static variable routes is saved that holds all the routes declared in the LAMDA expression, then finds and modifies in the existing controllers collection, replaces the AttributeRouteModel properties, and sets the HTTP Method of the response (if not set, All methods are allowed by default).

Here, we simply replace action.AttributeRouteModel , so will lead to a number of defects (such as an action can only support a routing path, whichever is the last), students can be based on their ability to optimize.

When optimizing, it is important to note that the collection on the controller is stored on the Route controller.Attributes property, and the route collection on the action is saved on the action.Attributes property and can be optimized.

Then, on mvcoptions, we add some extension methods to Typeroutemodel for ease of use, and the code is as follows:

public static class mvcoptionsextensions{public static Typedroutemodel Getroute (this mvcoptions opts, string template, Action<typedroutemodel> configsetup) {return Addroute (template, Configsetup).    Forhttpmethods ("GET"); } public static Typedroutemodel Postroute (this mvcoptions opts, string template, Action<typedroutemodel> Configse TUP) {return Addroute (template, Configsetup).    Forhttpmethods ("POST"); } public static Typedroutemodel Putroute (this mvcoptions opts, string template, Action<typedroutemodel> ConfigSet UP) {return Addroute (template, Configsetup).    Forhttpmethods ("PUT"); } public static Typedroutemodel Deleteroute (this mvcoptions opts, string template, action<typedroutemodel> Config Setup) {return Addroute (template, Configsetup).    Forhttpmethods ("DELETE"); } public static Typedroutemodel Typedroute (this mvcoptions opts, string template, Action<typedroutemodel> configs        Etup) {return Addroute (template, Configsetup); } private static Typedroutemodel Addroute (string template, action<typedroutemodel> configsetup) {var r        Oute = 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<typedroutemodel> {route}; TYPEDROUTINGAPPLICATIONMODELCONVENTION.ROUTES.ADD (route.        Controllertype, controlleractions);    } return route; public static void Enabletypedrouting (this mvcoptions opts) {opts.    Applicationmodelconventions.add (New Typedroutingapplicationmodelconvention ()); }}

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

Other extension methods are used to declare the associated route, and it is noted that in the very beginning of the example, we see that the method of getting the action information is called by the delegate (but not actually called), but some methods have parameters, what do you do? To do this, we set a Param class that ignores the arguments, and the code is as follows:

public static class Param<TValue>{    public static TValue Any    {        get { return default(TValue); }    }}

Thus, when we set the About method with parameters to route, we can define the code as follows:

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

In addition, since many of the 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<HomeController>(x => x.Index())).WithName("foo");

At this point, the entire strong-type routing function is complete, we are in use, there is a choice.

Malpractice (or bug)

We see that IApplicationModelConvention when we implement the interface above, we simply replace it, that is action.AttributeRouteModel , if you have an attribute on the action Route , he will overwrite your message and cause your route to expire. For example, if you define a custom route like this:

public class ProductsController : Controller{    [Route("index")]    public IActionResult Index()    {        return Content("Index");    }}

The strongly-typed route is then defined by the LAMDA expression and the code is as follows:

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

Well, you can only access it through the open, /homepage not through /index it, because it overwrites your route.

However, the LAMDA expression above does not override the route attribute definition defined on the controller, so if you define the route attribute on the ProductsController, the two will be grouped together, for example:

[Route("products")]public class ProductsController : Controller{        public IActionResult Index()    {        return Content("Index");    }}

Then your visit URL should be /product/homepage , not /homepage . But if your code in the LAMDA expression is the following:

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

Then your access URL should be /homepage , because the route character is an absolute path /homepage , not a homepage .

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

Synchronization and recommendations

This article has been synchronized to the Catalog index: Interpreting ASP. & MVC6 Series

Interpreting the ASP. 5 & MVC6 Series (12): implementation of strongly typed routing based on LAMDA expression

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.