How Do
Webhooks
Webhooks

Implement a webhook server in C#

You can also implement a server in C#. If you use different ports you can have as many servers as you want running.


In this example for Windows, the PC that the server runs on can be suspended, shutdown or restarted. It can also show a message box or be made to speak.

The device parameter that the server responds to is specified on the form along with the required port to use:

Webhooks Server

First set up the form and some constants and handle the close event.

Setup
public partial class Server : Form
{
    public Server()
    {
        InitializeComponent();
    }
    const int PHP_COM = 0;
    const int PHP_VAL = 1;
    const int PHP_KEY = 2;
    const int PHP_SUB = 3;
    const int PHP_DEV = 4;

    private void button1_Click(object sender, EventArgs e)
    {
        this.Close();
    }

The following functions is used to run commands from the Windows command line, so that the server can do something.

Function to run commands
    public static void StartProcess(string PathAndFileName)
    {
        System.Diagnostics.Process.Start("CMD.exe", PathAndFileName);
    }

Start the server on a different thread than the UI to prevent the program hanging.

Start thread
    Thread thread;
    private void button2_Click(object sender, EventArgs e)
    {
        thread = new Thread(StartListening);
        thread.Start();
    }

Initialise the speech object (available with the project download) and declare a string to store incoming data.

Initialise Speech
    Speech speech = new Speech();
    // Incoming data from the client.
    public string data = null;

Set up the server port and start listening, the port number is taken from the text box on the form and can be changed before starting the server.

Start the server
public void StartListening()
    {
        // Data buffer for incoming data.
        byte[] bytes = new Byte[1024];

        // Establish the local endpoint for the socket.
        // Dns.GetHostName returns the name of the
        // host running the application.
        IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
        IPAddress ipAddress = ipHostInfo.AddressList[1];
        IPEndPoint localEndPoint = new IPEndPoint(ipAddress, int.Parse(textBox2.Text));

        // Create a TCP/IP socket.
        Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

        // Bind the socket to the local endpoint and
        // listen for incoming connections.
        try
        {
            listener.Bind(localEndPoint);
            listener.Listen(10);

Run a loop that listens on the socket and performs an action when something is receieved. The loop runs until the form is closed.

Wait for a connection
            // Start listening for connections.
            while (!IsClosing)
            {
                Console.WriteLine("Waiting for a connection...");
                // Program is suspended while waiting for an incoming connection.
                Socket handler = listener.Accept();
                data = null;

Data is received so get it as text and add it to the 'data' string.

Receive data
                // An incoming connection needs to be processed.
                int bytesRec = handler.Receive(bytes);
                data += Encoding.ASCII.GetString(bytes, 0, bytesRec);

Split the parameters into the separate strings in an array so that it is easy to process.

Also initialise the return message 'Smsg' to the default value in case no command is found.

Split parametes
                // Show the data on the console.
                Console.WriteLine("Text received : {0}", data);
                String[] Args = data.Split(',');
                for (int s = 0; s < Args.Length; s++)
                {
                    Args[s] = Args[s].Replace("\0", String.Empty);
                }

                String Smsg = "Command Not Found";

Check if the command is for us then decode it and perform the required action.

Decode
                if (Args.Length >= 5)
                {
                    if (Args[PHP_DEV] == textBox1.Text) //check the device name
                    {
                        //check the command
                        switch (Args[PHP_COM])
                        {
                            case "msg":
                                //hangs website until ok clicked
                                MessageBox.Show(Args[PHP_VAL]);
                                Smsg = "Ok";
                                break;
                            case "alive":
                                //do nothing, just ok will be returned
                                Smsg = "I'm alive!";
                                break;
                            case "say":
                                speech.Say(Args[PHP_VAL], "0", "Microsoft Hazel Desktop");
                                Smsg = "Ok";
                                break;
                            case "inf":
                                //return available commands
                                if (Args[PHP_KEY] == "com")
                                {
                                    Smsg = "msg, alive, say, suspend, shutdown, restart";
                                }
                                break;
                            case "suspend":
                                Application.SetSuspendState(PowerState.Suspend, false, false);
                                Smsg = "Ok";
                                break;
                            case "shutdown":
                                StartProcess("/C shutdown -s -f -t 0");
                                Smsg = "Ok";
                                break;
                            case "restart":
                                StartProcess("/C shutdown -g -f -t 0");
                                Smsg = "Ok";
                                break;
                            default:
                                Smsg = "Fail - Command not recognised";
                                break;
                        }
                    }                  
                }
                else
                {
                    Smsg = "Fail";
                }

Send a message back to the client and close the socket.

Reply
                // Echo back to the client
                byte[] msg = Encoding.ASCII.GetBytes(Smsg);
                handler.Send(msg);

                handler.Shutdown(SocketShutdown.Both);
                handler.Close();
            }
        }

If something went wrong show the exception in the console window.

Catch exception
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

Set a flag when closing to allow us to exit the continuous loop.

Form close
    Boolean IsClosing = false;
    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        IsClosing = true;
        Environment.Exit(Environment.ExitCode);
    }
}