Nullable Route Constraint

March 23, 2017

В ASP.NET при настройки маршрутизации возможно указывать стандартные ограничения  на входные параметры. При этом параметр должен быть обязательным. Но иногда возникает необходимость накладывать ограничения в том случае, если параметр не NULL. Решение было найдено на stackoverflow.com (прямую ссылку не сохранил) и немного доработано.

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace WebViewStatistic.Infrastructure
{
    public class NullableConstraint : IRouteConstraint
    {
        private IRouteConstraint notNullConstraint;

        public NullableConstraint(IRouteConstraint notNullConstraint)
        {
            //Указываем ограничение, которое накладывается, если параметр не NULL
            this.notNullConstraint = notNullConstraint;
        }
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            if (routeDirection == RouteDirection.IncomingRequest)
            {
                // Если параметр null - возвращаем истину
                if (values[parameterName] == UrlParameter.Optional)
                    return true;
                //В противном случае передаем управление ограничению
                return notNullConstraint.Match(httpContext, route, parameterName, values, routeDirection);

            }

            return false;
        }
    }
}

И пример использования:

routes.MapRoute(
    name: "RuleName",
    url: "ControllerName/{action}/{year}/{month}/{day}/{daysCount}",
    defaults: new { controller = "ControllerName", year = DateTime.Now.Year, month = DateTime.Now.Month, day = DateTime.Now.Day, daysCount = UrlParameter.Optional },
    constraints: new
    {
        action = "Action1|Action2|Action3",
        year = @"\d+",
        month = new RangeRouteConstraint(1, 12),
        day = new RangeRouteConstraint(1, 31),
        daysCount = new NullableConstraint(new RangeRouteConstraint(1, 31)),
    }
);