Saturday, February 5, 2011

Get “Manage Hierarchy” and “Approve” role definitions programmatically in Sharepoint

In Sharepoint there are several OTB role definitions which are created during site creation:

Role name Description
Full Control Has full control
Design  Can view, add, update, delete, approve, and customize
Contribute Can view, add, update, and delete list items and documents
Read Can view pages and list items and download documents
Limited Access Can view specific lists, document libraries, list items, folders, or documents when given permissions
Approve Can edit and approve pages, list items, and documents
Manage Hierarchy Can create sites and edit pages, list items, and documents
Restricted Read Can view pages and documents, but cannot view historical versions or user permissions

You can access some of these role definitions via object model using SPRoleType enum using the following mapping table:

Role name SPRoleType member
Full Control SPRoleType.Administrator
Design SPRoleType.WebDesigner
Contribute SPRoleType.Contributor
Read SPRoleType.Reader
Limited Access SPRoleType.Guest
Approve SPRoleType.None
Manage Hierarchy SPRoleType.None
Restricted Read SPRoleType.None

Note that last 3 roles have SPRoleType.None type. It means that you can’t retrieve these role definitions using SPRoleDefinitionCollection.GetByType() method. Restricted Access is special role – it is shown when e.g. user has access on some folder in the list, but not has access to the whole list or web site. In most cases you should not use this role programmatically. But what with “Manage Hierarchy” and “Approve” roles? We also can’t use SPRoleDefinitionCollection.GetByType() method in order to get them programmatically. What options do we have?

The most often approach I found during investigation is to use hardcoded literals for the role name:

   1: string roleName = "Manage Hierarchy";
   2: SPRoleDefinition roleDefinition =
   3:     web.RoleDefinitions.Cast<SPRoleDefinition>().FirstOrDefault(r => r.Name == roleName);

This approach works, but if you have multilingual topology you will have problems, because “Manage Hierarchy” role name will be localized according to the web site name (e.g. on Finnish it will be “Hierarkian hallinta”). The best option would be retrieving of the role definition using the same way as Sharepoint uses.

After some investigation I found Microsoft.SharePoint.Publishing.Internal.StringIds class (defined in the Microsoft.SharePoint.Publishing.dll). It has a field StringIds.RoleNameHierarchyManager which seems like what I looking for. Unfortunately there is no so much information about it, so I used reflector to watch how Sharepoint uses it. Sharepoint uses these strings via internal class Microsoft.SharePoint.Publishing.Internal.Resources in the same Microsoft.SharePoint.Publishing.dll assembly like this (see Microsoft.SharePoint.Publishing.Internal.RootProvisioner.AddSecuritySettings() method):

   1: Resources.GetString("RoleNameHierarchyManager")

If you will investigate Microsoft.SharePoint.Publishing.Internal.Resources class you will find that it uses Microsoft.SharePoint.Publishing.Intl.dll assembly for retrieving resource values (this assembly is located in the GAC).

So in order to retrieve role name by the same way as Sharepoint retrieves it, you have several options:

  • use reflection
  • create custom class which works like internal class Microsoft.SharePoint.Publishing.Internal.Resources

I will show you 2nd variant. You can use the following class in order to retrieve resource strings from Microsoft.SharePoint.Publishing.Intl.dll assembly:

   1: public class PublishingResources
   2: {
   3:     private static ResourceManager resourceManager;
   4:  
   5:     static PublishingResources()
   6:     {
   7:         var resourceAssembly = Assembly.Load("Microsoft.SharePoint.Publishing.intl, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
   8:         resourceManager = new ResourceManager("Microsoft.SharePoint.Publishing.Strings", resourceAssembly);
   9:     }
  10:  
  11:     internal static string GetString(string resourceName, CultureInfo cultureInfo)
  12:     {
  13:         return resourceManager.GetString(resourceName, cultureInfo);
  14:     }
  15: }

Now you are able to retrieve “Manage Hierarchy” role definition programmatically without hardcoding role name:

   1: string roleName = PublishingResources.GetString(StringIds.RoleNameHierarchyManager, web.UICulture);
   2: SPRoleDefinition roleDefinition =
   3:     web.RoleDefinitions.Cast<SPRoleDefinition>().FirstOrDefault(r => r.Name == roleName);

All information from this post is also appliable for “Approve” role definition. Just instead of StringIds.RoleNameHierarchyManager you will need to use StringIds.RoleDescriptionApprover for it.

1 comment:

  1. Very useful tip, that I could have used a dozen times already. I added a reference to this post on my blog at http://spuser.blogspot.com. A few comments, though:

    - The publishing assembly in the above is the SharePoint 2010 version. To use it with SharePoint 2007, simply use version=12.0.0.0.

    - Instead of RoleDescriptionApprover you must use RoleNameApprover.

    - In my own implementation I have changed the GetString method to use uint instead of CultureInfo, allowing you can pass in the web.Language. This I consider more intuitive in a SharePoint environment, and also makes it easier to use in feature receivers, item event receivers etc. Within the GetString method I then use new CultureInfo((int)lcid)). Of course both methods could be implemented through overload.

    ReplyDelete