MVC Controller Action 应该只处理某些参数值,否则为 404

MVC Controller Action should only handle certain parameter values, 404 otherwise

我有一个带有一个参数的 MVC 控制器操作,只能使用该参数的特定值(null/empty 和一些特定字符串)调用,在其他情况下不应命中(大多数情况下为 404)。我试过使用如下所示的 RegexRouteConstraint。但这不会过滤特定的字符串。

var route = new Route("{soortAanbod}", new MvcRouteHandler())
{
    Defaults = new RouteValueDictionary(new { controller = "Homepage", action = "Index", soortAanbod = UrlParameter.Optional }),
    Constraints = new RouteValueDictionary(new { soortAanbod = new RegexRouteConstraint("a|b|c|d|e") }),
    DataTokens = new RouteValueDictionary { { "area", context.AreaName } }
};
context.Routes.Add("Homepage_soortAanbod", route);

控制器看起来像这样:public ActionResult Index(string soortAanbod)

我也尝试过使用动作过滤器,但这会弄乱其他过滤器。我怎样才能让这条路线只匹配 soortAanbod 的指定值?

我认为您可以尝试属性路由或者编写您自己的属性来检查参数或重定向到某处。

public class SomeAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var yourstring = filterContext.RequestContext.HttpContext.Request.QueryString["string"];
        if (!string.IsNullOrWhiteSpace(yourstring))
        {
            if (yourstring is not ok) 
            filterContext.Result =
                new RedirectToRouteResult(
                    new RouteValueDictionary
                    {
                        {"controller", "SomeCtrl"},
                        {"action", "SomeAction"}
                    });
        }
        base.OnActionExecuting(filterContext);

    }

您可以创建自定义约束并使用属性路由,在那里使用自定义约束并使约束构造函数接受您要避免的字符串列表

Custom MVC Route Constraint

Custom Constraint with Attribute Routing

您有 2 个问题:

  1. 您的正则表达式不包含 anchors^$)来分隔您尝试匹配的字符串。因此,它匹配 包含 任何这些字母的任何字符串。
  2. 您的URL将始终匹配默认路由,因此即使您的自定义路由不匹配,您仍然会到达该页面。默认路由将匹配长度为 0、1、2 或 3 段的 any URL。

您可以通过删除自定义路由并使用 IgnoreRoute(在幕后使用 StopRoutingHandler)来防止那些特定的 URL 匹配来解决这个问题。

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.IgnoreRoute("Homepage/Index/{soortAanbod}", 
            new { soortAanbod = new NegativeRegexRouteConstraint(@"^a$|^b$|^c$|^d$|^e$") });

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

不过有一个警告。 RegEx 是 not very good at doing negative matches,所以如果您不是 RegEx 大师,最简单的解决方案是构建一个 NegativeRegexRouteConstraint 来处理这种情况。

public class NegativeRegexRouteConstraint : IRouteConstraint
{
    private readonly string _pattern;
    private readonly Regex _regex;

    public NegativeRegexRouteConstraint(string pattern)
    {
        _pattern = pattern;
        _regex = new Regex(pattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Compiled);
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (parameterName == null)
            throw new ArgumentNullException("parameterName");
        if (values == null)
            throw new ArgumentNullException("values");

        object value;
        if (values.TryGetValue(parameterName, out value) && value != null)
        {
            string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
            return !_regex.IsMatch(valueString);
        }
        return true;
    }
}