user2030504
user2030504

Reputation: 35

Azure AD Graph client library batch processing

Could some one tell me whether I can use the batch processing to add group memberships?

if yes can you please give me an example

thanks in advance

kind regards,

Snegha

Upvotes: 1

Views: 1769

Answers (1)

Thomas
Thomas

Reputation: 29791

According to the documentation, Graph API support batch processing. The Microsoft Azure Active Directory Client support batch processing.

You can find a lot of samples to use the Azure AD Graph API here :

Especially you have a full sample on most of the actions that you can perform with the Graph API here :

Unfortunately batch processing is not working for navigation properties or at least I did not find a way to make it work...

So let's have a look at the documentation.

Graph API support for OData batch requests:

  • A query is a single query or function invocation.
  • A change set is a group of one or more insert, update, or delete operations, action invocations, or service invocations.
  • A batch is a container of operations, including one or more change sets and query operations.

The Graph API supports a subset of the functionality defined by the OData specification:

  • A single batch can contain a maximum of five queries and/or change sets combined.
  • A change set can contain a maximum of one source object modification and up to 20 add-link and delete-link operations combined. All operations in the change set must be on a single source entity.

Here is the batch request syntax :

https://graph.windows.net/TenantName/$batch?api-version=1.6

A batch request is sent to the server with a single POST directive.

The payload is a multi-part MIME message containing the batch and its constituent queries and change sets. The payload includes two types of MIME boundaries:

  • A batch boundary separates each query and/or change set in the batch.
  • A change set boundary separates individual operations within a change set.

An individual request within a change set is identical to a request made when that operation is called by itself. (here is a sample request)

You can find here the full sample code : azure-active-directory-batchprocessing So Basically, you need to obtain the authentication token:

var authority = "https://login.microsoftonline.com/mytenantName.onmicrosoft.com";
var resource = "https://graph.windows.net/";
var clientId = "ClientId of the application in the Azure Active Directory";
var clientSecret = "ClientSecret of the application in the Azure Active Directory";

var token = new AuthenticationContext(authority, false).AcquireToken(resource,
        new ClientCredential(clientId, clientSecret)).AccessToken;

In your question you'd like to add member to a group (see Graph API Documentation on groups):

// Get the objectId of the group
var groupId = ...

// Get the member ids you'd like to add to the group
var memberIds = ...

Here is the code to add members to a group:

private static async Task AddMemberToGroup(string token, string groupId, IList<string> memberIds)
{
    if (memberIds.Count > 100)
    {
        // A batch can contain up to 5 changesets. Each changeset can contain up to 20 operations.
        throw new InvalidOperationException("Cannot send more than 100 operation in an batch");
    }

    var batch = new BatchRequest("https://graph.windows.net/MyTenantName.onmicrosoft.com");

    // A changeset can contain up to 20 operations
    var takeCount = 20;
    var skipCount = 0;
    var take = memberIds.Skip(skipCount).Take(takeCount).ToList();
    while (take.Count > 0)
    {
        AddChangeset(batch, groupId, take);
        skipCount += takeCount;
        take = memberIds.Skip(skipCount).Take(takeCount).ToList();
    }

    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
        var response = await client.SendAsync(batch.Request);
    }
}

private static void AddChangeset(BatchRequest batch, string groupId, IEnumerable<string> memberIds)
{
    var changeset = batch.AddChangeSet();
    foreach (var memberId in memberIds)
    {
        // Create the HttpRequest to add a member to a group
        var request = AddMemberToGroupRequest(groupId, memberId);

        // Add the operation to the changeset
        changeset.AddOperation(request);
    }
}

private static HttpRequestMessage AddMemberToGroupRequest(string groupId, string memberId)
{
    // Create a request to add a member to a group
    var request = new HttpRequestMessage(HttpMethod.Post,
        $"https://graph.windows.net/MyTenantName.onmicrosoft.com/groups/{groupId}/$links/members?api-version=1.6");

    // Create the body of the request
    var jsonBody =
        JsonConvert.SerializeObject(new DirectoryObject($"https://graph.windows.net/MyTenantName.onmicrosoft.com/directoryObjects/{memberId}"));

    // Set the content
    request.Content = new StringContent(jsonBody, Encoding.UTF8, "application/json");

    // Return the request
    return request;
}

public class BatchRequest
{
    private readonly MultipartContent _batchContent;

    public BatchRequest(string tenantUrl)
    {
        // Create the batch request
        Request = new HttpRequestMessage(HttpMethod.Post,
            $"{tenantUrl}/$batch?api-version=1.6");

        // Initializes the batch content
        _batchContent = new MultipartContent("mixed", "batch_" + Guid.NewGuid());
        Request.Content = _batchContent;
    }

    public HttpRequestMessage Request { get; }

    public ChangeSet AddChangeSet()
    {
        // Create a new changeset
        var changeSet = new ChangeSet();

        // Add the content of the changeset to the batch
        _batchContent.Add(changeSet.Content);

        // return the changeset
        return changeSet;
    }

    public HttpMessageContent CreateOperation(HttpRequestMessage request)
    {
        var content = new HttpMessageContent(request);
        content.Headers.ContentType = new MediaTypeHeaderValue("application/http");
        content.Headers.Add("Content-Transfer-Encoding", "binary");
        return content;
    }
}

public class ChangeSet
{
    public ChangeSet()
    {
        Content = new MultipartContent("mixed", "changeset_" + Guid.NewGuid());
    }

    public MultipartContent Content { get; }

    public void AddOperation(HttpRequestMessage request)
    {
        var operationContent = new HttpMessageContent(request);
        operationContent.Headers.ContentType = new MediaTypeHeaderValue("application/http");
        operationContent.Headers.Add("Content-Transfer-Encoding", "binary");
        Content.Add(operationContent);
    }
}

public class DirectoryObject
{
    public DirectoryObject(string url)
    {
        this.url = url;
    }
        public string url { get; }
}

Upvotes: 2

Related Questions