Skip to main content

Thinking out aloud - Dave Hunter's SharePoint Blog

Go Search
Home
Blog
  

Home > Thinking out aloud - Dave Hunter's SharePoint Blog > Categories
Design Considerations for using the SharePoint UserProfileManager
I'm writing this post based on my experience with the UserProfileManager in SharePoint 2007.  I've seen many posts about people having issues using the UserProfileManager for normal users in SharePoint.
 
I will start with showing you how to access the user profiles using the UserProfileManager.  There are three ways to loop through the User Profiles, which are:
 
1.  For Each
// get the server context
Microsoft.Office.Server.ServerContext ctx = Microsoft.Office.Server.ServerContext.GetContext(HttpContext.Current);

// get the user profile manager
UserProfileManager userProfileManager = new UserProfileManager(ctx);

// get the count of the user profiles
int numberOfProfiles = userProfileManager.Count;

// loop through the user profiles
foreach(UserProfile profile in userProfileManager)
{
    // do some action on each currentProfile
}
2.  For Loop
// get the server context
Microsoft.Office.Server.ServerContext ctx = Microsoft.Office.Server.ServerContext.GetContext(HttpContext.Current);

// get the user profile manager
UserProfileManager userProfileManager = new UserProfileManager(ctx);

// get the count of the user profiles
int numberOfProfiles = userProfileManager.Count;

// loop through the user profiles
for (int i = 0; i < numberOfProfiles; i++)
{
    try
    {
        UserProfile profile = userProfileManager.GetUserProfile(i);

        // do some action on each currentProfile
    }
    catch (Exception ex)
    {
        // failed to get user profile
        // log the error
    }
}
3.  GetEnumerator
// get the server context
Microsoft.Office.Server.ServerContext ctx = Microsoft.Office.Server.ServerContext.GetContext(HttpContext.Current);

// get the user profile manager
UserProfileManager userProfileManager = new UserProfileManager(ctx);

UserProfile currentProfile;

// get the enumerator
System.Collections.IEnumerator enumProfs = userProfileManager.GetEnumerator();

bool continueEnum = true;

// loop through profiles
while (continueEnum)
{

    try
    {
        // move to next profile
        continueEnum = enumProfs.MoveNext();
    }
    catch (Exception ex)
    {
        // failed to get user profile
        // log the error
        // try to move to the next user profile

        continueEnum = enumProfs.MoveNext();
    }


    currentProfile = (UserProfile)enumProfs.Current;

    // do some action on each currentProfile

}
Using either of these methods with a user without rights for "Manage User Profiles" (set in the SSP Administration) returns a 403 Error in IIS.
 
If the user doesn't have rights you may think to use the SPSecurity.RunWithElevatedPrivileges for more information http://www.davehunter.co.uk/Blog/Lists/Posts/Post.aspx?ID=43.  RunWithElevatedPrivileges runs the code in the brackets under the SharePoint System Account.  This still fails.
 
If you debug the code you will receive the following error message:
 
 
After reviewing the MSDN Help, I found ...
 
 
<snip>
You must create the UserProfileManager object before accessing a UserProfile object. You can then retrieve the user profiles to which the user has access. Full access to everyone's user profile requires "Manage User Profiles" rights. Full access to your own profile requires "Use Personal Features" rights. Everyone has read access to all profiles.
</snip>
 
A workaround could be to iterate through a set number and trying to retrieve the profile relating to the current integer, for example:
// get the server context
Microsoft.Office.Server.ServerContext ctx = Microsoft.Office.Server.ServerContext.GetContext(HttpContext.Current);

// get the user profile manager
UserProfileManager userProfileManager = new UserProfileManager(ctx);

// set the number of profiles to iterate through
int numberOfProfiles = 400;

// loop through the user profiles
for (int i = 0; i < numberOfProfiles; i++)
{
    try
    {
        UserProfile profile = userProfileManager.GetUserProfile(i);

        // do some action on each currentProfile
    }
    catch (Exception ex)
    {
        // failed to get user profile
        // log the error
    }
}
 
I wouldn't recommend using this approach.  I feel the best approach would be to perform a search for people in SharePoint.  This can be created using a CAML query against the API or Web Service.  I will follow up this article with steps to achieve this.  A search would return public properties exposed to the search and wouldn't need administrative priviledges.
 
On summary ...
 
Iterating through the user profiles using UserProfileManager requires "Manage User Profiles" rights and therefore is an administrative function.
 
Only use the UserProfileManager if you are designing an administrative tool to modify the user profiles.  You should only use the UserProfileManager to retrieve a single user profile (either the current user or a known account by using the domain/username).
SharePoint and Silverlight
Some interesting articles and source code have been release recently regarding SharePoint and Silverlight.
 
Silverlight BluePrint for SharePoint
 
At the time of writing this post this site contains 6 samples for using Silverlight with SharePoint, these include:
  1. Hello Silverlight Web Parts and the SilverlightPart
  2. Silverlight Navigation Controls
  3. Silverlight Social Networking Web Part
  4. Visual How-To center with Silverlight
  5. Picture Viewer sample
  6. Silverlight Custom Field Types

All samples contain source code, video, setup instructions and code walkthrough.  http://www.ssblueprints.net/sharepoint/ 

Ian Morrish's Article about using the Silverlight and SharePoint using the DataView web part.  http://www.wssdemo.com/pages/silverlight.aspx.
 
 
Triplewood's SharePoint Silverlight Browser
 
From Triplewood ...
 
A SharePoint Silverlight Web Part which displays SharePoint Documents and Pictures in a rich Silverlight flow control.
 
 
 
For more information on Silverlight and to download please see http://silverlight.net/default.aspx.
Delving into SharePoint 2007 Event Receivers
 
What are they?
 
SharePoint 2007 Event Receivers are a type of feature which listens for certain events on a site, list or list item.  Event Receivers are the MOSS version of document event handlers (also known as Event Sink) in SharePoint V2 technologies (WSS and SPS).  Previously the document event handlers were only available for document libaries.  Event receivers are now available for any type of list. 
 
What can they be used for?
 
SharePoint 2007 Event Receivers add behaviours to lists or list items.  They are commonly used to perform data validation (beyond SharePoint standard capabilities), to ensure data integrity or to perform a business process.
 
Definition
 
Event Receivers have before and after events.
 
The events relating to a site are:
  • Before
    • SiteDeleting
    • WebDeleting
    • WebMoving
  • After
    • SiteDeleted
    • WebDeleted
    • WebMoved
A class needs to inherit from SPWebEventReceiver.  The behaviour is defined by overriding a method for one of the above before or after events.  You can access properties that relates to the event that the feature is listening using SPWebEventProperties.
 
The events relating to a list are:
  • Before
    • FieldAdding
    • FieldUpdating
    • FieldDeleting
  • After
    • FieldAdded
    • FieldUpdated
    • FieldDeleted

A class needs to inherit from SPListEventReceiver.  You define the behaviour by overriding a method for one of the above before or after events.  You can access the event properties using the parameter SPListEventProperties.

The events releating to list items are:

  • Before
    • ItemAdding
    • ItemUpdating
    • ItemDeleting
  • After
    • ItemAdded
    • ItemUpdated
    • ItemDeleted
    • ItemAttachmentAdded
    • ItemAttachmentDeleted
    • ItemCheckedIn
    • ItemCheckedOut
    • ItemFileConverted
    • ItemFileMoved
    • ItemUncheckedOut

A class needs to inherit from SPItemEventReceiver.  You then override a method for one of the above before or after events.  The event properties can be accessed by the local parameter SPItemEventProperties.  One of these is the list item.  For example:

public override void ItemAdded(SPItemEventProperties properties)
{
  SPListItem currentListItem = properties.ListItem;
  // other implementation here .....
}

Other important information of the properties object is the AfterProperties and BeforeProperties.  AfterProperties provide access to the modified properties.  BeforeProperties provide access to the column data before it was changed.  This enables you to perform changed based validation.

How are they assigned to a list?

Event Receivers can be bound by using the ListTemplateId specified in the feature or added to the EventReceivers Collection of a list.  If you are using the latter this is usually performed using a SPFeatureReceiver.  A Feature Receiver allows some custom code to be executed once the feature has been installed, activated, deactivating and uninstalling (note the first two are after events and the last two are before events).  The code for adding an Event Receiver to a list is:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    SPWeb web = properties.Feature.Parent as SPWeb;
    web.Lists["Rating History"].EventReceivers.Add(
SPEventReceiverType.ItemAdded,
"Dhunter.SharePoint.Eventhandlers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0a26195ff03df1fd",
"Dhunter.SharePoint.Eventhandlers.RatingSummaryEventHandler"); }

As you can see above, the Add method takes in the 4 part string that correctly identifies the assembly and class for the event handler.

How are events registered with the event receiver?

Events that the Event Receiver responds to are subscribed to using the feature file.  For example:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Receivers ListTemplateId="100">
    <Receiver>
      <Name>RatingSummaryEventHandler</Name>
      <Type>ItemAdded</Type>
      <SequenceNumber>10000</SequenceNumber>
      <Assembly>Dhunter.SharePoint.Eventhandlers, Version=1.0.0.0, Culture=neutral, 
PublicKeyToken=0a26195ff03df1fd</Assembly> <Class>Dhunter.SharePoint.Eventhandlers.RatingSummaryEventHandler</Class> <Data></Data> <Filter></Filter> </Receiver> </Receivers> </Elements>

Or if the event receiver is bound to the list by code, you specify this when adding the event handler using the enumeration SPEventReceiverType.  You add the event receiver to the EventReceivers collection once for every SPEventReciverType.

For example the code below adds the event handler for the ItemAdded and ItemUpdated events.

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    SPWeb web = properties.Feature.Parent as SPWeb;
    web.Lists["Rating History"].EventReceivers.Add(
SPEventReceiverType.ItemAdded,
"Dhunter.SharePoint.Eventhandlers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0a26195ff03df1fd",
"Dhunter.SharePoint.Eventhandlers.RatingSummaryEventHandler"); web.Lists["Rating History"].EventReceivers.Add(
SPEventReceiverType.ItemUpdated,
"Dhunter.SharePoint.Eventhandlers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0a26195ff03df1fd",
"Dhunter.SharePoint.Eventhandlers.RatingSummaryEventHandler"); }

 

Using Before Events

It's possible to cancel the task executed using a before event.  You may need to implement this behaviour because you dont want users to modify a schema of a list or that certain criteria failed when a new item has been entered.  For example:

properties.ErrorMessage = "Only Administrators are allowed to modify the definiton of this list";
properties.Cancel = true;

Before events are often referred to as synchronous events.  Synchronous events stop the current flow of execution until the code processed in the method for the event handler has run.  These are typically used to perform validation on the entered data to maintain data integrity or provide custom validation rules that the front-end cant provide.

Using After Events

After events are asynchronous events.  This doesn't stop the execution of the current flow.  These are typically used to kick off a business process.

How are they bound to a content type?

In the content type definition file you need to add a XmlDocuments element that contains a XMLDocument followed by spe:Receivers and Receiver elements.  For example:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <ContentType ID="CONTENT TYPE ID" Name="CONTENT TYPE NAME" Group="Custom" 
Description="CONTENT TYPE DESCRIPTION" Version="0"> <FieldRefs> <FieldRef ID="FIELD ID" Name="FIELD NAME" /> </FieldRefs> <XmlDocuments> <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/events"> <spe:Receivers xmlns:spe="http://schemas.microsoft.com/sharepoint/events"> <Receiver> <Name>RatingSummaryEventHandler</Name> <Type>ItemAdded</Type> <SequenceNumber>10000</SequenceNumber> <Assembly>Dhunter.SharePoint.Eventhandlers, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=0a26195ff03df1fd</Assembly> <Class>Dhunter.SharePoint.Eventhandlers.RatingSummaryEventHandler</Class> <Data></Data> <Filter></Filter> </Receiver> <Receiver> <Name>RatingSummaryEventHandler</Name> <Type>ItemUpdated</Type> <SequenceNumber>10000</SequenceNumber> <Assembly>Dhunter.SharePoint.Eventhandlers, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=0a26195ff03df1fd</Assembly> <Class>Dhunter.SharePoint.Eventhandlers.RatingSummaryEventHandler</Class> <Data></Data> <Filter></Filter> </Receiver> </spe:Receivers> </XmlDocument> </XmlDocuments>
</ContentType> </Elements>

What sequence numbers?

Sequence numbers apply the order that the event handlers should be executed.  Take this example ... You have a list which has multiple event handlers bound (Event handler 1 and Event handler 2).  Both event handlers are registered to the ItemAdded event.  Event handler 1 has a sequence number of 900 and Event handler 2 has a sequence number of 1000.  This means Event handler 1 will be executed first and then followed by Event handler 2.

Deployment considerations

The compiled class file must be strongly named and deployed to the GAC (Global Assembly Cache).

If you bind the event receiver using a feature file it can only be scoped at the site level.  It cannot be bound to an instance of a list or to a content type.

Points to note

Disable Event Firing. 

If you modify the current SPList for a List Event Receiver or SPListItem for an Item Event Receiver you must call DisableEventFiring() before commiting the change.  This stops recursive event firing and the possiblity of entering an infinite loop.  After you have committed the change, you should then call EnableEventFiring() to return the processing to its normal behaviour.

Performance

What effect would bulk creation or upload of items have on the perfromance of our system?  You should bear this in mind when designing, developing and testing the system.  Intensive calls during event handlers will hinder the performance of the system, especially with synchronous events as the flow of execution is stopped until the code within the event handler is executed.

Delving into SharePoint 2007 Lists and their Features
In simplest terms, as most of you know a list is defined by a list schema which is made available in SharePoint by a feature.  Important attributes of a list type definition are the Type ID and GUID.
  • The Type ID assigns a number to identify that the list has a custom definition.
  • The GUID of the list feature uniquely identifies the feature within the SharePoint farm.
The table shows the lists available in MOSS (some also available in WSS), their Type IDs and GUIDs.
 
Type ID
Description

GUID of feature

100

Generic list  00bfea71-de22-43b2-a848-c05709900100

101

Document library  00BFEA71-E717-4E80-AA17-D0C71B360101

102

Survey  00BFEA71-EB8A-40B1-80C7-506BE7590102

103

Links list  00BFEA71-2062-426C-90BF-714C59600103

104

Announcements list  00BFEA71-D1CE-42de-9C63-A44004CE0104

105

Contacts list  00BFEA71-7E6D-4186-9BA8-C047AC750105

106

Events list  00BFEA71-EC85-4903-972D-EBE475780106

107

Tasks list  00BFEA71-A83E-497E-9BA0-7A5C597D0107

108

Discussion board  00BFEA71-6A49-43FA-B535-D15C05500108

109

Picture library  00BFEA71-52D4-45B3-B544-B1C71B620109

110

Data sources  00BFEA71-F381-423D-B9D1-DA7A54C50110

111

Site template gallery  SYSTEM

113

Web Part gallery  SYSTEM

114

List template gallery  SYSTEM

115

XML Form library  00BFEA71-1E1D-4562-B56A-F05371BB0115

116

Masterpage and page layouts library SYSTEM

117

No-code workflow library  00BFEA71-F600-43F6-A895-40C0DE7B0117

118

Workflow process list  00BFEA71-2D77-4A75-9FCA-76516689E21A

119

Web page library  00BFEA71-C796-4402-9F2F-0EB9A6E71B18

120

Custom grid for a list  00BFEA71-3A1D-41D3-A0EE-651D11570120

130

Data connection library  00BFEA71-DBD7-4F72-B8CB-DA7AC0440130

140

Workflow history list  00BFEA71-4EA5-48D4-A4AD-305CF7030140

150

Gantt tasks list  00BFEA71-513D-4CA0-96C2-6A47775C0119

1100

Issue tracking  00BFEA71-5932-4F9C-AD71-1557E5751100

 

If you are adding a list to a site definition you will see the importance of the GUID (you need to specify this as the FeatureId) - this is also the same with a feature that provisions a list instance, like the example below.

<ListInstance FeatureId="00BFEA71-EC85-4903-972D-EBE475780106" TemplateType="106" Title="$Resources:compproc,CompEventsListTitle;"
                Url="$Resources:core,lists_Folder;/CompEvents" OnQuickLaunch="TRUE">
  </ListInstance>

The example below shows a list element in a site definition (onet.xml file) for a custom list called "Projects".

<List FeatureId="00bfea71-de22-43b2-a848-c05709900100" Type="100" Title="Projects" Url="Lists/Projects" />

All the information in the above table will help you add list instances to features and site definitions.  Hope this helps!

Consistent branding in SharePoint
Recently I've been working on applying Governance to SharePoint.  Microsoft have some great resources out there for planning and understanding what Governance is and how to apply it.
 
Governance Information
 
Sample Governance Plan
 
Governance Checklist
 
One of the areas to Governance is applying Branding to SharePoint so users see the SharePoint site as part of the Business's applications and not like an external site.
 
You may think consistent branding is achieved by developing a masterpage that applies the look and feel to the site.  The masterpage will brand the site pages but not the application pages (like settings.aspx and searchresults.aspx) that appear under the _layouts folder.
 
Consistent branding needs to be achieved using CSS
 
Apply the look and feel to the SharePoint site in the usual way (overriding style attributes) and create a css file.  You should then set the AlternateCssUrl either via code using a SPFeatureReceiver or using the Masterpage settings page (appears down the bottom).  This will apply the branding to the front and back-end pages.
 
Alternate CSS URL section on change master page.
This is because application pages use a masterpage called application.master (which you cannot change).  Application pages are dynamic and apply to the whole farm (settings.aspx is the same page used for all sites).  The only branding changes you can make to site pages and application pages is to change the logo and AlternateCssUrl.
 
Hope this helps.
 
Changing the boundaries
Site Collections by default are stored in the content database for the web application.  The diagram below illustrates this.
 
 
Using the administration user interface you cannot create a new site collection with its own content database.  This may lead you to create many web applications for your SharePoint site collections so that each one has its own database that can be backed up using SQL Server database backups and SharePoint backup and restore.
 
Restoring the backups may become awkward as you will have to restore the whole content database unless you have a 3rd party disaster recovery tool in place.
 
STSADM has an operation called "CreateSiteInNewDB".  The command line definition for this command is:

stsadm -o createsiteinnewdb -url <url> -owneremail <someone@example.com> [-ownerlogin <DOMAIN\name>] [-ownername <display name>] [-secondaryemail <someone@example.com>] [-secondarylogin <DOMAIN\name>] [-secondaryname <display name>] [-lcid <language>] [-sitetemplate <site template>] [-title <site title>] [-description <site description>] [-hostheaderwebapplicationurl <web application url>] [-quota <quota template>] [-databaseuser <database username>] [-databasepassword <database password>] [-databaseserver <database server name>] [-databasename <database name>]
 
for example:
 
stsadm -o createsiteinnewdb -url http://intranet/sites/HR -ownerlogin domain\spadmin -owneremail spadmin@company.com -sitetemplate SPSPORTAL#0 -title "HR" -databasename SharePoint_Content_HR
 
The diagram below illustrates the content boundaries when create site collections using stsadm -o createsiteinnewdb.
 
 
 
Of course there are considerations when deciding on which approach to choose.  When you have site collection webpart like the Content Query WebPart are limited to aggregating content within the current site collection.  The diagram below illustrates this.
 
 
 
If you decide to implement divisions of the company or site applications using site collections you just need to be aware of this, as its not alway fully understood.  One workaround is that the MOSS search picks up all data stored in the site collections because of the way the content source is defined.

 Latest Posts

I’m attending the first ever SharePoint Saturday in the UK31/08/2010 19:43
I’ve re-joined CIBER UK31/08/2010 19:26
I’ve been Awarded a MVP for SharePoint01/04/2010 19:49
SharePoint 2010 Training on Microsoft E-Learning15/03/2010 17:56
SharePoint UK User Group - Thursday 27th August London Meeting25/08/2009 17:56
CAML Query that filters on the current user23/07/2009 17:50
Microsoft Ramp Up Free SharePoint Developer Training22/07/2009 20:59
How To: Change a SharePoint Application Pool Programmatically07/07/2009 18:08
SharePoint Forums Topping 100 Answers06/07/2009 12:29
Find out the SharePoint Internal Name for a Column or Site Column28/05/2009 09:56
1 - 10 Next