工作中的一个项目,在做SharePoint online app时, 采用provider-host方式,在我们portal中的设置页面,需要搜索office 365中的用户信息,对用户的行为进行下限制。于是便诞生了如何搜索用户的需求。
刚开始实现时,采用了最省力的写法,使用SharePoint client api中提供的KeywordQuery,一直到项目开发接近尾声,这个方法一直没有问题的,到最后到SharePoint app store中提交app时,才发现微软对app的权限控制很严格,而这个方法需要app中配置Search的权限,Search 权限是tenant级别的,需要tenant administrator的权限才能在SharePoint站点中安装app,可能会导致app审核不通过。
var keywordQuery = new KeywordQuery(clientContext); keywordQuery.QueryText = String.Format("{0}*", key); keywordQuery.SourceId = new Guid("B09A7990-05EA-4AF9-81EF-EDFAB16C4E31"); keywordQuery.RowLimit = rowLimit; keywordQuery.TrimDuplicates = false; var searchExecutor = new SearchExecutor(clientContext); var results = searchExecutor.ExecuteQuery(keywordQuery); clientContext.ExecuteQuery(); var result = new List<IDictionary<String, Object>>(); foreach (var resultTable in results.Value) { result.AddRange(resultTable.ResultRows); } return result;
于是需要寻找替代方案,首先找到的是在Utility命名空间下的SearchPrincipals方法,但这个方法存在问题,首先是单个字母返回的结果是空的,其次输入的email必须从第一个字母开始匹配,再有,PrincipleSource为All时返回的结果中没有extranet user, 为UserInfoList时只包含了当前站点的user
using (var clientContext = this.CreateClientContext()) { var principalInfos = Utility.SearchPrincipals(clientContext, clientContext.Web, key, PrincipalType.User, PrincipalSource.All, null, Int32.MaxValue); clientContext.ExecuteQuery(); return principalInfos; }
于是便又寻找其他的解决方案,首先想到的是ClientContext.Web.UserInfoList.Get(CalmQuery query)中可以搜索出当前站点下所有的用户,单个字母也可匹配,只是不能返回office 365中所有的用户
var camlQuery = new CamlQuery(); camlQuery.ViewXml = @"<View Scope='RecursiveAll'> <Query> <Where> <Contains> <FieldRef Name='Name'/> <Value Type='Text'>{0}</Value> </Contains> </Where> </Query> <RowLimit>{1}</RowLimit> </View>".FormatWith(key, rowLimit); var siteUsers = clientContext.Web.SiteUserInfoList.GetItems(camlQuery); clientContext.Load(siteUsers); clientContext.ExecuteQuery();
最后,想到在SharePoint site中添加用户时,搜索出的结果是满足我们的需求的,于是便研究这个功能的实现细节:
发现请求的参数中包含一个叫ClientPeoplePickerSearchUser的参数,于是根据这个线索到client api中查找有没有类似的方法,最终在Microsoft.SharePoint.ApplicationPages.ClientPickerQuery中找到了ClientPeoplePickerWebServiceInterface.ClientPeoplePickerSearchUser方法,最终实现结果和SharePoint中添加用户相同
var param = new ClientPeoplePickerQueryParameters(); param.QueryString = key; param.AllowEmailAddresses = true; param.AllowMultipleEntities = true; param.PrincipalSource = PrincipalSource.All; param.PrincipalType = PrincipalType.User; param.MaximumEntitySuggestions = rowLimit; param.Required = true; var resu = ClientPeoplePickerWebServiceInterface.ClientPeoplePickerSearchUser(clientContext, param); clientContext.ExecuteQuery();
这四种方法中只有第一种是需要tenant级别的权限的,后面三种都不需要