Interpretation of ASP.net 5 & MVC6 Series (12): Strong-type routing based on LAMDA expressions Self-study process

Source: Internet
Author: User
Tags static class

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

The basic use 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 by extension methods such as Getroute or Postroute, and then use lambda expressions to set the controller type and action method.

Note that the method name of the action is obtained here by delegating execution of the action method (actually not executing, but based on this to get the action's MethodInfo).

Implementation principle

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

Public interface iapplicationmodelconvention
{
 void Apply (Applicationmodel application);
}

The method in the interface Apply receives the type of parameter ApplicationModel , and ApplicationModel there are two extremely important elements that we can manipulate, one is the controller model collection, the other is a collection of various filter types, which are 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 operable information, such as routing definition data on the class and related actions, API description information, routing constraints, and so on, 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 adjust and modify the entire MVC program model at the right time, and the strongly typed routing in this section is implemented using this feature.

Implementation steps

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

public class Typedroutemodel:attributeroutemodel {public Typedroutemodel (string template) {template = template;
 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 = GetMethod
  infointernal (expression);
  Controllertype = ActionMember.DeclaringType.GetTypeInfo ();
 return this; Public Typedroutemodel action<t> (expression<action<t>> Expression) {actionmember = GetMethodInfo
  Internal (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>> (); The 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 that this is a direct substitution, which affects the routing foreach (Var) in route that is defined on the route attribute on the existing controller. Httpmethods) {action.
      Httpmethods.add (method); }
     }
    }
   }
  }
 }
}

In this class, a static variable routes is saved to hold all the routes declared in Lamda expressions, then find and modify them in the existing controllers collection, replace the AttributeRouteModel attributes, and set the HTTP method of the response (if not set, is allowed by default in all ways).

Here, we are simply replacing action.AttributeRouteModel , so there will be some defects (such as an action can only support a routing path, whichever is the last), students can be based on their own ability to optimize.

When optimizing, be aware that the collection on the controller is saved 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 the mvcoptions, we add some extension methods for Typeroutemodel to make it easy to 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> ConfigSet UP) {return Addroute (template, Configsetup).
 Forhttpmethods ("POST"); public static Typedroutemodel Putroute (this mvcoptions opts, string template, Action<typedroutemodel> Configsetu P) {return Addroute (template, Configsetup).
 Forhttpmethods ("put"); public static Typedroutemodel Deleteroute (this mvcoptions opts, string template, Action<typedroutemodel> configs Etup) {return Addroute (template, Configsetup).
 Forhttpmethods ("DELETE"); public static Typedroutemodel Typedroute (this mvcoptions opts, string template, Action<typedroutemodel> Configse
 TUP) {return Addroute (template, Configsetup); } PRIvate static Typedroutemodel Addroute (string template, action<typedroutemodel> configsetup) {var route = new Typ
  Edroutemodel (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; The 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 related route, and it is noted that in the very beginning of the example, we see that the way to get the action information is through a delegate call to the action method (but not really called), but some methods have parameters, then what? To do this, we set a Param class that ignores the parameters, and the code is as follows:

public static class param<tvalue>
{public
 static TValue any
 {get
  {default (TValue);}
 }
}

In this way, when we set the About method that contains the parameters to be routed, we can define the code as follows:

Opt. Getroute ("Aboutpage/{name}", C => c.action 
 

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

Opt. Getroute ("homepage", c => c.action 
 

At this point, the entire strong-type routing function has been completed, we use the time, there is a choice.

Drawbacks (or bugs)

We see that when we implement the interface above, IApplicationModelConvention we simply action.AttributeRouteModel replace it, that is, if you have a feature on the action Route , he will overwrite your message and cause your route to fail. For example, if you define one of these custom routes:

public class Productscontroller:controller
{
 [Route (' Index ')] public
 Iactionresult Index ()
 {
  Return Content ("Index");
 }

Then again, a strongly typed route is defined through the LAMDA expression, as follows:

Opt. Getroute ("homepage", c => c.action<productscontroller> (x => x.index ()));

Well, you can only access it by visiting /homepage it, not through /index it, because it covers your route to you.

However, the above LAMDA expression does not override the definition of the route attribute defined on controller, so if you define the route feature 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 /products/homepage , instead of /homepage . But if you're in the code of the LAMDA expression, it's the following:

Opt. Getroute ("/homepage", C => c.action<productscontroller> (x => x.index ()));

Then your visit to the 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/

Related Article

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.