Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7
Чтобы создать собственное ограничение, нужно реализовать интерфейс IRouteConstraint с одним единственным методом Match, который имеет следующее определение:
public interface IRouteConstraint { bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection); }
Ограничение маршрута применяет этот интерфейс IRouteConstraint. Это вынуждает движок маршрутизации вызвать для ограничения маршрута метод IRouteConstraint.Match, чтобы определить, применяется ли данное ограничение к данному запросу или нет. Например, создадим ограничение, которое не будет пропускать запросу по некоторому url. Итак, добавим в приложение следующий класс:
public class CustomConstraint : IRouteConstraint { private string uri; public CustomConstraint(string uri) { this.uri = uri; } public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { return !(uri == httpContext.Request.Path); } }
Здесь мы говорим, что если запрашиваемый ресурс совпадает со значением свойства httpContext.Request.Path
, то запрос не будет
сопоставляться с маршрутом. Тогда определение маршрута может выглядеть следующим образом:
routeBuilder.MapRoute("default", "{controller}/{action}/{id?}", null, new { myConstraint = new CustomConstraint("/Home/Index/12") } );
Теперь запрос /Home/Index/12 не будет обрабатываться, даже если он удовлетворяет всем остальным условиям и ограничениям.
В случае выше было определено общее ограничение, которое применялось в целом к запросу. Но также можно задавать и ограничения для отдельных параметров. Допустим, создадим ограничение по должности:
public class PositionConstraint : IRouteConstraint { string[] positions = new[] { "admin", "director", "accountant" }; public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { return positions.Contains(values[routeKey]?.ToString().ToLowerInvariant()); } }
С помощью массива positions устанавливается допустимый набор значений, которые могут использовать в запросе.
В методе Match()
с помощью параметра routeKey
мы получаем параметр маршрута, для которого действует ограничение. А словарь
values
содержит набор значений маршрута. Используя выражение values[routeKey]
мы можем получить значение для параметра и что-то сделать с ним.
В данном случае мы смотрим, а содержится ли это значение в массиве positions.
Применим это ограничение:
routeBuilder.MapRoute( "default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index" }, new { id = new PositionConstraint() });
Теперь для соответствия маршруту параметр id должен иметь одно из следующих значений: "admin", "director" или "accountant". То есть строка запроса могла бы выглядеть так: http://localhost:59406/Home/Index/admin
Для создания inline-ограничений нам надо зарегистрировать их в методе ConfigureServices:
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using System.Linq; using Microsoft.Extensions.DependencyInjection; using System.Threading.Tasks; namespace RoutingApp { public class Startup { public void ConfigureServices(IServiceCollection services) { services.Configure<RouteOptions>(options => options.ConstraintMap.Add("position", typeof(PositionConstraint))); } public void Configure(IApplicationBuilder app) { var myRouteHandler = new RouteHandler(HandleAsync); var routeBuilder = new RouteBuilder(app, myRouteHandler); routeBuilder.MapRoute( "default", "{controller}/{action}/{id:position?}"); app.UseRouter(routeBuilder.Build()); app.Run(async (context) => { await context.Response.WriteAsync("Standard content"); }); } private async Task HandleAsync(HttpContext context) { var routeValues = context.GetRouteData().Values; var action = routeValues["action"].ToString(); var controller = routeValues["controller"].ToString(); string id = routeValues["id"]?.ToString(); await context.Response.WriteAsync($"controller: {controller} | action: {action} | id: {id}"); } } public class PositionConstraint : IRouteConstraint { string[] positions = new[] { "admin", "director", "accountant" }; public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { return positions.Contains(values[routeKey]?.ToString().ToLowerInvariant()); } } }
Основную работу по добавлению inline-ограничения выполняют следующие строки:
services.Configure<RouteOptions>(options => options.ConstraintMap.Add("position", typeof(PositionConstraint)));
Они устанавливают сопоставление ограничения "position" с классом PositionConstraint.