Unlocking the Power of Azure Functions in Dynamics 365 Plugins 

A screenshot of a computer Unlocking the Power of Azure Functions in Dynamics 365 Plugins

Table of Contents

Introduction 

In today’s rapidly evolving digital landscape, businesses are constantly looking for ways to streamline processes, enhance automation, and improve overall efficiency Microsoft Dynamics 365, with its robust set of CRM and ERP capabilities, offers a powerful platform for managing customer relationships, sales, and business operations. But what if you could supercharge these capabilities even further? 

This is where Azure Functions come into play. By integrating Azure Functions with Dynamics 365 Plugins, you can extend the platform’s capabilities beyond its native features, enabling highly scalable, event-driven workflows that are cost-effective and efficient. Azure Functions offer a serverless computing solution that allows you to run small pieces of code, or functions, in response to events, without having to worry about infrastructure management. 

In this blog, we’ll explore how to unlock the power of Azure Functions within Dynamics 365 Plugins. We’ll discuss the core benefits of integrating Azure Functions, how it enhances the functionality of Dynamics 365, and provide a step-by-step guide on setting up and utilizing these powerful tools together. Whether you’re new to Dynamics 365 or a seasoned developer, this integration is sure to elevate your solutions. Let’s dive in! 

What is Azure Functions? 

Azure Functions is a serverless compute service offered by Microsoft Azure that enables you to run small pieces of code—known as “functions” in the cloud without having to manage infrastructure. These functions are event-driven, meaning they execute in response to triggers such as HTTP requests, messages from a queue, changes in data, or scheduled tasks. 

The core appeal of Azure Functions lies in its scalability and simplicity. Developers can focus on writing just the code that matters to them, with Azure automatically handling the provisioning, scaling, and maintenance of the compute resources needed to run the functions. This makes it an ideal choice for lightweight, modular services that perform specific tasks—like processing incoming data, integrating external systems, or responding to events in real time. 

Functions can be written in various languages including C#, JavaScript, Python, PowerShell, and Java, and can easily integrate with other Azure services, making them highly flexible and extensible components within a broader cloud architecture. 
 

When to use Azure Functions 

Azure Functions are best suited for scenarios where lightweight, event-driven, and scalable logic is needed without the overhead of managing a full-blown application infrastructure. Here are some common use cases and scenarios where Azure Functions shine: 

Event-Driven Integrations:

When you need to react to specific events—like updates in a Dynamics 365 entity, messages from an Azure Service Bus, or file uploads to Azure Blob Storage—Azure Functions allow you to write concise logic that runs automatically in response. 

Data Processing Tasks:

For processing data streams, transforming input data, or performing calculations in the background (e.g., enriching CRM records or syncing with an external system), Functions provide a cost-effective and scalable approach. 

Microservice Logic Offloading:

If your Dynamics 365 plugin needs to perform logic that is compute-intensive or relies on external services, offloading it to an Azure Function can keep your plugin lightweight and performant. 

Scheduled or Recurring Jobs:

Azure Functions support time-based triggers (CRON expressions), making them ideal for running scheduled maintenance jobs, data cleanup, or regular sync tasks related to your Dynamics 365 environment. 

API Integration and Webhooks:

You can use HTTP-triggered Azure Functions as lightweight APIs to receive or send data from/to external systems or as endpoints for webhooks, enabling real-time integrations. 

Decoupling Complex Business Logic:

In scenarios where plugins become overly complex or hard to maintain, moving some logic to Azure Functions promotes cleaner architecture and separation of concerns. 

Getting Started 

Unlocking the Power of Azure Functions in Dynamics 365 Plugins 

We will be creating a basic Vendor Management app with two main entities, namely Vendor and Vendor Verification Log. The Vendor will add the record with particulars such as Tax Number and Business Registration Number. These fields will then be validated from the mock data available in Azure Function that will verify whether such details exist or not. If yes, the Verification Status will be set as Verified in the Vendor. Similarly, the logs of all the requests executed in the Azure Functions will be kept in another entity named Vendor Verification Log as well.  

Before you begin, ensure you have the following: 

  • An active Azure subscription 
  • Access to a Dynamics 365 instance (Power Platform environment) 
  • Visual Studio 2022 
  • Basic knowledge of C# and the Dynamics 365 plugin architecture 

Creating your first project 

Create a new Azure Function project in Visual Studio 2022 

dashboard showing Creating your first project 

Once created, add a new file inside the project, name it VendorValidator.cs and populate it with the following code:

using Microsoft.Azure.Functions.Worker; 
using Microsoft.Azure.Functions.Worker.Http; 
using Microsoft.Extensions.Logging; 
using System.Net; 
using System.Text.Json; 
namespace VendorValidator 

{ 
public class VendorValidator 

{ 
private readonly ILogger _logger; 
public VendorValidator(ILoggerFactory loggerFactory) 

{ 
_logger = loggerFactory.CreateLogger<VendorValidator>(); 

} 
[Function("VendorValidator")] 

public async Task<HttpResponseData> Run( 

[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req) 

{ 
_logger.LogInformation("Vendor verification request received."); 

var requestBody = await JsonSerializer.DeserializeAsync<VendorRequest>(req.Body); 

var response = req.CreateResponse(HttpStatusCode.OK); 

if (requestBody == null || string.IsNullOrEmpty(requestBody.TaxID) || string.IsNullOrEmpty(requestBody.BusinessRegistrationNumber)) 

{ 
response.StatusCode = HttpStatusCode.BadRequest; 

await response.WriteStringAsync("Invalid request. TaxID and BusinessRegistrationNumber are required."); 

return response; 

} 
var mockVendors = new List<MockVendor> 

{ 

new MockVendor { TaxID = "TX12345", BusinessRegistrationNumber = "BR67890" }, 

new MockVendor { TaxID = "TX99999", BusinessRegistrationNumber = "BR88888" }, 

new MockVendor { TaxID = "TX55555", BusinessRegistrationNumber = "BR55555" } 

}; 
var isValid = mockVendors.Any(v => 

v.TaxID.Equals(requestBody.TaxID, StringComparison.OrdinalIgnoreCase) && 

v.BusinessRegistrationNumber.Equals(requestBody.BusinessRegistrationNumber, StringComparison.OrdinalIgnoreCase) 

); 
if (isValid) 

{ 

var success = new VendorResponse 

{ 
Status = "Verified", 

Message = "Vendor details are verified successfully." 

}; 

await response.WriteAsJsonAsync(success); 

} 

else 

{ 

var failure = new VendorResponse 

{ 

Status = "Failed", 

Message = "Vendor verification failed. Tax ID or Business Registration Number is invalid." 

}; 

response.StatusCode = HttpStatusCode.BadRequest; 

await response.WriteAsJsonAsync(failure); 

} 

return response; 

} 

} 

public class VendorRequest 

{ 

public string TaxID { get; set; } 

public string BusinessRegistrationNumber { get; set; } 

} 
public class VendorResponse 

{ 

public string Status { get; set; } 

public string Message { get; set; } 

} 

public class MockVendor 

{ 

public string TaxID { get; set; } 

public string BusinessRegistrationNumber { get; set; } 

} 

} 
Creating your first project 

Once done, validate the code by building the solution. After success compilation, publish the code to Azure

Create a publish profile through Visual Studio 2022 by filling out the required details. 

Create a publish profile through Visual Studio 2022 by filling out the required details. 

Your Azure function is created successfully. You can verify by going to the Azure portal as well. 

Your Azure function is created successfully. You can verify by going to the Azure portal as well. 

Creating the Dynamics 365 model-driven app 

Now that you have successfully established the Azure Function, it’s time to create the entities that will be used to send and receive the responses. 

A Vendor entity with fields including Vendor Name, Tax ID, Business Reg. Number, Verification Status and Last Verified On. 

Creating the Dynamics 365 model-driven app 

A Vendor Verification Log entity with fields including Name, Vendor (lookup to Vendor entity), Verification Status, Tax ID and Business Reg. Number

Creating the Dynamics 365 model-driven app 

Establishing connection between Azure Function and Dynamics 365 

Create a plugin in the Dynamics 365 environment that runs on the creation of a vendor. Populate the plugin code with the following: 

public class ValidateVendorFromFunction : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var service = factory.CreateOrganizationService(context.UserId);
var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

        try
        {
            tracingService.Trace("Plugin execution started");

            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity entity)
            {
                tracingService.Trace("Target entity found");

                // Only proceed if entity is Vendor
                if (entity.LogicalName != "sam_vendor" && context.Depth > 2)
                {
                    tracingService.Trace("Entity is not Vendor or depth exceeds 2. Exiting...");
                    return;
                }

                string taxId = entity.Contains("sam_taxid") ? entity["sam_taxid"].ToString() : string.Empty;
                string businessRegNumber = entity.Contains("sam_businessregnumber") ? entity["sam_businessregnumber"].ToString() : string.Empty;

                tracingService.Trace($"Tax ID: {taxId}, Business Registration Number: {businessRegNumber}");

                if (string.IsNullOrEmpty(taxId) || string.IsNullOrEmpty(businessRegNumber))
                {
                    tracingService.Trace("Tax ID or Business Registration Number is empty");
                    throw new InvalidPluginExecutionException("Tax ID and Business Registration Number are required for verification.");
                }

                // Call Azure Function
                tracingService.Trace("Calling Azure Function to validate vendor...");
                var result = CallAzureFunction(taxId, businessRegNumber, tracingService).GetAwaiter().GetResult();

                if (result != null)
                {
                    tracingService.Trace("Azure Function returned result");

                    // Update Vendor record
                    Entity vendorToUpdate = new Entity(entity.LogicalName, entity.Id);
                    vendorToUpdate["sam_verificationstatus"] = new OptionSetValue(result.Status == "Verified" ? 918550000 : (result.Status == "Failed" ? 918550001 : 918550002)); // Update verification status
                    vendorToUpdate["sam_lastverifiedon"] = DateTime.UtcNow.Date; // Update last verified date (only date portion)
                    vendorToUpdate["sam_verificationmethod"] = new OptionSetValue(918550000);
                    tracingService.Trace("Updating vendor record...");
                    service.Update(vendorToUpdate);

                    // Create Vendor Verification Log
                    Entity verificationLog = new Entity("sam_vendorverificationlog");
                    verificationLog["sam_name"] = $"Verification for {taxId}";
                    verificationLog["sam_vendor"] = entity.ToEntityReference();
                    verificationLog["sam_verificationstatus"] = new OptionSetValue(result.Status == "Verified" ? 918550000 : (result.Status == "Failed" ? 918550001 : 918550002)); // Set verification status
                    verificationLog["sam_taxid"] = taxId;
                    verificationLog["sam_businessregnumber"] = businessRegNumber;
                    tracingService.Trace("Creating vendor verification log...");
                    service.Create(verificationLog);
                }
                else
                {
                    tracingService.Trace("No result returned from Azure Function.");
                }
            }
            else
            {
                tracingService.Trace("No Target entity found in input parameters.");
            }
        }
        catch (Exception ex)
        {
            tracingService.Trace($"VendorVerificationPlugin Error: {ex.Message}");
            throw new InvalidPluginExecutionException("An error occurred in Vendor Verification Plugin.", ex);
        }
    }

    private async Task<FunctionResult> CallAzureFunction(string taxId, string businessRegNumber, ITracingService tracingService)
    {
        using (var client = new HttpClient())
        {
            var functionUrl = "https://dynamics-365-fa.azurewebsites.net/api/VendorValidator?code=ADD-YOUR-AZURE-FUNCTION-CODE";

            var payload = new
            {
                TaxID = taxId,
                BusinessRegistrationNumber = businessRegNumber
            };

            var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json");

            tracingService.Trace("Sending request to Azure Function...");

            try
            {
                var response = await client.PostAsync(functionUrl, content);
                string responseContent = await response.Content.ReadAsStringAsync();

                tracingService.Trace($"Azure Function Response: {responseContent}");

                if (response.IsSuccessStatusCode)
                {
                    var result = JsonConvert.DeserializeObject<FunctionResult>(responseContent);
                    return result;
                }
                else
                {
                    tracingService.Trace("Azure Function returned an error response.");
                    var errorResult = JsonConvert.DeserializeObject<FunctionResult>(responseContent);
                    return new FunctionResult
                    {
                        Status = "Failed",
                        Message = errorResult?.Message ?? "Vendor verification failed."
                    };
                }
            }
            catch (Exception ex)
            {
                tracingService.Trace($"Error calling Azure Function: {ex.Message}");
                throw new InvalidPluginExecutionException("Error calling Azure Function.", ex);
            }
        }
    }

    public class FunctionResult
    {
        public string Status { get; set; }
        public string Message { get; set; }
    }
}

Make sure that your plugin runs on Post Operation. Additionally, you can retrieve the Azure Function key from the Azure Portal’s Function app dashboard

runs on Post Operation

When I give the wrong Tax ID and Business Registration Number (which is not present in the mock data list), following action occurs

Unlocking the Power of Azure Functions in Dynamics 365 Plugins 

Similarly, when the correct information is provided, the Function responds the following:

Conclusion 

Azure Functions unlock a new level of flexibility and scalability for extending Dynamics 365 beyond traditional plugin boundaries. By offloading complex, long-running, or external system interactions to serverless functions, developers can build more modular, maintainable, and performant solutions. 

Whether you’re looking to simplify integrations, reduce load on your CRM instance, or embrace event-driven architecture, Azure Functions provide a modern, cost-effective approach that complements Dynamics 365 perfectly. As cloud-native, event-based development becomes the norm, now is the ideal time to start incorporating Azure Functions into your D365 strategy. 

Start small—perhaps with a single function to handle a time-consuming API call—and gradually expand your usage. The combination of Dynamics 365 and Azure Functions offers a powerful toolkit to meet today’s integration and automation challenges head-on. 

Readmore : mastering workflow automation with microsoft power automate

FAQ’s

Can Azure Functions completely replace Dynamics 365 plugins?

No. Azure Functions are best used in conjunction with plugins—not as a replacement. Plugins are ideal for synchronous, in-platform logic, while Azure Functions excel at handling asynchronous, external, or long-running operations.

How do I securely call an Azure Function from a Dynamics 365 plugin?

Use Function Keys, Azure Active Directory (AAD) authentication, or expose the function via Azure API Management with proper security policies. Avoid using public endpoints without some form of authentication.

What are the performance implications of using Azure Functions with plugins?

Since Azure Functions are typically called asynchronously, they can offload heavy processing and reduce the load on the Dynamics 365 server. However, introducing external HTTP calls can increase latency if used within synchronous plugin execution contexts.

What triggers can be used with Azure Functions for Dynamics 365 scenarios?

While HTTP triggers are most common, you can also use Webhooks, Service Bus, Event Grid, or Queue triggers—especially for building event-driven or queued architectures around Dataverse activities.

Do I need premium connectors or licenses to use Azure Functions with Dynamics 365?

No, Azure Functions themselves do not require premium connectors. However, if your solution interacts with other services (e.g., Azure Service Bus, Logic Apps, or Power Automate), licensing requirements may apply based on the specific services used.

Picture of SkySoft Connections

SkySoft Connections

SkySoft Connections is a software solution company that was established in 2016. Our quality services begin with experience and end with dedication. Our directors have more than 15 years of IT experience to handle various projects successfully. Our dedicated teams are available to help our clients streamline their business processes, enhance their customer support, automate their day-to-day tasks, and provide software solutions tailored to their specific needs. We are experts in Dynamics 365 and Power Platform services, whether you need Dynamics 365 implementation, customization, integration, data migration, training, or ongoing support.

Conatct us