microsoft-graph-apimicrosoft-graph-sdksthrottling

Handling throttling Errors with Microsoft Graph SDK C# 5.2x


I'm using the Microsoft Graph SDK for C# to read data from Microsoft Graph. I also utilize the Microsoft Developer Proxy to simulate responses with an HTTP 429 status (TooManyRequests) for testing purposes.

However, upon encountering a 429 status, the SDK's default behavior is to retry the request up to three times. If it still gets a 429 response after the third retry, it throws a System.InvalidOperationException with the message "Too many retries performed." This behavior is evident from the proxy's output.

Here's the relevant code:

var authenticationProvider = new BaseBearerTokenAuthenticationProvider(new TokenProvider(_token));
var graphServiceClient = new GraphServiceClient(authenticationProvider);

var myTeams = await graphServiceClient
    .Me
    .JoinedTeams
    .GetAsync(requestConfiguration => requestConfiguration.QueryParameters.Select = new string[] { "Id" });

And the proxy's output:

 request     GET https://graph.microsoft.com/v1.0/me/joinedTeams?$select=Id
   chaos   ╭ 429 TooManyRequests
           ╰ GET https://graph.microsoft.com/v1.0/me/joinedTeams?$select=Id
...

My question is: How can I override the default behavior of the Microsoft Graph SDK for C# to handle the 429 status code myself? Ideally, I'd like to either adjust the request rate or implement other custom handling when this happens.


Solution

  • You can either pass per-request options to the default http middleware

    var retryHandlerOption = new RetryHandlerOption
    {
        MaxRetry = 7,
        ShouldRetry = (delay,attempt,message) => true
    };
    
    var myTeams = await graphServiceClient
        .Me
        .JoinedTeams
        .GetAsync(requestConfiguration =>
        {
            requestConfiguration.QueryParameters.Select = new string[] { "Id" };
            requestConfiguration.QueryParameters.Options.Add(retryHandlerOption);
        });
    

    Or replace the default RetryHandler with custom implementation

    public class CustomRetryHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // your code
        }
    }
    

    Creating GraphServiceClient with replaced default RetryHandler

    var authenticationProvider = new BaseBearerTokenAuthenticationProvider(new TokenProvider(_token));
    var handlers = GraphClientFactory.CreateDefaultHandlers();
    // dummy replacement
    var retryHandler = handlers.FirstOrDefault(x => x is RetryHandler);
    var index = handlers.IndexOf(retryHandler);
    handlers[index] = new CustomRetryHandler();
    var httpClient = GraphClientFactory.Create(handlers);
    
    var graphServiceClient = new GraphServiceClient(httpClient, authenticationProvider);