SiteMap Navigation and Query String

家住魔仙堡 提交于 2019-12-06 08:31:56

问题


Currently I am trying to figure out how I can add dynamic query string parameters to my sitemap navigation menu. For example, the user chooses the source and edition he wants to work with. I have a simple sitemap that creates navigational links but the parameters the user chose need to be passed in the query string. The default map looks like this:

<siteMapNode url="" title=""  description="" >
   <siteMapNode url="~/Image.aspx?location=Our Products" title="Our Products" description="Our Products" />
   <siteMapNode url="~/Headline.aspx?location=Our Authors" title="Our Authors"  description="Our Authors" />
</siteMapNode>

Now the links will need to have the parameters added dynamically depending on what was chosen by the user. For example:

<siteMapNode url="~/Image.aspx?location=Our Products&Source=12345&Edition=asdfff" title="Our Products"  description="Our Products" />
<siteMapNode url="~/Headline.aspx?location=Our Authors&Source=12345&Edition=asdfff" title="Our Authors"  description="Our Authors" />

Hopefully this is fairly clear. Let me know if anyone needs deeper explanation.

Thanks


回答1:


Unfortunately, this is not supported by default. But you can implement the SiteMap.SiteMapResolve event in your Global.asax to catch such extended urls, and call SiteMapProvider.FindSiteMapNode with the correct 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;
}

No need for custom SiteMapProviders, this works with any provider.

Now, if you want to be more dynamic, you can do several things, for example (there are may ways):

Flag all <siteMapNode> tags with partial querystring matching with a special attribute, and load this list by iterating the entire sitemap. The problem with that approach is that this can be very inefficient for some sitemap providers (the file-based provider is an example of a provider that is a good match for such an approach). What you'd do then, is to say something like

<siteMapNode url="~/Image.aspx?location=Our Products"
             queryStringField="location"
             title="Our Products" description="Our Products" />

In code you could find such nodes recursively by starting at the root node, and remembering all nodes with a queryStringField attribute:

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

With this list in hand, and some hand waving, you should be able to do the same trick. Note that you should probably need to cache this list, because the SiteMapResolve event can be called more often than you'd expect. Especially for database-type SiteMapProviders.

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



回答2:


The default SiteMap provider in ASP.NET doesn't allow for query strings unfortunately.

This is a problem many people have came across - it's easy enough to write your own provider however that has query string functionality.

The provider below has worked well for me for several years.

http://www.csharper.net/blog/custom_sitemapprovider_incorporates_querystring_reliance.aspx




回答3:


I had a similar issue related to using a base64, url encoded string as a query parameter in the site map. Simplest solution was to just handle the MenuItemDataBound event and do my encoding there:

    string[] url = e.Item.NavigateUrl.Split('?');

    if (url.Length == 2)
    {
        url[1] = WebUtils.encodeString(url[1]);
    }

    e.Item.NavigateUrl = string.Join("?", url);

My webutils method:

    public static string encodeString(string value)
{
    return HttpUtility.UrlEncode(Convert.ToBase64String(Encoding.UTF8.GetBytes(value)));
}

public static string decodeString(string value)
{
    return Encoding.UTF8.GetString(Convert.FromBase64String(HttpUtility.UrlDecode(value)));
}


来源:https://stackoverflow.com/questions/3113765/sitemap-navigation-and-query-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!