覆盖UrlHelper.RouteUrl

时间:2012-02-27 17:07:23

标签: c# asp.net asp.net-mvc nopcommerce

我正在使用NopCommerce 2.30构建网站。开箱即用,产品网址如下所示:

/p/16/build-your-own-computer/

我做了一些更改,以使网址如下所示:

/build-your-own-computer/

我已对Route进行了更改,以阻止其使用Id参数。但是,网站上的所有链接仍然通过Url.RouteUrl方法传递Id参数:

@Url.RouteUrl("Product", new { productId = Model.Id, SeName = Model.SeName })

这会产生以下网址:

/build-your-own-computer/?productId=16

我可以直接从方法调用中删除productId参数。但是,某些插件还会添加包含productId的链接,我无法更改。

有没有办法可以覆盖Url.RouteUrl方法来检查对产品Route的请求,然后删除productId

2 个答案:

答案 0 :(得分:0)

无需覆盖RouteUrl。它包含一组键/值对。只需修改路由,使其不再需要id并从@ Url.RouteUrl调用中删除id。您需要创建一个接受以下URL的路由:

/p/{productName}

您可以在Global.asax中执行此操作:

routes.MapRoute(
    "Products",
    "/p/{productName}",
    new { controller = "Products", action = "Details" }
);

现在您将生成这样的路线:

@Url.RouteUrl("Products", new { productName = Model.SeName })

现在,在您的控制器中,您还需要额外的工作来从名称而不是ID中查找产品。现在可能看起来像这样:

 public ActionResult Details(string productName)
 {
     var product = ProductRepository.FindByName(productName);

     return View(product);
 }

答案 1 :(得分:0)

我设法使用稍微修改过的解决方案来解决我的问题:http://erraticdev.blogspot.com/2011/03/removing-route-values-from-linksurls-in.html

罗伯特的解决方案没有包含名称空间,所以我在下面做了一些调整:

public static class CustomRouteExtensions
{

    public static Route MapRoute(this RouteCollection routes, string name, string url, string excludeRouteValueNames, object defaults)
    {
        return MapRoute(routes, name, url, excludeRouteValueNames, defaults, null, null);
    }

    public static Route MapRoute(this RouteCollection routes, string name, string url, string excludeRouteValueNames, object defaults, string[] namespaces)
    {
        return MapRoute(routes, name, url, excludeRouteValueNames, defaults, null, namespaces);
    }

    public static Route MapRoute(this RouteCollection routes, string name, string url, string excludeRouteValueNames, object defaults, object constraints)
    {
        return MapRoute(routes, name, url, excludeRouteValueNames, defaults, constraints, null);
    }

    public static Route MapRoute(this RouteCollection routes, string name, string url, string excludeRouteValueNames, object defaults, object constraints, string[] namespaces)
    {
        if (routes == null)
            throw new ArgumentNullException("routes");

        if (url == null)
            throw new ArgumentNullException("url");

        Route item = new CustomRoute(url, new MvcRouteHandler(), excludeRouteValueNames)
        {
            Defaults = new RouteValueDictionary(defaults),
            Constraints = new RouteValueDictionary(constraints),
            DataTokens = new RouteValueDictionary()
        };

        if ((namespaces != null) && (namespaces.Length > 0))
            item.DataTokens["Namespaces"] = namespaces;

        routes.Add(name, item);

        return item;
    }

}

我的自定义Route看起来像这样:

public class CustomRoute : Route
{

    #region Properties

    public ReadOnlyCollection<string> ExcludedRouteValuesNames { get; private set; }

    #endregion

    #region Constructor

    public CustomRoute(string url, IRouteHandler routeHandler, string commaSeparatedRouteValueNames)
        : this(url, routeHandler, (commaSeparatedRouteValueNames ?? string.Empty).Split(','))
    {
    }

    public CustomRoute(string url, IRouteHandler routeHandler, params string[] excludeRouteValuesNames)
        : base(url, routeHandler)
    {
        ExcludedRouteValuesNames = new ReadOnlyCollection<string>(excludeRouteValuesNames.Select(val => val.Trim()).ToList());
    }

    #endregion

    #region Route overrides

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        if (requestContext == null)
            throw new ArgumentNullException("requestContext");

        // create new route data and include only non-excluded values
        var excludedRouteData = new RouteData(this, this.RouteHandler);

        // add route values
        requestContext.RouteData.Values
            .Where(pair => !this.ExcludedRouteValuesNames.Contains(pair.Key, StringComparer.OrdinalIgnoreCase))
            .ToList()
            .ForEach(pair => excludedRouteData.Values.Add(pair.Key, pair.Value));

        // add data tokens
        requestContext.RouteData.DataTokens
            .ToList()
            .ForEach(pair => excludedRouteData.DataTokens.Add(pair.Key, pair.Value));

        // intermediary request context
        var currentContext = new RequestContext(new HttpContextWrapper(HttpContext.Current), excludedRouteData);

        // create new URL route values and include only none-excluded values
        var excludedRouteValues = new RouteValueDictionary(
            values
                .Where(v => !this.ExcludedRouteValuesNames.Contains(v.Key, StringComparer.OrdinalIgnoreCase))
                .ToDictionary(pair => pair.Key, pair => pair.Value)
        );

        var result = base.GetVirtualPath(currentContext, excludedRouteValues);

        return result;
    }

    #endregion

}

我的新Route.MapRoute看起来像这样:

routes.MapRoute("Product", 
                "{SeName}", 
                "productIdd", 
                new { controller = "Catalog", action = "UrlType" }, 
                new[] { "Nop.Plugin.FreshEgg.Seo.Controllers" });