How to create a webhook handler with ASP.NET C#

I struggled to figure out a solution for a C# webhook page. I tried the Javascript example with no success. After much trial and error (several days), I was able to get it working. So I decided to share my code.

When creating a webhook, you need to specify a url to send the event payload. The page below is designed to handle the challenge response to verify the webook. Then it will receive any event payload that occurs.

The code sample below is a page I called mondaywebhook.ashx .

<%@ WebHandler Language="C#" Debug="true" Class="MondayWebhookHandler" %>

using System;
using System.Web;
using System.IO;
using System.Net.Mail;



public class MondayWebhookHandler : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "application/json";

        string body = String.Empty;
        context.Request.InputStream.Position = 0;

        try
        {

            using (var inputStream = new StreamReader(context.Request.InputStream))
            {
                body = inputStream.ReadToEnd();
            }

            // the line below is used to verify the challenge, uncomment this line
            // if you need to send the challenge back to verify the webhook. Once verified,
            // it is no longer needed.
            context.Response.Write(body);

        //    context.Response.StatusCode = 200;

            // for troubleshooting
            SendMail("<br><br>body : " + body);         


        }
        catch (Exception ex)
        {   
            // for troubleshooting
            SendMail("\nError: " + ex.Message + "\n\n\n<br><br>" + body);
        }
        finally
        {
           context.Response.End();
        }

    }

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }   


    private void SendMail(string strBody)
    {

        string FromEmail = "youremail@somedomain.com";
        string ToEmail = "youremail@somedomain.com";
           

        MailAddress from = new MailAddress(FromEmail);
        MailAddress to = new MailAddress(ToEmail);
        MailMessage objMail = new MailMessage(from, to);
        objMail.IsBodyHtml = true;

        objMail.Subject = "Monday Webhook"; 
        objMail.Body = strBody;

        SmtpClient client = new SmtpClient();

         client.Host = "localhost";
         //  client.DeliveryMethod = SmtpDeliveryMethod.PickupDirectoryFromIis;

        client.Send(objMail);
        objMail.Dispose();
    }

}

The SendMail function was used for troubleshooting and is not needed for the webhook to work.
The code line: context.Response.Write(body); can be commented out after the webhook challenge is verified.
After verification, webhook events will be sent via email.
You’ll need to change the client.Host for your own environment.
When you have it working set Debug=“false”.

I hope this helps someone!

I’m struggling in working with this one. I can’t verify the webhook. Can you share more how was the structure of your code?

Once Monday sent the challenge, it goes through here. This is my sample code

using Microsoft.AspNet.WebHooks;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;

namespace Webhooks_Zapier_Monday
{
public class GenericJsonWebHookHandler : WebHookHandler
{

    public GenericJsonWebHookHandler()
    {

        this.Receiver = "genericjson";
    }

    [IgnoreAntiforgeryToken]
    public override Task ExecuteAsync(string generator, WebHookHandlerContext context)
    {

        // Get JSON from WebHook
        //JObject data = context.GetDataOrDefault<JObject>();

        var data = context.Data.ToString();

        var json = data == null ? "" : data.ToString();
        if (!string.IsNullOrEmpty(json))
        {
            var jObject = JObject.Parse(json);
        }


        return Task.FromResult(true);
    }

}

}

And I don’t know how can I return the challenge for Monday verification.

The following code is a webhook I use. The code is in a page called MondayWebhook.ashx.

<%@ WebHandler Language="C#" Debug="true" Class="TypeFormHandler" %>

using System;
using System.Web;
using System.IO;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.Web.Script.Serialization;


public class TypeFormHandler : IHttpHandler
{
  
    MondayAPIClass objMonday = new MondayAPIClass();
 
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "application/json";

        string body = String.Empty;
        context.Request.InputStream.Position = 0;

        try
        {

            using (var inputStream = new StreamReader(context.Request.InputStream))
            {
                body = inputStream.ReadToEnd();
            }

            // the line below is used to verify the challenge, uncomment this line
            // if you need to send the challenge back to verify the webhook. Once verified,
            // it is no longer needed.
            if (body.Contains("\"challenge\""))
                context.Response.Write(body);

          
            if (body != String.Empty)
            {

                string eventStr = JObject.Parse(body).SelectToken("event").ToString();
                string newValue = JObject.Parse(eventStr).SelectToken("value").ToString();
                string pulseName = JObject.Parse(eventStr).SelectToken("pulseName").ToString();
                string pulseId = JObject.Parse(eventStr).SelectToken("pulseId").ToString();
                string columnId = JObject.Parse(eventStr).SelectToken("columnId").ToString();
                string columnTitle = JObject.Parse(eventStr).SelectToken("columnTitle").ToString();
                string columnType = JObject.Parse(eventStr).SelectToken("columnType").ToString();

                if (newValue != "" && columnType != "dropdown")
                {

                    IJEnumerable<JToken> valuesArr = JObject.Parse(newValue).Values();
                    foreach (JToken token in valuesArr)
                    {
                        newValue = token.ToString();
                        break;
                    }
                }

                           

                string resultStr = "";
                if (context.Request.QueryString["type"] == "item_column_change")
                {
                    switch (columnId)
                    {

                        case "text8": //project name
                            resultStr = objMonday.UpdateSampleProjectName(pulseId, newValue);
                            break;
                        case "text": // account
                            resultStr = objMonday.UpdateSampleAccount(pulseId, newValue);
                            break;
                        case "status": // status
                            newValue = JObject.Parse(newValue).SelectToken("text").ToString();
                            resultStr = objMonday.UpdateSampleStatus(pulseId, newValue);
                            break;
                        case "status_1": // Sample Type
                            newValue = JObject.Parse(newValue).SelectToken("text").ToString();
                            resultStr = objMonday.UpdateSampleType(pulseId, newValue);
                            break;
                        case "ship_method": // Ship Method
                            if (newValue != "") { 
                                newValue = JObject.Parse(newValue).SelectToken("text").ToString();
                                resultStr = objMonday.UpdateSampleShipMethod(pulseId, newValue);
                            }
                            break;
                       
                        case "date": // datePrinted
                            if (newValue == "")
                                newValue = "1900-1-1";
                            resultStr = objMonday.UpdateSampleDatePrinted(pulseId, newValue);
                            break;
                        case "date0": // ship Date
                            if (newValue == "")
                                newValue = "1900-1-1";
                            resultStr = objMonday.UpdateSampleDateShipped(pulseId, newValue);
                            break;

                        case "date4": // desiredArrival clientNeedsBy
                            if (newValue == "")
                                newValue = "1900-1-1";
                            resultStr = objMonday.UpdateSampleDesiredArrivalDate(pulseId, newValue);
                            break;

                        default:
                            break;
                    }
                }

                if (context.Request.QueryString["type"] == "subitem_column_change")
                {
                    switch (columnId)
                    {                        
                       
                        case "long_text": // Sample Notes                           
                            resultStr = objMonday.UpdateSampleItemNotes(pulseId, newValue);
                            break;    
                                
                        case "numbers": // quantity
                            resultStr = objMonday.UpdateSampleItemQuantity(pulseId, newValue);
                            break;                                    

                        default:
                            break;
                    }
                }
              

            }

            context.Response.StatusCode = 200;

        }
        catch (Exception ex)
        {
            //Do something for the error
        }
        finally
        {

            context.Response.End();
        }



    }

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }


    

}