Pnp-sites-core: UnifiedGroupsUtility.CreateUnifiedGroup: set group's owners and members in single API call to avoid "Resource provisioning is in progress. Please try again" error

Created on 22 Nov 2018  路  8Comments  路  Source: pnp/PnP-Sites-Core

Category

[ ] Bug
[ x] Enhancement

Environment

[ x] Office 365 / SharePoint Online
[ ] SharePoint 2016
[ ] SharePoint 2013

Expected or Desired Behavior

When you use UnifiedGroupsUtility.CreateUnifiedGroup for creating groups you may face with the following error:

{
"error": {
"code": "ResourceNotFound",
"message": "Resource provisioning is in progress. Please try again.",
"innerError": {
"request-id": "...",
"date": "..."
}
}
}

This issue is reported here: After office 365 group is created, the group site provisioning is pending. Investigation showed that it is caused by the way how groups are created: at first group is created without owners/members and then owners and members are added using UpdateOwners/UpdateMembers methods with separate API calls. When we created support ticket in MS we got the following response of why we should not use PnP solution:

"The PnP solution is not suggested because it specifically does not pass the owners to the Graph API when creating a group. If you first create the group and then add the owners then the guidelines are not being followed. The scenario is supported as long as the time the group is created at least one owner is provided."

In order to create groups with owners/members with single API call REST may be used with OData binding syntax (see Create a Group in Microsoft Graph API with a Owner):

  "[email protected]": [
    "https://graph.microsoft.com/v1.0/users/{id1}"
  ],
  "[email protected]": [
    "https://graph.microsoft.com/v1.0/users/{id1}",
    "https://graph.microsoft.com/v1.0/users/{id2}"
  ]

This solution also can be used with Graph API .Net client library. We need to create new class which extends Group class:

public class GroupExtended : Group
{
    [JsonProperty("[email protected]", NullValueHandling = NullValueHandling.Ignore)]
    public string[] OwnersODataBind { get; set; }
    [JsonProperty("[email protected]", NullValueHandling = NullValueHandling.Ignore)]
    public string[] MembersODataBind { get; set; }
}

and then add groups with owners and members with single API call like that:

var newGroup = new GroupExtended
{
    DisplayName = displayName,
    Description = description,
    MailNickname = mailNickname,
    MailEnabled = true,
    SecurityEnabled = false,
    Visibility = isPrivate == true ? "Private" : "Public",
    GroupTypes = new List<string> { "Unified" }
};

if (owners != null && owners.Length > 0)
{
    var users = GetUsers(graphClient, owners);
    if (users != null)
    {
        newGroup.OwnersODataBind = users.Select(u => string.Format("https://graph.microsoft.com/v1.0/users/{0}", u.Id)).ToArray();
    }
}

if (members != null && members.Length > 0)
{
    var users = GetUsers(graphClient, members);
    if (users != null)
    {
        newGroup.MembersODataBind = users.Select(u => string.Format("https://graph.microsoft.com/v1.0/users/{0}", u.Id)).ToArray();
    }
}

await graphClient.Groups.Request().AddAsync(newGroup);
...

private static List<User> GetUsers(GraphServiceClient graphClient, string[] owners)
{
 if (owners == null)
 {
  return new List<User>();
 }
 var result = Task.Run(async () =>
 {
  var usersResult = new List<User>();
  var users = await graphClient.Users.Request().GetAsync();
  while (users.Count > 0)
  {
   foreach (var u in users)
   {
    if (owners.Any(o => u.UserPrincipalName.ToLower().Contains(o.ToLower())))
    {
     usersResult.Add(u);
    }
   }

   if (users.NextPageRequest != null)
   {
    users = await users.NextPageRequest.GetAsync();
   }
   else
   {
    break;
   }
  }

  return usersResult;
 }).GetAwaiter().GetResult();
 return result;
}

As result group will be created with owners/members with single API call and will allow to avoid "Resource provisioning is in progress. Please try again" error.

Most helpful comment

@wobba yes, direct query worked - will do, opening up a new issue. Thanks!

All 8 comments

@sadomovalex Feel free to create a PR for this one, and have been thinking about this myself as well.

@sadomovalex and @wobba - if you guys don't mind, can i pick this up ? I do have the time to test and debug this :) Also, now that teams API is in GA, can i add the ability to provision MS Teams team associated with the group after group has been provisioned PR 1628 ? It will be optional and will be false by default, something like below. I will create the necessary methods for that implementation as well.

CreateUnifiedGroup(string displayName, string description, string mailNickname, string accessToken, string[] owners = null, string[] members = null, Stream groupLogo = null, bool isPrivate = false, bool provisionTeam = false , int retryCount = 10, int delay = 500)

Let me know your thoughts on this :) !
Cheers,
Gautam

@erwinvanhunen @PaoloPia you guys ok with adding Teams support? I say it's ok until we rework things.

Hello, I've created PR for this feature: https://github.com/SharePoint/PnP-Sites-Core/pull/1991.

@gautamdsheth and @sadomovalex I will try to get this processed over the weekend, and pick and choose from both PR's :)

Hello - I'm trying this feature out but am getting an error when I call CreateUnifiedGroup with a list of owners. I set up a C# string array:

string[] ownerNames = new string[2];
ownerNames[0] = "[email protected]";
ownerNames[1] = "[email protected]";

var group = UnifiedGroupsUtulity.CreateUnifiedGroup("Group1", "Descr", "Group1", accesstoken, owners: ownerNames)

which comes back with the exception:
"Code: Request_BadRequestrnMessage: The value of 'odata.bind' property annotation is an empty array. The 'odata.bind' property annotation must have a non-empty array as its value.rnrnInner errorrn"

The users I'm supplying are valid users.

Works great otherwise - creating the team, setting public/private, and setting the site logo. Much appreciated!

Thanks!
Steve

@smushkat One, if you query graph directly and filter with user Principal Name does that work? Two, please open a new issue instead of commenting on a closed non-related issue so we can track issues more easily.

@wobba yes, direct query worked - will do, opening up a new issue. Thanks!

Was this page helpful?
0 / 5 - 0 ratings