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

发布于 2024-10-15 05:13:44 字数 1472 浏览 6 评论 0原文

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
        );

这是我的操作链接

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

当在操作链接中指定过滤器级别时,它会生成如下 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

---编辑 --- 抱歉,这是赏金的操作

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

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

Global.asax route values

        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
        );

Here's my actionlink

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

When the filterlevel is specified in the actionlink, it generates a url like this:

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

Which is the same page as I am currently on. If I change the actionlink to use a property other than one that has a default value in the route table (yes, if I use filterDate it messes up too), it generates a link like this:

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

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

Is this behavior correct? Should I not be able to override the defaults set up in the route table? I have confirmed that if I remove the filterLevel default from the route table this works as I expect:

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

---EDIT---
sorry, here is the action

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

For the bounty I want to know how to override the "default" values that are specified in the routes from global.asax. i.e. I want to be able to override filterLevel and filterDate.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

别靠近我心 2024-10-22 05:13:44

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);
    }
}

SLaks already said what is probably the best way to handle this problem. I don't know if this will work, but, what happens if you put this above the existing route (so there would be two in your global.asax now)?

        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"
                } 
            );

Also, it just occurred to me that the reason you don't like SLaks' solution is that it could be repetitive. Since you only have one route, these parameters probably indicate a global functionality, instead of an action-scoped functionality. You could fix this by adding the values in an action filter on each controller, or your could use a custom route handler to apply this globally. Either of these would allow you to take the filterLevel and filterDate fields out of your route definition and still get the scope you want. Then it should be no problem to pass the parameters in a querystring with Html.ActionLink().

To do this with the route handler, change your route definition to:

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

Your implementation of the route handler would be something like this:

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);
    }
}
琉璃繁缕 2024-10-22 05:13:44

我认为默认值始终适用于 URL 中定义的条目,您不能定义默认值来省略核心 URL 中没有的内容,并且其他任何内容都会作为查询字符串传递。

有趣的问题。

HTH。

I thought the defaults were always for entries defined in the URL, that you can't define a default to omit something not in the core URL, and anything else is passed as a querystring.

Interesting question.

HTH.

总以为 2024-10-22 05:13:44

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

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);
}

You should specify the default value in your method, like this:

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);
}
笑忘罢 2024-10-22 05:13:44

如果 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}”参数。

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

@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。

这种混乱就是为什么我总是建议始终使用命名路线

If there are default values that are not specified in the URL pattern, then you can't override them because they are used to determine route selection when matching routes for URL generation.

Let me give you an example. Suppose you had the following two routes.

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
        );

Notice that there's a default value for "filterLevel", but there is no "{filterLevel}" parameter within the URL pattern.

Which URL should match when you do this?

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

If you could override the default value for filterLevel, then you'd expect both of the routes to match. But that doesn't make sense. In this case, neither matches because filterLevel isn't in the URL pattern and therefore the supplied filterLevel must match the default value. That way, you can do this:

@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)

to generate a URL for the first and second route respectively.

This confusion is why I always recommend to always use named routes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文