5

要继续我之前的一个问题(生成传出 url 时选择了意外路由),请考虑以下路由(无默认值,无约束):

"{controller}/{month}-{year}/{action}/{user}"

假设在通过与此路由匹配的传入 url 呈现某些页面时(因此请求上下文包含每个路由段的值),我需要生成一个仅更改month和的 url,并year保留所有其他段的确切值。

根据规则,我在链接的问题中提到(即路由系统将仅重用在 URL 模式中出现的段变量的值,而不是提供的任何参数。),如果我指定新的month并且year仅通过匿名对象,我会失去user段的价值(即路线甚至不匹配)。

我知道有两种方法可以克服这个问题:

  1. 根本不要指定匿名对象;context.RouteData.Values但在;中设置必要的段值 生成所需的url后,返回原始值,以便使用原始请求段值执行其余页面渲染;这看起来像这样:

    public static MvcHtmlString GetDateUrl(this RequestContext context, 
                                           DateTime date)
    {
        UrlHelper url = new UrlHelper(context);
    
        object month = null, year = null;
        if (context.RouteData.Values.ContainsKey("month"))
        {
            month = context.RouteData.Values["month"];
            year = context.RouteData.Values["year"];
        }
    
        try
        {
            context.RouteData.Values["month"] = date.Month;
            context.RouteData.Values["year"] = date.Year;
            return MvcHtmlString.Create(
                url.Action((string)context.RouteData.Values["action"]));
        }
        finally
        {
            if (month == null)
            {
                if (context.RouteData.Values.ContainsKey("month"))
                {
                    context.RouteData.Values.Remove("month");
                    context.RouteData.Values.Remove("year");
                }
            }
            else
            {
                context.RouteData.Values["month"] = month;
                context.RouteData.Values["year"] = year;
            }
        }
    }
    
  2. RouteValueDictionary根据当前请求上下文,使用 , 而不是匿名对象:

    public static MvcHtmlString GetDateUrl(this RequestContext context, 
                                           DateTime date)
    {
        UrlHelper url = new UrlHelper(context);
    
        var values = new RouteValueDictionary(context.RouteData.Values);
        values["month"] = date.Month;
        values["year"] = date.Year;
    
        string action = (string)context.RouteData.Values["action"];
    
        return MvcHtmlString.Create(url.Action(action, values));
    }
    

第二个选项似乎更简短,而第一个不创建额外的字典,操纵请求上下文。

哪种方式更好?或者,也许我正在做/理解错误的事情?

Sanderson S., Freeman A. - Pro ASP.NET MVC 3 Framework(第 3 版)说不要依赖段值重用,而是指定在确切的地点和时间需要的所有值。

我展示了我发现执行此任务的方式,但是如果替换的段发生在路线的早期,那么替换段值的正确(或更好)方法是什么,保留其他值?

编辑

根据 Jani Hyytiäinen 的回答。所讨论的路线只是一个例子。目标 mvc 应用程序包含不同的路由,有些可能比这个更复杂。所以我正在寻找的方法应该能够与它们中的任何一个一起使用。我想说这个扩展方法只知道,它必须改变monthand year,同时保留所有其他段。其他段的数量是任意的。所以硬编码它们根本不是一个可能的解决方案。除了请求上下文本身之外,我还有当前段值的来源。

4

1 回答 1

2
public static MvcHtmlString GetDateUrl(this RequestContext context, DateTime date)
{
    var values = context.RouteData.values;

    var data = new{
        controller = values["controller"]  ?? "Home";
        action = values["action"]  ?? "Index";
        month = date.Month;
        year = date.Year;
        user = context.HttpContext.User.Identity.Name;
    };

    string url = UrlHelper.RouteUrl(data);
    return MvcHtmlString.Create(url);
}

为什么要让它变得更复杂?您可能会争辩说您想对 HttpContext 进行一些空值检查,但是当您有一个没有 HttpContext 的 RequestContext 时,这里的空值检查是您的问题中最少的。要么这样,要么你有一个程序员在做一些非常时髦的事情,你确实希望应用程序在那里吹出它所有的荣耀,让他们知道他们正在做一些不起作用的事情,他们应该在它出现之前就停下来生产。

您可能还想在此处对其他任何内容进行额外检查,但实际上,此方法的职责到此为止。它应该接受一个日期并将路由 url 作为 MvcHtmlString 返回。时期。

从性能的角度来看,您可以在生成 url 时在此处显式定义一个特定的路由名称,但要做到这一点,您需要有一个相当大的路由集合。考虑到您将在此方法和路由配置之间创建隐藏的依赖关系。有人更改路线名称的那一天,应用程序崩溃了,很难找到原因。

您可能还想使用 RouteValueDictionary,但没有理由。如果我没记错的话,UrlHelper 无论如何都会在内部使用对象。即使我记错了,它也可以为您转换它。

参考资料:“在确切的地点和时间指定所有需要的值”,Sanderson S.,Freeman A. - Pro ASP.NET MVC 3 Framework

http://msdn.microsoft.com/en-us/library/dd505226(v=vs.108).aspx

于 2013-01-13T00:44:25.227 回答