In this tutorial, you'll learn how to use the exyus engine to build client-side desktop applications that can talk to HTTP servers. You'll learn about the HTTPClient class and how you can use it to make requests to (and handle responses from) remote HTTP servers.
You can download the Win32 version of the TaskList Client application.
The exyus engine is more than a framework for building HTTP servers. It also contains all the neccessary support for building robust HTTP clients. That means you can use it to build desktop applications that have the full range of HTTP commands available when connecting to remote HTTP servers on the Internet. In this tutorial, you'll see how you can use exyus to build a small Win32 command-line application (in C#) that can interact with the TaskList server application.
You can read Tasklist Tutorial to learn more about how the server application was built.top
The basic functionality of the TaskList Client is simple. It will allow users to list, add, edit, and delete tasks from the list of tasks kept on the remote server. Since this will be a very simple command-line application, it will provide only the minimal UI neede to complete the work. All work will be done via a set of command-line arguments. Each execution of the application will handle a single task (add, edit, delete, list). Here's a list of the commands and their arguments:
The client application will also need a few internal routines to show a help screen with the commands, a screen to show the list of tasks, and any error messages recieved from the server. That's all we need for this simple application.
topBefore getting into the details of the HTTP requests and responses, let's first map out the high-level code that will be needed for the application. This includes handling the command-line arguments, dispatching the arguments to the proper routine and displaying the results (including any errors). Below is the high-level code for this application:
class Program { static void Main(string[] args) { TaskList tl = new TaskList("http://exyus.com/xcs/tasklist/"); Console.WriteLine("\nTaskList Utility\n2008-02-02 (mca)\n" + tl.Uri + "\n"); if (args.Length == 0) { ShowHelp(); return; } Console.WriteLine("Request:"); ShowCommand(args); Console.WriteLine("Response:"); try { switch (args[0].ToLower()) { case "-list": break; case "-add": if (args.Length > 2) tl.AddItem(args[1], args[2]); else tl.AddItem(args[1]); break; case "-toggle": tl.ToggleItem(args[1]); break; case "-delete": tl.DeleteItem(args[1]); break; case "-clear": tl.DeleteAll(); break; default: throw new IndexOutOfRangeException("Unknown command [" + args[0] + "]"); } // show current list Console.WriteLine(tl.ShowList()); } catch (Exception ex) { Console.WriteLine("ERROR: "+ex.Message); ShowHelp(); } return; } static void ShowCommand(string[] args) { for (int i = 0; i < args.Length; i++) { Console.Write(args[i] + " "); } Console.WriteLine("\n"); } static void ShowHelp() { Console.WriteLine("\nvalid commands:\n-list\n-add [name]\n-toggle [id]\n-delete [id]\n-clear"); } }
You'll notice that most of the code is devoted to collecting and interpreting the command-line
arguments. There is a routine to echo the user's commands back to the screen and one to show
a 'help text' in case the user enters invalid commands. Finally, there is a try...catch
block to capture any exceptions and display the related error message.
You should also notice that, at the top of the code, there is an instance declaration of the
TaskList
class. This is the class that does all the 'real work' for this application.
The details for this class are covered below.
Before getting into the details of the TaskList
class, it is important to take
some time to cover the
HTTPClient
class. This class is the part of the exyus engine
that provides HTTP client services. It acts very much like a web browser, but without all the
'bells and whistles.'
The HTTPClient
class has just one public method: Execute
. You use this method to execute an HTTP
request to an HTTP server. There are five versions of this method:
text/xml
as the Accept header.text/xml
as the Accept header.contentType
) as the Accept header.body
to the server. This is used for HTTP Put and HTTP Post methods.
The Execute
method returns a string which represents the
response recieved from the HTTP server. If there are any errors, an HttpException
is raised.
The HTTPClient class also has a number of optional public properties that you can set/get. They are:
That is all you need in order to make HTTP request to remote server. In the next section, you'll use the HTTPClient class to complete the sample command-line application.
top
The details of coding the TaskList
class involves creating a set of methods to
match the HTTP requests the client needs to make to the server along with some support routines
to handle displaying the results of the requests. Since the application needs to be able to
perform all the commands outlined at the start of this tutorial (list, add, toggle, delete, and clear),
there needs to be a method to match each command. Below is a complete list of all the methods in
the TaskList
class:
The first two methods are the constructors for the class. There is a public property for the
class (string Uri
) that contains the URL of the remote server. But you can also
pass this value in the constructor. The next several methods (3 through 9) handle the details
of communicating with the remote server. The last method (showList
) returns a
formatted list of the tasks for display at the console.
The GetList
method is an example of how to use the
HTTPClient
class. Below is the complete code for getting the task list from the server:
public XmlDocument GetList() { client.RequestHeaders.Set("cache-control", "no-cache"); string results = client.Execute(Uri, "get", "text/xml"); XmlDocument doc = new XmlDocument(); doc.LoadXml(results); return doc; }
Note the use of the RequestHeader
collection to send a "no-cache" message to
the server. This will force the server to send the client a fresh list instead of one that
might be in the server cache.
The GetItem
method is also instructive:
public XmlDocument GetItem(string id) { string results = client.Execute(Uri + id, "get", "text/xml"); p_etag = client.ResponseHeaders["etag"]; XmlDocument doc = new XmlDocument(); doc.LoadXml(results); return doc; }
The the GetItem
method, the ResponseHeaders
collection is used to
retrieve the ETag value of the record. The client will need to send this ETag value back to
the server when it attempts to update the task.
For this application, the process of updating an existing task involves getting the most recent
version of the task, "toggling" it's status (pending->done or done->pending), and sending that
updated task back to the server to storage. Here is the complete code for the ToggleItem
method:
public void ToggleItem(string id) { XmlDocument doc = GetItem(id); string results = doc.OuterXml; XmlNode completed = doc.SelectSingleNode("//is-completed"); if (completed.InnerText == "0") results = results.Replace(p_pending, p_done); else results = results.Replace(p_done, p_pending); client.RequestHeaders.Set("if-match", p_etag); client.Execute(Uri + id, "put", "text/xml", results); }
You should recoginize most of the details of this method. It makes a request to the server for
the indicated task; inspects the return results and updates the is-completed
value.
Then the data is sent back to the server using the HTTP PUT method along with the ETag for the
task record.
There are two ways to add a new task to the list. One just sends the task name. The other
sends both the name and the intial status. Here's the code for the Add
method:
public void AddItem(string name) { AddItem(name, "0"); } public void AddItem(string name, string completed) { client.Execute(Uri, "post", "text/xml", string.Format(p_new_task, name, completed)); }
Finally, there are two ways to delete tasks from the list. One way is to delete a single task.
The other way is to delete all the tasks on the server. Since the server only supports deleting
a single task at a time, the DeleteAll
client method simply uses a loop to make
repeated calls to the DeleteItem
method. The code for both methods is below:
public void DeleteItem(string id) { client.Execute(Uri + id, "delete", "text/xml"); } public void DeleteAll() { XmlDocument doc = GetList(); XmlNodeList tasks = doc.SelectNodes("//task"); for (int i = 0; i < tasks.Count; i++) { try { DeleteItem(tasks[i].Attributes["href"].Value); } catch (Exception ex) { Console.WriteLine("ERROR: "+ex.Message); } } }
The only other method not covered here is the ShowList
method. This is an internal
utility routine that takes the output of GetList
and formats it for display on the
console. You can view the entire
TaskList Client
code online.
Once you code and compile the command line application, you can start interacting directly with the TaskList Server hosted at exyus.com. Below is a sample session using the TaskList Client.
C:\>tasklist-cmd -add "my first task" Request: -add my first task Response: x8ca34279a4aa2cc my first task(0) C:\>tasklist-cmd -add "my second task" 1 Request: -add my second task 1 Response: x8ca34279a4aa2cc my first task(0) x8ca3427a1b2104a my second task(1) C:\>tasklist-cmd -toggle x8ca3427a1b2104a Request: -toggle x8ca3427a1b2104a Response: x8ca34279a4aa2cc my first task(0) x8ca3427a1b2104a my second task(0) C:\>tasklist-cmd -delete x8ca3427a1b2104a Request: -delete x8ca3427a1b2104a Response: x8ca34279a4aa2cc my first task(0)top
In this short tutorial you learned how to use the HTTPClient class from the exyus engine to build a comand-line client application that can "talk" to any HTTP server. In this example, you saw how you can build the TaskList Client application to list, add, edit, and delete tasks from the TaskList Server hosted at exyus.com.
topMike Amundsen lives and works as a contract programmer in Kentucky, USA. He currently spends most of his time creating and supporting large-scale web sites running under Windows and ASP.NET. In the past, he spent quite a bit of time as a trainer/speaker and was involved in the writing of several books on programming with Microsoft technologies.
top