Skip navigation

Getting Hooked on Episerver Webhooks

Episerver released its new Forms add-on, which was released earlier this month and looks super cool. One thing that looks especially intriguing is the idea of a webhook, which can alter the behavior of a webpage or web application with custom callbacks.

Webhooks let you send submitted form data to a remote URL. The data is sent asynchronously, which means the webhook can’t interfere with success messages displayed to the user. If the webhook fails, Episerver isn’t affected. These work great for sending data to a CRM system, or subscribing a user to an email list.

But one problem I was having was finding documentation on webhooks with Episerver. Forms itself had some documentation, but I couldn't find much of anything on webhooks. What’s a developer to do?

Well, I could wait for documentation to be released. Better yet, I could dig in and figure out for myself. And let’s be honest, isn’t that more fun anyway?

Here’s what I came up with:

First, we want to create an MVC controller for handling the webhook. I’m not sure at this point whether the webhook will be called using a GET or POST, so I’m going to wire up my action method to accept both verbs:

public class FormsController : Controller
{
   [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
   public ActionResult WebhookTest()
   {
       var method = Request.HttpMethod;
       return Content(method + ": Magical webhook unicorns abound.");
   }
}

Next, and since this is a vanilla MVC controller, we need to make sure the default MVC route is configured.  For this, we’ll override the RegisterRoutes method in our global.asax class:

public class EPiServerApplication : EPiServer.Global
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
    }
    protected override void RegisterRoutes(RouteCollection routes)
    {
        base.RegisterRoutes(routes);
        routes.MapRoute(
          name: "Default",
          url: "{controller}/{action}/{id}",
          defaults: new { action = "Index", id = UrlParameter.Optional });
    }
}

Make sure you call base.RegisterRoutes – this is what wires up the magic Episerver page routing. Not calling it will break all of your page URLs.

At this point, we should be able to browse to our webhook URL:

URL Webhook

 

 

 

 

The next step is to create a form and assign our URL as its webhook:

Save As Webhook

I’ve added this form to a page on my site, but before I start submitting the form, I want to add some diagnostic logging code to my action method. This will provide better visibility into the kind of information Episerver provides in the webhook request:

public class FormsController : Controller
{
    [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
    public ActionResult WebhookTest()
    {
        var method = Request.HttpMethod;
        Debug.WriteLine(method);
        var headers = ControllerContext.RequestContext.HttpContext.Request.Headers;
        Debug.WriteLine("-- HTTP Headers --");
        foreach (var key in headers.AllKeys)
        {
            Debug.WriteLine("\t" + key + ": " + headers[key]);
        }
        if (string.Equals(method, "POST", StringComparison.OrdinalIgnoreCase))
        {
            Request.InputStream.Seek(0, SeekOrigin.Begin);
            string body = new StreamReader(Request.InputStream).ReadToEnd();
            Debug.WriteLine("-- Request Body --");
            Debug.WriteLine(body);
        }
        return Content(method + ": Magical webhook unicorns abound.");
    }
}

With this in place, I can now submit my form and examine the output:

 Output

The request body contains a JSON-formatted string of key-value pairs for each of the fields on my form, but there is a slight problem. The Content-Type header is set to application/x-www-form-urlencoded.  Because of this content-type mismatch, we’re unable to use the default model binding that comes with ASP.NET MVC. We have to read the request body and manually deserialize it:

private IEnumerable<KeyValuePair<string, object>> GetFormData(string requestBody)
{
    if (string.IsNullOrWhiteSpace(requestBody))
        return Enumerable.Empty<KeyValuePair<string, object>>();
    return JsonConvert.DeserializeObject<IEnumerable<KeyValuePair<string, object>>>(requestBody);
}

Now that we know how to wire up a webhook for an Episerver form, the sky’s the limit. Happy webhooking!

What separates us from other Episerver partners? We're glad you asked