Переопределить UrlHelper.RouteUrl - PullRequest
0 голосов
/ 27 февраля 2012

Я создаю сайт, используя NopCommerce 2.30.Из коробки URL-адреса продуктов выглядят следующим образом:

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

Я внес некоторые изменения, чтобы URL-адреса выглядели следующим образом:

/build-your-own-computer/

Я внес изменениена Route, чтобы остановить использование параметра Id.Однако все ссылки на сайте по-прежнему передают параметр Id с помощью метода Url.RouteUrl:

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

В результате получается следующий URL:

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

Я мог бы просто перейтии удалите параметр productId из вызова метода.Однако некоторые плагины также добавляют ссылки, содержащие productId, которые я не могу изменить.

Есть ли способ переопределить метод Url.RouteUrl для проверки запросов к продукту Route а затем удалите productId?

Ответы [ 2 ]

0 голосов
/ 28 февраля 2012

Мне удалось решить мою проблему, используя слегка измененное решение этого: 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" });
0 голосов
/ 27 февраля 2012

Нет необходимости переопределять RouteUrl.Он принимает коллекцию пар ключ / значение.Просто измените маршрут, чтобы он больше не ожидал идентификатора, и удалите идентификатор из вызова @ Url.RouteUrl.Вам нужно будет создать маршрут, который принимает URL-адреса, например:

/p/{productName}

Вы можете сделать это в вашем Global.asax:

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

Теперь вывместо этого будет сгенерирован маршрут, подобный следующему:

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

Теперь в вашем контроллере вы должны выполнить дополнительную работу, чтобы найти продукт по имени, а не по идентификатору.Вероятно, теперь это будет выглядеть примерно так:

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

     return View(product);
 }
...