My career in technology

This is part five of my exploration of a solution I recently completed, using an event handler to programmatically create and configure a site based on form data provided by users and a site template created and managed by a SharePoint power user.

When last we left our intrepid hero, he had dared to enter the lair of

  //ToDo #2: Create the site user groups
  DoAllMembershipTasks();

and was about to DoAddUsersToGroups().

(Links to the other parts in the series are at the bottom of the post!)

  private void DoAddUsersToGroups()
        {
            //Add Users
            try
            {
                OwnerGroup.AddUser(owner);
            }
            catch (Exception ex)
            {
  LogTheError("EventHandlerName", "Error Adding " + owner.Name + " to " + OwnerGroup.Name + " in DoAddUsersToGroups(): " + ex.Message + " Stack Trace: " + ex.StackTrace);
            }

This first section adds the owner (the department’s power user) to the owners’ group, using the value of class-level variable “owner”, a string containing the user’s login name (“DomainName\\PowerUserName”, defined earlier).

  string[] UserFieldNames = new string[]
                                {
                                    "Project Manager",
                                    "LOB Manager",
                                    "Project Controls",
  "AdditionalUserFieldFromForm1",
  "AdditionalUserFieldFromForm2",
  "AdditionalUserFieldFromForm3",
  "AdditionalUserFieldFromForm4"
                                };
  foreach (string UserFieldName in UserFieldNames)
            {
  if (properties.ListItem[UserFieldName] != null)
                {
  NewUser = GetSPUserFromID("Project Database", UserFieldName);
                    try
                    {
  MemberGroup.AddUser(NewUser);
                    }
                    catch (Exception ex)
                    {
  LogTheError("EventHandlerName", "Error Adding " + NewUser.Name + " to " + MemberGroup.Name + " in DoAddUsersToGroups(): " + ex.Message + " Stack Trace: " + ex.StackTrace);
                    }

Using an array of field names from the SPList the event handler is attached to, this part of the code gets the user name from the event properties and creates an SPUser object called NewUser that represents the user from that field, and adds that user to the group.

GetSPUserFromID() is a bit of custom code that returns the SPUser object.

  private SPUser GetSPUserFromID(string listName, string UserFieldName)
        {
  SPFieldUser userField = (SPFieldUser)ProjectRequestWeb.Lists[listName].Fields.GetField(UserFieldName);
  SPFieldUserValue fieldValue = (SPFieldUserValue)userField.GetFieldValue(properties.ListItem[UserFieldName].ToString());
  SPUser user = fieldValue.User;
            return user;
        }

This code takes the list name and field name as parameters, and returns the user as an SPUser object. With a little modification, this could be rewritten to take the SPWeb as a parameter too, and used in a SharePoint site to retrieve a user anywhere from any list!

An SPFieldUser object is rendered through the UserField server control in an SPList form.  That’s the nifty little “Person or Group” control that will validate a user entered into the text box.  The field value for the SPFieldUser class is contained in the SPFieldUserValue class. Note that I had to explicitly cast the field as an SPFieldUser object, and the field value as an SPFieldUserValue. Also note that the SPUser object is contained in SPFieldUser.User.

  if (UserFieldName == "LOB Manager" | UserFieldName == "Project Manager" | UserFieldName == "Project Controls")
                    {
                        try
                        {
                            OwnerGroup.AddUser(NewUser);
                        }
                        catch (Exception ex)
                        {
  LogTheError("EventHandlerName", "Error Adding " + NewUser.Name + " to " + OwnerGroup.Name + " in DoAddUsersToGroups(): " + ex.Message + " Stack Trace: " + ex.StackTrace);
                        }
                    }
                }
            }

This adds the managers to the owners group for the site.

            if (properties.ListItem["Contributors"] != null)
            {
  //Person or Group field format for multiple users: <UserID1>;#;#;#;#;#
  string[] MultiUserSplit;
  string delimStr = "#;";
                char[] delimiter = delimStr.ToCharArray();
  MultiUserSplit = properties.ListItem["Contributors"].ToString().Split(delimiter, StringSplitOptions.RemoveEmptyEntries);
  for (int i = 0; i < MultiUserSplit.Length; i++)
                {
                    try
                    {
  MemberGroup.AddUser(BuildWeb.AllUsers.GetByID(Convert.ToInt32(MultiUserSplit[i])));
                    }
                    catch (Exception ex)
                    {
  LogTheError("EventHandlerName", "Error Adding Technical Contributor " + BuildWeb.AllUsers.GetByID(Convert.ToInt32(MultiUserSplit[i])).Name + " to " + MemberGroup.Name + " in DoAddUsersToGroups(): " + ex.Message + " Stack Trace: " + ex.StackTrace);
                    }
                    i++;
                }
                BuildWeb.Update();
            }
        }

Ah, this was fun. If your field was created as a “Person or Group” column, and you selected “yes” for “Allow multiple selections”, the SPFieldUserValue has a special format. As I noted in the code comments, the format is UserID1;#UserLoginName1;#UserID2;#UserLoginName2;#UserID3;#UserLoginName3. So I split the string on “;#” into an array, then retrieved the SPUser by the ID and set the loop to hit only the IDs by hitting every other item in the array (easier IMHO than converting the string into a multidimensional array).

As I said before, the requirement included subscribing the site members to a couple of lists – the Announcements and the Team Discussion. I had a bit of trouble with this one. Here is the code that actually worked:

  private void DoSubscribeMembersToLists()
        {
  SPList AnnouncementList = BuildWeb.Lists["Announcements"];
  SPList TeamDiscussionList = BuildWeb.Lists["Team Discussion"];
  SPEventType alertEventType = SPEventType.All;
  SPAlertFrequency alertFrequency = SPAlertFrequency.Immediate;

  foreach (SPUser user in BuildWeb.SiteGroups[MemberGroupName].Users)
            {
  DoAddThemToTheAlerts(AnnouncementList, alertEventType, alertFrequency, user);
  DoAddThemToTheAlerts(TeamDiscussionList, alertEventType, alertFrequency, user);
            }
        }

This sets the list, the alert type, the frequency, and passes them as parameters with the user object to the code that actually subscribes the users.

  private void DoAddThemToTheAlerts(SPList TargetList, SPEventType alertEventType, SPAlertFrequency alertFrequency, SPUser user)
        {
  SPAlert alert = BuildWeb.Alerts.Add();
            alert.AlertType = SPAlertType.List;
            alert.List = TargetList;
  alert.EventType = alertEventType;
            alert.User = user;
  alert.AlertFrequency = alertFrequency;
            //passing false to Update method will refrain from sending the alert confirmation mail
            //alert.Update(false);
            alert.Update();
        }

If you don’t want a user to be notified that they have been subscribed to the list (you are a sneaky b*stard and) you can pass “false” to SPAlert.Update(). The default is “true”, so you don’t have to specify it in the code.

This is the code that won’t work:

  foreach (SPUser user in BuildWeb.SiteGroups[MemberGroupName].Users)
            {
  user.Alerts.Add(AnnouncementList, alertEventType, alertFrequency);
  user.Alerts.Add(TeamDiscussionList, alertEventType, alertFrequency);
            }

It looks simple, elegant, and like it should work, but it won’t! Even though the SPUser object is the correct user, the alert is actually created on the user who is making the request which set off the event handler! Worse yet, as it loops through all of the users, it adds another alert to the user! This means that, if there are 10 people on the team, the loop is run ten times and ten alerts get added to the requestor (for each list) and every time the list is updated, the requestor gets ten copies of the alert e-mail! Bombs away!

Just don’t do it, okay?

I had hoped to make the contents of this entry part of Act Four, but even broken up part four is too long as it is! Of course, this left me with no snappy title for this entry (Act Three was “If You Build It…” and was on the actual creation of the site using SPWebCollection.Add(), and Act Four was “…They Will Come” about adding users to the site, both nods to the movie Field of Dreams). Fortunately, local radio station KUT recently had a live set with Terri Hendrix and Lloyd Maines, the highlight of which (for me) was a song whose title turned out to be appropriate for the subject of this post.

Coming up next,

                //ToDo #3:  Provision the site with the data about the project type for correct display
                DoAddControlEntries();
                DoActivateFeature_3rdPartyFeature();
                //ToDo #4:  Set the filters for the Eval Factors List in the new site
                DoChangeFactorFilters();

I’d love your feedback. Is there something you think I could be doing better? Are there questions about the code I haven’t answered? Am I full of it? Let me know! Feel free to use these code samples in accordance with my usage policy.

Check out Part One here (The Setup).
Check out Part Two here (The Decision).
Check out Part Three here (If You Built It…).
Check out Part Four here (…They Will Come).
You are reading Part Five.
Check out Part Six here (Ride the CAML!).
Check out Part Seven here (Pointing The Way).
Check out Part Eight here (Taking Part!).
Check out Part Nine here (Deconfigured).
Part Ten (The Log Blog) is coming!

More posts about SharePoint.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: