如何更换一些细分'保护他人的价值观?

时间:2013-01-09 06:27:34

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

要继续我以前的一个问题(Unexpected route chosen while generating an outgoing url),请考虑以下路线(无默认值,无约束):

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

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

根据规则,我在链接的问题中提到过(即路由系统将仅重用URL模式中较早出现的段变量的值,而不是任何提供的参数。),如果我只通过匿名对象指定新的monthyear,我将丢失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));
    }
    
  3. 第二个选项似乎更简短,而第一个选项不会创建额外的字典,操纵请求上下文。

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

    Sanderson S.,Freeman A. - Pro ASP.NET MVC 3 Framework(第3版)表示不依赖于段值重用,但确实指定了确切位置所需的所有值时间。

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

    修改

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

1 个答案:

答案 0 :(得分: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。周期。

从性能角度来看,您可以在生成网址时在此明确定义特定的路由名称,但为了使其有意义,您需要拥有相当大的路由集合。考虑到您将在此方法和路由配置之间创建隐藏的依赖关系。当有人更改路线名称时,应用程序会爆炸,很难找到原因。

您可能还想使用RouteValueDictionary,但没有理由。如果我没记错的话,UrlHelper会在内部使用对象。即使我记得它错了,它也能很好地为你转换它。

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

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