C# Code · Dynamics 365 WEB API

Dynamics CRM Web API C# Auto Refresh Access Token while performing API request to CDS

As we know to connect to CDS WEB API from C# application we first need to acquire access token and validity of that is 1 hour. While performing small number of requests this will be sufficient. However when we want to run long running process we will get HTTP 400 error when token expires.

To overcome this issue, The recommended approach is to implement a class derived from DelegatingHandler which will be passed to the constructor of the HttpClient. This handler will allow you to override the HttpClient.SendAsync method so that ADAL will call the AcquireToken method with each request sent by the http client.

Step – 1

Create new class in your project and add below code.

/// <summary>  
  ///Custom HTTP message handler that uses OAuth authentication through ADAL.  
  /// </summary>  
  class OAuthMessageHandler : DelegatingHandler
  {
    private UserCredential _credential;
    private AuthenticationContext _authContext = 
      new AuthenticationContext("https://login.microsoftonline.com/common", false);
    private string _clientId;
    private string _serviceUrl;

    public OAuthMessageHandler(string serviceUrl, string clientId, string userName, string password,
            HttpMessageHandler innerHandler)
        : base(innerHandler)
    {
      _credential = new UserCredential(userName, password);
      _clientId = clientId;
      _serviceUrl = serviceUrl;
    }

    protected override Task<HttpResponseMessage> SendAsync(
             HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
      try
      {
        request.Headers.Authorization =
        new AuthenticationHeaderValue("Bearer", _authContext.AcquireToken(_serviceUrl, _clientId, _credential).AccessToken);
      }
      catch (Exception ex)
      {
        throw ex;
      }      
      return base.SendAsync(request, cancellationToken);
    }
  }

Step – 2

Now change your HttpClient to use HttpMessageHandler so that for every request to CDS it will acquire access token.

Using this OAuthMessageHandler class, the simple program shown above would look like this, with some additional error handling included:

class SampleProgram
{
    private static string serviceUrl = "https://yourorg.crm.dynamics.com"; 
    private static string clientId = "51f81489-12ee-4a9e-aaae-a2591f45987d"; 
    private static string userName = "you@yourorg.onmicrosoft.com";
    private static string password = "yourpassword";

    static void Main(string[] args)
    {
       HttpMessageHandler messageHandler;

      try
      {
        messageHandler = new OAuthMessageHandler(serviceUrl, clientId, userName, password,
                         new HttpClientHandler());
        //Create an HTTP client to send a request message to the CRM Web service.  
        using (HttpClient client = new HttpClient(messageHandler))
        {
          //Specify the Web API address of the service and the period of time each request   
          // has to execute.  
          client.BaseAddress = new Uri(serviceUrl);
          client.Timeout = new TimeSpan(0, 2, 0);  //2 minutes
          client.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
          client.DefaultRequestHeaders.Add("OData-Version", "4.0");
          client.DefaultRequestHeaders.Accept.Add(
              new MediaTypeWithQualityHeaderValue("application/json"));

          //Send the WhoAmI request to the Web API using a GET request.   
          var response = client.GetAsync("api/data/v9.0/WhoAmI",
                  HttpCompletionOption.ResponseHeadersRead).Result;
          if (response.IsSuccessStatusCode)
          {
            //Get the response content and parse it.  
            JObject body = JObject.Parse(response.Content.ReadAsStringAsync().Result);
            Guid userId = (Guid)body["UserId"];
            Console.WriteLine("Your system user ID is: {0}", userId);
          }
          else
          {
            throw new Exception(response.ReasonPhrase);
          }
        }
      }
      catch (Exception ex)
      {
        DisplayException(ex);
      }
    }

    /// <summary> Displays exception information to the console. </summary>  
    /// <param name="ex">The exception to output</param>  
    private static void DisplayException(Exception ex)
    {
      Console.WriteLine("The application terminated with an error.");
      Console.WriteLine(ex.Message);
      while (ex.InnerException != null)
      {
        Console.WriteLine("\t* {0}", ex.InnerException.Message);
        ex = ex.InnerException;
      }
    }
}

If you are using Client ID and Client Secret for authentication then modify your code as below.

class OAuthMessageHandler : DelegatingHandler
    {
        private ClientCredential _credential;
        private AuthenticationContext _authContext =
          new AuthenticationContext("https://login.microsoftonline.com/common", false);
        private string _serviceUrl;

        public OAuthMessageHandler(string serviceUrl, string clientId, string secret, HttpMessageHandler innerHandler)
            : base(innerHandler)
        {
            _credential = new ClientCredential(clientId, secret);
            _serviceUrl = serviceUrl;
        }

        protected override Task<HttpResponseMessage> SendAsync(
                 HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            try
            {
                request.Headers.Authorization =
                new AuthenticationHeaderValue("Bearer", _authContext.AcquireToken(_serviceUrl, _credential).AccessToken);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return base.SendAsync(request, cancellationToken);
        }
    }

Hope this helps!

2 thoughts on “Dynamics CRM Web API C# Auto Refresh Access Token while performing API request to CDS

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s