Skip to main content

Notifications

Announcements

No record found.

Dynamics 365 Community / Blogs / Learn with Subs / Azure functions to interact...

Azure functions to interact with D365F&O using bearer tokens

Subhad365 Profile Picture Subhad365 7 User Group Leader



This article talks about performing CRUD operations, using trigger based Azure Functions, that can generate tokens and further posts the payload to D365FnO for processing. Broadly, for ease of understanding, I have split up the entire design into 


a. Token generation logic: we are going to generate a short lived bearer-token, and pass it on to FnO for further executions. 

b. Storing/retrieving Azure App based parameters: this is most tricky part of the solution. Typically, all developers have a habit of storing environment variables at configuration level. But unfortunately, we cannot take the configuration to server, during the deployment. We can see what all the choices could we have here.   

c. Posting the payload to D365FnO for furtherance. 

Additionally (not shown here), you can include logic to validate the incoming data of various fields' data given, to take necessary action, before committing to D365FnO.

So, buckle your seatbelt Dorothy, 'cause Kansas is saying bye-bye 😀

For ease of understanding, let me cover the 'point-b' first -- as 'point a' has dependencies on it. 

Assumptions:

a. We are referring to a recurring integration URL in D365FnO, which has already been created/ready.

b. We are using here an XML payload -- just as an example.


Storing/retrieving Azure App based parameters

We all know to obtain a token from Windows Live URL, we need these mandatory parameters: Client Id, Client secret, grant type, scope (D365FnO URL) and of course, not to mention, the window live token URL. We can achieve this directly, by keeping the values of the parameters openly in the code:




However, its never recommended to write these variables openly in the code. Instead, what we can do is:

1. We can keep them in Azure Key Vault by defining them as secrets:





2. Defining the secrets like this, can let you access them, by the following process:


3. In your function app project, define a new class called: KeyVaultManager. Go back to Azure Portal >> in your Azure function app which you will use to deploy your function >> Go to Configuration >> under the Application settings tab >>  you can define variable called 'VaultUri' (will show shortly, why we need this):



How to get the value of this variable: go back to the KeyVault which you created to store your Azure App Registration Parameters >> copy the value of Vault URI 






4. We can now come back to our code and start writing the logic to retrieve the value of these App registration parameters >> in the class KeyVaultManager (created above) >> use the following method:


 public string GetSecretValue(string secretName)

        {

            

            string kvUri = Environment.GetEnvironmentVariable("VAULTURI");

            var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());

            var secret = client.GetSecretAsync(secretName).GetAwaiter().GetResult().Value;

            return secret.Value;

        }

Look at how the variable of the VaultURI is fetched. Its playing with "Azure.Security.KeyVault.Secrets" to fetch the value of the variable of the name = secretName, passed as parameter to the method.

For our testing purpose, we can also define the VaultURI at the 'local.settings.JSON' file:





However, as stated previously, problem with function app deployment is: the publish doesn't copy the local settings file to server. Hence is this arrangement.
Please note: Alternately, you can keep all your App registration parameters in the configuration settings of your function app, instead of Key Vaults. In fact, this is a better arrangement, than keeping and fetching staffs from Azure Key-Vaults. There is a 'await' in the above method of GetSecretValue, which eventually could result in some performance tradeoffs. 


Token generation logic

Once the above step is complete, we can focus now on creating the token. We can create a new class as under the same namespace of your function app: TokenGenerator.

You can define the following method here, that can obtain the various parameters defined for Azure App, store them inside a collection class and then do a POST to the token generation URL:

public string GetToken(ILogger log)

        {

            string responseInString = String.Empty;

            using (var wb = new WebClient())

            {

                KeyVaultManager kvManager = new KeyVaultManager();


                string tokenUrl = kvManager.GetSecretValue("tokenurluat");


                var data = new NameValueCollection();

                data["client_id"] = kvManager.GetSecretValue("clientiduat");

                data["client_secret"] = kvManager.GetSecretValue("secretvaluat");


                data["grant_type"] = "client_credentials";

                data["Scope"] = kvManager.GetSecretValue("scopeurl");


                var response = wb.UploadValues(tokenUrl, "POST", data);

                responseInString = this.getTokenValue(Encoding.UTF8.GetString(response));

            }

            return responseInString;

        }

As you can guess, the return response is a JSON object, out of which we must take out the value of token, under the node 'access-token'. 




For ease of calculation, I have added one more method called: getTokenValue, which can be something like this:

public string getTokenValue(string responsePayload)

        {

            dynamic json= JObject.Parse(responsePayload);

            string accessToken = json.access_token;


            return accessToken;

        }

Its referring to 'dynamic' datatype, which evaluates/resolves any payload at the runtime, and is used to fetch the value of a node called 'access_token'.

Posting the payload to D365FnO for furtherance

And finally, we can now focus on creating the logic to pass on the obtained token to call our D365FnO URLs. You can come back to the main body of your function app. Here also, I have created a method that accepts the payload and then calls to D365FnO URL, by attaching the token:

public static string Call2EnqueueMethod(string token, string payload, ILogger log)

        {

            string URL = <You can define a key vault secret to hold the D365FnO Enqueue URL and fetch it by the process described above>;

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);

            request.Method = "POST";

            request.ContentType = "application/xml";

            request.ContentLength = payload.Length;

            StreamWriter requestWriter = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);

            request.Headers.Add("Authorization", string.Format("Bearer {0}", token));

            requestWriter.Write(payload);

            requestWriter.Close();

            string response = String.Empty;

            try

            {

                WebResponse webResponse = request.GetResponse();

                Stream webStream = webResponse.GetResponseStream();

                StreamReader responseReader = new StreamReader(webStream);

                response = responseReader.ReadToEnd();


                responseReader.Close();


            }

            catch (Exception e)

            {

                log.LogInformation(e.Message);

            }


            return response;

        }

Look at the parameters: its passing on the token, and the XML payload obtained in the body of the HTTP. The bearer tokens are entertained, only when you add the keyword 'Bearer' at the start of the token for identification:

request.Headers.Add("Authorization", string.Format("Bearer {0}", token));

Hence it has been added in the header.

Lastly you can call this method, from the main body of your function app as:

public static async Task<IActionResult> Run(

            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,

            ILogger log)

        {

            log.LogInformation("C# HTTP trigger function processed a request.");

            TokenGenerator generator = new TokenGenerator();

            string token = generator.GetToken(log);

            if (token != string.Empty)

            {

                string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

                string responseMessage = Call2EnqueueMethod(token, requestBody, log);

                return new OkObjectResult(responseMessage);

            }

            else

            {

                return new OkObjectResult("Token generation failed");

            }            

        }   

The process though has been written for XML based input payload, however could generalized for any incoming payload, managing the Azure app parameters and bearer token staffs. 

Talk to you soon....till then, stay safe, much love and Namaste. 😀😀😀

Comments

*This post is locked for comments