如何使用Html.ActionLink覆盖路由表默认值?

时间:2011-02-01 17:06:11

标签: asp.net asp.net-mvc-3 razor asp.net-mvc-routing actionlink

Global.asax路线值

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional, filterDate = DateTime.Now.AddDays(-1), filterLevel = "INFO" } // Parameter defaults
        );

这是我的actionlink

        @Html.ActionLink(item.MachineName, "Machine", new { id = item.MachineName, filterLevel = "hello" }, null)

当在actionlink中指定filterlevel时,它会生成一个这样的URL:

http://localhost:1781/LoggingDashboard/log/level/VERBOSE

这是我目前所在的页面。如果我更改actionlink以使用除路由表中具有默认值的属性之外的属性(是的,如果我使用filterDate它也会混乱),它会生成如下链接:

@Html.ActionLink(item.MachineName, "Machine", new { id = item.MachineName, foo = "bar" }, null)

http://localhost:1781/LoggingDashboard/log/Machine/C0UPSMON1?foo=bar

这种行为是否正确?我是否应该无法覆盖路由表中设置的默认值?我已经确认,如果我从路由表中删除filterLevel默认值,这可以正常工作:

http://localhost:1781/LoggingDashboard/log/Machine/C0UPSMON1?filterLevel=VERBOSE

--- --- EDIT 对不起,这是行动

        public ActionResult Machine(string id, DateTime filterDate, string filterLevel)
        {
...
            var model = new LogListViewModel { LogEntries = logEntries };
            return View(model);
        }

对于赏金,我想知道如何覆盖从global.asax路由中指定的“默认”值。即我希望能够覆盖filterLevel和filterDate。

4 个答案:

答案 0 :(得分:3)

SLaks已经说过可能是处理这个问题的最佳方法。我不知道这是否有效,但是,如果你把它放在现有路线之上会发生什么(所以你的global.asax现在会有两个)?

        routes.MapRoute(
            "Filtered",
            "{controller}/{action}/{id}?filterLevel={filterLevel}&filterDate={filterDate}",
            new
                {
                    controller = "Home",
                    action = "Index",
                    id = UrlParameter.Optional,
                    filterDate = DateTime.Now.AddDays(-1),
                    filterLevel = "INFO"
                } 
            );

另外,我刚想到你不喜欢SLaks解决方案的原因是它可能是重复的。由于您只有一个路由,因此这些参数可能表示全局功能,而不是动作范围的功能。您可以通过在每个控制器上的操作过滤器中添加值来解决此问题,或者您可以使用自定义路由处理程序来全局应用此值。这些中的任何一个都允许您从路径定义中取出filterLevelfilterDate字段,并仍然可以获得所需的范围。那么在Html.ActionLink()的查询字符串中传递参数应该没问题。

要使用路由处理程序执行此操作,请将路由定义更改为:

        routes.Add(
            new Route(
                    "{controller}/{action}/{id}", 
                    new RouteValueDictionary(new{ controller = "Home", action = "Index", id = UrlParameter.Optional}), 
                    new CustomRouteHandler()));

您对路由处理程序的实现将是这样的:

public class CustomRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        var routeValues =  requestContext.RouteData.Values;
        if(!routeValues.ContainsKey("filterLevel"))
        {
            routeValues.Add("filterLevel","INFO");
        }
        if(!routeValues.ContainsKey("filterDate"))
        {
            routeValues.Add("filterDate", DateTime.Now.AddDays(-1));
        }
        var mvcRouteHandler = new MvcRouteHandler(); 
        return (mvcRouteHandler as IRouteHandler).GetHttpHandler(requestContext);
    }
}

答案 1 :(得分:1)

我认为默认值始终是URL中定义的条目,您无法定义默认值以省略核心URL中没有的内容,而其他任何内容都作为查询字符串传递。

有趣的问题。

HTH。

答案 2 :(得分:1)

您应该在方法中指定默认值,如下所示:

public ActionResult Machine(string id, DateTime? filterDate = null, string filterLevel = "INFO")
{
    filterDate = filterDate ?? DateTime.Now.AddDays(-1);  
    var model = new LogListViewModel { LogEntries = logEntries };
    return View(model);
}

答案 3 :(得分:1)

如果在URL模式中指定了的默认值,则无法覆盖它们,因为它们用于在匹配URL生成路由时确定路由选择。

让我举个例子。假设你有以下两条路线。

routes.MapRoute(
            "Default1", // Route name
            "foo/{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional
            , filterLevel = "INFO" } // Parameter defaults
        );

routes.MapRoute(
            "Default2", // Route name
            "bar/{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional
            , filterLevel = "DEBUG" } // Parameter defaults
        );

请注意,“filterLevel”有一个默认值,但URL模式中没有“{filterLevel}”参数。

执行此操作时应匹配哪个网址?

@Html.ActionLink(item.MachineName, "Machine", 
new { id = item.MachineName, filterLevel = "RANDOM" }, null)

如果你可以覆盖filterLevel的默认值,那么你希望两个路由都匹配。但这没有意义。在这种情况下,两者都不匹配,因为filterLevel不在URL模式中,因此提供的filterLevel必须与默认值匹配。这样,你可以这样做:

@Html.ActionLink(item.MachineName, "Machine", 
new { id = item.MachineName, filterLevel = "INFO" }, null)

//AND

@Html.ActionLink(item.MachineName, "Machine", 
new { id = item.MachineName, filterLevel = "DEBUG" }, null)

分别生成第一条和第二条路线的URL。

这种混淆是我总是向always use named routes推荐的原因。