Now we’ve got the infrastructure sorted for the bot talking to Teams and getting it installed for users, we need to start letting it know when something interesting happens in D365 so the bot can send messages out to users. Enter the WebHook.

WebHooks

WebHooks are a simple way to register with D365 that some other web app is interested in an event. We can register a webhook similarly to a plugin step, so we can get D365 to send a message to our bot without writing any code.

I would normally register plugins and their steps using the Plugin Registration Tool in XrmToolBox, but it doesn’t currently support registering webhooks. Instead I had to download the official Microsoft one. Unfortunately, after installing this, I clicked “Register New Web Hook” and nothing happened. In fact, nothing happened when I clicked any of the buttons in the top ribbon. Eventually I downloaded an earlier version (9.1.0.12) from NuGet and that worked as expected.

This screen needs the URL that the details of the event are going to be sent to. In this case I’ve made up the /api/notification endpoint within my bot domain. I haven’t written any code to actually handle this yet – that’ll come next.

The other part I need to specify is how D365 will authenticate with the endpoint. I’ve picked the simple option of WebhookKey – this will append a code parameter to the query string and pass in the value I specify. In my code that receives the notification I can check that and reject any requests that don’t include the right value.

WebHook Steps

Now I’ve registered the webhook I can use the Register New Step option to add a step to the webhook. This is the registration step to get CDS to trigger the webhook in response to a particular event.

With this step registered, my bot will get a notification whenever someone writes a post on the timeline of a record. I’ll also repeat this for the postcomment entity to get notifications of any replies.

That’s all I need to do in D365 / CDS – no code needed!

Bot Endpoint

CDS is now going to send some details to my /api/notification endpoint when someone writes a post. Now I need to get my bot to handle it.

The sample code I based my bot on uses ASP.NET Core MVC, so I can easily add a handler for this endpoint as:

[Route("api/notification")]
[ApiController]
public class NotificationController : ControllerBase
{
    [HttpPost]
    public async Task<IActionResult> PostAsync([FromQuery] string code,  [FromBody] JObject requestContext)
    {
        if (code != "markcarrington.dev.notifications")
            return Unauthorized();

        // TODO: Process notification

        return Ok();
    }
}

A few things worth pointing out from this code:

  • the code parameter will be loaded from the query string. This should match the WebhookKey authentication value that we put into the webhook registration earlier. If we don’t get the expected value we return a 401 Unauthorized result. The documentation isn’t explicit on what error should be returned, only that the request should fail, but 401 seems a good fit.
  • the requestContext parameter is loaded from the body as a JObject rather than being deserialized to the RemoteExecutionContext object it represents. This is described as a best practise in the documentation. If you’re building your bot on ASP.NET Core 3.x you’ll need to install the Microsoft.AspNetCore.Mvc.NewtonsoftJson package and include
    services.AddMvc().AddNewtonsoftJson()
    in your startup.cs.

That’s hopefully the last bit of wiring I need to do, and next time I’ll be able to start using this webhook to push out the proactive Teams messages we’ve already done the groundwork for.

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.