Blog, Development

Migrate Azure Functions from .Net Framework (v1) to .Net Core (v3)

As a developer, I built multiple integrations with Dataverse using Azure Functions. Historically, XrmTooling (the firstparty library to perform operations with Dataverse) is .Net Framework based, so to leverage this Package I had to use V1 Azure Functions.

Microsoft released .Net Core version of the tooling for a public preview so at the moment it’s not supported to use it in production scenarios. In this post, I will provide step-by-step instructions for migrating existing v1 functions to v3.

Here is how your Azure Function can look like:

using System.Net;
using System.Net.Http;
using System.Configuration;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Xrm.Tooling.Connector;

namespace AB.Xrm.Azure
{
    public static class AzureOperationHandler
    {
        [FunctionName("AzureOperationHandler")]
        public static async Task<HttpResponseMessage> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, 
            TraceWriter log)
        {
            //...some preceding operations here

            var dataverseConnectionString = ConfigurationManager.AppSettings["DataverseConnectionString"];

            var serviceClient = new CrmServiceClient(dataverseConnectionString);

            if (!serviceClient.IsReady)
            {
                log.Error(serviceClient.LastCrmError);
                return req.CreateErrorResponse(HttpStatusCode.InternalServerError, serviceClient.LastCrmError);
            }

            //some operations that use serviceClient object here

            return req.CreateResponse(HttpStatusCode.OK, "Operation Completed");
        }
    }
}

Update the project file – the easiest way is clicking with the right of a mouse on your Azure Function project file and choosing “Edit project file” and editing “TargetFramework” and “AzureFunctionsVersion” properties of the project:

 

Change of settings will break your project. Here is the approximate list of changes you will have to perform to fix it.

  • NuGet Package references:
    • Update “Microsoft.Net.Sdk.Functions” to version 3.0.13.
    • Drop “Microsoft.CrmSdk.XrmTooling.CoreAssembly” package and install the latest “Microsoft.PowerPlatform.Dataverse.Client”
  • Assemblies:
    • Drop the reference to System.Configuration
    • Drop the reference to Microsoft.CSharp
  • Code:
    • Drop all usings of Microsoft.Xrm.Tooling.* namespaces
    • Replace CrmServiceClient with ServiceClient
    • Replace LastCrmError with LastError and LastCrmException with LastException
    • Change the way your code accesses configuration settings (like connection strings – use Environment.GetEnvironmentVariable instead of ConfigurationManager.AppSettings)
    • Replace obsolete TraceWriter with ILogger
    • For Http-triggered functions change call result from HttpResponseMessage to IActionResult and replace the result of the call with OkResult/OkObjectResult/BadRequestErrorMessageResult/InternalServerErrorResult depending on your scenario.

After all the mentioned code changes Azure Function can look like this:

using System;
using System.Net.Http;
using System.Web.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Microsoft.PowerPlatform.Dataverse.Client;

namespace AB.Xrm.Azure
{
    public static class AzureOperationHandler
    {
        [FunctionName("AzureOperationHandler")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, 
            ILogger log)
        {
            //...some preceding operations here

            var dataverseConnectionString = Environment.GetEnvironmentVariable("DataverseConnectionString");

            var serviceClient = new ServiceClient(dataverseConnectionString);

            if (!serviceClient.IsReady)
            {
                log.LogError(serviceClient.LastError);
                return new BadRequestErrorMessageResult(serviceClient.LastError);
            }

            //some operations that use serviceClient object here

            return new OkObjectResult("Operation Completed");
        }
    }
}

I had to perform a few additional changes to the code in order to fix it (mainly related to fixing namespaces) but there was nothing super tricky to make Azure Function work again.

3 Comments

  1. Do you think it’s time to start doing this for all Azure Functions? I’m not sure on the timelines because of the 2 unknowns. 1. When will v1 Functions be deprecated, and 2. when will the .Net Core version of tooling be out of preview? At the moment I feel like we are in a limbo state between the two.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.