ASP.NET Routing of core MVC learning course

Time:2020-6-24

preface

ASP.NET Core MVC routing is based on ASP.NET Core routing, a powerful URL mapping component, can build applications that understand and search web addresses. This allows us to customize the URL naming form of the application so that it works well in search engine optimization (SEO) and link generation, regardless of how the files on the web server are organized. We can easily use the routing template syntax to define routes. The routing template syntax supports route value constraints, default values and optional values.

Constraint based routing allows the global definition of the URL formats supported by the application and how these formats map to the specified action method in a given controller. When a request is received, the routing engine parses the URL and matches it to a defined URL format, and then calls the relevant controller operation method.


routes.MapRoute(
     name: "default",
     template: "{controller=Home}/{action=Index}/{id?}");

Attribute routing allows routing information to be specified in a way that adds attributes to controllers and methods to define an application’s route. This means that routes define the controllers and methods that are next to them.

ASP.NET Core MVC uses routing middleware to match the URLs of incoming requests and map them to the operation methods. The route is defined in the startup code or properties, which describes how the URL path should match the operation method, and is also used to generate links in the response and send them.

1. Set up routing Middleware

Create a ASP.NET The core web application can be found in the configure method of the startup class:


app.UseMvc(routes =>
   {
    routes.MapRoute(
     name: "default",
     template: "{controller=Home}/{action=Index}/{id?}");
   });

During the call to usemvc, maproute is used to create a single route, which is the default route. Most MVC applications use routes similar to the default route template.

Route template{controller=Home}/{action=Index}/{id?} It can match the URL path similar to blog / details / 5 and extract the route value{controller=Blog,action=Details,id=5}。 MVC will try to find the controller named blogcontroller and run the action method.

  {controller=Home}Define home as the default controller

  {action=Index}Define index as the default action

{ID?} defines ID as optional

The default and optional path parameters may not appear in the URL path that needs to be matched.

use{controller=Home}/{action=Index}/{id?}Template, you can execute the following URL paths HomeController.Index :

  /Home/Index/7

  /Home/Index

  /Home

  /

There’s a simple wayapp.UseMvcWithDefaultRoute() You can replace the above method.

Usemvc and usemvcwithdefaultroute both add instances of routemiddleware to the middleware pipeline. MVC does not directly interact with middleware, but uses routing to process requests. MVC links to the route through an instance of mvcproutehandler. The following code is similar to usemvc:

var route = new RouteBuilder(app);
   //Add connection to MVC and call maproute to call back
   route.DefaultHandler = new MvcRouteHandler(...);
   //Execute callback to register route
   route.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
   //Create route collection and add to middleware
   app.UseRouter(route.Build());

Usemvc does not define any routes directly, it adds a placeholder to the set of routes for attribute routes. Overloading usemvc allows us to add our own routes and also supports attribute routing. Usemvc and all its variants add placeholders to property routes, which makes property routes always available. Usemvcwithdefaultroute defines the default route and supports attribute route.

2. General routing

routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}"); This is a regular route because it establishes a contractual URL path:

First path segment mapped to controller name

Second path mapped to operation name

The third section is the optional ID, which is used to map to the model entity

Using the default route, the URL path / blog / index will be mapped to the BlogController.Index Operation. The mapping is based on controller and operation name, not namespace, source file location, etc.

Using the default route of a regular route can quickly build an application without defining the route for each operation. For crud style applications, the URL of the whole controller is consistent.

3. Multi route

You can add multiple routes by adding maproute in usemvc. This allows you to define multiple conventions, or add general routes that are specific to a particular operation:


app.UseMvc(routes =>
   {
    routes.MapRoute("blog", "blog/{*article}",
     defaults: new { Controller = "Blog", Action = "Index" });
    routes.MapRoute(
     name: "default",
     template: "{controller=Home}/{action=Index}/{id?}");
   });

The blog route here is a special regular route, which means that it does not use a regular routing system, but is dedicated to a specific action. This route always maps to BlogController.Index 。

The routes in the route collection are ordered and processed in the order in which they are added.

1. Fallback

As part of the request processing, MVC verifies that the routing values can be used to find controllers and operations in the application. If the route value does not match, the route is considered to be mismatched and the next route is attempted. This process is called fallback because of the overlap of conventional routes.

2. Action ambiguity

When two consistent operations are routed, MVC must disambiguate and select the best operation, otherwise an exception will be thrown. For example:


public class BlogController : Controller
 {
  public ActionResult Edit(int id)
  {
   return View();
  }

  [HttpPost]
  public ActionResult Edit(int id, IFormCollection collection)
  {
   try
   {
    // TODO: Add update logic here

    return RedirectToAction(nameof(Index));
   }
   catch
   {
    return View();
   }
  }

 }

URL / blog / edit / 7 can match these two operations, which is a typical mode of MVC controller, where edit (int) is used to display the edited form and edit (int, iformcollection) is used to process the submitted form. To achieve this, MVC needs to select edit (int, iformcollection) at http post and edit (int) at other HTTP verbs.

Httppostattribute is an implementation of iactionconstraint, which only allows actions to be selected when the HTTP verb is post. The existence of iactionconstraint makes edit (int, iformcollection) better match than edit (int).

If there are multiple routes matching and MVC cannot find the best route, an ambiguousactionexception exception will be thrown.

3. Route name

In the above example, “blog” and “default” strings are route names, which provide a logical name for routes so that named routes can be used to generate URLs. The route must have a unique name within the scope of the application.

The route name has no effect on URL matching or request processing and is only used for URL generation.

4. Routing characteristics

Attribute routing uses a set of attributes to map operations directly to a routing template. The following is called in Configure.app.UseMvc(); There is no delivery route.


public class HomeController : Controller
 {
  [Route("")]
  [Route("Home")]
  [Route("Home/Index")]
  public IActionResult Index()
  {
   return View();
  }

  [Route("Home/About")]
  public IActionResult About()
  {
   ViewData["Message"] = "Your application description page.";

   return View();
  }
}

HomeController.Index The operation will be performed on any URL access of /, / home or / home / index.

Feature routes require more input to specify a route, while regular routes are simpler to handle. However, feature routing allows precise control of the routing template for each operation.

The above template does not define the routing parameters for action, area and controller. In fact, these parameters are not allowed in the feature route, because the route template has an operation associated with it, so it is meaningless to resolve the operation name in the URL.

Feature routes can also use the HTTP [verb] feature, such as HTTP post:


  [HttpGet("/Blog")]
  public ActionResult Index()
  {
   return View();
  }

Because feature routing is suitable for specific operations, it is easy to make parameters a necessary part of the template definition. In the following example, ID is a necessary part of URL:


[HttpGet("Blog/Edit/{id}")]
  public ActionResult Edit(int id)
  {
   return View();
  }

The general default route defines the ID parameter as an optional ({ID?}), while the characteristic route is a required parameter, which can be precisely specified, such as the packet / blog / get and / blog / get / {ID} assigned to different operations.

5. Combined routing

In order to reduce the repetitive part of characteristic routes, the routing characteristics on the controller will be combined with the routing characteristics on each operation. Any route template defined on the controller is prefixed to the operation route template.


[Route("blog")]
 public class BlogController : Controller
 {
  [HttpGet]
  public ActionResult GetAll()
  {
   return View();
  }
  [HttpGet("{id}")]
  public ActionResult GetById(int id)
  {
   return View();
  }
}

/Blog matches getall method, / blog / 1 matches getbyid method.

Note that if the route template on the operation starts with / it will not be combined with the route template on the controller.

6. Sequence of characteristic routes

General routes are executed according to the defined order. In contrast, characteristic routes build a tree structure and match all routes at the same time. This looks like routing entries are placed in an ideal order, and the most specific route is executed before the general route. For example, routing blog / edit / 4 is more specific than blog / {* article}.

The attribute route uses the order attribute specific to all routes provided by the framework to configure the order, and processes the routes in ascending order according to the order attribute. The default is 0, which is set to – 1 before routes that are not set.

7. Mark replacement in routing template ([controller], [action], [area])

For convenience, feature routing supports tag substitution, that is, by enclosing a tag ([,]) in square brackets to replace the corresponding name. The tags [action], [area], [controller] will be replaced with the corresponding operation name, area name and controller name.

[Route("[controller]/[action]")]
 public class BlogController : Controller
 {
  [httpget] // match blog / getall
  public ActionResult GetAll()
  {
   return View();
  }
}

Tag substitution occurs in the last step of building a feature route. Same as the above results:

public class BlogController : Controller
 {
  [httpget ("[controller] / [action]")] // match blog / getall
  public ActionResult GetAll()
  {
   return View();
  }
}

Property routing can also be combined with inheritance, that is, inheriting the routing flag of the parent class.

Attribute routing supports a single operation to define a route. If multiple routing features implemented by iactionconstraint are defined on one operation, each operation constraint is combined with the route defined by the feature:

[Route("Store")]
 [Route("[controller]")]
 public class BlogController : Controller
 {
  [httpget ("getall")] // match get blog / getall and store / getall
  [httppost ("set")] // match post blog / set and store / set
  public ActionResult GetAll()
  {
   return View();
  }
}

While it might seem powerful to use multiple routes to an operation, it’s best to keep the space and definition of the URL simple. Using multiple routes to operations is only for special needs, such as supporting multiple clients.

8. Use iroutetemplateprovider to customize routing characteristics

All the routing features provided by the framework ([route (…)], [httpget (…)] and so on) implement the iroutetemplateprovider interface. When the program is started, MVC implements the characteristics of iroutetemplateprovider interface on both the controller class and the operation method to build the storage routing collection.

You can define your own routing characteristics by implementing iroutetemplateprovider. Each iroutetemplateprovider allows you to define a single route using a custom route template, sequence, and name:


public class MyApiControllerAttribute:Attribute, IRouteTemplateProvider
 {
  public string Template => "api/[controller]";
  public int? Order { get; set; }
  public string Name { get; set; }
 }

When the [myapicontroller] feature is applied, the template is automatically set to API / [controller].

9. Use the application model to customize feature routes

The object model created when the application model is launched, which contains all the metadata MVC uses to route and perform operations. The application model includes all the data collected from the routing feature (via iroutetemplateprovider). We can write conventions to modify the application model at startup to customize routing behavior.

public class NamespaceRoutingConvention:IControllerModelConvention
 {
  private readonly string _baseNamespace;
  public NamespaceRoutingConvention(string baseNamespace)
  {
   _baseNamespace = baseNamespace;
  }

  public void Apply(ControllerModel controller)
  {
   var hasRouteAttributes = controller.Selectors.Any(selector =>
    selector.AttributeRouteModel != null);
   if (hasRouteAttributes)
   {
    //This controller has customized some routes, so it is considered an override
    return;
   }


   //Use namespace and controller to infer the route of controller
   //
   // Example:
   //
   // controller.ControllerTypeInfo -> "My.Application.Admin.UsersController"
   // baseNamespace ->     "My.Application"
   //
   // template =>       "Admin/[controller]"
   //
   //This makes your route roughly consistent with your project structure
   //
   var namespc = controller.ControllerType.Namespace;
   var template = new StringBuilder();
   template.Append(namespc,_baseNamespace.Length+1,namespc.Length- _baseNamespace.Length-1);
   template.Replace('.','/');
   template.Append("/[controller]");

   foreach (var selector in controller.Selectors)
   {
    selector.AttributeRouteModel = new AttributeRouteModel()
    {
     Template = template.ToString()
    };
   }
  }
 }

How to use this part? I’m still not sure. It’s just an official document. Who knows who can tell me.

10. URL generation

MVC applications can use the routing URL generation feature to generate URL links to operations. Generating URLs eliminates hard coded URLs, making the code more robust and maintainable. The iurlhelper interface is the basic block of the infrastructure between MVC and generating URL routes. An available iurlhelper instance can be found through the controller, view, and URL properties in the view component:

public class HomeController : Controller
 {
  public IActionResult Index()
  {
   //Generate / home / contact
   var url = Url.Action("Contact");
   return View();
  }

  public IActionResult Contact()
  {
   ViewData["Message"] = "Your application description page.";

   return View();
  }
}

This URL path is created by combining the route value with the current request and passing the value to Url.Action , replacing the corresponding value in the route template.

above Url.Action (the example of is a regular route, but the URL generation is similar to the feature route, although the concept is different. In normal routing, the route value is used to extend the template, and the route value about controller and action usually appears in that template, because the route matching URL adheres to a convention. In feature routing, routing values about controller and action are not allowed to appear in the template — they are used to find which template should be used, for example:

//Modify configure
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  {
   app.UseMvc();

  }



 public class HomeController : Controller
 {
  [HttpGet("/")]
  public IActionResult Index()
  {
   //Generate / home / to / about
   var url = Url.Action("About");
   return View();
  }

  [HttpGet("Home/To/About")]
  public IActionResult About()
  {
   ViewData["Message"] = "Your application description page.";

   return View();
  }
}

MVC builds a lookup table for all characteristic routing operations, and matches the controller and action values to select the routing template for generating the URL.

11. Generate URL by operation name

Url.Action(this IUrlHelper helper, string action) And all related overloads specify what to link based on the specified controller name and operation name.

When using Url.Action When, the current routing values of controller and action are specified — the values of controller and action are part of both environment values and values. Url.Action Method always uses the current values of controller and action, and generates a URL path to route to the current action.

Routing attempts to fill information with values in environment values. At the same time, we can also specify routing parameters:

public class HomeController : Controller
 {
  public IActionResult Index()
  {
   //Generate / blog / edit / 1
   var url = Url.Action("Edit", "Blog",new { id=1});
   //Generate / blog / edit / 1?color=red
   var url1 = Url.Action("Edit", "Blog", new { id = 1 ,color="red"});
   return View();
  }
 }

If you want to create an absolute URL, you can use an overload that accepts protocol:Url.Action("Edit", "Blog",new { id=1},protocol:Request.Scheme);

12. Generate URL by routing name

Iurlhelper also provides Url.RouteUrl The most common method is to specify a route name to generate a URL using a specific route, usually without specifying the controller name or operation name:

public class HomeController : Controller
 {
  public IActionResult Index()
  {
   //Generate customer / to / url
   var url = Url.RouteUrl("AboutRoute");
   return View();
  }

  [HttpGet("customer/to/url",Name = "AboutRoute")]
  public IActionResult About()
  {
   ViewData["Message"] = "Your application description page.";

   return View();
  }
 }

The urlhtmlhelper generated in HTML provides the htmlhelper method Html.BeginForm And Html.ActionLink To generate < form > and < a > elements, respectively. These methods use Url.Action Method to generate a URL, and they take similar parameters. Url.RouteLink , they have similar functions. Taghelper generates URLs through form and < a > taghelper. These all use iurlhelper as their implementation. In the internal view, iurlhelper generates any specific URL that does not contain the above through the URL property.

13. Generate URL in operation result

A common use in controllers is to generate a URL as part of the result of an operation. The controller and controllerbase base classes provide a simple way to reference the results of other operations. A typical approach:

public class HomeController : Controller
 {
  public IActionResult Index()
  {
   //Generate customer / to / url
   var url = Url.RouteUrl("AboutRoute");
   return Redirect(url);
   //Or
   //return RedirectToAction("Contact");
  }

  [HttpGet("customer/to/url",Name = "AboutRoute")]
  public IActionResult About()
  {
   ViewData["Message"] = "Your application description page.";

   return View();
  }

  public IActionResult Contact()
  {
   ViewData["Message"] = "Your contact page.";

   return View();
  }
 }

The redirecttoaction method has multiple overloads to use.

14. Special case of special routine route

There is a special route called special regular route. The route named blog is as follows:


app.UseMvc(routes =>
   {
    routes.MapRoute("blog", "blog/{*article}",
     defaults: new { Controller = "Blog", Action = "Index" });
    routes.MapRoute(
     name: "default",
     template: "{controller=Home}/{action=Index}/{id?}");
   });

Url.Action("Index", "Home")The URL is generated using the default route.

The special regular route is a special behavior that depends on the default route. There is no corresponding route parameter to prevent the route from generating URL “too greedy”. When routing performs URL generation, the value provided must match the default value: otherwise, URL generation using blog fails because of the value{controller=Home,action=Index}Mismatch{controller=Blog,action=Index}。 Then route fallback attempts default and succeeds.  

15. Area

Areas is an MVC function that organizes related functions into a group as a separate routing namespace (for controller operations) and folder structure (for views). Using zones allows applications to have multiple controllers with the same name – as long as they have different zones. Using zones creates a hierarchy for routing purposes by adding another routing parameter to the controller and operation.

Use the default general routing configuration MVC to name the route of an OMS area:


app.UseMvc(routes =>
   {
    routes.MapAreaRoute("oms", "OMS", "OManage/{controller}/{action}/{id?}",
     defaults: new { Controller = "Order", Action = "Index" });
    routes.MapRoute(
     name: "default",
     template: "{controller=Home}/{action=Index}/{id?}");
   });

namespace Blog.Areas.OMS.Controllers
{
 [Area("OMS")]
 public class OrderController : Controller
 {
  // GET: Order
  public ActionResult Index()
  {
   return View();
  }
}

When the URL is / omanage / order / edit, the route value is matched {area = OMS,controller = Order , action = Edit}。 The area routing value is generated by the area default value. The maproute method can also be used to:


routes.MapRoute("oms", "OManage/{controller}/{action}/{id?}",
     defaults:new {area="OMS" },constraints:new { area = "OMS" });

Maparearoute creates a route, using both the default route and the area constraint, which uses the provided area name OMS. The default value guarantees that the route always processes {area = OMS}, and the constraint requires the value {area = OMS} for URL generation.

Regular routing is order dependent. General area routing is placed in front, because area routing is more specific.

Areaattribute means that the controller belongs to a part of a region, that is, the controller is in the OMS region. The controller does not belong to any area without the [area] feature.

When an operation is performed within a zone, the routing value of the zone is used as the environment value for URL generation, which means that by default, the zone is sticky to URL generation:

namespace Blog.Areas.OMS.Controllers
{
 [Area("OMS")]
 public class OrderController : Controller
 {
  // GET: Order
  public ActionResult Index()
  {
   //Build / omanage / home / create
   var url = Url.Action("Create","Home");
   //Build / home / create
   var url1 = Url.Action("Create", "Home",new { area=""});
   return View();
  }
 }
}

16.IActionConstraint

Usually, the application does not need to customize the iactionconstraint, [httpget] feature and similar features to implement the iactionconstraint interface to restrict the execution of methods.

When two operations are as like as two peas, one of them uses IActionConstraint, which is always better than the one that is not used, because it is considered more specific and the two operations can be selected in matching. (actions not used match any HTTP verbs)

Conceptually, iactionconstraint is a form of overload, but not an overload with the same name. It is an overload that matches the same URL operation. Feature routes also use the iactionconstraint, and can cause operations of different controllers to be considered candidate operations.

The easiest way to implement iactionconstraint is to create a class derived from System.Attribute , and place it on the operation and controller. MVC will automatically discover any iactionconstraint applied as a feature. You can use the program model to apply constraints, perhaps the most flexible method, because it allows you to metaprogram how they are applied.

For example, a constraint selects a country code operation based on the routing data:


public class CountrySpecificAttribute:Attribute,IActionConstraint
 {
  private readonly string _countryCode;
  public CountrySpecificAttribute(string countryCode)
  {
   _countryCode = countryCode;
  }

  public int Order { get { return 0; } }

  public bool Accept(ActionConstraintContext context)
  {
   return string.Equals(
    context.RouteContext.RouteData.Values["country"].ToString(),
    _countryCode,StringComparison.OrdinalIgnoreCase);
  }
 }

The accept method returns true, indicating that it is matched when the country route value matches. This is different from routevalueattribute in that it allows fallback to a non characteristic operation. This example shows that if an en US operation is defined and the country code is fr fr, it will fall back to a more general controller, which does not apply [countryspecific (…)].

The order property, like the order property in the [httpget] attribute, is used to determine the running order.

summary

The above is the whole content of this article. I hope that the content of this article has some reference learning value for your study or work. Thank you for your support for developepaer.