Создание ограничений маршрутов

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7

Последнее обновление: 16.11.2019

Чтобы создать собственное ограничение, нужно реализовать интерфейс 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-ограничений

Для создания 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.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850