查询字符串参数的 ASP.NET MVC 约束

Posted

技术标签:

【中文标题】查询字符串参数的 ASP.NET MVC 约束【英文标题】:ASP.NET MVC constraint for query string parameter 【发布时间】:2016-01-15 01:31:49 【问题描述】:

我有两个动作

public Action HasNumber(string name)  ... 

public Action DoesntHaveNumer(string name)  ... 

是否可以根据name 参数的值创建这样的路线,它会撞到一个或另一个?

例子:

myApp/Home?name=qwe 将点击DoesntHaveNumer

myApp/Home?name=q2e 将点击HasNumber

name是必填参数

【问题讨论】:

为什么不在重定向前检查,首先确定正确的路径 @EuphoriaGrogi 重定向之前是什么意思? 在这里找到答案:*** - Can my MVC2 app specify route constraints on Query String parameters? 【参考方案1】:

默认路由类不与查询字符串交互。但是,您可以继承它来添加额外的功能。

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

public class NumericCheckingQueryStringValueRoute : Route

    private readonly string queryStringKey;
    private readonly RouteValueDictionary defaultsIfNumeric;
    private readonly RouteValueDictionary defaultsIfNonNumeric;

    public NumericCheckingQueryStringValueRoute(
        string url,
        string queryStringKey,
        object defaultsIfNumeric,
        object defaultsIfNonNumeric)
        : base(url, new MvcRouteHandler())
    
        this.queryStringKey = queryStringKey;
        this.defaultsIfNumeric = new RouteValueDictionary(defaultsIfNumeric);
        this.defaultsIfNonNumeric = new RouteValueDictionary(defaultsIfNonNumeric);
    

    public override RouteData GetRouteData(HttpContextBase httpContext)
    
        var result = base.GetRouteData(httpContext);

        // If it matches, the result will be non-null
        if (result != null)
        
            var newResult = new RouteData(this, new MvcRouteHandler());

            // Copy the route values from the base class
            foreach (var value in result.Values)
            
                newResult.Values[value.Key] = value.Value;
            
            // Copy the data tokens from the base class
            foreach (var token in result.DataTokens)
            
                newResult.DataTokens[token.Key] = token.Value;
            

            var requestQueryString = httpContext.Request.QueryString;

            var queryStringValue = requestQueryString[this.queryStringKey];

            if (string.IsNullOrEmpty(queryStringValue))
            
                return null;
            

            RouteValueDictionary defaultsToUse;
            if (ContainsDigits(queryStringValue))
            
                defaultsToUse = this.defaultsIfNumeric;
            
            else
            
                defaultsToUse = this.defaultsIfNonNumeric;
            

            // Copy the numeric defaults to route values
            foreach (var value in defaultsToUse)
            
                newResult.Values[value.Key] = value.Value;
            

            // We matched, return the result
            return newResult;
        

        // Return null if no match
        return null;
    

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    
        // We just pass this through. If you add the value as a route value
        // when building ActionLink or RouteLink, it will automatically make
        // it into a query string value because it is not part of the url argument.
        return base.GetVirtualPath(requestContext, values);
    

    // Fastest way to check for digits
    // http://***.com/questions/7461080/fastest-way-to-check-if-string-contains-only-digits
    private bool ContainsDigits(string str)
    
        foreach (char c in str)
        
            if (c >= '0' && c <= '9')
                return true;
        

        return false;
    

用法

public class RouteConfig

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

        routes.Add(
            name: "CheckNumericName",
            item: new NumericCheckingQueryStringValueRoute(
                url: "Home",
                queryStringKey: "name",
                defaultsIfNumeric: new  controller = "Home", action = "HasNumber" ,
                defaultsIfNonNumeric: new  controller = "Home", action = "DoesntHaveNumer" 
                )
            );

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

要建立到页面的链接,您需要将查询字符串值添加到路由值集合中。您应该使用 RouteLink,因为您有 2 种不同的操作方法。

@html.RouteLink("Link with number", "CheckNumericName", new  name = "q2e" )
@Html.RouteLink("Link with no number", "CheckNumericName", new  name = "qwe" )

【讨论】:

以上是关于查询字符串参数的 ASP.NET MVC 约束的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC学习之路由篇

具有固定 URI 的 ASP.NET 路由不映射查询字符串参数

ASP.NET MVC 2 中带有约束的可选路由参数?

Asp.net core MVC post 参数始终为空

ASP.Net MVC:使用 RedirectToAction() 将字符串参数传递给操作

在 asp.net-mvc 中,查询字符串太长会导致 404 File not found 错误吗?