Simplicity is prerequisite for reliability

First, solve the problem. Then, write the code.

  • Tags

  •  

    August 2008
    M T W T F S S
    « Apr    
     123
    45678910
    11121314151617
    18192021222324
    25262728293031

SharePoint DelegateControl

Posted by ricetristan on April 11, 2008

One often under-appreciated feature of Windows SharePoint Services is the DelegateControl. This is new to WSS v3, and provides an excellent method of customization without touching the default SharePoint pages. Using delegate controls, we can easily customize or replace many of the default SharePoint pages and user controls, including those that are found in many disparate locations (such as the search bar). Many of the SharePoint pages have a reference for a DelegateControl, as follows:


<SharePoint:DelegateControl runat=”server” id=”DelctlProfileRedirection” ControlId=”ProfileRedirection” Scope=”Farm” />

This particular example is a reference from the userdisp.aspx page (located in c:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\LAYOUTS), which controls the display of the user profile details (available via Welcome > My Settings). Other files with references to Delegate Controls in the LAYOUTS directory include:

  • AddNavigationLinkDialog.aspx: ControlId=”AddNavigationLinkDialogPanel1″ Scope=”Site”
  • AddNavigationLinkDialog.aspx: ControlId=”AddNavigationLinkDialogPanel2″ Scope=”Web”
  • AreaNavigationSettings.aspx: ControlId=”NavigationSettingsPanel1″ Scope=”Site”
  • AreaNavigationSettings.aspx: ControlId=”NavigationSettingsPanel2″ Scope=”Web”
  • BackLinks.aspx: ControlId=”SmallSearchInputBox”
  • ExcelProfilePage.aspx: ControlId=”VariationsFlagControl”
  • ExcelProfilePage.aspx: ControlId=”GlobalSiteLink1″ Scope=”Farm”
  • ExcelProfilePage.aspx: ControlId=”GlobalSiteLink2″ Scope=”Farm”
  • groups.aspx: ControlId=”QuickLaunchDataSource”
  • listcontentsources.aspx: ControlId=”QuickLaunchDataSource”
  • listservernamemappings.aspx: ControlId=”QuickLaunchDataSource”
  • logsummary.aspx: ControlId=”QuickLaunchDataSource”
  • logviewer.aspx: ControlId=”QuickLaunchDataSource”
  • managecrawlrules.aspx: ControlId=”QuickLaunchDataSource”
  • managefiletypes.aspx: ControlId=”QuickLaunchDataSource”
  • manageprivacypolicy.aspx: ControlId=”QuickLaunchDataSource”
  • manageservicepermissions.aspx: ControlId=”QuickLaunchDataSource”
  • mycontactlinks.aspx: ControlId=”ColleaguesLink1″ Scope=”Farm”
  • newsbweb.aspx: ControlId=”CreateSitePanel1″ Scope=”Site”
  • people.aspx: ControlId=”QuickLaunchDataSource”
  • personalsites.aspx: ControlId=”QuickLaunchDataSource”
  • profmain.aspx: ControlId=”QuickLaunchDataSource”
  • quicklinks.aspx: ControlId=”AddColleaguesLink1″ Scope=”Farm”
  • regionalsetng.aspx: ControlId=”RegionalSettingsExtensions”
  • schema.aspx: ControlId=”QuickLaunchDataSource”
  • scsignup.aspx: ControlId=”CreateSiteCollectionPanel1″ Scope=”Farm” />
  • searchsspsettings.aspx: ControlId=”QuickLaunchDataSource”
  • SiteManager.aspx: ControlId=”GlobalSiteLink1″ Scope=”Farm”
  • SiteManager.aspx: ControlId=”GlobalSiteLink2″ Scope=”Farm”
  • user.aspx: ControlId=”QuickLaunchDataSource”
  • userdisp.aspx: ControlId=”ProfileRedirection” Scope=”Farm”
  • VersionDiff.aspx: ControlId=”SmallSearchInputBox”
  • viewlsts.aspx: ControlId=”QuickLaunchDataSource”
  • viewscopes.aspx: ControlId=”QuickLaunchDataSource”
  • XLViewer.aspx: ControlId=”GlobalSiteLink1″ Scope=”Farm”
  • XLViewer.aspx: ControlId=”GlobalSiteLink2″ Scope=”Farm”

However, lets get back to that userdisp.aspx page. I chose this reference because it ties in nicely with my previous posts as a next step in learning about WSS and MOSS user profiles. As you can see from the example above, this is a SharePoint-specific meta tag, which has two important attributes:

  • ControlId - This attribute provides the unique identifier that will be referenced by any delegate control implementations which will tie them to this location.
  • Scope - This attribute indicates the feature scope where SharePoint will look for delegates.

This meta-tag provides us with a point to hook up our own custom user controls to be included with the default SharePoint content, which we will call our “custom delegate control”. The most common method of implementing a custom delegate control is through the use of features containing control templates. Let’s start by looking at this in more detail. All SharePoint features live in the TEMPLATE\FEATURES directory within the 12-hive, commonly:


c:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\FEATURES

Each feature is defined within a subdirectory, by way of an xml definition. The top-level file is always called feature.xml, and it contains the actual definition of the feature properties, such as:

<Feature Id=”59BA9C79-766E-498d-AFD5-B90D6340ADDE”
Title=”User Profile Details”
Description=”"
Version=”1.0.0.0″
Scope=”Farm”
xmlns=”http://schemas.microsoft.com/sharepoint/”>
<ElementManifests>
<ElementManifest Location=”UserProfileElements.xml”/>
</ElementManifests>

Since this post is NOT about features, I won’t go into too much detail here. Rather, it is important to note that the Scope attribute defined here MUST match the Scope attribute defined by the SharePoint:DelegateControl reference. Possible values for Scope include:

  • Farm
  • Web Application
  • Site Collection
  • Web Site

You will also notice that within the feature.xml definition, there is reference to an Elements.xml file. This file further defines the feature by referencing any external files or assemblies that are used by the feature. An example of this Elements.xml file…

<Elements xmlns=”http://schemas.microsoft.com/sharepoint/”>
<Control Id=”ProfileRedirection” Sequence=”95″ ControlSrc=”~/_controltemplates/UserProfileRedirect.ascx”/>
</Elements>

Notice that this example references our custom delegate control, located within the control templates directory. The Elements.xml can also point to an assembly, but we won’t go into that here. There are two important attributes to make note of in reference to SharePoint delegate controls:

  • Id - This MUST match the ControlId attribute as defined in the SharePoint delegate control definition.
  • Sequence - This attribute must be an integer value, and is used in the case where multiple delegate controls have been defined. The lowest sequence number with matching ControlId is always used.

So, we have our feature defined, and we have a custom delegate control defined that we want to be a delegate. Now what? Well, all we have to do is install the feature, and then SharePoint takes care of all the ControlId matching for us. Features are installed via one of the following methods:

  • Manually - Installation can be performed manually by creating the feature directory within c:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\FEATURES, placing the xml files within that directory, and running the following command:
    stsadm.exe –o installfeature –filename [your feature dir]\feature.xml
  • Using Solutions - You can also install the feature as part of a solution, by referencing it in a solution’s manifest.xml as follows…


<Solution …>
<FeatureManifests>
<FeatureManifest Location=”CISUserProfile\feature.xml”/>
</FeatureManifests>

<TemplateFiles>
<TemplateFile Location=”CONTROLTEMPLATES\UserProfileRedirect.ascx” />
</TemplateFiles>
</Solution>

Once we have our feature in-place (via either method above), we just need to install and activate it. The easiest method for all features scopes is to activate using the command line, as follows:

stsadm -o installfeature -filename [feature dir]\feature.xml
stsadm -o activatefeature -filename [feature dir]\feature.xml -url [site-url]
iisreset

Once that is done, your custom delegate control is in-place and ready to use! I would be remiss if I didn’t reference the sources I used while learning these concepts a short while ago myself…

http://msdn2.microsoft.com/en-us/library/ms463169.aspx
http://zac.provoke.co.nz/archive/2007/10/14/how-to-customize-the-user-profile-display-page-part-1.aspx

Happy coding!
Tristan

Posted in Sharepoint | No Comments »

Sharepoint User Profiles (Part 2)

Posted by ricetristan on January 18, 2008

In my previous post, I discussed the basics of SharePoint user profiles for both WSS and MOSS environments. As an addition to this discussion, I feel the use of MOSS web services for user profile interaction should be covered. With the addition of the MOSS infrastructure to your WSS server, you gain many additional features including a wide array of web services for remote interaction with the MOSS framework.

For this discussion, we’ll be dealing with the User Profile web service, which can be found at http://<moss-server>/_vti_bin/userprofileservice.asmx

This web service provides the following functionality:

  • AddColleague
  • AddLink
  • AddMembership
  • AddPinnedLink
  • CreateMemberGroup
  • CreateUserProfileByAccountName
  • GetCommonColleagues
  • GetCommonManager
  • GetCommonMemberships
  • GetInCommon
  • GetPropertyChoiceList
  • GetUserColleagues
  • GetUserLinks
  • GetUserMemberships
  • GetUserPinnedLinks
  • GetUserProfileByGuid
  • GetUserProfileByIndex
  • GetUserProfileByName
  • GetUserProfileCount
  • GetUserProfileSchema
  • ModifyUserPropertyByAccountName
  • RemoveAllColleagues
  • RemoveAllLinks
  • RemoveAllMemberships
  • RemoveAllPinnedLinks
  • RemoveColleague
  • RemoveLink
  • RemoveMembership
  • RemovePinnedLink
  • UpdateColleaguePrivacy
  • UpdateLink
  • UpdateMembershipPrivacy
  • UpdatePinnedLink

In order to use this web service in a VS project, you would simply add a new Web Reference to your project, and point it to the url of the web service (similar to that shown above).  Once you’ve done that, the following code shows and example of how to use this service to enumerate all MOSS profiles:

UserProfileService service = new UserProfileService();
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
int numProfiles = (int)service.GetUserProfileCount();
for (int i = 0; i < numProfiles; i++)
{
    Console.WriteLine(service.GetUserProfileByIndex(i).UserProfile[1].Values[0].Value);
}

In the code above, the values displayed would be the Windows domain accounts (such as DOMAIN\user), and the credentials used when calling the web service must have the appropriate permissions to view user profiles.  Assuming the permissions are correct, you will see all user profiles for the MOSS site.  Keep in mind, however, that these are different than the simple WSS profiles for each Site Collection (see the previous part of this post for details).

What happens, you might ask, if I am using forms-based authentication rather than Windows authentication for my site? In that case, you will need to make use of the Authentication web service, which resides at http://<moss-server>/_vti_bin/authentication.asmx and provides the following methods:

  • Login
  • Mode

This service is used by passing a username/password to the Login method, and grabbing the ASP.NET forms auth cookie that is returned in the response. This cookie can then be used for calls to any of the other web services.  As usual, a few lines of codes speak louder than my words:

// First authenticate against the auth service
Authentication auth = new Authentication();
auth.CookieContainer = new System.Net.CookieContainer();
LoginResult res = auth.Login(activeUser.UserPrincipalName, login.Password); 

if (res.ErrorCode == LoginErrorCode.NoError)
{
    // If that succeeds, obtain auth cookie
    System.Net.CookieCollection cookies = auth.CookieContainer.GetCookies(new Uri(auth.Url));
    System.Net.Cookie authCookie = cookies[res.CookieName]; 

    // Now call the whatever service you want, and include the cookie
    UserProfileService service = new UserProfileService();
    service.CookieContainer = new System.Net.CookieContainer();
    service.CookieContainer.Add(authCookie); 

    //... same as previous example ...
}

That pretty much covers the user profile web service interface. Along with the methods listed above, there is a UserProfileChangeService that provides access to a change-history for the MOSS user profiles. This is not, however, essential to your understanding of this topic, so it has been left for your own study.

-Tristan

Posted in Uncategorized | 1 Comment »

Sharepoint User Profiles

Posted by ricetristan on January 14, 2008

To those doing software development for a Sharepoint environment, user profiles can be a mysterious and confusing area. This post will detail some of the basics, and outline some snafoos you may run into if you find yourself doing software development that interacts with the Sharepoint user profile information.

First, it should be explained that the user profile setup differs depending on whether you are operating in a full MOSS environment, or simply using the basic WSS structure. In the full MOSS environment, user profile information is stored in a central database, and profile information is shared across site collections that may be hosted on your server. This profile info can be read and/or edited via the UserProfileManager class within the Microsoft.Office.Server dll. For example, you can display all current profiles via the following:

using(Microsoft.Sharepoint.SPSite site = new Microsoft.Sharepoint.SPSite("http://url")){     Microsoft.Office.Server.UserProfiles.UserProfileManager mgr = new UserProfileManager(ServerContext.GetContext(site));

    foreach (UserProfile profile in mgr)

    {

        System.Console.WriteLine(profile.ID + ": " + profile.Name);

    }

}

As mentioned above, this profile information is held in a global profile database, and persists across different site collections on your server. On the other hand, if you are operating in only a WSS environment, the user profile information is stored directly in a hidden list specific to an individual site collection, which is called the User Information List. If multiple site collections exist, the server will store separate user profiles for each one. These profiles can be access via the following:

using(Microsoft.Sharepoint.SPSite site = new Microsoft.Sharepoint.SPSite("http://url")){

    Microsoft.Sharepoint.SPWeb web = site.RootWeb;

    Microsoft.SharePoint.SPList userList = web.Lists["User Information List"];

    foreach (Microsoft.SharePoint.SPListItem user in userList.Items)

    {

        Console.WriteLine(user["ID"] + ": " + user["Name"]);

    }

}

Before you begin screaming that this second method does not make use of the SPUser class, you should note that the SPUser class provides access to fewer properties than those that are available by accessing this user list directly. However, for sake of completeness (and for those of you who shy away from tinkering under the hood), a list of all SPUser objects associated with the site collection can be obtained via the following:

using(Microsoft.Sharepoint.SPSite site = new Microsoft.SharePoint.SPSite("http://url")){

    Microsoft.SharePoint.SPWeb web = site.RootWeb;

    foreach(Microsoft.SharePoint.SPUser user in web.Users){

        System.Console.WriteLine(user.ID + ": " + user.Name);

    }

}

As I stated above, the profile properties available from the SPUser class are fewer than those available from the User Information List. The SPUser class allows you to access/change the following profile properties (e.g. those that show up in the My Settings page):

- ID
- Email
- Name
- LoginName
- Notes

By comparison, the User Information List provides access to the following profile properties (plus many more that I’m not listing here):

- Title
- Name
- EMail
- Notes
- SipAddress
- Locale
- IsSiteAdmin
- Picture
- Department
- JobTitle
- IsActive
- FirstName
- LastName
- WorkPhone
- UserName
- WebSite
- Office
- ID
- Modified
- Created
- Author
- Editor

As you can see, these different methods of accessing user profile information can be a bit confusing. A good first step in tackling this problem is to look at the default layout of your website. If you have a link for My Site at the top, near your name, then you are in a full MOSS environment, and should access user profiles via the first method described. If this link does not exist, you may be only using WSS profiles, in which case either of the other methods will be your preferred mode of access.

Either way, there are MANY examples available on the web that provide samples of code used to access profile properties. In a future post, I’ll discuss an additional method of user profile access using the built-in Sharepoint web services. Hope this helped!

-Tristan

Posted in .NET Development, Sharepoint | 2 Comments »