Don’t you hate when you have access denied and you don’t know where it is coming from? It is even worse when it is related to anonymous access where a single detail can prevent a page from being rendered (IIS authentication, broken inheritance, you name it). The application will show the detailed cascade rights for anonymous, current user and given user for a given item in url. In the example below it will show all details from site to page item:
The output will look like it:
Object Type: File **** Start Miscellaneous for Site http://rviana-moss-w28 IIS Allow Anonymous: [True] IIS is impersonating: [False] Zone: [Default] Host Name: [rviana-moss-w28] Write Locked: [False] **** End Miscellaneous for Site **** Start Miscellaneous for Web http://rviana-moss-w28 Web Allow Anonymous: [True] Anonymous Access to Lists and Libraries: [On] ********* Start of List of Rights to anonymous in this web Perm Mask - Hex: 1000031041 Binary 1000000000000000000110001000001000001 ViewListItems Hex [00000001] Binary [1] ViewVersions Hex [00000040] Binary [1000000] ViewFormPages Hex [00001000] Binary [1000000000000] Open Hex [00010000] Binary [10000000000000000] ViewPages Hex [00020000] Binary [100000000000000000] UseClientIntegration Hex [1000000000] Binary [1000000000000000000000000000000000000] FullMask Hex [1000031041] Binary [1000000000000000000110001000001000001] ********* End of List of Rights to anonymous in this web
********* Start of List of Rights for User CONTOSO\alanew Perm Mask - Hex: 1b03c4312ef Binary 11011000000111100010000110001001011101111 ViewListItems Hex [00000001] Binary [1] AddListItems Hex [00000002] Binary [10] EditListItems Hex [00000004] Binary [100] DeleteListItems Hex [00000008] Binary [1000] OpenItems Hex [00000020] Binary [100000] (... lines removed for space ...) CreateAlerts Hex [8000000000] Binary [1000000000000000000000000000000000000000] EditMyUserInfo Hex [10000000000] Binary [10000000000000000000000000000000000000000] FullMask Hex [1b03c4312ef] Binary [11011000000111100010000110001001011101111] ********* End of List of Rights
********* Start of List of Rights for Current User CONTOSO\rviana Perm Mask - Hex: 7fffffffffffffff Binary 111111111111111111111111111111111111111111111111111111111111111 ViewListItems Hex [00000001] Binary [1] AddListItems Hex [00000002] Binary [10] EditListItems Hex [00000004] Binary [100] DeleteListItems Hex [00000008] Binary [1000] (... lines removed for space ...) EditMyUserInfo Hex [10000000000] Binary [10000000000000000000000000000000000000000] EnumeratePermissions Hex [4000000000000000] Binary [100000000000000000000000000000000000000000000000000000000000000] FullMask Hex [7fffffffffffffff] Binary [111111111111111111111111111111111111111111111111111111111111111] ********* End of List of Rights
**** End Miscellaneous for Web
**** Start Miscellaneous for List Pages at /Pages/Forms/AllItems.aspx Access to Template List is Restricted : [False] Users Access Limited to Items they Created: [False] Anonymous can access : [True] Everyone can view List : [False] ********* Start of List of Rights to anonymous in this List Perm Mask - Hex: 1000031041 Binary 1000000000000000000110001000001000001 ViewListItems Hex [00000001] Binary [1] ViewVersions Hex [00000040] Binary [1000000] ViewFormPages Hex [00001000] Binary [1000000000000] Open Hex [00010000] Binary [10000000000000000] ViewPages Hex [00020000] Binary [100000000000000000] UseClientIntegration Hex [1000000000] Binary [1000000000000000000000000000000000000] FullMask Hex [1000031041] Binary [1000000000000000000110001000001000001] ********* End of List of Rights to anonymous in this List
********* Start of List of Rights for User CONTOSO\alanew Perm Mask - Hex: 1b03c4312ef Binary 11011000000111100010000110001001011101111 ViewListItems Hex [00000001] Binary [1] AddListItems Hex [00000002] Binary [10] EditListItems Hex [00000004] Binary [100] DeleteListItems Hex [00000008] Binary [1000] OpenItems Hex [00000020] Binary [100000] ViewVersions Hex [00000040] Binary [1000000] (... lines removed for space ...) EditMyUserInfo Hex [10000000000] Binary [10000000000000000000000000000000000000000] FullMask Hex [1b03c4312ef] Binary [11011000000111100010000110001001011101111] ********* End of List of Rights
********* Start of List of Rights for Current User CONTOSO\rviana Perm Mask - Hex: 7fffffffffffffff Binary 111111111111111111111111111111111111111111111111111111111111111 ViewListItems Hex [00000001] Binary [1] AddListItems Hex [00000002] Binary [10] (... lines removed for space ...) EditMyUserInfo Hex [10000000000] Binary [10000000000000000000000000000000000000000] EnumeratePermissions Hex [4000000000000000] Binary [100000000000000000000000000000000000000000000000000000000000000] FullMask Hex [7fffffffffffffff] Binary [111111111111111111111111111111111111111111111111111111111111111] ********* End of List of Rights
**** End Miscellaneous for List
**** Start Miscelaneous for List Item default.aspx at Pages/default.aspx Anonymous has access to list item : [True] Permission Inheritance is broken : [False] ********* Start of List of Rights for User CONTOSO\alanew Perm Mask - Hex: 1b03c4312ef Binary 11011000000111100010000110001001011101111 ViewListItems Hex [00000001] Binary [1] AddListItems Hex [00000002] Binary [10] EditListItems Hex [00000004] Binary [100] (... lines removed for space ...) UpdatePersonalWebParts Hex [20000000] Binary [100000000000000000000000000000] UseClientIntegration Hex [1000000000] Binary [1000000000000000000000000000000000000] UseRemoteAPIs Hex [2000000000] Binary [10000000000000000000000000000000000000] CreateAlerts Hex [8000000000] Binary [1000000000000000000000000000000000000000] EditMyUserInfo Hex [10000000000] Binary [10000000000000000000000000000000000000000] FullMask Hex [1b03c4312ef] Binary [11011000000111100010000110001001011101111] ********* End of List of Rights
********* Start of List of Rights for Current User CONTOSO\rviana Perm Mask - Hex: 7fffffffffffffff Binary 111111111111111111111111111111111111111111111111111111111111111 ViewListItems Hex [00000001] Binary [1] AddListItems Hex [00000002] Binary [10] EditListItems Hex [00000004] Binary [100] (... lines removed for space ...) EnumeratePermissions Hex [4000000000000000] Binary [100000000000000000000000000000000000000000000000000000000000000] FullMask Hex [7fffffffffffffff] Binary [111111111111111111111111111111111111111111111111111111111111111] ********* End of List of Rights
********* Item Xml <z:row xmlns:z='#RowsetSchema' ows_ContentTypeId='0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF390064DEA0F50FC8C147B0B6EA0636C4A7D400B86BB823B4EF734998C6CF97A89029EE' ows_FileLeafRef='1;#default.aspx' ows_Modified_x0020_By='SHAREPOINT\system' ows_File_x0020_Type='aspx' ows_Title='Search Center' ows_PublishingPageLayout='http://rviana-moss-w28/_catalogs/masterpage/searchmain.aspx, Search Page' ows_ContentType='Welcome Page' ows_ID='1' ows_Created='2010-10-22 20:43:50' ows_Author='1073741823;#System Account' ows_Modified='2010-10-22 20:43:50' ows_Editor='1073741823;#System Account' ows__ModerationStatus='0' ows_FileRef='1;#Pages/default.aspx' ows_FileDirRef='1;#Pages' ows_Last_x0020_Modified='1;#2010-10-22 20:43:50' ows_Created_x0020_Date='1;#2010-10-22 20:43:50' ows_File_x0020_Size='1;#739' ows_FSObjType='1;#0' ows_PermMask='0x7fffffffffffffff' ows_CheckedOutUserId='1;#' ows_IsCheckedoutToLocal='1;#0' ows_UniqueId='1;#{B9F29A82-3E82-4817-B8A5-77CED27512E8}' ows_ProgId='1;#' ows_ScopeId='1;#{037929C6-B73A-4F2B-BD14-07003EADB4CD}' ows_VirusStatus='1;#739' ows_CheckedOutTitle='1;#' ows__CheckinComment='1;#' ows__EditMenuTableStart='default.aspx' ows__EditMenuTableEnd='1' ows_LinkFilenameNoMenu='default.aspx' ows_LinkFilename='default.aspx' ows_DocIcon='aspx' ows_ServerUrl='/Pages/default.aspx' ows_EncodedAbsUrl='http://rviana-moss-w28/Pages/default.aspx' ows_BaseName='default' ows_FileSizeDisplay='739' ows_MetaInfo='1;#vti_modifiedby:SR|SHAREPOINT\\system vti_parserversion:SR|12.0.0.6545 vti_cachedhastheme:BR|false vti_cachedcustomprops:VX|ContentType vti_title PublishingPageLayout ContentType:SW|Welcome Page vti_title:SR|Search Center vti_cachedtitle:SR|Search Center vti_charset:SR|utf-8 ContentTypeId:SW|0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF390064DEA0F50FC8C147B0B6EA0636C4A7D400B86BB823B4EF734998C6CF97A89029EE PublishingPageLayout:SW|/_catalogs/masterpage/searchmain.aspx, Search Page vti_author:SR| vti_setuppath:SX|SiteTemplates\\SRCHCEN\\default.aspx vti_cachedneedsrewrite:BR|false ' ows__Level='1' ows__IsCurrentVersion='1' ows_SelectTitle='1' ows_SelectFilename='1' ows_Edit='0' ows_owshiddenversion='2' ows__UIVersion='512' ows__UIVersionString='1.0' ows_Order='100.000000000000' ows_GUID='{5FAA46F1-443E-4FF7-A60B-7A229EBD9C03}' ows_WorkflowVersion='1' ows_ParentVersionString='1;#' ows_ParentLeafName='1;#' ows_Combine='0' ows_RepairDocument='0' ows_ServerRedirected='0'/>
********* End of Item XML
********* Role Assignments Xml <permissions><permission memberid='3' mask='9223372036854775807' /> <permission memberid='4' mask='756052856929' /> <permission memberid='5' mask='1856436900591' /> <permission memberid='6' mask='206292717568' /> <permission memberid='7' mask='1856438737919' /> <permission memberid='8' mask='4611688150860241903' /> <permission memberid='9' mask='1856436900863' /> <permission memberid='10' mask='206292848673' /> <permission memberid='11' mask='206292717568' /> <permission memberid='13' mask='756052856897' /> <permission memberid='1073741823' mask='206292717568' /> </permissions> ********* End of Role Assignments Xml
**** End Miscellaneous for List Item
*** File default.aspx content:
???<%@ Page Inherits="Microsoft.SharePoint.Publishing.TemplateRedirectionPage,Microsoft.SharePoint.Publishing,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" %> <%@ Reference VirtualPath="~TemplatePageUrl" %> <%@ Reference VirtualPath="~masterurl/custom.master" %>
<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"><head>
<!--[if gte mso 9]><xml> <mso:CustomDocumentProperties>
<mso:ContentType msdt:dt="string">Welcome Page</mso:ContentType>
<mso:PublishingPageLayout msdt:dt="string">/_catalogs/masterpage/searchmain.aspx, Search Page</mso:PublishingPageLayout>
</mso:CustomDocumentProperties> </xml><![endif]-->
<title>Search Center</title></head>
*** End File *** Anonymous has rights on File default.aspx: [True]
The code core is below. The cascade walking class was based on Sanjay’s class defined at http://blogs.msdn.com/b/sanjaynarang/archive/2009/04/07/find-sharepoint-object-type-from-url.aspx .
You can download code and executable here: http://rodneyviana.codeplex.com/releases/view/19103
It works for SharePoint 2010 but you have to change the references and recompile using 14.x assemblies.
using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Text; using System.Web; using Microsoft.SharePoint; using Microsoft.SharePoint.Administration; using Microsoft.SharePoint.Deployment;
namespace CheckEffectiveProperties { public class SPObjType { public Guid objectGuid; public object obj; public string url; public string siteRelativeUrl; public SPDeploymentObjectType objType; public StringBuilder message = new StringBuilder(2000); public SPBasePermissions currUserRights; public SPBasePermissions testUser; public SPBasePermissions anonymousMask; public bool? isAnonymousEnabled = null;
public static string EnumeratePermission(SPBasePermissions Mask) { StringBuilder sb = new StringBuilder(100); sb.AppendFormat("Perm Mask - Hex: {0} Binary {1}\n", ((ulong)Mask).ToString("x8"), Convert.ToString((Int64)Mask, 2)); foreach (string permName in Enum.GetNames(typeof(SPBasePermissions))) { ulong i = (ulong)Mask & (ulong)(Enum.Parse(typeof(SPBasePermissions), permName)); if (i > 0) { sb.Append(String.Format(" {0} Hex [{1}] Binary [{2}]\n", permName, i.ToString("x8"), Convert.ToString((Int64)i, 2))); } } return sb.ToString(); } public void GetFile(SPFile File, SPBasePermissions Mask) { try { byte[] binFile = File.OpenBinary(); ASCIIEncoding asc = new ASCIIEncoding(); string fileContent = asc.GetString(binFile); message.AppendFormat("\n*** File {0} content:\n\n{1}\n\n", File.Name, fileContent); message.Append("\n*** End File"); if (File.Item != null) { message.AppendFormat("\n*** Anonymous has rights on File {0}: [{1}]\n\n", File.Name, File.Item.DoesUserHavePermissions(Mask)); } else { message.AppendFormat("\n*** Unable to test Anonymous rights on File {0}\n\n", File.Name); } } catch (Exception ex) { message.AppendFormat("\n\n*************** Error opening file {0}: {1} ************\n\n", File.Name, ex.Message); }
} }
// The class below was originally created by Sanjay Narang to identify the object type from a URL // The code for this intent is found here: http://blogs.msdn.com/b/sanjaynarang/archive/2009/04/07/find-sharepoint-object-type-from-url.aspx // // It was modified to check properties and cascade access (Anonymous | Current User | GivenUser) // for an object pointed by Rodney Viana // You have to agree with this license to use this code/application: http://rodneyviana.codeplex.com/license // Details of the implementation can be found at: http://blogs.msdn.com/rodneyviana // This project can be downloaded at: http://rodneyviana.codeplex.com/releases/view/19103
class SanjayMossUtilities { public SPObjType GetObjectTypeFromURL(string passedUrl, string User) { SPObjType oType = new SPObjType(); oType.objType = SPDeploymentObjectType.Invalid;
oType.objectGuid = Guid.Empty;
SPSite site = null; SPWeb web = null; SPList list = null; oType.obj = null; oType.url = null; oType.siteRelativeUrl = null; NameValueCollection queryParams = null;
oType.url = GetModifiedUrl(passedUrl, out queryParams);
try { site = new SPSite(oType.url); oType.message.AppendFormat("**** Start Miscellaneous for Site {0}\n", site.Url); oType.message.AppendFormat("IIS Allow Anonymous: [{0}]\n", site.IISAllowsAnonymous); oType.message.AppendFormat("IIS is impersonating: [{0}]\n", site.Impersonating); oType.message.AppendFormat("Zone: [{0}]\n", site.Zone.ToString()); oType.message.AppendFormat("Host Name: [{0}]\n", site.HostName); oType.message.AppendFormat("Write Locked: [{0}]\n", site.WriteLocked); oType.message.Append("**** End Miscellaneous for Site\n");
web = site.OpenWeb(); oType.message.AppendFormat("**** Start Miscellaneous for Web {0}\n", web.Url); oType.message.AppendFormat("Web Allow Anonymous: [{0}]\n", web.AllowAnonymousAccess); oType.message.AppendFormat("Anonymous Access to Lists and Libraries: [{0}]\n", web.AnonymousState.ToString()); if (web.AllowAnonymousAccess) { oType.message.Append("********* Start of List of Rights to anonymous in this web\n"); oType.message.Append(SPObjType.EnumeratePermission(web.AnonymousPermMask64)); oType.message.Append("********* End of List of Rights to anonymous in this web\n\n"); }
if (!String.IsNullOrEmpty(User)) { oType.message.AppendFormat("********* Start of List of Rights for User {0}\n", User); oType.message.Append(SPObjType.EnumeratePermission(web.GetUserEffectivePermissions(User))); oType.message.Append("********* End of List of Rights\n\n");
} string curUser = Environment.UserDomainName + "\\" + Environment.UserName; if (User.ToLower().Trim() != curUser.ToLower().Trim()) { oType.message.AppendFormat("********* Start of List of Rights for Current User {0}\n", curUser); oType.message.Append(SPObjType.EnumeratePermission(web.GetUserEffectivePermissions(curUser))); oType.message.Append("********* End of List of Rights\n\n"); } oType.message.Append("**** End Miscellaneous for Web\n\n");
if (oType.url.Equals(site.Url, StringComparison.OrdinalIgnoreCase)) { oType.objectGuid = site.ID; oType.objType = SPDeploymentObjectType.Site; return oType; }
if (oType.url.Equals(web.Url, StringComparison.OrdinalIgnoreCase)) { oType.objectGuid = web.ID; oType.objType = SPDeploymentObjectType.Web; return oType; }
oType.siteRelativeUrl = oType.url.TrimStart(web.Url.ToCharArray());
try { list = web.GetList(oType.url); } catch(Exception ex) { oType.message.AppendFormat("\n\n ******* Error trying to retrieve List : {0} ***** \n\n", ex.Message); list = null; }
if (null != list ) { oType.objectGuid = list.ID; oType.objType = SPDeploymentObjectType.List;
oType.message.AppendFormat("**** Start Miscellaneous for List {0} at {1}\n", list.Title, list.DefaultViewUrl); oType.message.AppendFormat("Access to Template List is Restricted : [{0}]\n", list.RestrictedTemplateList); oType.message.AppendFormat("Users Access Limited to Items they Created: [{0}]\n", (list.ReadSecurity==2)); oType.message.AppendFormat("Anonymous can access : [{0}]\n", list.DoesUserHavePermissions(list.AnonymousPermMask64)); oType.message.AppendFormat("Everyone can view List : [{0}]\n", list.AllowEveryoneViewItems);
oType.message.Append("********* Start of List of Rights to anonymous in this List\n"); oType.message.Append(SPObjType.EnumeratePermission(list.AnonymousPermMask64)); oType.message.Append("********* End of List of Rights to anonymous in this List\n\n");
if (!String.IsNullOrEmpty(User)) { oType.message.AppendFormat("********* Start of List of Rights for User {0}\n", User); oType.message.Append(SPObjType.EnumeratePermission(list.GetUserEffectivePermissions(User))); oType.message.Append("********* End of List of Rights\n\n");
} if (User.ToLower().Trim() != curUser.ToLower().Trim()) { oType.message.AppendFormat("********* Start of List of Rights for Current User {0}\n", curUser); oType.message.Append(SPObjType.EnumeratePermission(list.GetUserEffectivePermissions(curUser))); oType.message.Append("********* End of List of Rights\n\n"); } oType.message.Append("**** End Miscellaneous for List\n\n");
if (oType.siteRelativeUrl.Equals(list.RootFolder.Url, StringComparison.OrdinalIgnoreCase)) { return oType; } }
// if we are here, it means URL is none of these: // site, web, list // So, it can be either file, folder or a list item. // Finding that is intricated.
oType.obj = web.GetObject(oType.url);
if (null != oType.obj) { SPListItem item = (oType.obj as SPListItem); if (item != null) { if (!String.IsNullOrEmpty(User)) { oType.message.AppendFormat("**** Start Miscellaneous for List Item {0} at {1}\n", item.Name, item.Url); oType.message.AppendFormat("Anonymous has access to list item : [{0}]\n", item.DoesUserHavePermissions( list.AnonymousPermMask64)); oType.message.AppendFormat("Permission Inheritance is broken : [{0}]\n", item.HasUniqueRoleAssignments);
// oType.message.Append(SPObjType.EnumeratePermission(web.AnonymousPermMask64));
oType.message.AppendFormat("********* Start of List of Rights for User {0}\n", User); oType.message.Append(SPObjType.EnumeratePermission(item.GetUserEffectivePermissions(User))); oType.message.Append("********* End of List of Rights\n\n");
} if (User.ToLower().Trim() != curUser.ToLower().Trim()) { oType.message.AppendFormat("********* Start of List of Rights for Current User {0}\n", curUser); oType.message.Append(SPObjType.EnumeratePermission(item.GetUserEffectivePermissions(curUser))); oType.message.Append("********* End of List of Rights\n\n"); } oType.message.AppendFormat("********* Item Xml\n", curUser); oType.message.AppendFormat("{0}\n", item.Xml);
oType.message.Append("********* End of Item XML\n\n"); oType.message.AppendFormat("********* Role Assignments Xml\n", curUser); oType.message.AppendFormat("{0}\n", item.RoleAssignments.Xml);
oType.message.Append("********* End of Role Assignments Xml\n\n");
oType.message.Append("**** End Miscellaneous for List Item\n\n"); } if (oType.obj is SPFile) { // Generally, we get here for Forms Pages, // such as DispForm.aspx, AllItems.aspx // so, a SPFile object could be a list item Or // a folder in a list or a Folder
// Pages in root of the web are also returned as // SPFiles e.g. http://moss/default.aspx
// The URLs that point to a file in doc lib are // returned as SPListItem by GetObject method //
SPFile file = oType.obj as SPFile;
if (null != queryParams) { // The logic to identify folder or item has // been explained in ValidateQueryString string idValue = queryParams["ID"]; string folderValue = queryParams["RootFolder"]; if (null != idValue) { item = list.GetItemById(int.Parse(idValue)); oType.objectGuid = item.UniqueId; oType.objType = SPDeploymentObjectType.ListItem; return oType; } else if (null != folderValue) { SPFolder folder = web.GetFolder(folderValue); oType.objectGuid = folder.UniqueId; oType.objType = SPDeploymentObjectType.Folder; return oType; } else { // Deployyment Object Type is: Invalid, so no need // to do anything } } else { oType.objectGuid = file.UniqueId; oType.objType = SPDeploymentObjectType.File; oType.GetFile(file, web.AnonymousPermMask64); return oType; } } else if (oType.obj is SPFolder) { SPFolder folder = oType.obj as SPFolder; oType.objectGuid = folder.UniqueId; oType.objType = SPDeploymentObjectType.Folder; return oType; } else if (oType.obj is SPListItem) {
item = oType.obj as SPListItem;
// item can contain a folder of file also. e.g. // http://moss.litwareinc.com/Documents/folderinlibrary // http://moss.litwareinc.com/Documents/FolderInLibrary/File2.doc
if (null != item.Folder) { oType.objectGuid = item.Folder.UniqueId; oType.objType = SPDeploymentObjectType.Folder; return oType; } else if (null != item.File) { oType.objectGuid = item.File.UniqueId; oType.objType = SPDeploymentObjectType.File; oType.GetFile(item.File, web.AnonymousPermMask64);
return oType; }
oType.objectGuid = item.UniqueId; oType.objType = SPDeploymentObjectType.ListItem; return oType; } }
} finally { if (web != null) { web.Dispose(); } if (site != null) { site.Dispose(); } } return oType; }
private string GetModifiedUrl(string url, out NameValueCollection queryParams) { string modUrl = url; //modified url string querystring = string.Empty; queryParams = null;
// if it's a site or web or folder, user can pass '/' at // the end, which we need to trim if (url.EndsWith("/")) { modUrl = url.TrimEnd(new char[] { '/' }); }
// we need to get the URL without query string as it creates // problem getting the parent folder if (url.Contains("?")) {
int tmp = url.IndexOf("?"); modUrl = url.Substring(0, tmp); querystring = url.Substring(tmp + 1);
queryParams = HttpUtility.ParseQueryString(querystring); // apply custom rules ValidateQueryString(queryParams); }
return modUrl; }
private void ValidateQueryString(NameValueCollection queryParams) { // when there's query string in the URL, the URL can point to a // list item (in a list) or a folder. // For example if an item is a folder // 'FolderInTasksList' the URL of item would look like this // http://moss.litwareinc.com/Lists/Tasks/DispForm.aspx?ID=2&RootFolder=/Lists/Tasks/FolderInTasksList OR // http://moss.litwareinc.com/Lists/Tasks/DispForm.aspx?ID=2&RootFolder=%2fLists%2fTasks%2fFolderInTasksList // // And if we need Url of the folder, it would be like this: // http://moss.litwareinc.com/Lists/Tasks/AllItems.aspx?RootFolder=%2fLists%2fTasks%2fFolderInTasksList&FolderCTID=&View=%7bD8E1251D%2d829B%2d4FCE%2d9127%2d5E4FC6E6A5C4%7d // // From the above two examples, I'm applying the following // rules on the query string // 1. It can contain only these keys: ID, RootFolder, FolderCTID, View // If there's any other key, i would treat that as invalid query string // // 2. ID and RootFolder should never be empty // otherwise, raise exception here rather than hitting that later // // 3. the query string has to contain at least one of the following // a. ID, b. RootFolder
// Build a string collection with possible values. For comparison, // we'll use lower case only StringCollection strColl = new StringCollection(); strColl.Add("ID".ToLower()); strColl.Add("RootFolder".ToLower()); strColl.Add("FolderCTID".ToLower()); strColl.Add("View".ToLower());
// Apply the Rules bool hasID = false; bool hasRootFolder = false;
Console.WriteLine(); foreach (string str in queryParams.AllKeys) { // can be used for debugging // Console.WriteLine("Name: " + str + " | Value: " + queryParams[str]);
// Rule 1 if (!(strColl.Contains(str.ToLower()))) { throw new ArgumentException("Invalid argument in passed query string"); } // Rule 2 if (str.Equals("id", StringComparison.OrdinalIgnoreCase)) { hasID = true; if (queryParams[str].Equals(String.Empty)) { throw new ArgumentException("Query string parameter \"" + str + "\" can not be empty."); } } // Rule 2 if (str.Equals("rootfolder", StringComparison.OrdinalIgnoreCase)) { hasRootFolder = true; if (queryParams[str].Equals(String.Empty)) { throw new ArgumentException("Query string parameter \"" + str + "\" can not be empty."); } } } // Rule 3 Console.WriteLine(); if (!(hasID || hasRootFolder)) { throw new ArgumentException("Query string must have at least one parameter from these: ID and RootFolder"); } }