The basic lifecycle of a [successful] TaskRouter Task is as follows:
Task Created → eligible Worker becomes available → Worker reserved → Reservation accepted → Task assigned to Worker.
In this part of the tutorial, we'll create Tasks and observe them through each of these stages. We start by creating a Task using the Tasks REST API. First time around we accept the Task using the Reservations REST API, then we create another Task and accept it using assignment callback instructions.
Both the Reservations REST API and assignment callback instructions are valid methods for accepting a Reservation; it's likely that you'll choose one or the other based on the amount of background work that must be performed by your server before it accepts or rejects a Reservation. For example, due to the amount of time required, if you were to build a user interface that allowed human agents to inspect a Task before accepting it, you would need to accept the Reservation asynchronously using the Reservations REST API.
Whether we accept Reservations via the REST API or via assignment callback instructions, we always need an Assignment Callback URL that is reachable by TaskRouter. This is the URL at which TaskRouter will notify us when a Worker is reserved to perform a Task. Before creating any Tasks, let's get the Assignment Callback URL up and running.
Finally time to write some (albeit minimalist!) code.
We are going to write a C# server to respond to HTTP requests, so we can tell Twilio what to do when we receive an assignment callback.
_35using System;_35using System.Net;_35using SimpleWebServer;_35_35namespace taskroutercsharp_35{_35 class MainClass_35 {_35 public static void Main (string[] args)_35 {_35 WebServer ws = new WebServer (SendResponse, "http://localhost:8080/");_35 ws.Run ();_35 Console.WriteLine ("A simple webserver. Press a key to quit.");_35 Console.ReadKey ();_35 ws.Stop ();_35 }_35_35 public static HttpListenerResponse SendResponse(HttpListenerContext ctx)_35 {_35 HttpListenerRequest request = ctx.Request;_35 HttpListenerResponse response = ctx.Response;_35_35 String endpoint = request.RawUrl;_35_35 if (endpoint.EndsWith("assignment_callback")) {_35 response.StatusCode = (int) HttpStatusCode.OK;_35 response.ContentType = "application/json";_35 response.StatusDescription = "{}";_35 return response;_35 }_35 response.StatusCode = (int) HttpStatusCode.OK;_35 return response;_35 }_35 }_35}
_78using System;_78using System.Net;_78using System.Threading;_78using System.Linq;_78using System.Text;_78_78namespace SimpleWebServer_78{_78 public class WebServer_78 {_78 private readonly HttpListener _listener = new HttpListener();_78 private readonly Func<HttpListenerContext, HttpListenerResponse> _responderMethod;_78_78 public WebServer(string[] prefixes, Func<HttpListenerContext, HttpListenerResponse> method)_78 {_78 if (!HttpListener.IsSupported)_78 throw new NotSupportedException(_78 "Needs Windows XP SP2, Server 2003 or later.");_78_78 // URI prefixes are required, for example_78 // "http://localhost:8080/index/"._78 if (prefixes == null || prefixes.Length == 0)_78 throw new ArgumentException("prefixes");_78_78 // A responder method is required_78 if (method == null)_78 throw new ArgumentException("method");_78_78 foreach (string s in prefixes)_78_78 _listener.Prefixes.Add(s);_78_78 _responderMethod = method;_78 _listener.Start();_78 }_78_78 public WebServer(Func<HttpListenerContext, HttpListenerResponse> method, params string[] prefixes)_78 : this(prefixes, method) { }_78_78 public void Run()_78 {_78 ThreadPool.QueueUserWorkItem((o) =>_78 {_78 Console.WriteLine("Webserver running...");_78 try_78 {_78 while (_listener.IsListening)_78 {_78 ThreadPool.QueueUserWorkItem((c) =>_78 {_78 var ctx = c as HttpListenerContext;_78 try_78 {_78 HttpListenerResponse response = _responderMethod(ctx);_78 byte[] buf = Encoding.UTF8.GetBytes(response.StatusDescription);_78 response.ContentLength64 = buf.Length;_78 response.OutputStream.Write(buf, 0, buf.Length);_78 }_78 catch { } // suppress any exceptions_78 finally_78 {_78 // always close the stream_78 ctx.Response.OutputStream.Close();_78 }_78 }, _listener.GetContext());_78 }_78 }_78 catch { } // suppress any exceptions_78 });_78 }_78_78 public void Stop()_78 {_78 _listener.Stop();_78 _listener.Close();_78 }_78 }_78}
This returns an empty JSON document to TaskRouter with a 200 (OK) response code. This tells TaskRouter that the assignment callback was successfully received and parsed, but that we don't want to take any action on the Reservation right now. Instead, it's implied that we will use the REST API to accept or reject the Reservation when we are ready.
Make sure your C# server is running. Your server will be available here: http://localhost:8080
.
For this tutorial, we'll use ngrok. After installing ngrok to your $PATH, run the following command at your terminal to start listening for requests from the outside world:
ngrok 8080
Your local C# server is now accessible to anyone (including Twilio's servers) at your ngrok URL.
With those things working, edit your "Incoming Customer Care Requests" Workflow to point at the newly implemented Assignment Callback URL:
http://yourngrokserver.com/assignment_callback
Excellent. We're ready to create Tasks and accept Reservations.