http://www.developer.com/

Back to article

Simple Custom Group Assignments in SharePoint


August 19, 2009

Many of my clients ask for ways to give certain, very specific rights to their users without giving other rights within the same standard SharePoint role. For instance, it would be nice if distributed site/content managers could add users to SharePoint security groups on their site without actually giving them explicit rights via SharePoint roles and permissions to add users to groups within their site.

Out-of-the-box, in order to be able to add and remove users from a group, you need to be the Group Owner, have Full Control rights to the site, be the Site Administrator, or be the Site Collection Administrator. In many cases, none of those options are acceptable, as they all potentially bring along other rights that clients are not willing to give a content or site manager within the construct of their corporate and/or SharePoint governance policies. They simply want a user to be able to add other users to existing SharePoint groups on their site and that's it. They don't want that user to have any rights whatsoever to change the groups on the site, other than adding new users to them.

This article presents a simple solution I have found to allow this functionality.

Step 1: Create and Configure the Project

In your Visual Studio product of choice, create a new Class Library project. Please note that I am not using the SharePoint Web Part templates provided by Microsoft; I'm just creating my own Class Library from scratch and implementing the SharePoint Web Part class. If you are comfortable with using the SharePoint templates for your version of Visual Studio, please feel free to do so.

So, create a Class Library project. In my case, I am calling it “CustomGroupAssignment”. Once you have created the project, you will need to add references to System.Web and Microsoft.SharePoint. Now, add the following "using" directives if they do not exist already:

using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Collections;

Step 2: Setting up the Class

At this point, go ahead and set up the class. Please note that I am inheriting from Microsoft.SharePoint.WebPartPages.WebPart and not from System.Web.UI.WebControls.WebParts.WebPart. You are going to override the two core web part methods, CreateChildControls and RenderWebPart, so you will add some placeholders in the code as well. Please add the placeholders like so:

namespace TPG.WebParts
{
    public class CustomGroupAssignment : Microsoft.SharePoint.WebPartPages.WebPart
    {
        protected override void CreateChildControls()
        {
   base.CreateChildControls();
        }
        protected override void RenderWebPart(HtmlTextWriter writer)
        {
        }
    }
}

Once you have the shell for your class in place, go ahead and add in some class-level variables for the child controls that you will use in the web part.

        //People Picker UI controls
        Label lblPplPicker;
        PeopleEditor pplPicker;
        Label lblPplPickerDesc;
        //Groups UI controls
        Label lblGroups;
        CheckBoxList cblGroups;
        Label lblGroupsDesc;
        //Button controls
        Button btnSubmit;
        Button btnCancel;
        //Status "window"
        TextBox txtStatus;

Basically, what you are going to do is incorporate a few controls into your web part that will allow you to provide the user with some guidance about what to do, require the user to choose one or more users, assign them to groups via checkboxes and click the "Submit" button.

Step 3: CreateChildControls

The next thing you need to do is add all of your custom controls into the CreateChildControls method. First, implement a base method. In case it was not included when you typed in your shell earlier, or you deleted it by accident, here is the statement to do so:

            base.CreateChildControls();

Then, put in the PeoplePicker section.

            //Create People Picker Label
            lblPplPicker = new Label();
            lblPplPicker.Text = "Users:";
            this.Controls.Add(lblPplPicker);
            //Create People Picker Control
            pplPicker = new PeopleEditor();
            pplPicker.AllowEmpty = false;
            pplPicker.ValidatorEnabled = true;
            pplPicker.SelectionSet = "User";
            this.Controls.Add(pplPicker);
            //Create People Picker Description
            lblPplPickerDesc = new Label();
            lblPplPickerDesc.Text = "Please select the users you would like to add to the current site.";
            this.Controls.Add(lblPplPickerDesc);

Now, add in the section for the Group controls.

            //Create Groups Label
            lblGroups = new Label();
            lblGroups.Text = "Groups:";
            this.Controls.Add(lblGroups);
            //Create Groups Control
            cblGroups = new CheckBoxList();
            cblGroups.ID = "groupsList";
            
            using (SPWeb oWebSite = SPContext.Current.Web)
            {
                SPGroupCollection collGroups = oWebSite.Groups;
                foreach (SPGroup oGroup in collGroups)
                {
                    cblGroups.Items.Add(oGroup.Name.ToString());
                }
            }
            this.Controls.Add(cblGroups);
            //Create Groups Description
            lblGroupsDesc = new Label();
            lblGroupsDesc.Text = "Please select the groups to which you would like to add the selected user(s).";
            this.Controls.Add(lblGroupsDesc);

As you may have noticed, the main actionable Groups control is built by grabbing the current site’s groups, storing them in an SPGroupCollection object, and then iterating through that collection, creating a check box for each group, using the actual group name, which will serve you well in the next step.

Now, for the Submit Button, the Cancel Button and our “Status” Window. Please note the treatment of the Click events for the two buttons.

            //Create Submit Button
            btnSubmit = new Button();
            btnSubmit.Text = "Submit";
            btnSubmit.Click += new EventHandler(btnSubmit_Click);
            this.Controls.Add(btnSubmit);
            //Create Cancel Button
            btnCancel = new Button();
            btnCancel.Text = "Cancel";
            btnCancel.Attributes.Add("onClick", "history.back(); return false;");
            this.Controls.Add(btnCancel);
            //Create “Status” Window
            txtStatus = new TextBox();
            txtStatus.TextMode = TextBoxMode.MultiLine;
            txtStatus.Width = 500;
            txtStatus.Rows = 10;
            txtStatus.Visible = false;
            this.Controls.Add(txtStatus);

Hopefully you noticed the way the Click events were handled. For the Cancel button, you merely send it to the previous page in the browser’s history by adding an onClick attribute through code, and then assigning some JavaScript as the value for that attribute. The Submit button is using the .NET EventHandler, which will be explored next.

Step 4: Submit Button

Now it’s time for the heavy lifting of this web part—adding the users to the groups. Here is the basic code to do that, and we will walk through it briefly below.

void btnSubmit_Click(object sender, EventArgs e)
{
   try
   {
       SPSecurity.RunWithElevatedPrivileges(delegate
       {
           using (SPSite spSite = new SPSite(Page.Request.Url.ToString()))
           {
               using (SPWeb spWeb = spSite.OpenWeb())
               {
                   try
                   {
                       //Temporarily allow unsafe updates
                       spWeb.AllowUnsafeUpdates = true;
                       SPGroup spGroup;
                       string userLogin = "";
                       string userEmail = "";
                       string userDisplayName = "";
                       foreach (ListItem cblItem in cblGroups.Items)
                       {
                          if (cblItem.Selected)
                          {
                              spGroup = spWeb.Groups[cblItem.Text];
                              txtStatus.Text += "Found Group:  " + spGroup.Name.ToString() + 
                                  " ... Adding Usersrn------------rn";
                              foreach (PickerEntity pe in pplPicker.Entities)
                              {
                                 userLogin = pe.Key;
                                 Hashtable userData = pe.EntityData;
                                 if (userData.ContainsKey("Email"))
                                     userEmail = userData["Email"].ToString();
                                 if (userData.ContainsKey("DisplayName"))
                                     userDisplayName = userData["DisplayName"].ToString();
                                 txtStatus.Text += "Found user: " + userLogin.ToString() + "rn";
                                 spGroup.AddUser(userLogin, userEmail, userDisplayName, "");
                                 txtStatus.Text += "Added user:  " + userLogin + "rn";
                              }
                              txtStatus.Text += "============rn";
                          }
                       }
                   }
                   catch (Exception ex)
                   {
                        txtStatus.Text += ex.Message;
                   }
                   finally
                   {
                       spWeb.AllowUnsafeUpdates = false;
                   }
               }
           }
       });
   }
   catch (Exception exception)
   {
       txtStatus.Text += exception.Message;
   }
   txtStatus.Visible = true;
}

First things first — the SPSecurity.RunWithElevatedPrivileges method is being used to make sure that the code is going to run as a user with the proper rights. You could just as easily have explicitly declared some credentials, but the SPSecurity class has provided us with this excellent alternative.

The next thing that jumps out is the AllowUnsafeUpdates property. In order for the code to be able to add users to groups within the site, this property must first be set to “true” temporarily.

After that, it is just a simple nested loop wherein each checkbox is inspected to see if it is checked, and if it is, each user is retrieved from the Entities collection of the People Picker control in the web part, and added to the group. A few things are also written to the “Status” window so that you can see what is happening. Obviously this status updating is removed before being put into production, where you would send the user to a follow-on page that lets them know if the users were successfully added to the groups or not. I would highly encourage you to do something similar if you implement this kind of functionality in your SharePoint environment.

You also have the clean-up action of setting the AllowUnsafeUpdates property back to “false” on your way out of this function. Hopefully, I do not need to remind you how crucial this one line of code could be to your happiness and career longevity as a SharePoint developer.

Step 5: Rendering the Web Part

The final thing to do is to render the content of the web part, which is accomplished through the code below. As you will notice, an ever-so-simple HTML table is created to house the controls in an easy way for the user to interact with the controls and meet our expectation of choosing one or more users using the People Picker, selecting one or more groups to which they want to add the user(s) and clicking the Submit button.

        protected override void RenderWebPart(HtmlTextWriter writer)
        {
            EnsureChildControls();
            writer.Write("<TABLE><TR><TD>");
            this.lblPplPicker.RenderControl(writer);
            writer.Write("</td><td>");
            this.pplPicker.RenderControl(writer);
            writer.Write("<BR />");
            this.lblPplPickerDesc.RenderControl(writer);
            writer.Write("</td></tr>");
            writer.Write("<tr><td>");
            this.lblGroups.RenderControl(writer);
            writer.Write("</td><td>");
            this.cblGroups.RenderControl(writer);
            writer.Write("<BR />");
            this.lblGroupsDesc.RenderControl(writer);
            writer.Write("</td></tr>");
            writer.Write("<tr><td colspan="2" align="center">");
            btnSubmit.RenderControl(writer);
            btnCancel.RenderControl(writer);
            writer.Write("</td></tr></table>");
            writer.Write("<BR/><BR/>");
            this.txtStatus.RenderControl(writer);
        }

Once again, this is a very simple treatment of the RenderWebPart method. You may want to provide additional detail to your users in this method or in the CreateChildControls method.

Deploying the Web Part

All that is left to do is deploy your Web Part to your SharePoint environment and add it to a page to see it in action. In order to deploy the web part, you need to either:

  • Add the assembly to the global assembly cache (GAC) on your SharePoint server(s); this method requires that the assembly be strongly named
  • Add the assembly to the bin folder within the virtual directory for your web application(s)
I am going to use the second option during this article.

The simple and easiest way to ensure that you always have the latest version of the DLL(s) from your Web Part in the bin folder for your SharePoint web application is to add the appropriate folder to the Output Path property of your Visual Studio project. In order to do so:

  • Right-click the project name in your Solution Explorer from within Visual Studio
  • Click the Build tab
  • In the Output section, enter the location for your application's bin folder in the Output path property (If you do not know the location of your web application, you can get it from the IIS Admin interface)

The next step is to add a SafeControl entry in the configuration file (web.config) for your SharePoint web application. In Windows Explorer, browse to the location of the files for your web application. By default, it will look similar to this: C:\intepub\wwwroot\wss\VirtualDirectories\<<ApplicationNameandPort>>. Web.config is located in the root folder for the web applicaiton. Open it in a text editor and find the <SafeControls> section.

The easiest way to add a new safe control is to just copy the tag from the last SafeControl in the list already and modify it for your web part. In this case, your SafeControl tag should like almost exactly like this, depending on whether or not you used a different name for your Assembly and/or Namespace:

 <SafeControl Assembly="CustomGroupAssignment" Namespace="TPG.WebParts" TypeName="*" Safe="True" />

While you have web.config open, you should also ensure that you have the correct setting for the trust property. Since our web part is going to be using the SharePoint Object Model, we need to have a trust level of WSS_Medium. Your trust tag should look like this:

 <trust level="WSS_Medium" originUrl="" />

Save web.config, run an iisreset and you should be ready to add your web part to your SharePoint site collection.

Configuring Your Site Collection to Use the Web Part

Now that you have finished deploying the web part, you need to add it to the Web Part Gallery of your web application's top-level site collection.

  • Browse to the top-level site of your web application
  • Click on Site Actions then "Site Settings"
  • In the Galleries column, click on Web Parts
  • In the Web Part Gallery, click on the New button
  • Find your new Web Part on the list, click the check box to its left and click the Populate Gallery button

Now your web part is ready to use on any web part page in your site collection.

Using Your Web Part

Here are the steps for adding the web part to a web part page.

  • Navigate to the web part page where you would like to add the web part
  • Click Site Actions then Edit Page
  • Within the Web Part Zone where you would like to add the Web Part, click the Add a Web Part button at the top of the Web Part Zone
  • Find your new web part, click the check box to its left and click the Add button

Because our web part is running with elevated priviledges, we only want to allow certain users to use the web part. Luckily, every SharePoint web part comes along with this functionality in the form of audience targeting. In order to implement audience targeting for your web part, click the edit button in the upper right corner of your web part and select Modify Shared Web Part. On the Task Pane, expand the Advanced node, scroll all the way to the bottom and use the Target Audiences control to add in the user(s) / group(s) that you want to be able to use this web part.

You may also want to control access at the page level. This makes the most sense if you want to combine this web part with some others into an Admin Console for your distributed content managers to accomplish certain Administrative tasks without giving them access to perform other things when you are not comfortable with them doing so.

Conclusion

You may have noticed that there are a few things missing here that you would most certainly want to incorporate into a production system, but those should be relatively simple for a programmer. Hopefully, if you have not worked with this kind of a customization in SharePoint before, you can use this article as a good starting point.

About the Author

Joe Mack is a Knowledge Management Evangelist and SharePoint Solution Architect, Consultant and Programmer. He has been working with SharePoint for over 6 years and has over 50 successful SharePoint implementations under his belt. He blogs at The Mack Page, tweets under mack247 and can usually be found at a client site somewhere in the world trying to proliferate his special brand of Knowledge Management, SharePoint, Business Transformation and/or Business Intelligence insanity.

He is a graduate of The United States Military Academy at West Point and lives in Indianapolis with his family.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date