带有查询字符串的RouteUrl - 具有重复键

时间:2015-04-21 06:27:29

标签: c# asp.net-mvc asp.net-mvc-5 asp.net-mvc-routing

我使用此扩展来创建RouteUrl,并附加当前查询字符串。这适用于没有相同密钥两次或更多次的查询字符串。

public static string CurrentQueryStringRouteUrl(this UrlHelper url, string routeName, RouteValueDictionary routeValues)
{
    var context = url.RequestContext;
    var combinedRouteValues = new RouteValueDictionary();
    var queryString = context.HttpContext.Request.QueryString;

    foreach (var key in queryString.AllKeys.Where(key => key != null))
    {
        combinedRouteValues[key] = queryString[key];
    }

    if (routeValues != null)
    {
        foreach (var routeValue in routeValues)
        {
            combinedRouteValues[routeValue.Key] = routeValue.Value;
        }
    }

    return url.RouteUrl(routeName, combinedRouteValues);
}

当存在具有相同名称的查询字符串键时,例如?id=1&id=2&id=3,使用上述方法将其转换为?id=1,2,3。有什么办法可以避免吗?我希望保留原始查询字符串,因为我将这些值绑定在模型列表上。

我知道我可以创建一个自定义模型绑定器来将逗号分隔的字符串绑定到string[](或者在此示例中为int[])但是我希望尽可能避免这种情况。

2 个答案:

答案 0 :(得分:0)

你可以做到这一点,但它是肮脏的黑客:

string _rawstring = context.HttpContext.Request.RawUrl;
int _f;
_f = _rawstring.IndexOf('?');
string _resultString = _rawstring.SubString(_f, _rawstring.Length);

您可以在此处找到有关该问题的有用信息:How to deal with more than one value per key in ASP.NET MVC 3?

答案 1 :(得分:0)

我采用了稍微不同的方法,因为我的查询字符串中确实需要单独的重复键。我使用计数器更改密钥,然后在呈现url字符串后,我恢复原始参数名称。我需要GridMvc的grid_filter查询,但您可以根据自己的需要进行调整。

/// <summary>
/// Allows you to create or extend a collection of route values to use in a url action
/// </summary>
public class RouteValueBuilder
{
    readonly RouteValueDictionary routeValues;
    private int gridFilterCounter = 0;

    public RouteValueBuilder(object existingRouteValues = null)
    {
        routeValues = existingRouteValues as RouteValueDictionary ?? new RouteValueDictionary(existingRouteValues);
    }

    public void Add(string field, object value)
    {
        if (field == "grid_filter" && routeValues.ContainsKey(field))
        {
            // Because we can't add duplicate keys and GridMvc doesn't support joined comma format for query strings,
            // we briefly rename each new filter, and then the Finalise method must be called after the url
            // string is rendered to restore the grid_filter names back to normal.
            gridFilterCounter++;
            routeValues.Add(field + gridFilterCounter, value);
        }
        else if (routeValues.ContainsKey(field))
        {
            // Since duplicate key names are not supported, the concatenated comma approach can be used
            routeValues[field] += "," + value;
        }
        else
        {
            routeValues.Add(field, value);
        }
    }

    public RouteValueDictionary Get()
    {
        return routeValues;
    }

    /// <summary>
    /// Cleans up the final string url, fixing workarounds done during the building process.
    /// This must be called after the final url string is rendered.
    /// </summary>
    public static string Finalise(string url)
    {
        // Restores grid_filter parameters to their correct naming.  See comments on Add method.
        for (var i = 0; i < 100; i++)
        {
            url = url.Replace("grid_filter" + i, "grid_filter");
        }

        return url;
    }
}

用法:

var builder = new RouteValueBuilder();
builder.Add("grid_filter", "value1");
builder.Add("grid_filter", "value2");
string url = Html.Action("Index", "Home", builder.Get());
url = RouteValueBuilder.Finalise(url);

编辑:请注意,逗号连接方法实际上在类中不起作用,因为它被编码,但对复制的支持是此示例中的主要接受者。