Tasklist Client Tutorial

Date: 2008-02-02
Author: Mike Amundsen

Abstract

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.

Introduction

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

Basic Functionality

Basic Functionality 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:

-list
Return a list of tasks from the server
-add name [status]
Add a new task to the list on the server. The name is required; status (1=done, 0=pending) is optional.
-toggle id
Toggle the status of the indicated task. The id is required.
-delete id
Delete the indicated task. The id is required.
-clear
Delete all the tasks from the list.

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.

top

The High-level Code

Before 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.

top

Using the HTTPClient Class

The HTTP Client 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 Execute Method

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:

string Execute(string url)
Performs an HTTP GET on the supplied URL with text/xml as the Accept header.
string Execute(string url, string method)
Performs the request to the URL using the HTTP method provided with text/xml as the Accept header.
string Execute(string url, string method, string contentType)
Performs the request to the URL using the HTTP method provided with the provided value (contentType) as the Accept header.
string Execute(string url, string method, string contentType, string body)
Performs the request as described and sends the contents of 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 TaskList Class

The TaskList Client 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:

  1. TaskList()
  2. TaskList(string uri)
  3. XmlDocument GetList()
  4. XmlDocument GetItem(string id)
  5. void AddItem(string name)
  6. void AddItem(string name, string completed)
  7. void ToggleItem(string id)
  8. void DeleteItem(string id)
  9. void DeleteAll()
  10. string ShowList()

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.

Getting Data from the Server

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.

Sending Updates to the Server

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.

top

A Sample Client Session

Sample Client Session 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

Summary

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.

top

About the Author

Mike Amundsen Mike 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