Web services are a very powerful technology, greatly motivating the idea of distributed computing. Rather than creating or reinventing protocols for the sake of better technology, web services make use of strong, dependable technologies like XML, HTTP, and SSL.
Web service creation has been greatly improved from the days of the Microsoft SOAP Toolkit. Web service architecture has been integrated into the .NET framework, which enables you to get a working web service with just a few clicks.
With this article, I plan to give you a basic introduction to creating a web service, using the Microsoft .NET framework and Visual Studio .NET. I will walk you through the creation of a web service that retrieves the daily Dilbert image, and also a client that consumes that service.
This article will assume that you have a basic understanding of the C# language, and are also familiar with the Visual Studio .NET IDE.
We will create a new ASP.NET Web Service project entitled DailyDilbert. Once this project is created, you will see a few project files in the Solution Explorer. The web service itself is located in Service1.asmx. To make things a little clearer, our first step we will rename this file to something more appropriate. Let’s call it DilbertService.asmx.
To create a web service from our class, we will need to derive our class from
System.Web.Services.WebService. Using attributes, we will describe our web service class, giving it a namespace, and a description. The MSDN library defines XML namespaces as "a way to create names in an XML document that are identified by a Uniform Resource Identifier (URI). By using XML namespaces, you can uniquely identify elements or attributes in an XML document. The service description for an XML web service is defined in XML, specifically in Web Services Description Language (WSDL)." The namespace is arbitrary and does not need to point to an Internet site.
The code should resemble this:
Description="Provides methods to access the daily Dilbert image",
Our web service will utilize functions in the
System.Text.RegularExpressions namespaces, so lets add the following lines to the top of the DilbertService.asmx.cs file:
Now that we have our class declaration in order, let’s get on to the fun part. Add the following method to your
public string GetDailyDilbertUrl()
string address = "http://www.dilbert.com/comics/dilbert/archive/";
WebClient httpRequest = new WebClient();
StreamReader rdr = new StreamReader(httpRequest.OpenRead(address),
string streamText = rdr.ReadToEnd();
Match match = Regex.Match(streamText,
if (match != Match.Empty)
return "http://www.dilbert.com" + match.Value;
This method is fairly straight forward. We open a web request to the daily Dilbert page, and retrieve a string of the HTML page. When you do a View Source from http://www.dilbert.com/comics/dilbert/archive/, we see that the displayed image is located in /comics/dilbert/archive/images. The regular expression matches that pattern and takes one more more word character up to the point that it encounters .gif. If the regular expression parser encounters a match, the value of that match is appended to the base URL and returned to the client.
So, we now have a method that retrieves the URL for the daily Dilbert image. However, when we run our web service (via F5), we see that there are no available operations on our web service. To make our method callable from remote Web clients, we need to apply the
WebMethod attribute to our method. Add the following line directly above your method declaration:
Description="Retrieve the URL for the daily Dilbert image")]
Now, when we run our web service, we see that our method is available by clicking on the link in Internet Explorer. When you click on this link, there is an auto generated page that displays information about our method. This information includes syntax information for accessing this service via SOAP and HTTP POST. You also are provided an opportunity to test your web service via the "Invoke" button.
Let’s add one more method to our web service, which will return a byte array of the image itself. Add the following code to the
Description="Retrieve a byte array containing the daily Dilbert image")]
public byte GetDailyDilbertImage()
WebClient httpRequest = new WebClient();
String imageUrl = GetDailyDilbertUrl();
BinaryReader rdr = new BinaryReader(
byte imageArray = ConvertStreamToByteArray(rdr.BaseStream);
private byte ConvertStreamToByteArray(Stream theStream)
MemoryStream tempStream = new MemoryStream();
while( (b1 = theStream.ReadByte()) != -1)
Again, this is a very straight forward method. We use our previously created method to retrieve the image URL, and then create a
BinaryReader to read in the .gif file. We have added a simple helper method to convert the
Stream object to a byte array.
Now, when we run the project, we see that this additional method is available as well. When we click on the new method, and test it, we get back a base64encoded string containing the image data.
Our web service is not useful if we don’t have anyone consuming it, so let’s go ahead and create a simple WinForms application to consume our new web service.
Add a new Windows application named DilbertServiceClient to your solution. To reference the web service, we will need to add a web reference. Right click on the DilbertServiceClient project and select Add Web Reference. Type http://localhost/DailyDilbert/DilbertService.asmx into the URL box and click Go. Again, you will see the same page that you saw when you executed the web service through Visual Studio (via F5). Update the web reference name to a namespace you desire. For this article, I will use
MattBerther.DailyDilbert. Consuming this web service is now as simple as creating an instance and calling the appropriate method, as demonstrated in the following code located in Form1.cs.
protected override void OnLoad(EventArgs e)
MattBerther.DailyDilbert.DilbertService ws =
Byte imageData = ws.GetDailyDilbertImage();
System.IO.MemoryStream strm = new System.IO.MemoryStream(imageData);
Bitmap bmp = new Bitmap(strm);
PictureBox box = new PictureBox();
box.Image = bmp;
box.Height = bmp.Height;
box.Width = bmp.Width;
this.Height = bmp.Height;
this.Width = bmp.Width;
this.Text = "Daily Dilbert Image: " + ws.GetDailyDilbertUrl();
Now that we have created both a web service and a client that consumes it, let’s look at some ways that we can enhance this service. First of all, you may realize that the output from these methods only change once per day. Rather than parsing the daily Dilbert page upon every request, it would make sense to cache the request. Caching a web method result is very straight forward. Simply add the
CacheDuration property to the
WebMethod attribute as shown below:
Description="Retrieve the URL for the daily Dilbert image",
CacheDuration gets or sets the number of seconds the response should be held in the cache. To make as few requests as possible to the main Dilbert page, let’s set it to cache the response for 12 hours (43200 seconds). We can verify that the caching is working, by placing a breakpoint on the first line in our web method, and then running the client consecutive times. The client will be fed the cached response up until either:
- The cached timeout has expired, or
- IIS has been reset.
As we look to deploy our Dilbert application to other desktops, we may want to provide some functionality to change the URL our web service points to. Using Visual Studio .NET and the .NET framework, this is as simple as changing the
URLBehavior property on our web reference from static to dynamic. When you change to dynamic, a key entitled
DilbertServiceClient.MattBerther.DailyDilbert.DilbertService will be added in the app.config file. The value of this key is the URL to point to for consumption of the web service.