From 7940dd9a0d5bc8059c1406faae5f414c8e32773d Mon Sep 17 00:00:00 2001 From: Shad Storhaug Date: Fri, 28 Feb 2014 19:20:27 +0700 Subject: [PATCH] Fixes #213, added IncludeAmbientRequestValues as a feature of ISiteMapNode and provided support for populating this property through XML, Dynamic Nodes, and MvcSiteMapNodeAttribute. --- .../Builder/AspNetSiteMapBuilder.cs | 1 + .../Builder/AspNetSiteMapNodeProvider.cs | 1 + .../Builder/ReflectionSiteMapBuilder.cs | 1 + .../Builder/ReflectionSiteMapNodeProvider.cs | 1 + .../Builder/ReservedAttributeNameProvider.cs | 1 + .../Builder/XmlSiteMapBuilder.cs | 1 + .../Builder/XmlSiteMapNodeProvider.cs | 1 + .../MvcSiteMapProvider/DynamicNode.cs | 9 +++++++++ .../IMvcSiteMapNodeAttribute.cs | 7 +++++++ .../MvcSiteMapProvider/ISiteMapNode.cs | 1 + .../MvcSiteMapProvider/LockableSiteMapNode.cs | 15 +++++++++++++++ .../MvcSiteMapProvider/MvcSiteMapNodeAttribute.cs | 8 ++++++++ .../MvcSiteMapProvider/SiteMapNode.cs | 10 +++++++++- .../MvcSiteMapProvider/SiteMapNodeSecurityBase.cs | 1 + .../Web/UrlResolver/SiteMapNodeUrlResolver.cs | 6 +++--- .../MvcSiteMapProvider/Xml/MvcSiteMapSchema.xsd | 9 +++++++++ 16 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/AspNetSiteMapBuilder.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/AspNetSiteMapBuilder.cs index 528e0ada..2ecc3b47 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/AspNetSiteMapBuilder.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/AspNetSiteMapBuilder.cs @@ -151,6 +151,7 @@ protected virtual ISiteMapNode GetSiteMapNodeFromProviderNode(ISiteMap siteMap, } siteMapNode.PreservedRouteParameters.AddRange(node.GetAttributeValue("preservedRouteParameters"), new[] { ',', ';' }); siteMapNode.UrlResolver = node.GetAttributeValue("urlResolver"); + siteMapNode.IncludeAmbientRequestValues = bool.Parse(node.GetAttributeValueOrFallback("includeAmbientRequestValues", "false")); // Add inherited route values to sitemap node foreach (var inheritedRouteParameter in node.GetAttributeValue("inheritedRouteParameters").Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)) diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/AspNetSiteMapNodeProvider.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/AspNetSiteMapNodeProvider.cs index 5ece1af5..cb59f1ca 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/AspNetSiteMapNodeProvider.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/AspNetSiteMapNodeProvider.cs @@ -148,6 +148,7 @@ protected virtual ISiteMapNodeToParentRelation GetSiteMapNodeFromProviderNode(Sy } siteMapNode.PreservedRouteParameters.AddRange(node.GetAttributeValue("preservedRouteParameters"), new[] { ',', ';' }); siteMapNode.UrlResolver = node.GetAttributeValue("urlResolver"); + siteMapNode.IncludeAmbientRequestValues = bool.Parse(node.GetAttributeValueOrFallback("includeAmbientRequestValues", "false")); // Add inherited route values to sitemap node foreach (var inheritedRouteParameter in node.GetAttributeValue("inheritedRouteParameters").Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)) diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/ReflectionSiteMapBuilder.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/ReflectionSiteMapBuilder.cs index b13a8152..8e68d7ac 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/ReflectionSiteMapBuilder.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/ReflectionSiteMapBuilder.cs @@ -464,6 +464,7 @@ protected virtual ISiteMapNode GetSiteMapNodeFromMvcSiteMapNodeAttribute(ISiteMa siteMapNode.RouteValues.AddRange(attribute.Attributes, false); siteMapNode.PreservedRouteParameters.AddRange(attribute.PreservedRouteParameters, new[] { ',', ';' }); siteMapNode.UrlResolver = attribute.UrlResolver; + siteMapNode.IncludeAmbientRequestValues = attribute.IncludeAmbientRequestValues; // Specified area, controller and action properties will override any // provided in the attributes collection. diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/ReflectionSiteMapNodeProvider.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/ReflectionSiteMapNodeProvider.cs index 0c8742a4..5d47fcf3 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/ReflectionSiteMapNodeProvider.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/ReflectionSiteMapNodeProvider.cs @@ -261,6 +261,7 @@ protected virtual ISiteMapNodeToParentRelation GetSiteMapNodeFromMvcSiteMapNodeA node.RouteValues.AddRange(attribute.Attributes, false); node.PreservedRouteParameters.AddRange(attribute.PreservedRouteParameters, new[] { ',', ';' }); node.UrlResolver = attribute.UrlResolver; + node.IncludeAmbientRequestValues = attribute.IncludeAmbientRequestValues; // Specified area, controller and action properties will override any // provided in the attributes collection. diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/ReservedAttributeNameProvider.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/ReservedAttributeNameProvider.cs index 05b7bb8b..9b2ae728 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/ReservedAttributeNameProvider.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/ReservedAttributeNameProvider.cs @@ -67,6 +67,7 @@ protected virtual bool IsKnownAttribute(string attributeName) || attributeName == "imageUrl" || attributeName == "inheritedRouteParameters" || attributeName == "preservedRouteParameters" + || attributeName == "includeAmbientRequestValues" || attributeName == "canonicalUrl" || attributeName == "canonicalKey" || attributeName == "metaRobotsValues"; diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/XmlSiteMapBuilder.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/XmlSiteMapBuilder.cs index a8fe9343..bd6fec1a 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/XmlSiteMapBuilder.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/XmlSiteMapBuilder.cs @@ -169,6 +169,7 @@ protected virtual ISiteMapNode GetSiteMapNodeFromXmlElement(ISiteMap siteMap, XE siteMapNode.RouteValues.AddRange(node, false); siteMapNode.PreservedRouteParameters.AddRange(node.GetAttributeValue("preservedRouteParameters"), new[] { ',', ';' }); siteMapNode.UrlResolver = node.GetAttributeValue("urlResolver"); + siteMapNode.IncludeAmbientRequestValues = bool.Parse(node.GetAttributeValueOrFallback("includeAmbientRequestValues", "false")); // Area and controller may need inheriting from the parent node, so set (or reset) them explicitly siteMapNode.Area = area; diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/XmlSiteMapNodeProvider.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/XmlSiteMapNodeProvider.cs index c5c028cd..dda5e9f5 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/XmlSiteMapNodeProvider.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/Builder/XmlSiteMapNodeProvider.cs @@ -242,6 +242,7 @@ protected virtual ISiteMapNodeToParentRelation GetSiteMapNodeFromXmlElement(XEle siteMapNode.RouteValues.AddRange(node, false); siteMapNode.PreservedRouteParameters.AddRange(node.GetAttributeValue("preservedRouteParameters"), new[] { ',', ';' }); siteMapNode.UrlResolver = node.GetAttributeValue("urlResolver"); + siteMapNode.IncludeAmbientRequestValues = bool.Parse(node.GetAttributeValueOrFallback("includeAmbientRequestValues", "false")); // Area and controller may need inheriting from the parent node, so set (or reset) them explicitly siteMapNode.Area = area; diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/DynamicNode.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/DynamicNode.cs index d572775b..2c9dac90 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/DynamicNode.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/DynamicNode.cs @@ -191,6 +191,13 @@ public virtual UpdatePriority UpdatePriority /// public virtual bool? Clickable { get; set; } + /// + /// Gets or sets a value indicating whether to include ambient request values + /// (from the RouteValues and/or query string) when resolving URLs. + /// + /// true to include ambient values (like MVC does); otherwise false. + public virtual bool? IncludeAmbientRequestValues { get; set; } + /// /// Copies the values for matching properties on an instance, but /// doesn't overwrite any values that are not set in this instance. @@ -276,6 +283,8 @@ public virtual void SafeCopyTo(ISiteMapNode node) node.UrlResolver = this.UrlResolver; if (this.Clickable != null) node.Clickable = (bool)this.Clickable; + if (this.IncludeAmbientRequestValues != null) + node.IncludeAmbientRequestValues = (bool)this.IncludeAmbientRequestValues; } diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/IMvcSiteMapNodeAttribute.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/IMvcSiteMapNodeAttribute.cs index 7dbb1ed1..bec5d984 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/IMvcSiteMapNodeAttribute.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/IMvcSiteMapNodeAttribute.cs @@ -152,6 +152,13 @@ public interface IMvcSiteMapNodeAttribute /// string PreservedRouteParameters { get; set; } + /// + /// Gets or sets a value indicating whether to include ambient request values + /// (from the RouteValues and/or query string) when resolving URLs. + /// + /// true to include ambient values (like MVC does); otherwise false. + bool IncludeAmbientRequestValues { get; set; } + /// /// Gets or sets the attributes (optional). /// diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/ISiteMapNode.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/ISiteMapNode.cs index 685f0f9d..94ada548 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/ISiteMapNode.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/ISiteMapNode.cs @@ -74,6 +74,7 @@ public interface ISiteMapNode IPreservedRouteParameterCollection PreservedRouteParameters { get; } RouteData GetRouteData(HttpContextBase httpContext); bool MatchesRoute(IDictionary routeValues); + bool IncludeAmbientRequestValues { get; set; } string Area { get; set; } string Controller { get; set; } diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/LockableSiteMapNode.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/LockableSiteMapNode.cs index 3cebe9f1..eb6bb443 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/LockableSiteMapNode.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/LockableSiteMapNode.cs @@ -331,6 +331,21 @@ public override string Route } } + /// + /// Gets or sets a value indicating whether to include ambient request values + /// (from the RouteValues and/or query string) when resolving URLs. + /// + /// true to include ambient values (like MVC does); otherwise false. + public override bool IncludeAmbientRequestValues + { + get { return base.IncludeAmbientRequestValues; } + set + { + this.ThrowIfReadOnly("IncludeAmbientRequestValues"); + base.IncludeAmbientRequestValues = value; + } + } + #endregion #region MVC diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/MvcSiteMapNodeAttribute.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/MvcSiteMapNodeAttribute.cs index 7e04900b..93faa029 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/MvcSiteMapNodeAttribute.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/MvcSiteMapNodeAttribute.cs @@ -15,6 +15,7 @@ public class MvcSiteMapNodeAttribute : Attribute, IMvcSiteMapNodeAttribute public MvcSiteMapNodeAttribute() { Clickable = true; + IncludeAmbientRequestValues = false; } /// @@ -163,6 +164,13 @@ public MvcSiteMapNodeAttribute() /// public string PreservedRouteParameters { get; set; } + /// + /// Gets or sets a value indicating whether to include ambient request values + /// (from the RouteValues and/or query string) when resolving URLs. + /// + /// true to include ambient values (like MVC does); otherwise false. + public bool IncludeAmbientRequestValues { get; set; } + /// /// Gets or sets the attributes (optional). /// diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNode.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNode.cs index c5f16eba..e23ab027 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNode.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNode.cs @@ -375,7 +375,7 @@ public override string Url public override void ResolveUrl() { if (this.CacheResolvedUrl && string.IsNullOrEmpty(this.UnresolvedUrl) && - this.preservedRouteParameters.Count == 0 && !this.RouteValues.ContainsCustomKeys) + this.preservedRouteParameters.Count == 0 && !this.IncludeAmbientRequestValues) { this.resolvedUrl = this.GetResolvedUrl(); } @@ -657,6 +657,13 @@ public override bool MatchesRoute(IDictionary routeValues) return this.RouteValues.MatchesRoute(routeValues); } + /// + /// Gets or sets a value indicating whether to include ambient request values + /// (from the RouteValues and/or query string) when resolving URLs. + /// + /// true to include ambient values (like MVC does); otherwise false. + public override bool IncludeAmbientRequestValues { get; set; } + #endregion #region MVC @@ -723,6 +730,7 @@ public override void CopyTo(ISiteMapNode node) node.Route = this.Route; this.RouteValues.CopyTo(node.RouteValues); this.PreservedRouteParameters.CopyTo(node.PreservedRouteParameters); + node.IncludeAmbientRequestValues = this.IncludeAmbientRequestValues; // NOTE: Area, Controller, and Action are covered under RouteValues. } diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNodeSecurityBase.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNodeSecurityBase.cs index 675d2b4b..c203ba9a 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNodeSecurityBase.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNodeSecurityBase.cs @@ -81,6 +81,7 @@ public virtual bool IsAccessibleToUser() public abstract IPreservedRouteParameterCollection PreservedRouteParameters { get; } public abstract RouteData GetRouteData(HttpContextBase httpContext); public abstract bool MatchesRoute(IDictionary routeValues); + public abstract bool IncludeAmbientRequestValues { get; set; } public abstract string Area { get; set; } public abstract string Controller { get; set; } public abstract string Action { get; set; } diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/Web/UrlResolver/SiteMapNodeUrlResolver.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/Web/UrlResolver/SiteMapNodeUrlResolver.cs index 4f5461e8..8d58d798 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/Web/UrlResolver/SiteMapNodeUrlResolver.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/Web/UrlResolver/SiteMapNodeUrlResolver.cs @@ -69,7 +69,7 @@ protected virtual string ResolveRouteUrl(ISiteMapNode node, string area, string // which doesn't consume resources using (var nullWriter = new StreamWriter(Stream.Null)) { - var requestContext = this.CreateRequestContext(node, true, nullWriter); + var requestContext = this.CreateRequestContext(node, nullWriter); result = this.ResolveRouteUrl(node, area, controller, action, routeValues, requestContext); } @@ -110,9 +110,9 @@ protected virtual HttpContextBase CreateHttpContext(ISiteMapNode node, TextWrite return this.mvcContextFactory.CreateHttpContext(node, uri, writer); } - protected virtual RequestContext CreateRequestContext(ISiteMapNode node, bool includeAmbientRequestValues, TextWriter writer) + protected virtual RequestContext CreateRequestContext(ISiteMapNode node, TextWriter writer) { - if (!includeAmbientRequestValues) + if (!node.IncludeAmbientRequestValues) { var httpContext = this.CreateHttpContext(node, writer); return this.mvcContextFactory.CreateRequestContext(httpContext); diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/Xml/MvcSiteMapSchema.xsd b/src/MvcSiteMapProvider/MvcSiteMapProvider/Xml/MvcSiteMapSchema.xsd index 2a291612..7be3a5aa 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/Xml/MvcSiteMapSchema.xsd +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/Xml/MvcSiteMapSchema.xsd @@ -176,6 +176,15 @@ + + + + Optional. Whether or not to include request route values and/or query string values when resolving the + URL (for route/action URLs only). Default is false. + + + +