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/