Getting random user profiles

Getting random user profiles is quite an easy task, but there is not much to be found on the internet about it except for some less than ideal solutions in my opinion.

My ideal solution would be something that is scalable and takes into account the security of the User Profile Application.

The solutions that I found all shared the same approach:

  • Open the User Profile Application Service
  • Get the count of user profiles
  • Get X numbers between 0 and the number of user profiles
  • Get those user profiles

I do have some issues with this which I would like to point out:

The count of the number of user profiles requires you to use an administrative account, which often works in a development environment (single machine, one account to rule them all kind of gig).. but when you deploy to a real live SharePoint farm you might encounter problems such as:

  • The account used with the SPSecurity.RunWithElevatedPrivileges might not be administrator of the User Profile Application, thus giving you an access denied. This means going through even more unconfortable steps to get this working.
  • If you try to iterate over your User Profiles it goes quite slow (do not try to iterate over 10000+ userprofiles, you’ll be stuck for minutes)

What my suggestion would be is to make use of the SharePoint search API and look for your user profiles there, the SharePoint search is very scalable and gets your results much faster than then the regular user profile API.

using (SPMonitoredScope scope = new SPMonitoredScope("Get random profiles"))
{
StringBuilder Output = new StringBuilder();

FullTextSqlQuery q = new FullTextSqlQuery(SPContext.Current.Site);
q.QueryText = "SELECT AccountName,FirstName,LastName,PictureURL,Path FROM Scope() WHERE \"Scope\"='People' AND Contains(PictureURL, 'http')";
q.ResultTypes = ResultType.RelevantResults;
q.RowLimit = 10000;
ResultTableCollection results = q.Execute();
ResultTable queryResultsTable = results[ResultType.RelevantResults];

DataTable queryDataTable = new DataTable();
queryDataTable.Load(queryResultsTable, LoadOption.OverwriteChanges);

Random random = new Random();
int randomId = random.Next(queryDataTable.DefaultView.Count - 5);

DataTable dataTableToBind = new DataTable();
List<string> columns = new List<string>() { "AccountName", "FirstName", "LastName", "PictureURL", "Path" };
foreach (string column in columns)
dataTableToBind.Columns.Add(column);
for (int id = randomId; id < randomId + 4; id++)
dataTableToBind.ImportRow(queryDataTable.Rows[id]);

rptUserProfiles.DataSource = dataTableToBind.DefaultView;
rptUserProfiles.DataBind();
}

The result can be as follows:

image

Note:

  • In the above example one random ID is chosen and then it takes the next X random profiles to show, you can also take just X random profiles but then you would need to add some extra logic to it to avoid duplicates.
  • It is also recommended to cache the results you get back for performance reasons.
  • The above code is not production proof, it is a simple POC

Just a closing note: if you try to iterate the user profiles through the user profile API you will quickly be stuck for seconds or even minutes, so it is highly recommended not to try this approach.

The method of using the search API is highly underused in my opinion and should be used as much as possible for the iteration over items that are spread across the farm, including – but not limited to – the search of user profiles.

Special thanks to St├ęphane Eyskens (http://www.silver-it.com/)!

Sourcecode: http://www.skavi.be/wp-content/uploads/2011/09/Skavi.UserProfiles.zip