К сожалению, это не поддерживается по умолчанию.Но вы можете реализовать событие SiteMap.SiteMapResolve
в вашем Global.asax
для перехвата таких расширенных URL-адресов и вызвать SiteMapProvider.FindSiteMapNode
с правильным URL-адресом:
private void Application_Start(object sender, EventArgs e)
{
SiteMap.SiteMapResolve += ResolveCustomNodes;
}
private SiteMapNode ResolveCustomNodes(object sender, SiteMapResolveEventArgs e)
{
// catch ~/Image.aspx and ~/Headline.aspx
if (e.Context.Request.AppRelativeCurrentExecutionFilePath.Equals(
"~/Image.aspx", StringComparison.OrdinalIgnoreCase)
|| e.Context.Request.AppRelativeCurrentExecutionFilePath.Equals(
"~/Headline.aspx", StringComparison.OrdinalIgnoreCase))
{
string location = context.Request.QueryString["location"];
if (location != null) // ignore everything except location=
return e.Provider.FindSiteMapNode(
e.Context.Request.AppRelativeCurrentExecutionFilePath
"?location=" + HttpUtility.UrlEncode(location));
}
return null; // use default implementation;
}
Нет необходимости в пользовательских SiteMapProvider
s, это работаетс любым провайдером.
Теперь, если вы хотите быть более динамичным, вы можете сделать несколько вещей, например (возможны разные способы):
Пометить все <siteMapNode>
теги частичной строкой запросасопоставление со специальным атрибутом и загрузка этого списка путем итерации всей карты сайта.Проблема с этим подходом состоит в том, что это может быть очень неэффективным для некоторых провайдеров карты сайта (провайдер на основе файлов является примером провайдера, который хорошо подходит для такого подхода).Тогда вы должны сказать что-то вроде
<siteMapNode url="~/Image.aspx?location=Our Products"
queryStringField="location"
title="Our Products" description="Our Products" />
В коде вы можете найти такие узлы рекурсивно, начав с корневого узла и запомнив все узлы с атрибутом queryStringField
:
private IEnumerable<SiteMapNode> FindNodesWithQueryString(SiteMapNode node)
{
if (node["queryStringField"] != null)
yield return node;
foreach (SiteMapNode childNode in node.ChildNodes)
{
foreach (SiteMapNode matchingNode in FindNodesWithQueryString(childNode))
{
yield return matchingNode;
}
}
}
Имея этот список в руке и помахивая рукой, вы сможете сделать тот же трюк.Обратите внимание, что вам, вероятно, нужно кэшировать этот список, потому что событие SiteMapResolve
может вызываться чаще, чем вы ожидаете.Специально для базы данных типа SiteMapProvider
s.
private SiteMapNode ResolveCustomNodes(object sender, SiteMapResolveEventArgs e)
{
string path = e.Context.Request.AppRelativeCurrentExecutionFilePath;
foreach (var candidate in from node in FindNodesWithQueryString(
SiteMap.RootNode)
select new {
Url = node.Url,
UrlNoQuery = node.Url.Split('?')[0],
QueryStringField = node["queryStringField"],
Node = node
} into x
where path.Equals(x.UrlNoQuery,
StringComparison.OrdinalIgnoreCase)
select x)
{
string paramValue = context.Request.QueryString[
candidate.QueryStringField];
if (paramValue != null)
{
string url = candidate.UrlNoQuery + "?" + candidate.QueryStringField
+ "=" + HttpUtility.UrlEncode(paramValue);
if (url.Equals(candidate.Url, StringComparison.OrdinalIgnoreCase))
return candidate.Node;
}
}
return null;
}