Microsoft Graph API: C# / Filtering / Pagination

THIS BLOG MAY CONTAIN AFFILIATE LINKS, MEANING I GET A COMMISSION IF YOU DECIDE TO MAKE A PURCHASE THROUGH MY LINKS, AT NO COST TO YOU. THIS HELPS ME KEEP RUNNING THIS BLOG. THANK YOU!

Microsoft Graph API is a convenient way to query Microsoft Azure service resources. Recently, I have finished working on the SSO authentication project, which is based on ASP.NET Core and Azure AD B2C.

So, with this project, I’ve created the ability for users to sign-up, login from many different applications (SSO), user assignment to groups, and many other things. To achieve all that, one of the things that I had to implement was the Microsoft Graph API client. So with this article, I wanted to share a couple of thoughts and techniques that were necessary for me, and maybe it will help you with your project.

There are a couple of ways of how you can write the Microsoft Graph API client.

For instance, you can use Microsoft Graph Explorer, you can also write a RESTful API client or use the nuget package Microsoft.Graph. Some people tend to write their own RESTful API clients instead when there’s a RESTful service available. Most of the time, I do that as well, however, in this case, it was easier to use the nuget package that had all the functionality wrapped up.

It had much more than I need to be fair. Maybe that’s the reason why I shouldn’t have used it. Or maybe in the future, I will require the rest of it. You never know. Oh well. There’s no perfection in programming, is it?

So, how do you query Microsoft Graph API?

Let’s get into it.

Microsoft Graph Explorer

Microsoft Graph Explorer is like a sandbox that you play with to test requests and responses to the Microsoft Graph. It’s worth the try, especially if you have never worked with the Microsoft Graph API before if you want to understand what queries you can run, and what responses to expect back. Of course, you should read the documentation at the same time to find out what API endpoints are available and how to consume them.

There is some sample data available, so you don’t have to sign-up or login to start with. Here’s how the Microsoft Graph Explorer looks like. I’m querying the Users endpoint.

microsoft graph explorer

You have probably noticed that the responses are based on some standard. If you didn’t know, it’s called the OData. If you’re curious to thoroughly understand it, you can read the documentation here. Have fun!

back to menu ↑

Microsoft Graph API: RESTful client

The second option of implementing Microsoft Graph API client is to write the RESTful client. This means you will need to write the client request authentication and endpoint querying yourself. Although it’s easy to implement, I did not choose this path as I prefer using wrappers when they are available and created by the manufacturer itself. If you can’t, for some reason, feel free to implement the RESTful client yourself.

Microsoft has done quite a good job on the documentation, and it will be your good friend. However, sometimes, I found that the documentation wasn’t quite accurate.

Anyway, in this documentation, along with sample queries, you’ll find all the permissions that your application needs to query one or another endpoint, so you’ll need to assign your application corresponding permissions via the Azure Portal.

Remember: these endpoints will be called by your application, which needs to be registered in the Azure AD B2C. Also, this is where you’ll need to give all the permissions as well.

Filtering using Graph API RESTful service

Here’s an example on how you can filter data by the displayName:

https://graph.microsoft.com/v1.0/users?$select=displayName&$filter=startswith(displayName, 'Conf')

Pagination using RESTful service

Pagination using the RESTful service is easy as making the following request:

https://graph.microsoft.com/v1.0/users?$top=5

You’ll see the NextLink field in the response, so you can you its value to fetch the next page.

restful pagination
back to menu ↑

Microsoft Graph API: C# (.NET Core) client

Using pre-baked client libraries is a lot quicker than writing your own RESTful client, that is obvious but it’s not always a better choice. I tend to write things myself, rather than using tons of external libraries. In this case, the nuget package, Microsoft.Graph, is provided by Microsoft, and is recently updated, so why not use it.

By the way, you’ll also need another package, called Microsoft.Graph.Auth. This one is needed for acquiring access tokens for your Microsoft Graph API client.

In my project, I’ve created a factory service class that produces the instance of IGraphServiceClient, which comes from Microsoft.Graph nuget package. More or less, my factory class looks like this:

public IGraphServiceClient Create()
{
    if (configuration == null)
    {
        throw new ArgumentNullException($"{configuration} cannot be null.");
    }

    GraphServiceClient graphClient;

    try
    {
        // Initiate client application
        var confidentialClientApplication = ConfidentialClientApplicationBuilder
            .Create(configuration.ClientId)
            .WithTenantId(configuration.TenantId)
            .WithClientSecret(configuration.ClientSecret)
            .Build();

        // Create the auth provider
        var authProvider = new ClientCredentialProvider(confidentialClientApplication);

        // Create Graph Service Client
        graphClient = new GraphServiceClient(authProvider);
    }
    catch (ServiceException ex)
    {
        throw new GraphApiClientException(
            HttpStatusCode.BadRequest,
            $"Could not create a Graph Service Client: {ex.Message}");
    }

    // Return
    return graphClient;
}

As you can see, to create an instance of the IGraphServiceClient, you’ll need to have the Client Id (ApplicationId), Tenant Id (the unique identifier), and the Client Secret. This is all the basic information you can easily get from your Azure AD B2C tenant.

Now that you have the Graph API client instance, you can start querying the Graph API. The rest of the examples can be found in the documentation.

var graphServiceClient = graphServiceClientFactory.Create();

var azureUsers = await GraphServiceClient
        .Users
        .Request()
        .Select(x => new
        {
            x.Id,
            x.DisplayName,
            x.GivenName,
            x.Surname,
            x.UserPrincipalName,
            x.AccountEnabled,
            x.Identities,
            x.BusinessPhones,
            x.JobTitle,
            x.MobilePhone,
            x.OfficeLocation,
            x.PreferredLanguage,
            x.Mail
        })
        .GetAsync();

Microsoft Graph API filter example with C#

Filtering is easy, all you have to do is to pass the filter string to the Filter method:

var azureUsers = await GraphServiceClient
        .Users
        .Request()
        .Filter(filterString)
        .Select(x => new
        {
            x.Id,
            x.DisplayName,
            x.GivenName,
            x.Surname,
            x.UserPrincipalName,
            x.AccountEnabled,
            x.Identities,
            x.BusinessPhones,
            x.JobTitle,
            x.MobilePhone,
            x.OfficeLocation,
            x.PreferredLanguage,
            x.Mail
        })
        .GetAsync();

The filterString can be something like that:

var filterString = $"startswith(givenName, '{firstName}')";
var filterString = $"startswith(displayName, '{displayName}')";

Or you can combine multiple filters like that:

var filterString = $"startswith(givenName, '{firstName}') and startswith(surname, '{lastName}')";

Filtering by email is as easy as this:

var filterString = $"Identities/any(id:id/Issuer eq '{TenantName}' and id/IssuerAssignedId eq '{emailAddress}')";

Make sure you have all the necessary fields included in the .Select() method. I had filtering issues because of that.

At the time of writing this article, Microsoft Graph API did not support the Contains operator, which would have been useful. Hope they will add it later at some point.

Microsoft Graph API: Paging with C#

Pagination is also easy, unfortunately, not all endpoints support the pagination. You have to pass the parameter of type List<QueryOption> to the .Request() method. By the way, the pagination is forward-only. You can’t move through pages backward.

When using the $top operator, in every response object, you’ll have the SkipToken field if there are more records left on the next page. Then, you need to pass that SkipToken in your next request to fetch the next page. This way you do the pagination. With the code snippet below we are filtering and paginating the Users data. For the other types of resources, the same thing would apply.

public async Task<AzureUserDto> GetUsersPage(int pageSize, string skipToken)
{
    var filterString = $"startswith(givenName, '{firstName}')";

    var queryOptions = new List<QueryOption>
    {
        new QueryOption("$top", pageSize)
    };

    if (!string.IsNullOrEmpty(skipToken))
    {
        queryOptions.Add(new QueryOption("$skiptoken", skipToken));
    }

    var azureUsers = await GraphServiceClient.Users
            .Request(queryOptions)
            .Filter(filterString)
            .Select(x => new
            {
                x.Id,
                x.DisplayName,
                x.GivenName,
                x.Surname,
                x.UserPrincipalName,
                x.AccountEnabled,
                x.Identities,
                x.BusinessPhones,
                x.JobTitle,
                x.MobilePhone,
                x.OfficeLocation,
                x.PreferredLanguage,
                x.Mail
            })
            .GetAsync();

    // Get SkipToken, if exists
    var skipToken = azureUsers
        .NextPageRequest?
        .QueryOptions?
        .FirstOrDefault(
            x => string.Equals("$skiptoken", x.Name, StringComparison.InvariantCultureIgnoreCase))?
        .Value;

    var azureUserDto = new AzureUserDto
    {
        // Map the azureUsers to AzureUsersDto or something similar and return
        // don't forget to include the SkipToken
    };

    return azureUsers;
}

As you can see, the pagination is fairly simple, hope all makes sense.

back to menu ↑

Microsoft Graph API – Learning more

If you are interested in learning more about the Microsoft Graph API and how to use it, I’d highly recommend these LinkedIn Learning courses:

azure for developers

Happy pagination and filtering!