Pergunta

Eu gostaria de corresponder a partidas "aproximadas" no web.sitemap

O provedor de sitemap estático da Web.sitemap funciona bem, exceto por uma coisa. É estático!

Então, se eu tivesse que ter um sitemapnode para cada um dos 10.000 artigos na minha página como:

  • site.com/articles/1/article-title
  • site.com/articles/2/another-article-title
  • site.com/articles/3/another-article-again
  • ...
  • sites.com/articles/9999/the-last-ticle

Existe algum tipo de mapeamento curinga que eu possa fazer com o sitemap para combinar com qualquer coisa em Artigos?

Ou talvez na minha página Webforms, existe uma maneira de definir manualmente o nó atual?

Eu encontrei um "pedaço" de ajuda em esta página Ao fazer isso com a estrutura do ASP.NET MVC, mas ainda procurando uma boa solução para WebForms.

Acho que o que vou ter que fazer é criar um provedor de mapa de sitemas personalizado

Foi útil?

Solução

Isso é uma resposta ao comentário acima. Não posso postar o código completo, mas é basicamente assim que meu provedor funciona.

Suponha que você tenha um artigo de página.aspx e ele use o parâmetro da string de consulta "id" para recuperar e exibir um título e corpo de artigo. Então isso está no web.sitemap:

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

Então, você cria esta classe:

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);
    }
  }
}

Por fim, você usa esse provedor em seu código, assim como usaria o provedor estático.

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

Minha aula é mais complicada do que isso, mas esses são o básico. Em vez de usar um parâmetro de consulta, você pode analisar o URL amigável que está usando e usá -lo para recuperar o conteúdo correto. Para minimizar as pesquisas adicionais de banco de dados a cada solicitação, você pode adicionar um mecanismo de cache ao provedor (o título do artigo geralmente não muda com frequência).

Espero que isto ajude.

Outras dicas

Isso não é inteiramente uma resposta para sua pergunta, eu acho, mas talvez lhe dê uma ideia. Certa vez, escrevi uma classe DynamicSitemappath herdando o SiteMappath. Eu uso um atributo personalizado em cada <siteMapNode> Tag em web.sitemap, como este:

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

Em seguida, a classe DynamicSItemAppath recebe o valor do parâmetro "ID", recupera o conteúdo do banco de dados e substitui o nó do item do sitemap atualmente renderizado com o título e o link corretos. Vai demorar um pouco, mas quando feito corretamente, essa é uma maneira muito interessante de fornecer suporte dinâmico na página.

Eu tenho encontrado esse problema e, francamente, não encontrei soluções que me fizeram feliz ... então pego emprestado idéias daqui e ali. Minha solução é várias partes: a) Peça ao sitemaprovider que encontre a página real que lida com a solicitação e use seu nó e b) use técnicas padrão para atualizar o sitemapnode a partir daí.

A) O problema em que continuava correndo é que, se eu não tivesse o caminho virtual correto, o sitemap.CurrentNode seria nulo e o fogo da função SiteMapResolve. Para resolver isso, subclassei XMLSItemApprovider e substitui o 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;
            }
        }
    }
}

Basicamente, se a implementação padrão não encontrar nada, procure a rota (se houver) e tente encontrar o nó usando o caminho virtual do manipulador.

Para referência, aqui faz parte dos meus arquivos web.config, global.asax e sitemap:

Adicionando o provedor

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

O percurso:

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

E o mapa do site:

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

B) I Subclass System.Web.ui.Page, apropriadamente nomeado Baseclass, que adiciona um método para registrar manipuladores para o evento 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;
    }

Eu ainda preciso ter o mapa dos URLs adequadamente (o URL da página recebendo a rota), que é sem informações de roteamento. Provavelmente usarei um atributo personalizado no sitemap para dizer ao nó como renderizar o URL.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top