mvc2.net路由中的环境值

时间:2010-08-13 10:26:38

标签: asp.net-mvc url-routing

我在global.asax文件中注册了两条路线

routes.MapRoute(
    "strict",
    "{controller}.mvc/{docid}/{action}/{id}",
    new { action = "Index", id = "", docid = "" },
    new { docid = @"\d+"}
);
routes.MapRoute(
    "default",
    "{controller}.mvc/{action}/{id}",
    new { action = "Index", id = "" },
    new { docConstraint = new DocumentConstraint() }
);

我的标签页中有一个静态的“仪表板”链接,其他一些由db中的值构成的链接是代码

 <ul id="globalnav" class = "t-reset t-tabstrip-items">
     <li class="bar" id = "dashboard">
         <%=Html.ActionLink("dash.board", "Index", pck.Controller,  new{docid =string.Empty,id = pck.PkgID }, new { @class = "here" })%>
     </li>
     <%  
         foreach (var md in pck.sysModules)
         {
     %>
     <li class="<%=liClass%>">
         <%=Html.ActionLink(md.ModuleName, md.ActionName, pck.Controller, new { docid = md.DocumentID}, new { @class = cls })%>
     </li>
     <%
         }
     %>
 </ul>

现在我的发布地址localhost/oa.mvc/index/11与第二条路线明显匹配。但是,当我访问已映射到第一条路线的任何网页,然后返回dash.board链接时,它会向我显示localhost/oa.mvc/7/index/11 7docid并从之前的网址中挑选。

我知道我的行动方法是在docid之后,并且更改它不会清除docid。

我的问题是,我可以在不更改路线的情况下删除docid吗?

6 个答案:

答案 0 :(得分:4)

我有同样的“不清算”价值问题...

我已经介入了源代码,我不明白将段注释为: //添加所有当前不在URL中的当前值

从第91行到第100行的

@ System\Web\Routing\ParsedRoute.cspublic BoundUrl Bind(RouteValueDictionary currentValues, RouteValueDictionary values, RouteValueDictionary defaultValues, RouteValueDictionary constraints)方法

虽然在前面的方法步骤中正确处理了清除过程,但是此代码将不需要的参数“重新注入”到acceptedValues字典中??

答案 1 :(得分:4)

我的路由以这种方式定义:

routes.MapRoute(
    "Planning",
    "Plans/{plan}/{controller}/{action}/{identifier}",
    new { controller = "General", action = "Planning", identifier = UrlParameter.Optional },
    new { plan = @"^\d+$" }
);

// default application route
routes.MapRoute(
    "Default",
    "{controller}/{action}/{identifier}",
    new {
        controller = "General",
        action = "Summary",
        identifier = UrlParameter.Optional,
        plan = string.Empty // mind this default !!!
    }
);

这与您正在使用的非常相似。但请注意我定义默认值的默认路线。即使我的默认路由未定义plan路由值,我仍然将其设置为string.Empty。因此,每当我使用Html.ActionLink()Url.Action()并希望从网址中删除plan时,我就会按照通常的方式调用它:

Url.Action("Action", "Controller", new { plan = string.Empty });

并且计划不再包含在URL查询字符串中。自己尝试一下也可以。

答案 2 :(得分:2)

穆罕默德,我建议这样的事情: (5分钟前写的,未在生产中测试过)

public static class MyHtmlHelperExtensions {

    public static MvcHtmlString FixActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes) {
        var linkRvd = new RouteValueDictionary(routeValues);
        var contextRvd = htmlHelper.ViewContext.RouteData.Values;
        var contextRemovedRvd = new RouteValueDictionary();

        // remove clearing route values from current context
        foreach (var rv in linkRvd) {
            if (string.IsNullOrEmpty((string)rv.Value) && contextRvd.ContainsKey(rv.Key)) {
                contextRemovedRvd.Add(rv.Key, contextRvd[rv.Key]);
                contextRvd.Remove(rv.Key);
            }
        }

        // call ActionLink with modified context
        var htmlString = htmlHelper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);

        // restore context
        foreach (var rv in contextRemovedRvd) {
            contextRvd.Add(rv.Key, rv.Value);
        }

        return htmlString;
    }
}

答案 3 :(得分:2)

这是一个令人沮丧的问题,我敢说它甚至是ASP.Net MVC中的一个错误。幸运的是,使用ActionFilters很容易解决。如果您正在使用MVC3,那么我只是将其作为全局属性来清除环境值。我使这个属性具有歧视性,但您可以更改它以清除所有属性。

这里的假设是,当结果执行时(您的视图最有可能),您已经明确指定了所有ActionLinks和表单操作。因此,这将在它们(链接)被评估之前执行,为您提供生成它们的新基础。

public class ClearAmbientRouteValuesAttribute : ActionFilterAttribute 
{
    private readonly string[] _keys;

    public ClearAmbientRouteValuesAttribute(params string [] keys)
    {
        if (keys == null)
            _keys = new string[0];

        _keys = keys;
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        foreach (var key in _keys) {
            // Why are you sticking around!!!
            filterContext.RequestContext.RouteData.Values.Remove(key);        
        }
    }
}

// Inside your Global.asax
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    filters.Add(new ClearAmbientRouteValuesAttribute("format"));
}

希望这有助于某人,因为它确实帮助了我。谢谢你提出这个问题。

答案 4 :(得分:0)

在这种特殊情况下,我有两条建议:

  1. 使用命名路由。 MapRoute方法的第一个参数是名称。要生成链接,请使用Html.RouteLink()(以及其他类似的API)。这样你就可以随时选择你想要的完全路线,而不必想知道选择了什么。

  2. 如果您仍想使用Html.ActionLink(),请明确设置docid=""以清除其值。

答案 5 :(得分:0)

以下是我解决问题的方法,可能需要一点调整才能让它发挥作用,但我觉得我可以得到我需要的东西,只是或多或少正常使用路由:

摘自Apress Pro ASP.Net.MVC 3框架:

  • 必须为URL模式中定义的每个段变量提供一个值。 要查找每个段变量的值,路由系统首先查看 我们提供的值(使用匿名类型的属性),然后是 当前请求的变量值,最后是在中定义的默认值 路线。 (我们将在本章后面回到这些值的第二个来源。)

  • 我们为细分变量提供的值都不一致 路径中定义的默认变量。这些变量是默认值 已提供值,但URL模式中不会出现这些值。对于 例如,在此路由定义中,myVar是一个仅默认变量:

    routes.MapRoute(“MyRoute”,“{controller} / {action}”, new {myVar =“true”});

    要使此路线成为匹配,我们必须注意不要为myVar提供值或制作 确保我们提供的值与默认值匹配。

  • 所有段变量的值必须满足路径约束。看到 本章前面的“约束路径”部分提供了不同的示例 各种约束。

基本上我使用了关于路由不匹配的规则,如果它没有定义一个段,但是有一个默认变量用来让我更多地控制路由是否被选择用于出站路由。

这是我的固定路线,请注意我如何为永远无效的类别指定值,并且不指定类别的段。这意味着如果我有一个类别,将跳过路由,但如果我只有一个页面,则会使用它:

routes.MapRoute(null, "receptionists/faq/{page}", new { controller = "Receptionist", action = "Faq", page = 1, category = (Object)null }, new { page = @"^\d+$" });

routes.MapRoute(null, "receptionists/faq/{category}/{page}", new { controller = "Receptionist", action = "Faq", page = 1 }, new { category = @"^\D+$", page = @"^\d+$" });

对于类别链接

@Html.ActionLink("All", "Faq", new { page = 1 })

@foreach (var category in Model.Categories)
{
@Html.ActionLink(category.DisplayName, "faq", new { category = category.DisplayName.ToLower(), page = 1 })
}

对于页面链接

@for (var p = 1; p <= Model.TotalPages; p++)
{
@Html.ActionLink(p.ToString(), "Faq", new { page = p, category = Model.CurrentCategory})
}