Dynamics Ninja Logo

Blog.

D365 Webhooks – Part 3

Cover Image for D365 Webhooks – Part 3
·
5 min read

Introduction

In the last blog of the series, we looked into the structure of webhook response and managed to parse it to the known object that is easy to use. This time we will deep dive into the debugging part.

Debugging issue

If we think about debugging in the context of webhooks we must have in mind that most of the time we will have both parts located in the cloud. The issue is how to debug the webhook handler Function/API when the request is coming from the cloud system.

As we used Azure Functions as handler example before we will do it in this post too.

Try #1

In this example, we will use Visual Studio + Postman to debug the Azure Function that will be running on our local machine.

Let's use the slightly modified function that we used in the last blog that will log the request body instead of the user that created the contact.

[FunctionName("LogUser")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
    string requestBody = await req.Content.ReadAsStringAsync();

    var remoteContext = GetRemoteExecutionContextFromJson(requestBody);

    log.Info(requestBody);

    return req.CreateResponse(HttpStatusCode.OK, remoteContext.InitiatingUserId);
}

public static RemoteExecutionContext GetRemoteExecutionContextFromJson(string jsonString)
{
    using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
    {
        var serializer = new DataContractJsonSerializer(typeof(RemoteExecutionContext));
        var context = (RemoteExecutionContext)serializer.ReadObject(ms);
        return context;
    }
}

That way we can catch the request payload in our Azure Function monitoring section. Let's preform simple contact create action and wait for the trace log in the Azure portal.

After a few minutes, we can find the log in the monitor section of our function deployed in Azure and it will look similar like the image below.

You can see the request payload displayed in the large text area on the bottom right of the image. You can select all the text inside and copy it to the clipboard for the next step.

Let's run our function project locally on our machine. When you run it you will get the CMD popup like the one shown below.

The important part here is the URL marked in green color.

http://localhost:7071/api/LogUser

Now we have our function up and running on our local machine so it's time to mock the incoming request from the webhook by making the POST request from Postman to the URL we noted above.

Open the Postman and set the request type to POST. In the address bar type in URL http://localhost:7071/api/LogUser. Change to the Body tab, select the raw radio button option, past in the request payload that we copied to the clipboard from the Azure portal and select JSON (application/json) from the dropdown on the right that has Text as default value.

http://localhost:7071/api/LogUser. Change to the Body tab, select the raw radio button option, past in the request payload that we copied to the clipboard from the Azure portal and select JSON (application/json) from the dropdown on the right that has Text as default value.

Steps are shown in the image below.

Now it's time to set a breakpoint in our C# code. Set a breakpoint on the line that we parse the incoming JSON to the RemoteExecutionContext object and run the request in Postman.

If you did everything right your code will hit the breakpoint and you will be able to check the values of your variables and step through the code, but it's only the start of your debugging nightmare.

This method will take you a large amount of time and it's maybe the first thing that you will try when debugging the webhooks, but it's kinda not the best way to debug your function because you need to wait for every call to be logged on the Azure portal before you test it locally on your machine.

The good news is that there is a much better way of doing it.

Try #2

This example will use Visual Studio + ngrok and trust me it's by far the most efficient way of doing the webhooks debugging.

First of all, what does ngrok do? ngrok exposes local servers behind NATs and firewalls to the public internet over secure tunnels. In other words, it exposes our applications to the internet just by running the simple command in the command prompt.

First, you need to create the account on the ngrok website and install ngrok by downloading the installer afterward.

After you download and install it's a good idea to add the ngrok folder to the Windows PATH so you can easily call it afterward in the command line.

Next step is to save your auth token to the ngrok config by running the command in CMD.

ngrok authtoken <YOUR_AUTH_TOKEN>

Auth token can be found in the Connect your account section.

Saving the auth token created the config file in

C:\Users\<YOUR_USER>\.ngrok2\ngrok.yml

Open that file so we can modify it a little bit.

Add a snippet below the authtoken line

region: eu
tunnels:
  functions:
    proto: http
    addr: 7071
    host_header: localhost:7071

Be careful while pasting the configuration because if you don't indent the lines properly it will not work at all and you will get dozens of errors.

This configuration sets the EU tunnel that will be created with name functions on the HTTP protocol and port 7071 that is used for Azure Functions local debugging. By setting this config we can easily fire up our tunnel via CMD.

We can start our tunnel by simply typing the following command into CMD.

ngrok start functions

When the tunnel is created you will see the information about it in the CMD and it will be similar like on the image below.

The important thing here is to copy one of the URLs in the line that says Forwarding.

http://31b1a2b8.eu.ngrok.io

or

https://31b1a2b8.eu.ngrok.io

This will be the base URL that must be configured in the webhook configuration via the Plugin Registration Tool. Let's open the PRT and edit the webhook configuration we used before.

All you need to do here is to change the Endpoint URL value to http://31b1a2b8.eu.ngrok.io/api/LogUser which is ngrok forwarding URL followed by api/<FUNCTION_NAME> and hit save. Authentication value can be set to WebhookKey and some random value in it.

Now you can perform the action on which you registered your webhook (create of contact in our case) and you will hit the breakpoint if everything is set right.

Also, your request will be logged in the ngrok console

and you can view it on the web interface that can be reached on

http://127.0.0.1:4040

when ngrok tunnel is up and running.

This way you can easily see what is coming in the request from the Dynamics in the GUI and you can also hit the Reply button to perform the exact same webhook like it was sent from the Dynamics before. I think that this one is pretty neat functionality that will save you some time when debugging the same request over and over again.

Conclusion

I hope that after going through this 3 part webhooks series you can start making your own webhooks solution, know when and how to use them and finally debug them in the right way.

Feel free to ask any questions regarding the whole webhooks series and I will try to answer them as soon as I can.

I'm also open for continuing the series if someone has the topic that I didn't cover or maybe needs to be covered in a more deeper discussion.

Let's make webhooks get some love like they really deserve!