SharePoint CSOM (Client-Site Object Model) 的冷門茶包,搞了快兩小時,寫篇筆記留給有緣人。

要授與 SharePoint 清單讀者權限給 Domain\Account,參考官方範例 BreakRoleInheritance()、建立 RoleDefinitionBindingCollection 加 RoleDefinition,RoleAssignments.Add() 行禮如儀,AD 帳號則需透過 Utility.ResolvePrincipal () 解析成 Microsoft.SharePoint.Client.Principal:

var rdbc = new RoleDefinitionBindingCollection(Context);
rdbc.Add(Web.RoleDefinitions.GetByType(RoleType.Reader));
list.RoleAssignments.Add(ResolvePrincipal("Domain\\Account"), rdlc);
Context.ExecuteQuery();

public Microsoft.SharePoint.Client.Principal ResolvePrincipal(string ntAccount)
{
    var info = Utility.ResolvePrincipal(Context, Web, ntAccount, PrincipalType.All, PrincipalSource.Windows, null, false);
    Context.ExecuteQuery();
    Microsoft.SharePoint.Client.Principal p = null;
    var type = info.Value.PrincipalType;
    if (type == PrincipalType.User)
        p = Web.EnsureUser(info.Value.LoginName);
    else if (type == PrincipalType.SharePointGroup || type == PrincipalType.SecurityGroup)
        p = Web.SiteGroups.GetById(info.Value.PrincipalId);
    else
        throw new ApplicationException($"Unsupported PrincipalType - {type}");
    Context.Load(p);
    Context.ExecuteQuery();
    return p;
}

程式噴出「Cannot add a role assignment with empty role definition binding collection / 無法用空角色定義䌓結集合來新增角色指派」錯誤。訊息很明確,理應不難查,但幾乎把所有 Google 到的文章看完也沒看出所以然,最後在 StackExchange SharePoint 版 找到答案:

It appears that CSOM does not like the new RoleDefinitionBindingCollection being instaniated, calling ExecuteQuery(), and then calling ExecuteQuery() again after the RoleDefinitionBindingCollection is added to the folder.

new RoleDefinitionBindingCollection(Context) 之後到被 RoleAssignments.Add() 加入之間不能呼叫 Context.ExecuteQuery()! 我在 ResolvePrincipal() 方法中呼叫了兩次。故要修正這個問題,方法有二:

// 解析函式(ExecuteQuery())移到 new RoleDefinitionBindingCollection() 之前
var principal = ResolvePrincipal("Domain\\Account");

var rdbc = new RoleDefinitionBindingCollection(Context);
rdbc.Add(Web.RoleDefinitions.GetByType(RoleType.Reader));
list.RoleAssignments.Add(principal, rdlc);
Context.ExecuteQuery();

或用 Collection Initializer 寫成一行,放在 ResolvePrincipal() 之後:

list.RoleAssignments.Add(ResolvePrincipal("Domain\\Account"), 
    new RoleDefinitionBindingCollection(Context) {
        Web.RoleDefinitions.GetByType(RoleType.Reader)
    });
Context.ExecuteQuery();


Comments

Be the first to post a comment

Post a comment