- Modern Web Development with ASP.NET Core 3
- Ricardo Peres
- 804字
- 2021-06-18 18:35:59
Applying route constraints
When we define a route template or pattern, we may also want to specify how that route shall be matched, which is constraining it. We can constrain a route in a number of ways, such as these:
- The request needs to match a given HTTP method.
- The request needs to match a given content type.
- Its parameters need to match certain rules.
A constraint can be expressed in the route template or as a discrete object, using the MapControllerRoute method. If you choose to use the route template, you need to specify its name next to the token to which it applies:
{controller=Home}/{action=Index}/{id:int}
Notice {id:int}: this constrains the id parameter to an integer, and is one of the provided constraints that we will talk about in a moment. Another option is to make use of the defaults parameter:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { id = new IntRouteConstraint() });
});
You should be able to guess that the anonymous class that is passed in the constraints parameter must have properties that match the route parameters.
Following on from this example, you can also pass constraints that are not bound to any route parameter, but instead perform some kind of bespoke validation, as follows:
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { foo = new BarRouteConstraint() });
In this case, the BarRouteConstraintconstraint class will still be called and can be used to invalidate a route selection.
HTTP methods
As we said earlier, in order to make an action method available to only some HTTP verbs or a specific content type, you can use one of the following:
- HttpGetAttribute
- HttpPostAttribute
- HttpPutAttribute
- HttpDeleteAttribute
- HttpOptionsAttribute
- HttpPatchAttribute
- HttpHeadAttribute
- ActionVerbsAttribute
- ConsumesAttribute
The names should be self-explanatory. You can add attributes for different verbs, and if any of them is present, the route will only match if its verb matches one of these attributes. ActionVerbsAttribute lets you pass a single method, or a list of methods, that you wish to support. ConsumesAttribute takes a valid content type.
Default constraints
ASP.NET Core includes the following constraints:

A route parameter can take many constraints at once, separated by :, as here:
Calculator/Calculate({a:int:max(10)},{b:int:max(10)})
In this example, the a and bparameters need to be integers and have a maximum value of 10, at the same time. Another example follows:
Book/Find({isbn:regex(^d{9}[d|X]$)])
This will match an ISBN string starting with nine digits and followed by either a trailing digit or the X character.
It is also possible to provide your own custom constraints, which we will see next.
Creating custom constraints
A constraint is any class that implements IRouteConstraint. If it is meant to be used inline in a route template, then it must be registered. Here's an example of a route constraint for validating even numbers:
public class EvenIntRouteConstraint : IRouteConstraint
{
public bool Match(
HttpContext httpContext,
IRouter route,
string routeKey,
RouteValueDictionary values,
RouteDirection routeDirection)
{
if ((!values.ContainsKey(routeKey)) || (values[routeKey] == null))
{
return false;
}
var value = values[routeKey].ToString();
if (!int.TryParse(value, out var intValue))
{
return false;
}
return (intValue % 2) == 0;
}
}
You should be able to tell that all route parameters are provided in the values collection and that the route parameter name is in routeKey. If no route parameter is actually supplied, it will just return false, as it will if the parameter cannot be parsed into an integer. Now, to register your constraint, you need to use the AddRouting method shown earlier this chapter:
services.AddRouting(options =>
{
options.ConstraintMap.Add("evenint", typeof(EvenIntRouteConstraint));
});
This is actually the same as retrieving RouteOptions from the registered configuration:
services.Configure<RouteOptions>(options => {
//do the same });
That's all there is to it.
If you wish to use a route constraint to validate a URL—or any of the request parameters—you can use a route constraint not bound to a route key:
public class IsAuthenticatedRouteConstraint : IRouteConstraint
{
public bool Match(
HttpContext httpContext,
IRouter route,
string routeKey,
RouteValueDictionary values,
RouteDirection routeDirection)
{
return httpContext.Request.Cookies.ContainsKey("auth");
}
}
Granted, there are other (even better) ways to do this; this was only included as an example.
Now we can use it like this, in a route:
Calculator/Calculate({a:evenint},{b:evenint})
If, on the other hand, you prefer to use the constraint classes directly in your MapControllerRoute calls, you do not need to register them. Regardless, the route constraint collection is available as the IInlineConstraintResolver service:
var inlineConstraintResolver = routes
.ServiceProvider
.GetRequiredService<IInlineConstraintResolver>();
In this chapter, we've seen how to define constraints for route tokens, including creating our own, which can be very useful for validating URLs upfront. The next section explains what data tokens are.
- PWA入門與實(shí)踐
- 解構(gòu)產(chǎn)品經(jīng)理:互聯(lián)網(wǎng)產(chǎn)品策劃入門寶典
- Redis入門指南(第3版)
- Easy Web Development with WaveMaker
- 軟件測(cè)試技術(shù)指南
- HTML5游戲開(kāi)發(fā)實(shí)戰(zhàn)
- 從零開(kāi)始構(gòu)建深度前饋神經(jīng)網(wǎng)絡(luò):Python+TensorFlow 2.x
- Java語(yǔ)言程序設(shè)計(jì)實(shí)用教程(第2版)
- WCF全面解析
- Java服務(wù)端研發(fā)知識(shí)圖譜
- 你好!Python
- C++從零開(kāi)始學(xué)(視頻教學(xué)版)(第2版)
- 高性能Java架構(gòu):核心原理與案例實(shí)戰(zhàn)
- Microsoft Team Foundation Server 2015 Cookbook
- C語(yǔ)言程序設(shè)計(jì)教程(微課版)