All posts by Mike Hacker

HttpListener and Forms

As shown in the previous few posts the HttpListener class can be very useful for handling basic HTTP requests to your custom application. I have shown how you can use the class to respond to basic HTTP requests, but what if you need to request information from a user? Simple, just have your application create a standard HTML page with the necessary form fields. Then you need to decide what method you will use to send that form data back to your application. You have a choice of using GET or POST. The GET method sends all of the form fields across in the querystring of the HTML request. A POST sends the information as a stream of data inside the actual request.

So what is the best method to use, get or post? It really depends on the amount of data you need to send back to your application. If you only have a few fields then "get" will work fine. If you have a large amount of data or you are trying to upload a file you will need to use "post". Most browsers have a size limit for a URL and since "get" uses the querystring you can easily exceed the URL size limit.

As a quick recap of HTML 101; to create a form that uses the "get" method you would use something like:

<form method="get" action="someURL">

And for a post:

<form method="post" action="someURL">

Now that you know the difference between get and post methods for a form, how do we use that with the HttpListener class? If you are using the "get" method it is pretty simple. In the callback method for your HttpListener class you will use the request object to access the querystring property directly. Below is an example for reading a value from the querystring:

string myValue = request.QueryString["myValue"];

As you can see pulling information out of the querystring is very simple and exactly like you would do when working within ASP.NET. Getting data from a form that used the post method is not so straight forward. The request object for the HttpListener class does not contain a Forms method for retrieving the data. We can, however, get access directly to the request object’s data stream and then parse out the form fields using a custom helper method:

 

private Hashtable GetFormValues(HttpListenerRequest request)

{

Hashtable formVars = new Hashtable();

 

//add request data at bottom of page

if (request.HasEntityBody)

{

System.IO.Stream body = request.InputStream;

System.Text.Encoding encoding = request.ContentEncoding;

System.IO.StreamReader reader = new System.IO.StreamReader(body, encoding);

if (request.ContentType.ToLower() == "application/x-www-form-urlencoded")

{

string s = reader.ReadToEnd();

string[] pairs = s.Split(‘&’);

for (int x = 0; x < pairs.Length; x++)

{

string[] item = pairs[x].Split(‘=’);

formVars.Add(item[0],System.Web.HttpUtility.UrlDecode(item[1]));

}

}

body.Close();

reader.Close();

}

return formVars;

}

 

A couple things to note about the code sample above; we use the HasEntityBody property of the request object to make sure that we do have some data to work with. Once we know we have data we need to use the ContentType property of the request object to make sure the data that was sent is form field data. It is then a simple process of breaking apart the data and placing it into a Hashtable for use in other parts of the application.

You could also modify the method shown above to also pull out all of the variables in the querystring and place them in the Hashtable. This would then provide you with one single place to go for all of your form data.

for (int x = 0; x < request.QueryString.Count; x++)

{

if (!formVars.ContainsKey(request.QueryString.Keys[x]))

{

formVars.Add(request.QueryString.Keys[x], request.QueryString[x]);

}

}

 

To use the GetFormValues method you need to create a new Hashtable object and assign it to the results of the GetFormsValues method. Example:

Hashtable formVals = GetformValues(myRequest);

Now to access a form value you simple use the formVals hashtable:

string myFormValue = formVals["myFormValue"].ToString();

As you can see using a simple helper method you can quickly and easily utilize forms and querystring or form values within your application using the HttpListener class.

HttpListener Continued

As promised, below is a short example of how to use the HttpListener class. After you have started the sample server below, open your web browser and load the URL http://blog.mikehacker.net:8080. You should see the words "Hello World". Try http://blog.mikehacker.net:8080/date to see the current date or http://blog.mikehacker.net:8080/time to see the current time. Very cool eh?

You may need to remove some of the line wraps when you copy the code to VS.NET.

Code:

using System;

using System.Collections.Generic;

using System.Text;

using System.Net;

namespace httplistenertest

{

class Program

{

static void Main(string[] args)

{

HttpListener listener = new HttpListener();

listener.Prefixes.Add("http://blog.mikehacker.net:8080/");

listener.Start();

 

IAsyncResult result = listener.BeginGetContext(new AsyncCallback(ListnerCallback), listener);

Console.WriteLine("Waiting for request");

 

while (true) { }

 

listener.Close();

Console.WriteLine("done");

Console.ReadLine();

}

 

public static void ListnerCallback(IAsyncResult result)

{

HttpListener listener = (HttpListener)result.AsyncState;

HttpListenerContext context = listener.EndGetContext(result);

HttpListenerRequest request = context.Request;

HttpListenerResponse response = context.Response;

 

string responseString="";

switch (request.Url.AbsolutePath)

{

case "/time":

responseString = "<html><body>The current time is: " + DateTime.Now.ToLongTimeString() + "</body></html>";

break;

 

case "/date":

responseString = "<html><body>The current date is: " + DateTime.Now.ToLongDateString() + "</body></html>";

break;

 

 

default:

responseString = "<html><body>Hello World!";

break;

}

 

 

byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);

response.ContentLength64 = buffer.Length;

System.IO.Stream output = response.OutputStream;

output.Write(buffer, 0, buffer.Length);

output.Close();

 

listener.BeginGetContext(new AsyncCallback(ListnerCallback), listener);

}

 

}

}

 

Sorry about the code formatting, some reason it was messed up during the publishing of this entry.

 

Dynamic GridView Paging Issue – NullReferenceException

Today I ran into a very strange situation with the ASP.NET 2.0 GridView control.   I was creating a SharePoint 2007 web part which consisted of a gridview control which was being dynamically created during the CreateChildControls method of the web part.    The gridview was being added to the web part’s control collection after the DataBind method was called on the gridview.   Everything was displaying correctly until I turned on paging for the gridview.   Once paging was turned on I started receiving a NullReferenceException error.   I used VS.NET to debug the web part and found that the error was being thrown as soon as the DataBind method was called.     In the stack trace of the error I noticed that the last entry referenced a method called BuildCallbackArgument(Int32 pageIndex).    I did a few searches on the net and came up with no information that was usefull on that method or on the error I was seeing.
 
I finally was able to track down the problem.  It appears that the gridview needs to be added to a controls collection prior to calling the DataBind method.   I modified my code so that immediately after creating the gridview control I added it to the web part’s control collection.  Once I did that the web part worked as expected and the gridview displayed properly.  

Web UI for Windows Service

I have been spending some time thinking about how I could allow a user to interact with a custom Windows service that I had written.   I want to allow the user to alter the configuration of the service and to receive feedback on the different processes occurring inside this service.   In the past I had written a Windows application that used TCP/IP to communicate with the service.    To me this seemed a bit much since I now have to maintain not only a Windows service but also a Windows client application… not to mention all of the work to add the TCP/IP communication layer.    I want something simple to deploy, simple to manage and of course simple to code.

In my search for the ultimate solution I came across a nice little gem in the .NET 2.0/3.0 framework that I had not previously not seen; the HttpListener class.   This class is amazing!  Before jumping to far into this you need to understand that the HttpListner class only works for Windows XP SP2 and Windows Server 2003.   I have not tested it on Vista but I am guessing that it would also work under that operating system;  you can always use the HttpListner.IsSupported static property to check if the run time operating system supports this class.

With the HttpListener class I can easily have my Windows service accept HTTP connections and respond to them appropriately.   This means I can have a simple HTML UI for my Windows Service without any IIS configuration or complex coding.  

The HttpListener class can handle connections in either a synchronous or asynchronous manner.   In my Windows service I have decided to use the asynchronous method so that my service can continue to operate without the need for me to write any complex threading code.    Therefore I utilized the BeginGetContext and EndGetContext methods of the HttpListener class.  

The BeginGetContext method accepts two parameters;  a callback delegate and a state object.   The callback delegate is pretty self-explanatory but you may wonder what the state object is.   The state object is any object that you want passed to the callback method.   I would believe that most of the time you would want to use the instance of your HttpListener class as the state object so you have access to the HttpListener class methods and properties in your callback.

Using HttpListener

Using the HttpListener class is simple.  Below is a quick checklist that will get you started. 

Starting the HttpListener

1.       Verify that the user’s OS supports HttpListener by using the IsSupported static property.

2.       Create an instance of the HttpListener class.

3.       Specify the prefixes that the HttpListener will respond to.  For example http://blog.mikehacker.net:8080

4.       Start the listener using the Start method.

5.       Call the BeginGetContext method passing in the callback delegate and the instance of HttpListener created in step 2.

Responding to connections

1.       Create a new method with the name used for the delegate in the BeginGetContext call.  This method should accept an IASyncResult parameter.

2.       Retrieve the HttpListener instance from the IASyncResult parameter using the get_AsyncState method.

3.       Use the HttpListener object from step #2 to access the context, request and response objects.

4.       Craft your HTML output string and then convert it to a ubyte array.

5.       Specify the length of the output HTML ubyte array in the HttpListener’s response object.   Do this using the set_ContentLength64 method.

6.       Use the HttpListener’s response object’s get_OutputStream method to access the response data stream.  

7.       Write your HTML ubyte array to the output stream.

8.       Call the BeginGetContext method so that the listener can respond to the next connection.

Ok… so starting the HttpListener sounds simple but the responding to connections does appear to be a bit more complicated.   In a future post I will show the code for creating a simple asynchronous HttpListener.   Stay tuned for more…. J