0

我正在使用 NopCommerce 2.30 构建一个站点。开箱即用的产品 URL 如下所示:

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

我进行了一些更改以使 URL 看起来像这样:

/build-your-own-computer/

我对 a 进行了更改以Route阻止它使用该Id参数。但是,整个站点的所有链接仍然通过该Url.RouteUrl方法传递 Id 参数:

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

这会产生以下 URL:

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

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

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

4

2 回答 2

1

我已经设法使用稍微修改的解决方案解决了我的问题: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" });
于 2012-02-28T14:14:18.067 回答
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);
 }
于 2012-02-27T18:20:17.250 回答