Dynamics 365 Integration: Create Dynamics 365 records using Http trigger

Introduction

Integrating Dynamics 365 with Azure Functions provides a powerful way to automate business processes and connect external applications with your CRM system. In this guide, we’ll explore how to create new records in Microsoft Dynamics 365 using an Azure Function App with an HTTP trigger. This approach enables developers to expose lightweight, scalable APIs that can receive data from external systems or web services and push it directly into Dynamics 365 — without the need for complex middleware or plugins.

You’ll learn how to set up an Azure Function, authenticate securely with Dynamics 365, and write C# code that creates contact records via the Dynamics Web API. By the end, you’ll have a working integration that demonstrates how easily Azure Functions can extend Dynamics 365 functionality and streamline data synchronization.

Steps:

  • Open Visual Studio. Create New Project -> Select Azure Function
  • Give Name to Function App Project. Select Function worked to .Net Framework and Function as Http Trigger.
  • Project will be created. Rename Function1.cs to name of your Function.
  • Copy below code and Install required NuGet packages. This code using Http request to Dynamics API create Contacts. We can also use Remote Execution Context method, if call is from Dynamics Webhook or Plugins. Will create separate blog to demonstrate it.
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Poc
{
public static class CreateContact
{
// Azure AD App details (replace with Key Vault values in production)
private static string ClientId = Environment.GetEnvironmentVariable("Client_Id");
private static string ClientSecret = Environment.GetEnvironmentVariable("Client_Secret");
private static string Resource = Environment.GetEnvironmentVariable("Resource_URL");
private static string Authority = Environment.GetEnvironmentVariable("Authority");

[FunctionName("CreateContact")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage req,
TraceWriter log)
{
log.Info("Processing Dynamics 365 contact creation request.");

try
{
var body = await req.Content.ReadAsStringAsync();
var data = JsonConvert.DeserializeObject<JObject>(body);

if (data == null)
return req.CreateResponse(HttpStatusCode.BadRequest, "Invalid JSON body.");

var firstName = data["FirstName"]?.ToString();
var lastName = data["LastName"]?.ToString();
var email = data["Email"]?.ToString();
var phone = data["Phone"]?.ToString();

if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
return req.CreateResponse(HttpStatusCode.BadRequest, "FirstName and LastName are required.");

var accessToken = await GetAccessTokenAsync();

if (string.IsNullOrEmpty(accessToken))
return req.CreateResponse(HttpStatusCode.Unauthorized, "Access token not found.");

var contactId = await CreateContactInCRMAsync(accessToken, firstName, lastName, email, phone);

if (!string.IsNullOrEmpty(contactId))
return req.CreateResponse(HttpStatusCode.OK, $"Contact created successfully. ID: {contactId}");
else
return req.CreateResponse(HttpStatusCode.BadRequest, "Failed to create contact.");
}
catch (Exception ex)
{
log.Error("Error creating contact.", ex);
return req.CreateResponse(HttpStatusCode.InternalServerError, $"Error: {ex.Message}");
}
}

private static async Task<string> GetAccessTokenAsync()
{
var authContext = new AuthenticationContext(Authority);
var credentials = new ClientCredential(ClientId, ClientSecret);
var result = await authContext.AcquireTokenAsync(Resource, credentials);
return result.AccessToken;
}

private static async Task<string> CreateContactInCRMAsync(string accessToken, string firstName, string lastName, string email = null, string phone = null)
{
using (var httpClient = new HttpClient
{
BaseAddress = new Uri(Resource),
Timeout = TimeSpan.FromMinutes(2)
})
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

// Prepare contact data
var contactData = new JObject
{
["firstname"] = firstName,
["lastname"] = lastName
};

if (!string.IsNullOrEmpty(email)) contactData["emailaddress1"] = email;
if (!string.IsNullOrEmpty(phone)) contactData["mobilephone"] = phone;

var postRequest = new HttpRequestMessage(HttpMethod.Post, "api/data/v9.2/contacts")
{
Content = new StringContent(contactData.ToString(), System.Text.Encoding.UTF8, "application/json")
};

var response = await httpClient.SendAsync(postRequest);

if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadAsStringAsync();
throw new Exception($"Failed to create contact: {response.ReasonPhrase} - {error}");
}

// Extract the contact GUID from OData-EntityId header
if (response.Headers.TryGetValues("OData-EntityId", out var values))
{
var entityUri = values.FirstOrDefault();
return entityUri?.Split('(', ')')[1];
}

return null;
}
}
}
}

Note: This code using Http request to Dynamics API create Contacts. We can also use Remote Execution Context method, if call is from Dynamics Webhook or Plugins. Will create separate blog to demonstrate it.

  • Test Locally:
      • Create Environment Variables used in Functions code. To do that, navigate to Environment Variables in Azure Function App and click create.
      • Test live function:

      Leave a Reply

      Up ↑

      Discover more from Customizers

      Subscribe now to keep reading and get access to the full archive.

      Continue reading