How can I efficiently grab users (with their properties) from a SharePoint web using CSOM? The code below results in multiple calls to the server (one for each user). It's ridiculously inefficient.
Also, is it possible to perform a Filter on the server?
public static List<Contact> GetUsers(Uri requestUri, string Filter = "")
{
ClientContext context;
var users = new List<Contact>();
if (ClientContextUtilities.TryResolveClientContext(requestUri, out context, null))
{
using (context)
{
var web = context.Web;
var peopleManager = new PeopleManager(context);
context.Load(web, w => w.Title, w => w.Description, w => w.SiteUsers);
var siteUsers = web.SiteUsers;
context.ExecuteQuery();
foreach (var user in siteUsers)
if (user.PrincipalType == Microsoft.SharePoint.Client.Utilities.PrincipalType.User)
if (user.Title.ToLower().Contains(Filter.ToLower()) && !users.Any(x => x.FullName == user.Title))
{
var userProfile = peopleManager.GetPropertiesFor(user.LoginName);
context.Load(userProfile);
context.ExecuteQuery();
var contact = new Contact() { FullName = user.Title, EmailAddress = user.Email };
if (userProfile.IsPropertyAvailable("Title"))
contact.Position = userProfile.Title;
if (userProfile.IsPropertyAvailable("UserProfileProperties") && userProfile.UserProfileProperties.ContainsKey("WorkPhone"))
contact.PhoneNumber = userProfile.UserProfileProperties["WorkPhone"];
users.Add(contact);
}
}
}
return users;
}
Major improvements
Since SharePoint CSOM supports Request Batching all the user profiles could be retrieved using a single request , for example instead of:
foreach (var user in siteUsers)
{
var userProfile = peopleManager.GetPropertiesFor(user.LoginName);
context.Load(userProfile);
context.ExecuteQuery();
}
user profiles could be retrieved as:
var userProfilesResult = new List<PersonProperties>(); //for storing user profiles
foreach (var user in siteUsers)
{
var userProfile = peopleManager.GetPropertiesFor(user.LoginName);
context.Load(userProfile);
userProfilesResult.Add(userProfile);
}
context.ExecuteQuery(); //submit a single request
Minor improvements
1)Since SharePoint CSOM supports CAML queries , the filtering operation could be performed on the server side, for example:
var siteUsers = from user in web.SiteUsers
where user.PrincipalType == Microsoft.SharePoint.Client.Utilities.PrincipalType.User
select user;
var usersResult = context.LoadQuery(siteUsers);
context.ExecuteQuery();
2)You could also use the following checking to determine whether user profile exist for a specified user:
var hasUserProfile = userProfile.ServerObjectIsNull != null && userProfile.ServerObjectIsNull.Value != true;
Modified example
public static List<Contact> GetUsers(Uri requestUri, ICredentials credentials, string filter = "")
{
ClientContext context;
var users = new List<Contact>();
if (ClientContextUtilities.TryResolveClientContext(requestUri, out context, credentials))
{
var userProfilesResult = new List<PersonProperties>();
using (context)
{
var web = context.Web;
var peopleManager = new PeopleManager(context);
var siteUsers = from user in web.SiteUsers
where user.PrincipalType == Microsoft.SharePoint.Client.Utilities.PrincipalType.User
select user;
var usersResult = context.LoadQuery(siteUsers);
context.ExecuteQuery();
foreach (var user in usersResult)
{
if (user.Title.ToLower().Contains(filter.ToLower()) && !users.Any(x => x.FullName == user.Title))
{
var userProfile = peopleManager.GetPropertiesFor(user.LoginName);
context.Load(userProfile);
userProfilesResult.Add(userProfile);
}
}
context.ExecuteQuery();
var result = from userProfile in userProfilesResult
where userProfile.ServerObjectIsNull != null && userProfile.ServerObjectIsNull.Value != true
select new Contact() {
FullName = userProfile.Title,
EmailAddress = userProfile.Email,
Position = userProfile.IsPropertyAvailable("Title") ? userProfile.Title : string.Empty,
PhoneNumber = userProfile.IsPropertyAvailable("UserProfileProperties") && userProfile.UserProfileProperties.ContainsKey("WorkPhone") ? userProfile.UserProfileProperties["WorkPhone"] : string.Empty
};
users = result.ToList();
}
}
return users;
}
When you are in a specific context of a website you can do followings:
using (var ctx = new ClientContext("http://theWebsite"))
{
var list = ctx.Web.SiteUserInfoList;
var users = list.GetItems(new CamlQuery());
ctx.Load(users);
ctx.ExecuteQuery();
// do what you want with the users
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.