访问通过查询字符串传递的路由值参数的一致方式

Consistent way to access route value parameters passed through querystring

我在 global.asax

中定义了以下路线
routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Portal", action = "Index", id = UrlParameter.Optional }
);

我无法控制用户是否访问带有“/useraccount/edit/1”或“/useraccount/edit?id=1”的页面。使用 UrlHelper Action 方法生成 url 时,如果将 id 作为查询字符串参数传递,则 id 值不包含在 RouteData 中。

new UrlHelper(helper.ViewContext.RequestContext).Action(
                            action, helper.ViewContext.RouteData.Values)

我正在寻找一种访问 id 值的一致方法,无论使用哪个 url 访问页面,或者一种自定义 RouteData 对象初始化的方法,以便它检查缺少路由参数的查询字符串,如果找到则添加它们。

您可以使用

@Url.RouteUrl("Default", new { id = ViewContext.RouteData.Values["id"] != null ? ViewContext.RouteData.Values["id"] : Request.QueryString["id"] })

试试这个解决方案

  var qs = helper.ViewContext
                .HttpContext.Request.QueryString
                .ToPairs()
                .Union(helper.ViewContext.RouteData.Values)
                .ToDictionary(x => x.Key, x => x.Value);

            var rvd = new RouteValueDictionary(qs);

            return new UrlHelper( helper.ViewContext.RequestContext).Action(action, rvd);

转换 NameValueCollection 试试这个

public static IEnumerable<KeyValuePair<string, object>> ToPairs(this NameValueCollection collection)
        {
            if (collection == null)
            {
                throw new ArgumentNullException("collection");
            }

            return collection.Cast<string>().Select(key => new KeyValuePair<string, object>(key, collection[key]));
        }

Extending Route 最终成为满足我需求的最简单的解决方案;感谢你的建议!让我知道我的解决方案是否有任何明显的问题(class 名称除外)。

FrameworkRoute.cs

public class FrameworkRoute: Route
{
    public FrameworkRoute(string url, object defaults) :
        base(url, new RouteValueDictionary(defaults), new MvcRouteHandler())
    {
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var routeData = base.GetRouteData(httpContext);
        if (routeData != null)
        {
            foreach (var item in routeData.Values.Where(rv => rv.Value == UrlParameter.Optional).ToList())
            {
                var val = httpContext.Request.QueryString[item.Key];
                if (!string.IsNullOrWhiteSpace(val))
                {
                    routeData.Values[item.Key] = val;
                }
            }
        }

        return routeData;
    }
}

Global.asax.cs

protected override void Application_Start()
{
       // register route
       routes.Add(new FrameworkRoute("{controller}/{action}/{id}", new { controller = "Portal", action = "Index", id = UrlParameter.Optional }));