This is another tricky one. And I think I had this problem long time ago which I had this workaround but couldn’t remember about it until I’ve looked into an old code snippet.
Here’s the scenario.
You need to retrieve the total number of user profiles in SharePoint. The API has a property for that in the UserProfileManager class. You could just write some code like this:
UserProfileManager profileManager = new UserProfileManager(serviceContext); long ProfileCount = profileManager.Count;
But the problem is that in order to retrieve this you need to have admin privileges on the User Profile Service. So the logical way of doing this is to run the code with Elevated privileges and ensure the identity used by the application pool of your site has admin privileges on the User Profile service. So I’ve tried that using the code below:
SPSite siteColl = SPContext.Current.Site;
try{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite ElevatedsiteColl = new SPSite(siteColl.ID))
{
SPServiceContext serviceContext = SPServiceContext.GetContext(ElevatedsiteColl);
UserProfileManager profileManager = new UserProfileManager(serviceContext);
ProfileCount = profileManager.Count;
}
});
}
catch (Exception ex)
{
LogException(ex);
}
Testing the code running under an Admin account it was fine (because it was the same account used by the site’s application pool). But when I tested the code using a regular user this code should still run fine (because I was running it elevated). Unfortunately that’s not what happened. For some weird reason seems that the SharePoint API was trying to impersonate the current user thus throwing an exception and showing an Access Denied error which said Access Denied: Only an administrator may retrieve a count of all users.
So after sleepless nights (just kidding it was just some banging my head on the wall), I finally remembered to take a look at an old code snippet that I had when facing the same issue in the past, and I’ve decided to write this post (blog posts are a great way to use as a diary).
The Workaround
Basically my workaround is to set the current HttpContext to null inside the code, but keeping the existing context in a temp variable so I can revert it back once I run the snippet. You have to revert it back to the original context otherwise you are going to get a lot of errors. The code looks like this:
SPSite siteColl = SPContext.Current.Site;
HttpContext tempCtx = HttpContext.Current;
try
{
SPSecurity.RunWithElevatedPrivileges(delegate() {
using (SPSite ElevatedsiteColl = new SPSite(siteColl.ID))
{
SPServiceContext serviceContext = SPServiceContext.GetContext(ElevatedsiteColl);
HttpContext.Current = null;
UserProfileManager profileManager = new UserProfileManager(serviceContext);
ProfileCount = profileManager.Count;} });
}
catch (Exception ex){ LogException(ex);}
finally{ HttpContext.Current = tempCtx;}
Using the code above I could retrieve the count even using a regular user (no admin access) .
I hope this saves some time on your side and avoid some head banging on the wall
Have a nice one !
Andy Nogueira.