Использование Web.SiteMap с динамическими URL-адресами (маршрутизация URL-адресов)

Я хотел бы сопоставить "приблизительные" совпадения в Web.SiteMap

Поставщик статической карты сайта Web.Sitemap работает хорошо, за исключением одного момента. ЭТО СТАТИЧЕСКОЕ!

Итак, если бы мне пришлось иметь узел карты сайта для каждой из 10 000 статей на моей странице, например:

  • site.com/articles/1/название статьи
  • site.com/articles/2/другое-название-статьи
  • site.com/articles/3/другая-статья-снова
  • ...
  • site.com/articles/9999/последняя-статья

Есть ли какое-то сопоставление с подстановочными знаками, которое я могу сделать с SiteMap, чтобы сопоставить что-нибудь в статьях?

Или, возможно, на моей странице веб-форм есть способ вручную установить текущий узел?

Я нашел «немного» помощи на этой странице когда делаете это с помощью ASP.Net MVC Framework, но все еще ищете хорошее решение для веб-форм.

Я думаю, что мне нужно будет создать собственный провайдер SiteMap.


person Armstrongest    schedule 15.11.2008    source источник


Ответы (3)


Это ответ на комментарий выше. Я не могу опубликовать полный код, но в основном так работает мой провайдер.

Предположим, у вас есть страница article.aspx, и она использует параметр строки запроса "id" для извлечения и отображения заголовка и текста статьи. Тогда это в Web.sitemap:

<siteMapNode url="/article.aspx" title="(this will be replaced)" param="id" />

Затем вы создаете этот класс:

public class DynamicSiteMapPath : SiteMapPath
{
  protected override void InitializeItem(SiteMapNodeItem item)
  {
    if (item.ItemType != SiteMapNodeItemType.PathSeparator)
    {
      string url = item.SiteMapNode.Url;
      string param = item.SiteMapNode["param"];

      // get parameter value
      int id = System.Web.HttpContext.Current.Request.QueryString[param];

      // retrieve article from database using id
      <write your own code>

      // override node link
      HyperLink link = new HyperLink();
      link.NavigateUrl = url + "?" + param + "=" + id.ToString();
      link.Text = <the article title from the database>;
      link.ToolTip = <the article title from the database>;
      item.Controls.Add(link);
    }
    else
    {
      // if current node is a separator, initialize as usual
      base.InitializeItem(item);
    }
  }
}

Наконец, вы используете этот провайдер в своем коде точно так же, как если бы вы использовали статический провайдер.

<mycontrols:DynamicSiteMapPath ID="dsmpMain" runat="server" />

Мой класс сложнее, чем этот, но это основы. Вместо использования параметра строки запроса вы можете просто проанализировать удобный URL-адрес, который вы используете, и использовать его вместо этого для получения правильного контента. Чтобы свести к минимуму дополнительные поиски в базе данных при каждом запросе, вы можете добавить к провайдеру механизм кэширования (название статьи обычно не меняется часто).

Надеюсь это поможет.

person user39603    schedule 20.11.2008
comment
Прохладный! Спасибо. Я собираюсь опубликовать решение, которое я придумал тоже. - person Armstrongest; 28.11.2008
comment
Как я могу использовать этот класс на моей странице aspx? любая помощь, пожалуйста - person Mr_Hmp; 25.03.2015

Я думаю, это не совсем ответ на ваш вопрос, но, возможно, это даст вам представление. Однажды я написал класс DynamicSiteMapPath, наследующий SiteMapPath. Я использую пользовательский атрибут в каждом теге <siteMapNode> в Web.sitemap, например:

<siteMapNode url="dynamicpage.aspx" title="blah" params="id" />

Затем класс DynamicSiteMapPath получает значение параметра «id», извлекает содержимое из базы данных и переопределяет отображаемый в данный момент узел элемента карты сайта с правильным заголовком и ссылкой. Это потребует небольшой работы, но при правильном выполнении это очень удобный способ обеспечения динамической поддержки страниц.

person user39603    schedule 19.11.2008
comment
Я хотел бы знать больше информации об этом. Звучит интересно. - person Armstrongest; 20.11.2008

Я столкнулся с этой проблемой и, честно говоря, не нашел решений, которые бы меня порадовали... поэтому я заимствую идеи тут и там. Мое решение состоит из нескольких частей: а) заставить SiteMapProvider найти фактическую страницу, обрабатывающую запрос, и использовать ее узел, и б) использовать стандартные методы для обновления узла карты сайта оттуда.

A) Проблема, с которой я постоянно сталкивался, заключается в том, что если бы у меня не было правильного виртуального пути, SiteMap.CurrentNode был бы нулевым и сработала бы функция SiteMapResolve. Чтобы решить эту проблему, я создал подкласс XmlSiteMapProvider и переопределил CurrentNode:

 namespace WebFormTools
{
    class RouteBaseSitemapProvider : XmlSiteMapProvider
    {
        public override SiteMapNode CurrentNode
        {
            get
            {
                var node = base.CurrentNode;


                if (node == null) 
                {
                    // we don't have a node, see if this is from a route
                    var page = HttpContext.Current.CurrentHandler as System.Web.UI.Page;

                    if (page != null && page.RouteData != null)
                    {
                        // try and get the Virtual path associated with this route
                        var handler = page.RouteData.RouteHandler as PageRouteHandler;

                        if (handler != null) {
                            // try and find that path instead.
                            node = FindSiteMapNode(handler.VirtualPath);
                        }
                    }

                }

                return node;
            }
        }
    }
}

По сути, если реализация по умолчанию ничего не находит, найдите маршрут (если есть) и попытайтесь найти узел, используя виртуальный путь обработчика.

Для справки вот часть моих файлов Web.Config, Global.asax и SiteMap:

Добавление провайдера

    <siteMap defaultProvider="RouteBaseSitemapProvider">
  <providers>
    <add name="RouteBaseSitemapProvider" type="WebFormTools.RouteBaseSitemapProvider" siteMapFile="Web.sitemap" />
  </providers>
</siteMap>

Маршрут:

            routes.MapPageRoute("EvalRoutes",
            "Evals/{type}/New.aspx",
            "~/Evals/New.aspx");

И карта сайта:

        <siteMapNode url="~/Evals/New.aspx" title="New Eval - {type}"  description="" />

Б) Я создаю подкласс System.Web.UI.Page, удачно названный BaseClass, который добавляет метод для регистрации обработчиков события SiteMapResolve:

public System.Web.SiteMapNode Process(System.Web.SiteMapNode currentNode)
    {
        if (currentNode == null) return currentNode;

        var page = HttpContext.Current.CurrentHandler as System.Web.UI.Page;

        if (page != null && page.RouteData != null)
        {

            Dictionary<Regex, string> replacements = new Dictionary<Regex, string>();

            // build a list of RegEx to aid in converstion, using RegEx so I can ignore class.  Technically I could also
            foreach (var key in page.RouteData.Values.Keys)
            {
                replacements.Add(new Regex(string.Format("\\{{{0}\\}}", key), RegexOptions.IgnoreCase), page.RouteData.Values[key].ToString());              
            }


            // navigate up the nodes
            var activeNode = currentNode;
            while (activeNode != null)
            {
                // to the replacements
                foreach(var replacement in replacements)
                {
                    activeNode.Title =  replacement.Key.Replace(activeNode.Title, replacement.Value);
                }

                activeNode = activeNode.ParentNode;
            }

        }

        return currentNode;
    }

Мне по-прежнему нужно правильно отображать URL-адреса (используется URL-адрес страницы, получающей маршрут), которая не содержит информации о маршрутизации. Я, вероятно, буду использовать пользовательский атрибут в карте сайта, чтобы сообщить узлу, как отображать URL-адрес.

person Graham    schedule 17.12.2010