SharePoint客户端开发:增加用户信息到用户信息列表

用户信息列表(User Information List),这个隐藏的SharePoint列表,主要用来储存一些用户Profile的基本数据。这个列表不能使用普通的方式去添加或者删除数据。

首先,为什么要在这个列表中增加数据?

这个列表是由SharePoint进行管理的,在使用PeoplePicker控件的时候,点时候就会自动把用户添加进用户信息列表。对于列表中的用户类型的字段来说,这个会利用ID关联到用户信息列表。

我碰到过2个典型场景:

  1. 实际用户操作中,对于批量数据导入的时候,一般使用的是Datasheet View,通过Excel导入。如果张三从来没有访问过网站,导入的时候有张三这个人,这个时候Datasheet View就会报错。无法保存。
  2. 开发跨站点集的数据迁移同步,张三是A网站用户,却不是B网站用户,需要把涉及到张三的数据迁移到B网站。

对于第一个场景,可以让用户随便找个PeoplePicker控件,输入缺失的人信息,然后点,就可以补充回来。

 

对于开发者,一般情况下,服务端开发,可以用SPWeb.EnsureUser来添加用户到这个列表中。

对应客户端开发:

大多数情况下,前面一种Client OM可以满足需要了。

 

不过Web.EnsureUser有个问题就是一次只能添加一个用户,并且这个是一个完整的服务请求,大数据量的情况下效率很成问题。

为了解决这个问题,需要利用到多线程。

这里我有一段我实际使用的代码作为参考:

实际使用多线程的过程中,我遇到了一个问题,参考了这篇讨论中给出的方法:Workaround for the WaitHandle.WaitAll 64 handle limit?

UserInfoList targetList = new UserInfoList(Parameters.TargetUrl, Parameters.ListNames.UserInformation);

IList<User> resolvedUsers = new List<User>();

logger.Info("Sync User Information from {0} to {1} started...", Parameters.SourceUrl, Parameters.TargetUrl);

int threadCount = 0;

ManualResetEvent finished = new ManualResetEvent(false);

foreach (var u in Users)

{

Interlocked.Increment(ref threadCount);

ThreadPool.QueueUserWorkItem(delegate

{

try

{

logger.Info("Resolving user in target web site:", u.SipAddress, u.Account);

if (!String.IsNullOrEmpty(u.Account) && targetList.GetUserInfoByAccount(u.Account) == null)

{

User targetUser = targetList.Web.EnsureUser(u.Account);

targetList.Context.Load(targetUser);

targetList.Context.ExecuteQuery();

resolvedUsers.Add(targetUser);

logger.Info("User resolved:", u.SipAddress, u.Account);

}

else

{

logger.Info("User exists or user is not valid:", u.SipAddress, u.Account);

}

}

catch (Exception)

{

logger.Info("Cannot update user information for {0} ({1})", u.SipAddress, u.Account);

}

finally

{

if (Interlocked.Decrement(ref threadCount) == 0)

{

finished.Set();

}

}

});

}

finished.WaitOne();

logger.Info("Sync User Information from {0} to {1} completed...", Parameters.SourceUrl, Parameters.TargetUrl);

 

 

如果不熟悉多线程,为了提高性能,只能用传统的Web Service来做,用People.ResolvePrincipals方法,因为这个方法的参数允许数组。在一次HTTP请求中可以传递多个用户,大大节约了HTTP往返时间。

同样,我也有一段我实际使用的代码作为参考:

值得注意的问题时,使用的时候,不能一次性的添加过多的用户,这样会导致Web Service超时失败。

public UserInfo[] EnsureUsers(string[] accounts, int batch = 200, string url = default(string))

{

if (url == default(string)) { url = WebUrl; }

logger.Info("Ensuring user information in {0} web site", url);

List<PrincipalInfo> pi = new List<PrincipalInfo>();

for (int i = 0; i < Math.Ceiling((double)accounts.Length / batch); i++)

{

string[] batchAccounts = accounts.Skip(i * batch).Take(batch).ToArray();

People peopleService = new People();

peopleService.Url = url + "/_vti_bin/people.asmx";

peopleService.Credentials = System.Net.CredentialCache.DefaultCredentials;

pi.AddRange(peopleService.ResolvePrincipals(batchAccounts, SPPrincipalType.User, true));

}

List<UserInfo> users = Convert(pi);

logger.Info("Found {0} user information items and updated to user information store", users.Count);

return users.ToArray();

 

}

 

posted @ 2013-03-28 22:28  Lambert Qin  Views(1855)  Comments(1Edit  收藏  举报