Chapter 8: Building Personalized Solutions (Part 1 of 2)

This article is an excerpt from Professional SharePoint 2007 Development by John Holliday, John Alexander, Jeff Julian, Eli Robillard, Brendon Schwartz, Matt Ranlett, J. Dan Attis, Adam Buenz, and Tom Rizzo (Chapter 8 written by Brendon Schwartz) from Wrox(ISBN 978-0-470-11756-9, copyright Wrox 2007, all rights reserved). No part of this chapter may be reproduced, stored in a retrieval system, or transmitted in any form or by any means—electronic, electrostatic, mechanical, photocopying, recording, or otherwise—without the prior written permission of the publisher, except in the case of brief quotations embodied in critical articles or reviews.

Next Part: Chapter 8: Building Personalized Solutions (Part 2 of 2)

A portal is a single point of entry for a family of web sites. Often these sites have complex relationships, such as multiple tree structures or a complicated grid or network topology. The portal takes care of common tasks such as user login, authentication, authorization, and personalization. In addition, the portal typically provides common user interface artifacts such as master pages and themes, giving the underlying sites a common appearance that can be easily personalized to suit each user's tastes. Finally, most portals offer artifacts such as "breadcrumb" controls that simplify navigation into the underlying sites.

ASP.NET 2.0 contains most of the building blocks you need to construct a portal, and several starter kits are available to help do that, such as DotNetNuke. SharePoint 2007 (that is, WSS 3.0 and MOSS 2007) uses these ASP.NET features, so you can build portals that greatly simplify access to complex SharePoint site topologies.

This chapter introduces you to the key concepts of building a SharePoint portal site:

  • Using built-in features such as profiles, colleagues, and audiences

  • Creating custom applications by developing with the Profiles API

  • Managing membership by designing your own custom people picker

  • Working with audiences programmatically

Contents

  • Building Rich Portal Solutions on SharePoint

  • Membership and User Profiles

  • Managing a User Profile

  • Setting Up Connections

  • User Profile API

Building Rich Portal Solutions on SharePoint

Portals were originally created by providers of large public Internet services, such as Yahoo and MSN, that manage thousands of content-rich sites under a common umbrella. However, as corporate intranets and extranets have become more complex, portals have become popular aspects of company infrastructure. They provide employees and business partners with easy access to information such as company news, contact lists, documents, and reports. In addition, portals serve as entry points to back-end business services such as purchasing, manufacturing, and accounting. Human resources departments are deploying portals that provide convenient access to public documents such as the employee handbook as well as private access to an employee's own records. Furthermore, many HR portals include self-help features for tasks such as updating information related to health insurance and retirement plans.

As the needs of these applications have grown, the applications running these sites have grown. They have become easier to customize and have started to use more powerful user data. The portals used by many companies take the form of many different applications today as follows:

  • Standard sets of web pages

  • Content Management Servers (CMS systems)

  • User portal-based applications

  • Internal portals for company use

  • External portals for business-to-business use

Although it is difficult to be everything to everyone, Windows SharePoint Services provides a framework that Office SharePoint Server builds upon to build these types of portal systems. One of the most important features needed for a portal are the user profiles. Each user has a set of profile data that can be used to display information to other users or determine which content the user should see. The profile data can be managed easily from a central location and can be shared across multiple web applications. This data can be imported from other sources or used from a central source.

SharePoint also includes the My Site feature that enables each user to create a personal site with public and private views. This enables users to save, manage, and share information much more conveniently than older file-sharing techniques allowed. This chapter looks at how to manage My Site with the user interface as well as through the object model.

To make the sites dynamic, SharePoint uses audiences to determine the correct content to display to the right users. In addition to audiences, you can use specific Web Parts to show data about yourself and other Colleagues. This allows you to set up a group of users that match a certain profile to be shown the data they need immediately.

Membership and User Profiles

User profiles are a collection of information that can be imported from a database or manually entered. The data in a user profile can then also be further customized by the user. Profiles store personal information about the users in your company or organization. All of the user profiles are stored in Profile Services, which is part of the Shared Service Provider for the site collection. User profiles can be helpful when you need to determine some type of personal information about another user. Also, user profiles help by pointing out the connections, or relationships, that a user has with other users. For example, a manager would be able to see other managers in the organization, and use them as a resource when help is needed.

You can use user profiles through the user interface or through the APIs provided by the object model. There are many ways that user profiles can be helpful to an organization. For example, if a department is trying to use an unfamiliar program, they could search all of the user profiles to find someone who lists using that product as one of their skills. If there are only a handful of people in the organization who have experience using that product, the user profiles would provide a way to find them quickly and get the help needed. Figure 8-1 shows an advanced search of user profiles.

Figure 8-1

Figure 8-1

Managing a User Profile

To update the user profile, end users will use their My Site page, the administrator will use the Shared Service Provider, and you as the developer can access web services or the object model. When users set up a My Site page, there are five links provided in the Get Started with My Site section to help them personalize their site. The first link allows the user to describe themselves, and it takes the user to a personal profile form. The personal profile is where users can view and modify available user profile fields about themselves. Filling in the information is part of the process of creating memberships and helps other people find them through enterprise search, and also give colleagues some information about each other. This type of information can be very useful in large organizations, where many people don't know what others do or how to find them.

User profile data can be imported from many different connections such as Active Directory or another third-party data store. The administrator can manage the user profiles through the Shared Service Provider User Profiles and Properties screen. From this screen you can add, view, and create new imports for the user profile as well as manage the profile properties of each user. (See Figure 8-2.)

Although the administrator may already have some information set up to be displayed, each user should fill out all of the optional information to create a more robust site and user profile system. It is helpful for users to provide as much information as possible in their profiles, to increase the effectiveness of searches within your organization.

Figure 8-2

Figure 8-2

Setting Up Connections

To pull user profile information into SharePoint's user profile system, SharePoint sets up a connection to a data store that provides user information. This can include Active Directory, a Lightweight Directory Access Protocol (LDAP) server, or Business Data Catalog. There are two connection types used to bring the profile data into SharePoint.

  • Master Connection

  • Sub Connection

A master connection is used as the primary source of the profile data. The master connection is set up to use either Active Directory or LDAP. Sub connections are used to provide supplemental information to the user profile system of SharePoint. The Business Data Catalog can be used as a supplemental store.

User Profile API

The SharePoint Administration Site enables administrators to create and update user profiles as well as manage them from a central location. There are many times when more functionality is required, and custom code can be used to easily extend the user profiles. The primary namespace that was used in SharePoint 2003 for profiles was Microsoft.SharePoint.Portal.UserProfiles. This namespace has now been replaced by the Microsoft.Office.Server.UserProfiles namespace.

Each SharePoint web application uses a Shared Service Provider to manage the user profile data store. Because web applications can use the same Shared Service Provider, more than one SharePoint web application can use the same set of users stored in the User Profile section.

If you want to import a set of users from another application, SharePoint provides you with a few options. You can use the Business Data Catalog or the built-in APIs from the SharePoint object model, or even the user profile web services. If you are importing users on a regular basis and want to keep two systems synchronized, then the Business Data Catalog is probably the right solution. But if you are creating Web Parts or simple management tools, then the API or web services will provide you with the ability to create those.

To set up users in your SharePoint web application, you can either use the user interface that is provided or you can programmatically create users in custom code. You will look at how to create the users in code shortly. The two major classes that are used are:

  • UserProfile class

  • UserProfileManager class

Let's take a look at the classes that are used and how to work with the User Profile API in code.

Managing Users in the User Profile

UserProfileManager is the main object for accessing the user profile data stored on the web application's shared service. This class can be used to create users, delete users, and provide information about the profile service.

Note When working with the object model classes make sure to add a reference to the Windows SharePoint Services DLL as well as the required Microsoft Office SharePoint Server components' DLLs. If you don't have a reference to System.Web.dll, then you will need to add that also.

Creating a UserProfileManager is straightforward and can be done with the new syntax for SharePoint 2007. The following simple console application creates a UserProfileManager that is connected to the ServerContext of a SharePoint site. Then it displays the number of user profiles in the console window.

To create your own console application that displays the number of users in a site follow these steps:

  1. Open Visual Studio, and create a new console application called UserProfileManagerApp.

  2. Make sure to add the SharePoint references:

    using Microsoft.SharePoint;
    using Microsoft.Office.Server;
    using Microsoft.Office.Server.UserProfiles;
    
  3. Then in the main function, add the following code:

    using System;
    using Microsoft.SharePoint;
    using Microsoft.Office.Server;
    using Microsoft.Office.Server.UserProfiles;
    namespace UserProfileManagerApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    using (SPSite spSite = new SPSite(@"https://localhost"))
                    {
                        ServerContext siteContext = ServerContext.GetContext(spSite);
                        UserProfileManager pmManager = new UserProfileManager(siteContext);
                        Console.WriteLine("Number of users: " + pmManager.Count);
                    }
                }
                catch (Exception exp)
                {
                    Console.WriteLine(exp.Message);
                }
            }
        }
    }
    

In addition to the Count property, the UserProfileManager class contains methods to manage user profile data, including the following:

Name

Description

CreateUserProfile

Creates a user profile with the provided values. If the profile already exists, an exception is thrown.

GetUserProfile

Returns a reference to the user profile specified

RemoveUserProfile

Removes user profiles. The method has multiple overrides to provide options when deleting users.

UserExists

Returns a value indicating whether the user for a specified account name has a profile.

Creating New User Profiles

Creating a new user in the user profile system only requires that the user name match an existing user in the current SharePoint site.

A good policy when creating user profiles is to check to make sure that the profile does not exist already. Although the profile system doesn't let you add a new profile if one already exists, it is much better practice to use the built-in methods for checking for the user, than to try to manage the exceptions that occur when trying to add the user a second time. In some cases, there are no built-in methods for performing a check and you must use the try/catch method. This is true when looking for a specific list in the object model.

The following code adds a new profile after checking to make sure that the user doesn't already have one:

  1. Using the console application above, add the new code to check if a user exists before you create a new user and profile:

    using System;
    using Microsoft.SharePoint;
    using Microsoft.Office.Server;
    using Microsoft.Office.Server.UserProfiles;
    namespace UserProfileManagerApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    using (SPSite spSite = new SPSite(@"https://localhost"))
                    {
                        ServerContext siteContext = ServerContext.GetContext(spSite);
                        UserProfileManager pmManager =
                                  new UserProfileManager(siteContext);
                        Console.WriteLine("Number of users: " + pmManager.Count);
                        string strUserName = "wrox\\brendon";
                        UserProfile newUser = null;
                        if (!pmManager.UserExists(strUserName))
                        {
                            newUser = pmManager.CreateUserProfile(strUserName);
                        }
                    }
                }
                catch (Exception exp)
                {
                    Console.WriteLine(exp.Message);
                }
            }
        }
    }
    

Deleting User Profiles

The code for deleting profiles is very similar to the code for adding them, except that the method RemoveUserProfile is used. This method accepts either the user's name or the GUID that is the unique key for the user.

The following code removes the profile that was created in the preceding example. This process does not delete the user from the main connection such as Active Directory. Deleting the user from Active Directory will still have to be done from outside SharePoint.

Remember that you are also checking to see if the user profile exists before you can delete it. If the user profile does not exist, then you do not have to take any action.

using System;
using Microsoft.SharePoint;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;
namespace DeleteUser
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using (SPSite spSite = new SPSite(@"https://localhost"))
                {
                    ServerContext siteContext = ServerContext.GetContext(spSite);
                    UserProfileManager pmManager =
                                   new UserProfileManager(siteContext);
                    Console.WriteLine("Number of users: " + pmManager.Count);
                    string strUserName = "wrox\\brendon";
                    if (pmManager.UserExists(strUserName))
                    {
                        pmManager.RemoveUserProfile(strUserName);
                    }
                }
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.Message);
            }
            Console.ReadLine();

        }
    }
}

Working with User Profiles

At the core of the user profile objects is the UserProfile class, which represents a single instance of a user profile. Once you have an object of this type, you can read and change the profile properties, assuming that the code is running with appropriate privileges.

To retrieve a profile, you just provide the user's name or GUID, as shown here:

  1. Open Visual Studio and create a new console application called RetrieveUser.

  2. Make sure to add the SharePoint references:

    using System.Collections.Generic;
    using Microsoft.SharePoint;
    using Microsoft.Office.Server;
    using Microsoft.Office.Server.UserProfiles;
    
  3. Now get a reference to the correct SharePoint site and UserProfileManager associated with that site:

    using System;
    using System.Collections.Generic;
    using Microsoft.SharePoint;
    using Microsoft.Office.Server;
    using Microsoft.Office.Server.UserProfiles;
    
    namespace RetrieveUser
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    using (SPSite spSite = new SPSite(@"https://localhost"))
                    {
                        ServerContext siteContext = ServerContext.GetContext(spSite);
                        UserProfileManager pmManager =
                                 new UserProfileManager(siteContext);
                    }
                }
                catch (Exception exp)
                {
                    Console.WriteLine(exp.Message);
                }
            }
        }
    }
    
  4. Check if the user exists, and get the user profile if the user is available:

    using System;
    using System.Collections.Generic;
    using Microsoft.SharePoint;
    using Microsoft.Office.Server;
    using Microsoft.Office.Server.UserProfiles;
    
    namespace RetrieveUser
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    using (SPSite spSite = new SPSite(@"https://localhost"))
                    {
                        ServerContext siteContext = ServerContext.GetContext(spSite);
                        UserProfileManager pmManager =
                                 new UserProfileManager(siteContext);
                        string strUserName = "devcow\\brendon";
                        UserProfile userProfile = null; 
    
                        if (pmManager.UserExists(strUserName))
                        {
                            userProfile = pmManager.GetUserProfile(strUserName);
                        }
                    }
                }
                catch (Exception exp)
                {
                    Console.WriteLine(exp.Message);
                }
            }
        }
    }
    

The UserProfile class contains many useful properties that can be leveraged when programming with the User Profile services of SharePoint 2007. The following table describes two properties used to identify the user profile and to return information about a given user profile.

Name

Description

ID

The unique GUID value of the current user profile. This value can be used when working with the UserProfile in the UserProfileManager.

Item

Contains a property value for the current user profile.

The UserProfileManager contains the list of user profile properties that are stored in the user profile data store. These properties are stored in the Shared Service Provider of the web site related to the UserProfileManager. To determine which properties are needed in the user profile store, use the UserProfileManager class. It is important to remember the difference between the name and the DisplayName when dealing with properties in SharePoint. The name is the value used when getting and setting the values, and the DisplayName is what is shown on the user interface. Sometimes these can be the same, but they are usually different. The IsRequired field shows which properties need to have values entered when the profile is updated in the user interface.

The following code sample demonstrates some of the default property values of the UserProfileManager. The code loops through all of the properties that have been created for the user profiles in the Shared Service. This will display the Name, Display Name, Description, and if the field is required in the console application you just created above.

//Get the properties of the Property Manager
foreach (Property property in pmManager.Properties)
{
   Console.WriteLine("Name: " + property.Name);
   Console.WriteLine("DisplayName: " + property.DisplayName);
   Console.WriteLine("Description: " + property.Description);
   Console.WriteLine("Required: " + property.IsRequired);
}

Setting User Profile Value Properties

User profile value properties can be entered and edited through the administrative screen, the user's My Site, or through code. The site administrator is also able to add properties to a user profile. These properties provide metadata that describes the user such as email, manager, and skills. You can have as many properties on a user to provide information about that user as needed. These properties can be set through an import from another system such as Active Directory or the Business Data Catalog.

Note Only the properties that have been created for the user have values, and the rest of the properties will not contain any value. It is good to check to make sure that the property exists for the user before trying to use the value.

The collection returned from the UserProfile class is a set of Name/Value pairs. Name is simply set as a string value that can be shown to the user, but Value is now a collection called UserProfileValueCollection. Value is a collection in SharePoint 2007 because the properties now have the ability to contain multivalues, which is something you will look at shortly. For now, just return the values as the value field.

The following code shows how you can loop through each value and display the results to the command window:

Using the RetrieveUser console application above, add the following lines to the main method:

foreach (KeyValuePair<string,UserProfileValueCollection> NameValues in userProfile)
{
   // Displays all of the name value pairs
   Console.WriteLine(NameValues.Key + ": " + NameValues.Value);
}

Now that you have seen what the values are for the properties of your user, you can add the correct values for the fields that are missing but required. You can also update the properties that are already set in the user profile.

Setting Single Value Properties

The standard type of property contained in the UserProfile class is a single value property. This property contains a Name/Value pair that has the information entered about the user.

To update the properties through the SharePoint object model follow these steps:

  1. Create a console application called UserProfileProperties.

  2. Add the references to SharePoint:

    using System;
    using System.Collections.Generic;
    using Microsoft.SharePoint;
    using Microsoft.Office.Server;
    using Microsoft.Office.Server.UserProfiles;
    
  3. Connect to the user profile store and then retrieve a user from the data store. Once you have the user, you can use the indexer method to get the property that is expected. Add the following code to the main method to perform these actions:

                try
                {
                    using (SPSite spSite = new SPSite(@"https://localhost"))
                    {
                        ServerContext siteContext = ServerContext.GetContext(spSite);
                        UserProfileManager pmManager =
                                 new UserProfileManager(siteContext);
                        string strUserName = "devcow\\brendon";
                        UserProfile userProfile = null;
                        if (pmManager.UserExists(strUserName))
                        {
                            userProfile = pmManager.GetUserProfile(strUserName);
                        }
                    }
                }
                catch (Exception exp)
                {
                    Console.WriteLine(exp.Message);
                }
    
  4. Update a value such as Department. To persist the values back to the user profile system, you must call the Commit() method on the UserProfile that has new changes. This allows you to make many changes in memory and then commit all of the changes at once.

    using System;
    using System.Collections.Generic;
    using Microsoft.SharePoint;
    using Microsoft.Office.Server;
    using Microsoft.Office.Server.UserProfiles;
    
    namespace UserProfileProperties
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    using (SPSite spSite = new SPSite(@"https://localhost"))
                    {
                        ServerContext siteContext = ServerContext.GetContext(spSite);
                        UserProfileManager pmManager =
                                 new UserProfileManager(siteContext);
                        string strUserName = "devcow\\brendon";
                        UserProfile userProfile = null;
                        if (pmManager.UserExists(strUserName))
                        {
                            userProfile = pmManager.GetUserProfile(strUserName);
                            userProfile["Department"].Value = "Information Technology";
                            userProfile.Commit();
                        }
                    }
                }
                catch (Exception exp)
                {
                    Console.WriteLine(exp.Message);
                }
            }
        }
    }
    

    Setting the value requires knowing the string name of the field. SharePoint helps provide a base set of values used in the user profile system. These values are in a class called PropertyConstants. The PropertyConstants class only contains a set of constants that return the correct string value that is used for the name of the user profile property it refers to.

    For example the value of PropertyConstants.WorkPhone is WorkPhone, whereas the value for UserGuid is UserProfile_GUID.

    As you can see, some of the values are the same, but some can be different. The PropertyConstants class will help you retrieve and set all of the common properties in the user profile.

    Look at how the following code uses the PropertyConstants, as well as a string, to set the value of each property.

  5. Update another property, this time using the PropertyConstants class:

    userProfile = pmManager.GetUserProfile(strUserName);
    userProfile [PropertyConstants.WorkPhone].Value = "555-555-5555";
    userProfile.Commit();
    

Multivalue Properties

A big improvement in SharePoint 2007 is the use of properties called multivalue properties. Sometimes you want the ability to store more than one value for a given field. This can come in very handy for multiple value properties such as sales area if you cover more than one area. Microsoft has some standard fields that are already set up for multivalue use such as Responsibilities, Skills, Past Projects, Interests, and Schools.

To determine whether the property is a multivalued property, the property IsMultiValued is provided. This value is a read-only property and can only be set by creating the user profile property as a multivalue property.

As you saw earlier, the multiple values have to be returned as a collection, and these values are returned as an ArrayList object. However, if you just display the properties value, the first element of the collection is the value that is displayed.

To add multiple values to the property, just call the Add method on the returned ArrayList property collection of the user:

Property skillProperty =
          pmManager.Properties.GetPropertyByName(PropertyConstants.Skills);
if (skillProperty.IsMultivalued)
{
   if (pmManager.UserExists(strUserName))
   {
      newUser = pmManager.GetUserProfile(strUserName);
      newUser[PropertyConstants.Skills].Add("ASP.NET");
      newUser[PropertyConstants.Skills].Add("SQL Server");
      newUser.Commit();
    }
}

Each value in the user interface will be separated by a single character. The default character that is used is the comma. Some values might contain a comma, so SharePoint 2007 allows you to modify the separator character of a multivalue property. Use the MultiValueSeparator enumeration to select a different value for the property's Separator value. There are four values to choose from in the MultiValueSeparator class. The most common separator values are provided for you, as well as an Unknown value.

  • Comma

  • Semicolon

  • Newline

  • Unknown

When using the multivalue properties, you will need to pick which type of separator you will use. If the property type is a multivalue, set the separator:

property.Separator = MultiValueSeparator.Semicolon;

Providing Properties in Choice Lists

In addition to having the ability to add multiple values to a property, you can also allow your users to select from a list of possible values known as a choice list. There are three different values that can be set for the ChoiceList property as follows:

  • None—The property is not currently using a choice list.

  • Closed—The choices have been added to the property and the users cannot edit the choices

  • Open—Users and administrators can add new choices to the list.

User Profile Relationships

Some of the most common methods return information about the user or provide the application with more information about a user, such as relationships to other profiles. The UserProfile class is full of information about the user— such as lists of Managers and Peers—and provides the ability to create the user's personal site. The user will have access to this site by using the My Site link in the user interface of SharePoint.

The following table lists the UserProfile methods:

Name

Description

Colleagues

Returns a ColleagueManager to work with the current colleagues

GetCommonManager

Gets the user profile of the common managers of the current user

GetDirectReports

Returns a list of UserProfiles that contains the users that report to the current user

GetManager

Gets the current user's immediate manager

GetManagers

Returns a list of all the managers that the current user reports to

GetPeers

Gets a list of user profiles of all users that are the current user's peers

Memberships

Returns a list of the current user's memberships

RefreshManagers

Updates the list of managers the user has as associations

Adding the SharePoint People Picker to the Web Site

The people pickers in SharePoint make it easy to work with any of the users from the data source locations. To work with the control in the user interface, add the PeopleEditor control, as shown in the following code, to a Web Part or web page, and then you will have full control over how the people picker control is displayed and interacts with the user. You will be able to set properties of the PeoplePicker to modify how it is displayed. This is the same control that is used in a list or profile. The following code adds the PeoplePicker to a Web Part, but it could just as easily be added to a web page.

  1. Start off by creating a new Web Part called PeoplePickerWebPart.

  2. Add the required references:

    using System;
    using System.Runtime.InteropServices;
    using System.Web.UI;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml.Serialization;
    
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.WebPartPages;
    using System.Web.UI.WebControls;
    
  3. In the CreateChildControls method create a new instance of the PeopleEditor control:

    PeopleEditor PeoplePickerControl = new PeopleEditor();
    this.Controls.Add(PeoplePickerControl);
    base.CreateChildControls();
    
  4. Update some of the properties of the control, such as allowing the control so that they are empty, allowing the end user to type in information, and changing the look and feel by changing the button names:

    using System;
    using System.Runtime.InteropServices;
    using System.Web.UI;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml.Serialization;
    
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.WebPartPages;
    using System.Web.UI.WebControls;
    
    namespace PeoplePickerWebPart
    {
        public class AgentPicker : System.Web.UI.WebControls.WebParts.WebPart
        {
            protected override void CreateChildControls()
            {
                try
                {
                    PeopleEditor PeoplePickerControl = new PeopleEditor();
                    PeoplePickerControl.AllowEmpty = true;
                    PeoplePickerControl.AllowTypeIn = true;
                    PeoplePickerControl.BrowseButtonImageName = "browse";
                    PeoplePickerControl.BrowseButtonToolTip = "Pick an Agent";
                    PeoplePickerControl.CheckButtonImageName = "Validate user";
                    PeoplePickerControl.ErrorMessage = "No Agent Found";
    
                    this.Controls.Add(PeoplePickerControl);
                    base.CreateChildControls();
                }
                catch (Exception ex)
                {
                    Literal _ErrorMessageLiteral = new Literal();
                    _ErrorMessageLiteral.Text = "Custom Error: " + ex.Message;
    
                    this.Controls.Clear();
                    this.Controls.Add(_ErrorMessageLiteral);
                }
            }
    
        }
    }
    

Developing Using the User Profile Change Log

When working with changes to used profiles, the UserProfileChangeQuery class provides the ability to filter based on the following types:

  • Add

  • Anniversary

  • Colleague

  • Delete

  • DistributionListMembership

  • MultiValueProperty

  • PersonalizationSite

  • QuickLink

  • SingleValueProperty

  • SiteMembership

  • Update

  • UpdateMetadata

  • UserProfile

  • Weblog

To filter, set one of these values to true once you have created an instance of the class. Multiple filter values can be set to true. The anniversary value will return all profile values that have dates in them. SharePoint considers each date field an anniversary and will create an anniversary event when the date reaches the machine date.

Each change type has a class that is associated with it that contains specific information for that type of change.

The UserProfile class contains methods to get changes about the user or the user's colleagues.

Name

Description

CurrentChangeToken

Represents a timestamp of the last time the current user was modified

GetChanges

Returns a collection of the changes that have happened to the current user

GetColleagueChanges

Returns a collection of changes that have happened to all of the colleagues associated with the current user

To get the change information, you must get the user profile and call the method GetChanges as follows:

  1. Create a new console application named ProfileChanges.

  2. Add the required SharePoint references:

    using System;
    using System.Collections.Generic;
    using Microsoft.SharePoint;
    using Microsoft.Office.Server;
    using Microsoft.Office.Server.UserProfiles;
    
  3. Get a reference to the Site and User Profile Manager.

    try
    {
       using (SPSite spSite = new SPSite(@"https://localhost"))
       {
          ServerContext siteContext = ServerContext.GetContext(spSite);
          UserProfileManager pmManager = new UserProfileManager(siteContext);
       }
    }
    catch (Exception exp)
    {
       Console.WriteLine(exp.Message);
    }
    
  4. Determine and set the range for the number of days you want to look at in changes, then set the change token that will be used with that amount of time. This example uses the last 30 days.

    // Display the changes that have occurred in the last month
    DateTime dtNumberDays = DateTime.UtcNow.Subtract(TimeSpan.FromDays(30));
    // Create a change token to compare the number of days
    UserProfileChangeToken upChangeToken = new 
            UserProfileChangeToken(dtNumberDays);
    
  5. Now create a query object to determine which changes will be returned. For this example, set the Anniversary and Colleague changes to true, and set the ChangeTokenStart value from the change token created above.

    // Create a query object to determine which changes are displayed
    UserProfileChangeQuery QueryAnniversayAndColleagues = new
                  UserProfileChangeQuery(false,true);
    QueryAnniversayAndColleagues.ChangeTokenStart = upChangeToken;
    QueryAnniversayAndColleagues.Anniversary = true;
    QueryAnniversayAndColleagues.Colleague = true;
    
  6. Now perform the standard steps to get a user profile, and this time call the method GetChanges with the query object you just created.

    string strUserName = "heididev\\brendon";
    if (pmManager.UserExists(strUserName))
    {
        UserProfile spMyUser = pmManager.GetUserProfile(strUserName);
    
        UserProfileChangeCollection MyUserProfileChanges =
                    spMyUser.GetChanges(QueryAnniversayAndColleagues);
    }
    
  7. Loop through each change in the returned collection of user profile changes, determine what type of change it is, and display information about that type of change:

    try
    {
       using (SPSite spSite = new SPSite(@"https://localhost"))
       {
          ServerContext siteContext = ServerContext.GetContext(spSite);
          UserProfileManager pmManager = new UserProfileManager(siteContext);
    
          // Gets some subset of changes from a user profile.
    
          // Display the changes that have occurred in the last month
          DateTime dtNumberDays = DateTime.UtcNow.Subtract(TimeSpan.FromDays(30));
          // Create a change token to compare the number of days
          UserProfileChangeToken upChangeToken = new 
                        UserProfileChangeToken(dtNumberDays);
    
          // Create a query object to determine which changes are displayed
          UserProfileChangeQuery QueryAnniversayAndColleagues = new
                        UserProfileChangeQuery(false,true);
          QueryAnniversayAndColleagues.ChangeTokenStart = upChangeToken;
          QueryAnniversayAndColleagues.Anniversary = true;
          QueryAnniversayAndColleagues.Colleague = true;
    
          string strUserName = "heididev\\brendon";
          if (pmManager.UserExists(strUserName))
          {
             UserProfile spMyUser = pmManager.GetUserProfile(strUserName);
    
             UserProfileChangeCollection MyUserProfileChanges =
                         spMyUser.GetChanges(QueryAnniversayAndColleagues);
    
             foreach (UserProfileChange MyUserChange in MyUserProfileChanges)
             {
                Console.WriteLine(MyUserChange.EventTime.ToString());
                if (MyUserChange is UserProfileAnniversaryChange)
                {
                   UserProfileAnniversaryChange AnniversryEvent =
                         (UserProfileAnniversaryChange)MyUserChange;
                   Console.WriteLine(AnniversryEvent.Anniversary);
                   Console.WriteLine(AnniversryEvent.ProfileProperty);
                }
                else if (MyUserChange is UserProfileColleagueChange)
                {
                   UserProfileColleagueChange ColleagueEvent =
                          (UserProfileColleagueChange)MyUserChange;
                }
             }
          }
       }
    }
    catch (Exception exp)
    {
       Console.WriteLine(exp.Message);
    }
    

Next Part: Chapter 8: Building Personalized Solutions (Part 2 of 2)