简体   繁体   English

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

[英]ASP.NET MVC constraint for query string parameter

I have 2 actions 我有2个动作

public Action HasNumber(string name) { ... }

public Action DoesntHaveNumer(string name) { ... }

Is it possible to create such route that it will hit one or anothere depending on the value of name parameter? 是否可以创建这样的路由,使其根据name参数的值击中一个或另一个?

Example: 例:

myApp/Home?name=qwe will hit DoesntHaveNumer myApp/Home?name=qwe将命中DoesntHaveNumer

myApp/Home?name=q2e will hit HasNumber myApp/Home?name=q2e将命中HasNumber

name is a mandatory parameter name是必填参数

The default Route class does not interact with the query string. 默认的Route类不与查询字符串交互。 But, you can inherit it to add additional functionality. 但是,您可以继承它以添加其他功能。

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://stackoverflow.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;
    }
}

Usage 用法

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 }
        );
    }
}

And to build links to the page, you will need to add the query string value to the route values collection. 并建立到页面的链接,您需要将查询字符串值添加到路由值集合。 You should use RouteLink since you have it going to 2 different action methods. 您应该使用RouteLink,因为您将使用2种不同的操作方法。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM