1 //------------------------------------------------------------------------------
2 // <copyright file="SiteMapProvider.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
8 * Copyright (c) 2002 Microsoft Corporation
10 namespace System.Web {
13 using System.Collections;
14 using System.Collections.Specialized;
15 using System.Configuration.Provider;
16 using System.Web.Security;
18 using System.Web.Util;
19 using System.Security.Permissions;
21 public abstract class SiteMapProvider : ProviderBase {
23 private bool _securityTrimmingEnabled;
24 private bool _enableLocalization;
25 private String _resourceKey;
27 internal const String _securityTrimmingEnabledAttrName = "securityTrimmingEnabled";
28 private const string _allRoles = "*";
30 private SiteMapProvider _rootProvider;
31 private SiteMapProvider _parentProvider;
32 private object _resolutionTicket = new object();
34 internal readonly object _lock = new Object();
36 public virtual SiteMapNode CurrentNode {
38 HttpContext context = HttpContext.Current;
39 SiteMapNode result = null;
41 // First check the SiteMap resolve events.
42 result = ResolveSiteMapNode(context);
45 result = FindSiteMapNode(context);
48 return ReturnNodeIfAccessible(result);
52 public bool EnableLocalization {
54 return _enableLocalization;
57 _enableLocalization = value;
62 public virtual SiteMapProvider ParentProvider {
64 return _parentProvider;
67 _parentProvider = value;
71 public string ResourceKey {
80 public virtual SiteMapProvider RootProvider {
82 if (_rootProvider == null) {
84 if (_rootProvider == null) {
85 Hashtable providers = new Hashtable();
86 SiteMapProvider candidate = this;
88 providers.Add(candidate, null);
89 while (candidate.ParentProvider != null) {
90 if (providers.Contains(candidate.ParentProvider))
91 throw new ProviderException(SR.GetString(SR.SiteMapProvider_Circular_Provider));
93 candidate = candidate.ParentProvider;
94 providers.Add(candidate, null);
97 _rootProvider = candidate;
102 return _rootProvider;
106 public virtual SiteMapNode RootNode {
108 SiteMapNode node = GetRootNodeCore();
109 return ReturnNodeIfAccessible(node);
113 public bool SecurityTrimmingEnabled {
115 return _securityTrimmingEnabled;
119 public event SiteMapResolveEventHandler SiteMapResolve;
122 /// <para>Add single node to provider.</para>
124 protected virtual void AddNode(SiteMapNode node) {
128 protected internal virtual void AddNode(SiteMapNode node, SiteMapNode parentNode) {
129 throw new NotImplementedException();
132 public virtual SiteMapNode FindSiteMapNode(HttpContext context) {
133 if (context == null) {
137 string rawUrl = context.Request.RawUrl;
139 SiteMapNode result = null;
141 // First check the RawUrl
142 result = FindSiteMapNode(rawUrl);
144 if (result == null) {
145 int queryStringIndex = rawUrl.IndexOf("?", StringComparison.Ordinal);
146 if (queryStringIndex != -1) {
147 // check the RawUrl without querystring
148 result = FindSiteMapNode(rawUrl.Substring(0, queryStringIndex));
151 if (result == null) {
152 Page page = context.CurrentHandler as Page;
154 // Try without server side query strings
155 string qs = page.ClientQueryString;
157 result = FindSiteMapNode(context.Request.Path + "?" + qs);
161 if (result == null) {
162 // Check the request path
163 result = FindSiteMapNode(context.Request.Path);
171 public virtual SiteMapNode FindSiteMapNodeFromKey(string key) {
172 return FindSiteMapNode(key);
175 public abstract SiteMapNode FindSiteMapNode(string rawUrl);
177 public abstract SiteMapNodeCollection GetChildNodes(SiteMapNode node);
179 public virtual SiteMapNode GetCurrentNodeAndHintAncestorNodes(int upLevel) {
181 throw new ArgumentOutOfRangeException("upLevel");
187 public virtual SiteMapNode GetCurrentNodeAndHintNeighborhoodNodes(int upLevel, int downLevel) {
189 throw new ArgumentOutOfRangeException("upLevel");
192 if (downLevel < -1) {
193 throw new ArgumentOutOfRangeException("downLevel");
199 public abstract SiteMapNode GetParentNode(SiteMapNode node);
201 public virtual SiteMapNode GetParentNodeRelativeToCurrentNodeAndHintDownFromParent (
202 int walkupLevels, int relativeDepthFromWalkup) {
204 if (walkupLevels < 0) {
205 throw new ArgumentOutOfRangeException("walkupLevels");
208 if (relativeDepthFromWalkup < 0) {
209 throw new ArgumentOutOfRangeException("relativeDepthFromWalkup");
212 // First get current nodes and hints about its ancestors.
213 SiteMapNode currentNode = GetCurrentNodeAndHintAncestorNodes(walkupLevels);
215 // Simply return if the currentNode is null.
216 if (currentNode == null) {
220 // Find the target node by walk up the parent tree.
221 SiteMapNode targetNode = GetParentNodesInternal(currentNode, walkupLevels);
223 if (targetNode == null) {
227 // Get hints about its lower neighborhood nodes.
228 HintNeighborhoodNodes(targetNode, 0, relativeDepthFromWalkup);
233 public virtual SiteMapNode GetParentNodeRelativeToNodeAndHintDownFromParent(
234 SiteMapNode node, int walkupLevels, int relativeDepthFromWalkup) {
236 if (walkupLevels < 0) {
237 throw new ArgumentOutOfRangeException("walkupLevels");
240 if (relativeDepthFromWalkup < 0) {
241 throw new ArgumentOutOfRangeException("relativeDepthFromWalkup");
245 throw new ArgumentNullException("node");
248 // First get hints about ancestor nodes;
249 HintAncestorNodes(node, walkupLevels);
251 // walk up the parent node until the target node is found.
252 SiteMapNode ancestorNode = GetParentNodesInternal(node, walkupLevels);
254 if (ancestorNode == null) {
258 // Get hints about its neighthood nodes
259 HintNeighborhoodNodes(ancestorNode, 0, relativeDepthFromWalkup);
264 private SiteMapNode GetParentNodesInternal(SiteMapNode node, int walkupLevels) {
265 Debug.Assert(node != null);
266 if (walkupLevels <= 0) {
271 node = node.ParentNode;
273 } while (node != null && walkupLevels != 0);
279 * A reference node that must be returned by all sitemap providers, this is
280 * required for the parent provider to keep track of the relations between
282 * For example, the parent provider uses this method to keep track of the parent
283 * node of child provider's root node.
285 protected internal abstract SiteMapNode GetRootNodeCore();
287 protected static SiteMapNode GetRootNodeCoreFromProvider(SiteMapProvider provider) {
288 return provider.GetRootNodeCore();
291 public virtual void HintAncestorNodes(SiteMapNode node, int upLevel) {
293 throw new ArgumentNullException("node");
297 throw new ArgumentOutOfRangeException("upLevel");
301 public virtual void HintNeighborhoodNodes(SiteMapNode node, int upLevel, int downLevel) {
303 throw new ArgumentNullException("node");
307 throw new ArgumentOutOfRangeException("upLevel");
310 if (downLevel < -1) {
311 throw new ArgumentOutOfRangeException("downLevel");
315 public override void Initialize(string name, NameValueCollection attributes) {
316 if (attributes != null) {
317 if (string.IsNullOrEmpty(attributes["description"])) {
318 attributes.Remove("description");
319 attributes.Add("description", this.GetType().Name);
322 ProviderUtil.GetAndRemoveBooleanAttribute(attributes, _securityTrimmingEnabledAttrName, Name, ref _securityTrimmingEnabled);
325 base.Initialize(name, attributes);
328 public virtual bool IsAccessibleToUser(HttpContext context, SiteMapNode node) {
330 throw new ArgumentNullException("node");
333 if (context == null) {
334 throw new ArgumentNullException("context");
337 if (!SecurityTrimmingEnabled) {
341 if (node.Roles != null) {
342 foreach (string role in node.Roles) {
343 // Grant access if one of the roles is a "*".
344 if (role == _allRoles ||
345 context.User != null && context.User.IsInRole(role)) {
351 VirtualPath virtualPath = node.VirtualPath;
352 if (virtualPath == null ||
353 !virtualPath.IsWithinAppRoot) {
358 return System.Web.UI.Util.IsUserAllowedToPath(context, virtualPath);
361 protected internal virtual void RemoveNode(SiteMapNode node) {
362 throw new NotImplementedException();
365 protected SiteMapNode ResolveSiteMapNode(HttpContext context) {
366 SiteMapResolveEventHandler eventHandler = SiteMapResolve;
367 if (eventHandler == null)
370 if (!context.Items.Contains(_resolutionTicket)) {
371 context.Items.Add(_resolutionTicket, true);
374 Delegate[] ds = eventHandler.GetInvocationList();
376 for (int i = 0; i < len; i++) {
377 SiteMapNode ret = ((SiteMapResolveEventHandler)ds[i])(this, new SiteMapResolveEventArgs(context, this));
383 context.Items.Remove(_resolutionTicket);
391 internal SiteMapNode ReturnNodeIfAccessible(SiteMapNode node) {
392 if (node != null && node.IsAccessibleToUser(HttpContext.Current)) {