/// <summary>
        /// Gets the site map node from MVC site map node attribute.
        /// </summary>
        /// <param name="attribute">The attribute.</param>
        /// <param name="type">The type.</param>
        /// <param name="methodInfo">The method info.</param>
        /// <param name="helper">The node helper.</param>
        /// <returns></returns>
        protected virtual ISiteMapNodeToParentRelation GetSiteMapNodeFromMvcSiteMapNodeAttribute(
            IMvcSiteMapNodeAttribute attribute, Type type, MethodInfo methodInfo, ISiteMapNodeHelper helper)
        {
            if (attribute == null)
            {
                throw new ArgumentNullException("attribute");
            }
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            if (!String.IsNullOrEmpty(attribute.SiteMapCacheKey))
            {
                // Return null if the attribute doesn't apply to this cache key
                if (!helper.SiteMapCacheKey.Equals(attribute.SiteMapCacheKey))
                {
                    return null;
                }
            }

            if (methodInfo == null) // try to find Index action
            {
                var ms = type.FindMembers(MemberTypes.Method, BindingFlags.Instance | BindingFlags.Public,
                                          (mi, o) => mi != null && string.Equals(mi.Name, "Index"), null);
                foreach (MethodInfo m in ms.OfType<MethodInfo>())
                {
                    var pars = m.GetParameters();
                    if (pars.Length == 0)
                    {
                        methodInfo = m;
                        break;
                    }
                }
            }

            string area = "";
            if (!String.IsNullOrEmpty(attribute.AreaName))
            {
                area = attribute.AreaName;
            }
            if (String.IsNullOrEmpty(area) && !String.IsNullOrEmpty(attribute.Area))
            {
                area = attribute.Area;
            }
            // Determine area (will only work if controller is defined as [<Anything>.]Areas.<Area>.Controllers.<AnyController>)
            if (String.IsNullOrEmpty(area))
            {
                var m = Regex.Match(type.Namespace, @"(?:[^\.]+\.|\s+|^)Areas\.(?<areaName>[^\.]+)\.Controllers");
                if (m.Success)
                {
                    area = m.Groups["areaName"].Value;
                }
            }

            // Determine controller and (index) action
            string controller = type.Name.Substring(0, type.Name.IndexOf("Controller"));
            string action = (methodInfo != null ? methodInfo.Name : null) ?? "Index";

            if (methodInfo != null)
            {
                // handle ActionNameAttribute
                var actionNameAttribute = methodInfo.GetCustomAttributes(typeof(ActionNameAttribute), true).FirstOrDefault() as ActionNameAttribute;
                if (actionNameAttribute != null)
                {
                    action = actionNameAttribute.Name;
                }
            }

            string httpMethod = String.IsNullOrEmpty(attribute.HttpMethod) ? HttpVerbs.Get.ToString().ToUpperInvariant() : attribute.HttpMethod.ToUpperInvariant();

            // Handle title and description
            var title = attribute.Title;
            var description = String.IsNullOrEmpty(attribute.Description) ? title : attribute.Description;

            // Handle implicit resources
            var implicitResourceKey = attribute.ResourceKey;

            // Generate key for node
            string key = helper.CreateNodeKey(
                attribute.ParentKey,
                attribute.Key,
                attribute.Url,
                title,
                area,
                controller, action, httpMethod,
                attribute.Clickable);

            var nodeParentMap = helper.CreateNode(key, attribute.ParentKey, SourceName, implicitResourceKey);
            var node = nodeParentMap.Node;

            // Assign defaults
            node.Title = title;
            node.Description = description;
            AcquireAttributesFrom(attribute, node.Attributes, helper);
            AcquireRolesFrom(attribute, node.Roles);
            node.Clickable = attribute.Clickable;
            node.VisibilityProvider = attribute.VisibilityProvider;
            node.DynamicNodeProvider = attribute.DynamicNodeProvider;
            node.ImageUrl = attribute.ImageUrl;
            node.TargetFrame = attribute.TargetFrame;
            node.HttpMethod = httpMethod;
            if (!string.IsNullOrEmpty(attribute.Url)) node.Url = attribute.Url;
            node.CacheResolvedUrl = attribute.CacheResolvedUrl;
            node.CanonicalUrl = attribute.CanonicalUrl;
            node.CanonicalKey = attribute.CanonicalKey;
            AcquireMetaRobotsValuesFrom(attribute, node.MetaRobotsValues);
            node.LastModifiedDate = attribute.LastModifiedDate;
            node.ChangeFrequency = attribute.ChangeFrequency;
            node.UpdatePriority = attribute.UpdatePriority;
            node.Order = attribute.Order;

            // Handle route details
            node.Route = attribute.Route;
            AcquireRouteValuesFrom(attribute, node.RouteValues, helper);
            AcquirePreservedRouteParametersFrom(attribute, node.PreservedRouteParameters);
            node.UrlResolver = attribute.UrlResolver;

            // Specified area, controller and action properties will override any
            // provided in the attributes collection.
            if (!string.IsNullOrEmpty(area)) node.RouteValues.Add("area", area);
            if (!string.IsNullOrEmpty(controller)) node.RouteValues.Add("controller", controller);
            if (!string.IsNullOrEmpty(action)) node.RouteValues.Add("action", action);

            // Handle MVC details

            // Add defaults for area
            if (!node.RouteValues.ContainsKey("area"))
            {
                node.RouteValues.Add("area", "");
            }

            return nodeParentMap;
        }
        /// <summary>
        /// Maps an XMLElement from the XML file to an MvcSiteMapNode.
        /// </summary>
        /// <param name="node">The element to map.</param>
        /// <param name="parentNode">The parent ISiteMapNode</param>
        /// <param name="helper">The node helper.</param>
        /// <returns>An MvcSiteMapNode which represents the XMLElement.</returns>
        protected virtual ISiteMapNodeToParentRelation GetSiteMapNodeFromXmlElement(XElement node, ISiteMapNode parentNode, ISiteMapNodeHelper helper)
        {
            // Get data required to generate the node instance

            // Get area and controller from node declaration or the parent node
            var area                = this.InheritAreaIfNotProvided(node, parentNode);
            var controller          = this.InheritControllerIfNotProvided(node, parentNode);
            var action              = node.GetAttributeValue("action");
            var url                 = node.GetAttributeValue("url");
            var explicitKey         = node.GetAttributeValue("key");
            var parentKey           = parentNode == null ? "" : parentNode.Key;
            var httpMethod          = node.GetAttributeValueOrFallback("httpMethod", HttpVerbs.Get.ToString()).ToUpper();
            var clickable           = bool.Parse(node.GetAttributeValueOrFallback("clickable", "true"));
            var title               = node.GetAttributeValue("title");
            var implicitResourceKey = node.GetAttributeValue("resourceKey");

            // Generate key for node
            string key = helper.CreateNodeKey(
                parentKey,
                explicitKey,
                url,
                title,
                area,
                controller,
                action,
                httpMethod,
                clickable);

            // Create node
            var nodeParentMap = helper.CreateNode(key, parentKey, SourceName, implicitResourceKey);
            var siteMapNode   = nodeParentMap.Node;

            // Assign values
            siteMapNode.Title       = title;
            siteMapNode.Description = node.GetAttributeValue("description");
            siteMapNode.Attributes.AddRange(node, false);
            siteMapNode.Roles.AddRange(node.GetAttributeValue("roles"), new[] { ',', ';' });
            siteMapNode.Clickable           = clickable;
            siteMapNode.VisibilityProvider  = node.GetAttributeValue("visibilityProvider");
            siteMapNode.DynamicNodeProvider = node.GetAttributeValue("dynamicNodeProvider");
            siteMapNode.ImageUrl            = node.GetAttributeValue("imageUrl");
            siteMapNode.ImageUrlProtocol    = node.GetAttributeValue("imageUrlProtocol");
            siteMapNode.ImageUrlHostName    = node.GetAttributeValue("imageUrlHostName");
            siteMapNode.TargetFrame         = node.GetAttributeValue("targetFrame");
            siteMapNode.HttpMethod          = httpMethod;
            siteMapNode.Url = url;
            siteMapNode.CacheResolvedUrl          = bool.Parse(node.GetAttributeValueOrFallback("cacheResolvedUrl", "true"));
            siteMapNode.IncludeAmbientValuesInUrl = bool.Parse(node.GetAttributeValueOrFallback("includeAmbientValuesInUrl", "false"));
            siteMapNode.Protocol             = node.GetAttributeValue("protocol");
            siteMapNode.HostName             = node.GetAttributeValue("hostName");
            siteMapNode.CanonicalKey         = node.GetAttributeValue("canonicalKey");
            siteMapNode.CanonicalUrl         = node.GetAttributeValue("canonicalUrl");
            siteMapNode.CanonicalUrlProtocol = node.GetAttributeValue("canonicalUrlProtocol");
            siteMapNode.CanonicalUrlHostName = node.GetAttributeValue("canonicalUrlHostName");
            siteMapNode.MetaRobotsValues.AddRange(node.GetAttributeValue("metaRobotsValues"), new[] { ' ' });
            siteMapNode.ChangeFrequency  = (ChangeFrequency)Enum.Parse(typeof(ChangeFrequency), node.GetAttributeValueOrFallback("changeFrequency", "Undefined"));
            siteMapNode.UpdatePriority   = (UpdatePriority)Enum.Parse(typeof(UpdatePriority), node.GetAttributeValueOrFallback("updatePriority", "Undefined"));
            siteMapNode.LastModifiedDate = DateTime.Parse(node.GetAttributeValueOrFallback("lastModifiedDate", DateTime.MinValue.ToString()));
            siteMapNode.Order            = int.Parse(node.GetAttributeValueOrFallback("order", "0"));

            // Handle route details
            siteMapNode.Route = node.GetAttributeValue("route");
            siteMapNode.RouteValues.AddRange(node, false);
            siteMapNode.PreservedRouteParameters.AddRange(node.GetAttributeValue("preservedRouteParameters"), new[] { ',', ';' });
            siteMapNode.UrlResolver = node.GetAttributeValue("urlResolver");

            // Area and controller may need inheriting from the parent node, so set (or reset) them explicitly
            siteMapNode.Area       = area;
            siteMapNode.Controller = controller;
            siteMapNode.Action     = action;

            // Add inherited route values to sitemap node
            foreach (var inheritedRouteParameter in node.GetAttributeValue("inheritedRouteParameters").Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries))
            {
                var item = inheritedRouteParameter.Trim();
                if (node.Attribute(item) != null)
                {
                    throw new MvcSiteMapException(string.Format(Resources.Messages.SiteMapNodeSameKeyInRouteValueAndInheritedRouteParameter, key, title, item));
                }

                if (parentNode.RouteValues.ContainsKey(item))
                {
                    siteMapNode.RouteValues.Add(item, parentNode.RouteValues[item]);
                }
            }

            return(nodeParentMap);
        }
        /// <summary>
        /// Maps an XMLElement from the XML file to an MvcSiteMapNode.
        /// </summary>
        /// <param name="node">The element to map.</param>
        /// <param name="parentNode">The parent ISiteMapNode</param>
        /// <param name="helper">The node helper.</param>
        /// <returns>An MvcSiteMapNode which represents the XMLElement.</returns>
        protected virtual ISiteMapNodeToParentRelation GetSiteMapNodeFromXmlElement(XElement node, ISiteMapNode parentNode, ISiteMapNodeHelper helper)
        {
            // Get area, controller and action from node declaration
            string area = node.GetAttributeValue("area");
            string controller = node.GetAttributeValue("controller");
            var parentKey = parentNode == null ? "" : parentNode.Key;
            var httpMethod = node.GetAttributeValueOrFallback("httpMethod", HttpVerbs.Get.ToString()).ToUpperInvariant();
            // Handle title and description
            var title = node.GetAttributeValue("title");
            var description = String.IsNullOrEmpty(node.GetAttributeValue("description")) ? title : node.GetAttributeValue("description");

            // Generate key for node
            string key = helper.CreateNodeKey(
                parentKey,
                node.GetAttributeValue("key"),
                node.GetAttributeValue("url"),
                title,
                area,
                controller,
                node.GetAttributeValue("action"),
                httpMethod,
                !(node.GetAttributeValue("clickable") == "false"));

            // Handle implicit resources
            var implicitResourceKey = node.GetAttributeValue("resourceKey");

            // Create node
            var nodeParentMap = helper.CreateNode(key, parentKey, SourceName, implicitResourceKey);
            var siteMapNode = nodeParentMap.Node;

            // Assign defaults
            siteMapNode.Title = title;
            siteMapNode.Description = description;
            AcquireAttributesFrom(node, siteMapNode.Attributes, helper);
            AcquireRolesFrom(node, siteMapNode.Roles);
            siteMapNode.Clickable = bool.Parse(node.GetAttributeValueOrFallback("clickable", "true"));
            siteMapNode.VisibilityProvider = node.GetAttributeValue("visibilityProvider");
            siteMapNode.DynamicNodeProvider = node.GetAttributeValue("dynamicNodeProvider");
            siteMapNode.ImageUrl = node.GetAttributeValue("imageUrl");
            siteMapNode.TargetFrame = node.GetAttributeValue("targetFrame");
            siteMapNode.HttpMethod = httpMethod;
            siteMapNode.Url = node.GetAttributeValue("url");
            siteMapNode.CacheResolvedUrl = bool.Parse(node.GetAttributeValueOrFallback("cacheResolvedUrl", "true"));
            siteMapNode.CanonicalUrl = node.GetAttributeValue("canonicalUrl");
            siteMapNode.CanonicalKey = node.GetAttributeValue("canonicalKey");
            this.AcquireMetaRobotsValuesFrom(node, siteMapNode.MetaRobotsValues);
            siteMapNode.ChangeFrequency = (ChangeFrequency)Enum.Parse(typeof(ChangeFrequency), node.GetAttributeValueOrFallback("changeFrequency", "Undefined"));
            siteMapNode.UpdatePriority = (UpdatePriority)Enum.Parse(typeof(UpdatePriority), node.GetAttributeValueOrFallback("updatePriority", "Undefined"));
            siteMapNode.LastModifiedDate = DateTime.Parse(node.GetAttributeValueOrFallback("lastModifiedDate", DateTime.MinValue.ToString()));
            siteMapNode.Order = int.Parse(node.GetAttributeValueOrFallback("order", "0"));

            // Handle route details

            // Assign to node
            siteMapNode.Route = node.GetAttributeValue("route");
            AcquireRouteValuesFrom(node, siteMapNode.RouteValues, helper);
            AcquirePreservedRouteParametersFrom(node, siteMapNode.PreservedRouteParameters);
            siteMapNode.UrlResolver = node.GetAttributeValue("urlResolver");

            // Add inherited route values to sitemap node
            foreach (var inheritedRouteParameter in node.GetAttributeValue("inheritedRouteParameters").Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries))
            {
                var item = inheritedRouteParameter.Trim();
                if (siteMapNode.RouteValues.ContainsKey(item))
                    throw new MvcSiteMapException(String.Format(Resources.Messages.SiteMapNodeSameKeyInRouteValueAndInheritedRouteParameter, key, title, item));

                if (parentNode.RouteValues.ContainsKey(item))
                {
                    siteMapNode.RouteValues.Add(item, parentNode.RouteValues[item]);
                }
            }

            // Handle MVC details

            // Inherit area and controller from parent
            if (parentNode != null)
            {
                if (string.IsNullOrEmpty(area) && !siteMapNode.RouteValues.ContainsKey("area"))
                {
                    siteMapNode.Area = parentNode.Area;
                }
                if (string.IsNullOrEmpty(controller) && !siteMapNode.RouteValues.ContainsKey("controller"))
                {
                    siteMapNode.Controller = parentNode.Controller;
                }
            }

            // Add defaults for area
            if (!siteMapNode.RouteValues.ContainsKey("area"))
            {
                siteMapNode.RouteValues.Add("area", "");
            }

            return nodeParentMap;
        }
        /// <summary>
        /// Gets the site map node from MVC site map node attribute.
        /// </summary>
        /// <param name="attribute">The attribute.</param>
        /// <param name="type">The type.</param>
        /// <param name="methodInfo">The method info.</param>
        /// <param name="helper">The node helper.</param>
        /// <returns></returns>
        protected virtual ISiteMapNodeToParentRelation GetSiteMapNodeFromMvcSiteMapNodeAttribute(
            IMvcSiteMapNodeAttribute attribute, Type type, MethodInfo methodInfo, ISiteMapNodeHelper helper)
        {
            if (attribute == null)
            {
                throw new ArgumentNullException("attribute");
            }
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            if (!string.IsNullOrEmpty(attribute.SiteMapCacheKey))
            {
                // Return null if the attribute doesn't apply to this cache key
                if (!helper.SiteMapCacheKey.Equals(attribute.SiteMapCacheKey))
                {
                    return(null);
                }
            }

            if (methodInfo == null) // try to find Index action
            {
                var ms = type.FindMembers(MemberTypes.Method, BindingFlags.Instance | BindingFlags.Public,
                                          (mi, o) => mi != null && string.Equals(mi.Name, "Index"), null);
                foreach (MethodInfo m in ms.OfType <MethodInfo>())
                {
                    var pars = m.GetParameters();
                    if (pars.Length == 0)
                    {
                        methodInfo = m;
                        break;
                    }
                }
            }

            string area = "";

            if (!string.IsNullOrEmpty(attribute.AreaName))
            {
                area = attribute.AreaName;
            }
            if (string.IsNullOrEmpty(area) && !string.IsNullOrEmpty(attribute.Area))
            {
                area = attribute.Area;
            }
            // Determine area (will only work if controller is defined as [<Anything>.]Areas.<Area>.Controllers.<AnyController>)
            if (string.IsNullOrEmpty(area))
            {
                var m = Regex.Match(type.Namespace, @"(?:[^\.]+\.|\s+|^)Areas\.(?<areaName>[^\.]+)\.Controllers");
                if (m.Success)
                {
                    area = m.Groups["areaName"].Value;
                }
            }

            // Determine controller and (index) action
            string controller = type.Name.Substring(0, type.Name.IndexOf("Controller"));
            string action     = (methodInfo != null ? methodInfo.Name : null) ?? "Index";

            if (methodInfo != null)
            {
                // handle ActionNameAttribute
                var actionNameAttribute = methodInfo.GetCustomAttributes(typeof(ActionNameAttribute), true).FirstOrDefault() as ActionNameAttribute;
                if (actionNameAttribute != null)
                {
                    action = actionNameAttribute.Name;
                }
            }

            string httpMethod = (string.IsNullOrEmpty(attribute.HttpMethod) ? HttpVerbs.Get.ToString() : attribute.HttpMethod).ToUpper();

            // Handle title
            var title = attribute.Title;

            // Handle implicit resources
            var implicitResourceKey = attribute.ResourceKey;

            // Generate key for node
            string key = helper.CreateNodeKey(
                attribute.ParentKey,
                attribute.Key,
                attribute.Url,
                title,
                area,
                controller, action, httpMethod,
                attribute.Clickable);

            var nodeParentMap = helper.CreateNode(key, attribute.ParentKey, SourceName, implicitResourceKey);
            var node          = nodeParentMap.Node;

            // Assign defaults
            node.Site        = attribute.Site;
            node.Title       = title;
            node.Description = attribute.Description;
            node.Attributes.AddRange(attribute.Attributes, false);
            node.Roles.AddRange(attribute.Roles);
            node.Clickable           = attribute.Clickable;
            node.VisibilityProvider  = attribute.VisibilityProvider;
            node.DynamicNodeProvider = attribute.DynamicNodeProvider;
            node.ImageUrl            = attribute.ImageUrl;
            node.ImageUrlProtocol    = attribute.ImageUrlProtocol;
            node.ImageUrlHostName    = attribute.ImageUrlHostName;
            node.TargetFrame         = attribute.TargetFrame;
            node.HttpMethod          = httpMethod;
            if (!string.IsNullOrEmpty(attribute.Url))
            {
                node.Url = attribute.Url;
            }
            node.CacheResolvedUrl          = attribute.CacheResolvedUrl;
            node.IncludeAmbientValuesInUrl = attribute.IncludeAmbientValuesInUrl;
            node.Protocol             = attribute.Protocol;
            node.HostName             = attribute.HostName;
            node.CanonicalKey         = attribute.CanonicalKey;
            node.CanonicalUrl         = attribute.CanonicalUrl;
            node.CanonicalUrlSeo      = attribute.CanonicalUrlSeo;
            node.CanonicalUrlProtocol = attribute.CanonicalUrlProtocol;
            node.CanonicalUrlHostName = attribute.CanonicalUrlHostName;
            node.MetaRobotsValues.AddRange(attribute.MetaRobotsValues);
            node.Include          = attribute.Include;
            node.Exclude          = attribute.Exclude;
            node.LastModifiedDate = string.IsNullOrEmpty(attribute.LastModifiedDate) ? DateTime.MinValue : DateTime.Parse(attribute.LastModifiedDate);
            node.ExpirationDate   = string.IsNullOrEmpty(attribute.ExpirationDate) ? DateTime.Today.AddYears(2) : DateTime.Parse(attribute.ExpirationDate);
            node.ChangeFrequency  = attribute.ChangeFrequency;
            node.UpdatePriority   = attribute.UpdatePriority;
            node.Order            = attribute.Order;

            node.IsVideo              = attribute.IsVideo;
            node.ContentLocationUrl   = attribute.ContentLocationUrl;
            node.PlayerLocationUrl    = attribute.PlayerLocationUrl;
            node.PlayerAllowEmbed     = attribute.PlayerAllowEmbed;
            node.PlayerAutoplay       = attribute.PlayerAutoplay;
            node.VideoDuration        = attribute.VideoDuration;
            node.ViewCount            = attribute.ViewCount;
            node.VideoRating          = attribute.VideoRating;
            node.FamilyFriendly       = attribute.FamilyFriendly;
            node.GalleryLocation      = attribute.GalleryLocation;
            node.GalleryTitle         = attribute.GalleryTitle;
            node.RequiresSubscription = attribute.RequiresSubscription;
            node.VideoUploader        = attribute.VideoUploader;
            node.VideoUploaderUrl     = attribute.VideoUploaderUrl;
            node.VideoLive            = attribute.VideoLive;

            // Handle route details
            node.Route = attribute.Route;
            node.RouteValues.AddRange(attribute.Attributes, false);
            node.PreservedRouteParameters.AddRange(attribute.PreservedRouteParameters, new[] { ',', ';' });
            node.UrlResolver = attribute.UrlResolver;

            // Specified area, controller and action properties will override any
            // provided in the attributes collection.
            if (!string.IsNullOrEmpty(area))
            {
                node.RouteValues.Add("area", area);
            }
            if (!string.IsNullOrEmpty(controller))
            {
                node.RouteValues.Add("controller", controller);
            }
            if (!string.IsNullOrEmpty(action))
            {
                node.RouteValues.Add("action", action);
            }

            return(nodeParentMap);
        }
        /// <summary>
        /// Maps an XMLElement from the XML file to an MvcSiteMapNode.
        /// </summary>
        /// <param name="node">The element to map.</param>
        /// <param name="parentNode">The parent ISiteMapNode</param>
        /// <param name="helper">The node helper.</param>
        /// <returns>An MvcSiteMapNode which represents the XMLElement.</returns>
        protected virtual ISiteMapNodeToParentRelation GetSiteMapNodeFromXmlElement(XElement node, ISiteMapNode parentNode, ISiteMapNodeHelper helper)
        {
            // Get data required to generate the node instance

            // Get area and controller from node declaration or the parent node
            var area = this.InheritAreaIfNotProvided(node, parentNode);
            var controller = this.InheritControllerIfNotProvided(node, parentNode);
            var action = node.GetAttributeValue("action");
            var url = node.GetAttributeValue("url");
            var explicitKey = node.GetAttributeValue("key");
            var parentKey = parentNode == null ? "" : parentNode.Key;
            var httpMethod = node.GetAttributeValueOrFallback("httpMethod", HttpVerbs.Get.ToString()).ToUpper();
            var clickable = bool.Parse(node.GetAttributeValueOrFallback("clickable", "true"));
            var title = node.GetAttributeValue("title");
            var implicitResourceKey = node.GetAttributeValue("resourceKey");

            // Generate key for node
            string key = helper.CreateNodeKey(
                parentKey,
                explicitKey,
                url,
                title,
                area,
                controller,
                action,
                httpMethod,
                clickable);

            // Create node
            var nodeParentMap = helper.CreateNode(key, parentKey, SourceName, implicitResourceKey);
            var siteMapNode = nodeParentMap.Node;

            // Assign values
            siteMapNode.Title = title;
            siteMapNode.Description = node.GetAttributeValue("description");
            siteMapNode.Attributes.AddRange(node, false);
            siteMapNode.Roles.AddRange(node.GetAttributeValue("roles"), new[] { ',', ';' });
            siteMapNode.Clickable = clickable;
            siteMapNode.VisibilityProvider = node.GetAttributeValue("visibilityProvider");
            siteMapNode.DynamicNodeProvider = node.GetAttributeValue("dynamicNodeProvider");
            siteMapNode.ImageUrl = node.GetAttributeValue("imageUrl");
            siteMapNode.ImageUrlProtocol = node.GetAttributeValue("imageUrlProtocol");
            siteMapNode.ImageUrlHostName = node.GetAttributeValue("imageUrlHostName");
            siteMapNode.TargetFrame = node.GetAttributeValue("targetFrame");
            siteMapNode.HttpMethod = httpMethod;
            siteMapNode.Url = url;
            siteMapNode.CacheResolvedUrl = bool.Parse(node.GetAttributeValueOrFallback("cacheResolvedUrl", "true"));
            siteMapNode.IncludeAmbientValuesInUrl = bool.Parse(node.GetAttributeValueOrFallback("includeAmbientValuesInUrl", "false"));
            siteMapNode.Protocol = node.GetAttributeValue("protocol");
            siteMapNode.HostName = node.GetAttributeValue("hostName");
            siteMapNode.CanonicalKey = node.GetAttributeValue("canonicalKey");
            siteMapNode.CanonicalUrl = node.GetAttributeValue("canonicalUrl");
            siteMapNode.CanonicalUrlProtocol = node.GetAttributeValue("canonicalUrlProtocol");
            siteMapNode.CanonicalUrlHostName = node.GetAttributeValue("canonicalUrlHostName");
            siteMapNode.MetaRobotsValues.AddRange(node.GetAttributeValue("metaRobotsValues"), new[] { ' ' });
            siteMapNode.ChangeFrequency = (ChangeFrequency)Enum.Parse(typeof(ChangeFrequency), node.GetAttributeValueOrFallback("changeFrequency", "Undefined"));
            siteMapNode.UpdatePriority = (UpdatePriority)Enum.Parse(typeof(UpdatePriority), node.GetAttributeValueOrFallback("updatePriority", "Undefined"));
            siteMapNode.LastModifiedDate = DateTime.Parse(node.GetAttributeValueOrFallback("lastModifiedDate", DateTime.MinValue.ToString()));
            siteMapNode.Order = int.Parse(node.GetAttributeValueOrFallback("order", "0"));

            // Handle route details
            siteMapNode.Route = node.GetAttributeValue("route");
            siteMapNode.RouteValues.AddRange(node, false);
            siteMapNode.PreservedRouteParameters.AddRange(node.GetAttributeValue("preservedRouteParameters"), new[] { ',', ';' });
            siteMapNode.UrlResolver = node.GetAttributeValue("urlResolver");
            
            // Area and controller may need inheriting from the parent node, so set (or reset) them explicitly
            siteMapNode.Area = area;
            siteMapNode.Controller = controller;
            siteMapNode.Action = action;

            // Add inherited route values to sitemap node
            foreach (var inheritedRouteParameter in node.GetAttributeValue("inheritedRouteParameters").Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries))
            {
                var item = inheritedRouteParameter.Trim();
                if (node.Attribute(item) != null)
                    throw new MvcSiteMapException(string.Format(Resources.Messages.SiteMapNodeSameKeyInRouteValueAndInheritedRouteParameter, key, title, item));

                if (parentNode.RouteValues.ContainsKey(item))
                {
                    siteMapNode.RouteValues.Add(item, parentNode.RouteValues[item]);
                }
            }

            return nodeParentMap;
        }
Пример #6
0
        /// <summary>
        /// Maps an XMLElement from the XML file to an MvcSiteMapNode.
        /// </summary>
        /// <param name="node">The element to map.</param>
        /// <param name="parentNode">The parent ISiteMapNode</param>
        /// <param name="helper">The node helper.</param>
        /// <returns>An MvcSiteMapNode which represents the XMLElement.</returns>
        protected virtual ISiteMapNodeToParentRelation GetSiteMapNodeFromXmlElement(XElement node, ISiteMapNode parentNode, ISiteMapNodeHelper helper)
        {
            // Get area, controller and action from node declaration
            string area       = node.GetAttributeValue("area");
            string controller = node.GetAttributeValue("controller");
            var    parentKey  = parentNode == null ? "" : parentNode.Key;
            var    httpMethod = node.GetAttributeValueOrFallback("httpMethod", HttpVerbs.Get.ToString()).ToUpperInvariant();
            // Handle title and description
            var title       = node.GetAttributeValue("title");
            var description = String.IsNullOrEmpty(node.GetAttributeValue("description")) ? title : node.GetAttributeValue("description");

            // Generate key for node
            string key = helper.CreateNodeKey(
                parentKey,
                node.GetAttributeValue("key"),
                node.GetAttributeValue("url"),
                title,
                area,
                controller,
                node.GetAttributeValue("action"),
                httpMethod,
                !(node.GetAttributeValue("clickable") == "false"));

            // Handle implicit resources
            var implicitResourceKey = node.GetAttributeValue("resourceKey");

            // Create node
            var nodeParentMap = helper.CreateNode(key, parentKey, SourceName, implicitResourceKey);
            var siteMapNode   = nodeParentMap.Node;

            // Assign defaults
            siteMapNode.Title       = title;
            siteMapNode.Description = description;
            AcquireAttributesFrom(node, siteMapNode.Attributes, helper);
            AcquireRolesFrom(node, siteMapNode.Roles);
            siteMapNode.Clickable           = bool.Parse(node.GetAttributeValueOrFallback("clickable", "true"));
            siteMapNode.VisibilityProvider  = node.GetAttributeValue("visibilityProvider");
            siteMapNode.DynamicNodeProvider = node.GetAttributeValue("dynamicNodeProvider");
            siteMapNode.ImageUrl            = node.GetAttributeValue("imageUrl");
            siteMapNode.TargetFrame         = node.GetAttributeValue("targetFrame");
            siteMapNode.HttpMethod          = httpMethod;
            siteMapNode.Url = node.GetAttributeValue("url");
            siteMapNode.CacheResolvedUrl = bool.Parse(node.GetAttributeValueOrFallback("cacheResolvedUrl", "true"));
            siteMapNode.CanonicalUrl     = node.GetAttributeValue("canonicalUrl");
            siteMapNode.CanonicalKey     = node.GetAttributeValue("canonicalKey");
            this.AcquireMetaRobotsValuesFrom(node, siteMapNode.MetaRobotsValues);
            siteMapNode.ChangeFrequency  = (ChangeFrequency)Enum.Parse(typeof(ChangeFrequency), node.GetAttributeValueOrFallback("changeFrequency", "Undefined"));
            siteMapNode.UpdatePriority   = (UpdatePriority)Enum.Parse(typeof(UpdatePriority), node.GetAttributeValueOrFallback("updatePriority", "Undefined"));
            siteMapNode.LastModifiedDate = DateTime.Parse(node.GetAttributeValueOrFallback("lastModifiedDate", DateTime.MinValue.ToString()));
            siteMapNode.Order            = int.Parse(node.GetAttributeValueOrFallback("order", "0"));

            // Handle route details

            // Assign to node
            siteMapNode.Route = node.GetAttributeValue("route");
            AcquireRouteValuesFrom(node, siteMapNode.RouteValues, helper);
            AcquirePreservedRouteParametersFrom(node, siteMapNode.PreservedRouteParameters);
            siteMapNode.UrlResolver = node.GetAttributeValue("urlResolver");

            // Add inherited route values to sitemap node
            foreach (var inheritedRouteParameter in node.GetAttributeValue("inheritedRouteParameters").Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries))
            {
                var item = inheritedRouteParameter.Trim();
                if (siteMapNode.RouteValues.ContainsKey(item))
                {
                    throw new MvcSiteMapException(String.Format(Resources.Messages.SiteMapNodeSameKeyInRouteValueAndInheritedRouteParameter, key, title, item));
                }

                if (parentNode.RouteValues.ContainsKey(item))
                {
                    siteMapNode.RouteValues.Add(item, parentNode.RouteValues[item]);
                }
            }

            // Handle MVC details

            // Inherit area and controller from parent
            if (parentNode != null)
            {
                if (string.IsNullOrEmpty(area) && !siteMapNode.RouteValues.ContainsKey("area"))
                {
                    siteMapNode.Area = parentNode.Area;
                }
                if (string.IsNullOrEmpty(controller) && !siteMapNode.RouteValues.ContainsKey("controller"))
                {
                    siteMapNode.Controller = parentNode.Controller;
                }
            }

            // Add defaults for area
            if (!siteMapNode.RouteValues.ContainsKey("area"))
            {
                siteMapNode.RouteValues.Add("area", "");
            }

            return(nodeParentMap);
        }
        /// <summary>
        /// Gets the site map node from MVC site map node attribute.
        /// </summary>
        /// <param name="attribute">The attribute.</param>
        /// <param name="type">The type.</param>
        /// <param name="methodInfo">The method info.</param>
        /// <param name="helper">The node helper.</param>
        /// <returns></returns>
        protected virtual ISiteMapNodeToParentRelation GetSiteMapNodeFromMvcSiteMapNodeAttribute(
            IMvcSiteMapNodeAttribute attribute, Type type, MethodInfo methodInfo, ISiteMapNodeHelper helper)
        {
            if (attribute == null)
            {
                throw new ArgumentNullException("attribute");
            }
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            if (!string.IsNullOrEmpty(attribute.SiteMapCacheKey))
            {
                // Return null if the attribute doesn't apply to this cache key
                if (!helper.SiteMapCacheKey.Equals(attribute.SiteMapCacheKey))
                {
                    return null;
                }
            }

            if (methodInfo == null) // try to find Index action
            {
                var ms = type.GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(x => x.Name.Equals("Index"));
                foreach (MethodInfo m in ms)
                {
                    var pars = m.GetParameters();
                    if (pars.Length == 0)
                    {
                        methodInfo = m;
                        break;
                    }
                }
            }

            string area = "";
#pragma warning disable 612,618
            if (!string.IsNullOrEmpty(attribute.AreaName))
            {
                area = attribute.AreaName;
            }
#pragma warning restore 612,618
            if (string.IsNullOrEmpty(area) && !string.IsNullOrEmpty(attribute.Area))
            {
                area = attribute.Area;
            }
            // Determine area (will only work if controller is defined as [<Anything>.]Areas.<Area>.Controllers.<AnyController>)
            if (string.IsNullOrEmpty(area))
            {
                var m = Regex.Match(type.Namespace, @"(?:[^\.]+\.|\s+|^)Areas\.(?<areaName>[^\.]+)\.Controllers");
                if (m.Success)
                {
                    area = m.Groups["areaName"].Value;
                }
            }

            // Determine controller and (index) action
            string controller = type.Name.Substring(0, type.Name.IndexOf("Controller"));
            string action = (methodInfo != null ? methodInfo.Name : null) ?? "Index";
            
            if (methodInfo != null)
            {
                // handle ActionNameAttribute
                var actionNameAttribute = methodInfo.GetCustomAttributes(typeof(ActionNameAttribute), true).FirstOrDefault() as ActionNameAttribute;
                if (actionNameAttribute != null)
                {
                    action = actionNameAttribute.Name;
                }
            }

            string httpMethod = (string.IsNullOrEmpty(attribute.HttpMethod) ? HttpVerbs.Get.ToString() : attribute.HttpMethod).ToUpper();

            // Handle title
            var title = attribute.Title;

            // Handle implicit resources
            var implicitResourceKey = attribute.ResourceKey;

            // Generate key for node
            string key = helper.CreateNodeKey(
                attribute.ParentKey,
                attribute.Key,
                attribute.Url,
                title,
                area,
                controller, action, httpMethod,
                attribute.Clickable);

            var nodeParentMap = helper.CreateNode(key, attribute.ParentKey, SourceName, implicitResourceKey);
            var node = nodeParentMap.Node;

            // Assign defaults
            node.Title = title;
            node.Description = attribute.Description;
            node.Attributes.AddRange(attribute.Attributes, false);
            node.Roles.AddRange(attribute.Roles);
            node.Clickable = attribute.Clickable;
            node.VisibilityProvider = attribute.VisibilityProvider;
            node.DynamicNodeProvider = attribute.DynamicNodeProvider;
            node.ImageUrl = attribute.ImageUrl;
            node.ImageUrlProtocol = attribute.ImageUrlProtocol;
            node.ImageUrlHostName = attribute.ImageUrlHostName;
            node.TargetFrame = attribute.TargetFrame;
            node.HttpMethod = httpMethod;
            if (!string.IsNullOrEmpty(attribute.Url)) node.Url = attribute.Url;
            node.CacheResolvedUrl = attribute.CacheResolvedUrl;
            node.IncludeAmbientValuesInUrl = attribute.IncludeAmbientValuesInUrl;
            node.Protocol = attribute.Protocol;
            node.HostName = attribute.HostName;
            node.CanonicalKey = attribute.CanonicalKey;
            node.CanonicalUrl = attribute.CanonicalUrl;
            node.CanonicalUrlProtocol = attribute.CanonicalUrlProtocol;
            node.CanonicalUrlHostName = attribute.CanonicalUrlHostName;
            node.MetaRobotsValues.AddRange(attribute.MetaRobotsValues);
            node.LastModifiedDate = string.IsNullOrEmpty(attribute.LastModifiedDate) ? DateTime.MinValue : DateTime.Parse(attribute.LastModifiedDate);
            node.ChangeFrequency = attribute.ChangeFrequency;
            node.UpdatePriority = attribute.UpdatePriority;
            node.Order = attribute.Order;

            // Handle route details
            node.Route = attribute.Route;
            node.RouteValues.AddRange(attribute.Attributes, false);
            node.PreservedRouteParameters.AddRange(attribute.PreservedRouteParameters, new[] { ',', ';' });
            node.UrlResolver = attribute.UrlResolver;
            
            // Specified area, controller and action properties will override any 
            // provided in the attributes collection.
            if (!string.IsNullOrEmpty(area)) node.RouteValues.Add("area", area);
            if (!string.IsNullOrEmpty(controller)) node.RouteValues.Add("controller", controller);
            if (!string.IsNullOrEmpty(action)) node.RouteValues.Add("action", action);

            return nodeParentMap;
        }