我想在Web.SiteMap中匹配“近似”匹配
Web.Sitemap静态站点地图提供程序运行良好,除了一件事。这是静止的!
所以,如果我必须为我页面上的每篇10,000篇文章都有一个sitemapnode:
我可以使用SiteMap进行某种通配符映射以匹配文章下的任何内容吗?
或许在我的Webforms页面中,有没有办法手动设置当前节点?
我使用ASP.Net MVC框架在this page上找到了一点帮助,但仍然在为Webforms寻找一个好的解决方案。
我认为我要做的是创建一个自定义的SiteMap提供程序
答案 0 :(得分:7)
这是对上述评论的回应。我无法发布完整的代码,但这基本上是我的提供商的工作方式。
假设您有一个页面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,而不是使用查询字符串参数,而是使用它来检索正确的内容。要最小化每个请求的额外数据库查找,您可以向提供程序添加缓存机制(文章标题通常不会经常更改)。
希望这有帮助。
答案 1 :(得分:2)
这不完全是我想到的问题的答案,但也许它会给你一个想法。我曾经写过一个继承SiteMapPath的DynamicSiteMapPath类。我在Web.sitemap中的每个<siteMapNode>
标记中使用自定义属性,如下所示:
<siteMapNode url="dynamicpage.aspx" title="blah" params="id" />
然后,DynamicSiteMapPath类获取“id”参数值,从数据库中检索内容,并使用正确的标题和链接覆盖当前呈现的站点地图项节点。它需要一些工作,但如果正确完成,这是提供动态页面支持的一种非常巧妙的方式。
答案 2 :(得分:2)
我一直在遇到这个问题,坦率地说,没有找到让我开心的任何解决方案......所以我从这里和那里借鉴意见。我的解决方案是多部分:a)让SiteMapProvider找到处理请求的实际页面并使用它的节点,b)使用标准技术从那里更新sitemapnode。
A)我遇到的问题是,如果我没有正确的虚拟路径,则SiteMap.CurrentNode将为null并触发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");
SiteMap:
<siteMapNode url="~/Evals/New.aspx" title="New Eval - {type}" description="" />
B)我是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。