Interpretation of ASP. NET 5 & MVC6 series tutorial (12): implementation of strong-type Routing Based on Lamda expressions, interpretation of ASP. NET

Source: Internet
Author: User

Interpretation of ASP. NET 5 & MVC6 series tutorial (12): implementation of strong-type Routing Based on Lamda expressions, interpretation of ASP. NET

In the previous in-depth understanding of Routing, we have discussed 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. This chapter describes a type that is strongly typed Based on Lambda expressions.

The basic usage example of this method is 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()));});

From the example, we can use GetRoute or PostRoute extension methods to define the route, and use Lambda expressions to determine the Controller type and Action method.

Note that the method name for obtaining an Action is implemented by entrusting it to execute this Action (the method is not actually executed, but the MethodInfo of the Action is obtained based on this ).

Implementation Principle

InStratup.csOfConfigureServicesWhen configuring services in the method, we can use the core configuration file for the MVC siteMvcOptionsConfiguration.ApplicationModelConventionsProperty (List<IApplicationModelConvention>) You can saveIApplicationModelConventionInterface set. You can modify the interface to process the pipeline of the MVC program model. The interface is defined as follows:

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

InterfaceApplyThe parameter type received by the method isApplicationModel, AndApplicationModelThere are two extremely important items for us to operate. One is the Controller model set and the other is the set of various filters. The definition of this class is as follows:

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

The most important thing here isControllerModelClass, which stores a variety of important and operational information on the instance, such as the routing definition data on the class and related actions, API description information, routing constraints, and so on, this information can be operated.

The new IApplicationModelConvention registration method is as follows:

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

Therefore, we can use this method to adjust and modify the response of the entire MVC program model at the right time. This feature is used to implement the strong-type routing in this chapter.

Steps

First, define a strongly typed routing model.TypedRouteModelClass, which must inherit fromAttributeRouteModel,AttributeRouteModelClass is a basic model based on Attribute routing,TypedRouteModelThe class code 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 = GetMethodInfoInternal(expression);  ControllerType = ActionMember.DeclaringType.GetTypeInfo();  return this; } public TypedRouteModel Action<T>(Expression<Action<T>> expression) {  ActionMember = GetMethodInfoInternal(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 main functions of this class are: support for incoming Controller type definition and support for chain call.

Then define an inheritanceIApplicationModelConventionInterfaceTypedRoutingApplicationModelConventionClass. The Code is as follows:

Public class usage: 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 [control Ler. 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 replacement, which will affect the routing foreach (var method in Route. httpMethods) {action. httpMethods. add (method );}}}}}}}

In this class, a static variable Routes is saved to save all the Routes declared in the Lamda expression mode. Then, the existing Controllers set is searched and modified, and then replaced.AttributeRouteModelAnd set the Http Method for the response (if not set, all methods are allowed by default ).

Here, we simply replaceaction.AttributeRouteModelTherefore, it may lead to some defects (for example, an Action can only support one route path, whichever is the last one). You can optimize it based on your own capabilities.

When optimizing, pay attention toRouteThe set is saved incontroller.AttributesAttribute, the Route set on the Action is saved inaction.AttributesAttribute, You can optimize it.

Then, on MvcOptions, we add some extension methods for TypeRouteModel for ease of use. 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> configSetup) {  return AddRoute(template, configSetup).ForHttpMethods("POST"); } public static TypedRouteModel PutRoute(this MvcOptions opts, string template, Action<TypedRouteModel> configSetup) {  return AddRoute(template, configSetup).ForHttpMethods("PUT"); } public static TypedRouteModel DeleteRoute(this MvcOptions opts, string template, Action<TypedRouteModel> configSetup) {  return AddRoute(template, configSetup).ForHttpMethods("DELETE"); } public static TypedRouteModel TypedRoute(this MvcOptions opts, string template, Action<TypedRouteModel> configSetup) {  return AddRoute(template, configSetup); } private static TypedRouteModel AddRoute(string template, Action<TypedRouteModel> 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<TypedRouteModel> { 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 addedEnableTypedRoutingExtension MethodMvcOptions.ApplicationModelConventionsAdd a newTypedRoutingApplicationModelConventionType example.

Other extension methods are used to declare related route. Note that in the initial example, we can see that the method to obtain the action information is to call this action method through delegation (but not actually called), but some methods have parameters. What should we do? Therefore, we define a Param class that ignores parameters. The Code is as follows:

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

In this way, we can define the routing for the About method containing parameters as follows:

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

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

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

So far, the entire strong-type routing function has been completed. When you are using it, there is another option.

Disadvantages (or bugs)

We can see that the above implementationIApplicationModelConventionInterface, we just have a simpleaction.AttributeRouteModelIn other words, if you already haveRouteIf it is a feature, it overwrites your information to you, leading to invalid route. For example, if you define a custom route:

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

Then, a strong-type route is defined using the Lamda expression. The Code is as follows:

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

Then, you can only/homepageOpen access, but not through/indexBecause it overwrites your Route.

However, the above Lamda expression does not cover the Route feature definition defined on the Controller. Therefore, if you define the Route feature on the ProductsController, the two will be combined. For example:

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

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

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

Then your access URL should be/homepageBecause the route character is an absolute path/homepageInsteadhomepage.

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.