Web Service: Transfer Binary Data via HTTP

Although XML Web Services generally return XML (that is, text), it's possible to have a Web Service return binary information, as well. Because the SOAP serializer automatically serializes byte arrays using Base64 encoding, your Web Service applications can easily return images, sounds, and more--it's just up to you to convert the source files into byte arrays. The .NET Framework takes care of the rest.

This demonstration includes a .NET Web Service that returns images, and a Windows application that consumes the methods of the Web Service.  Specifically, the ImageService.asmx page provides three publicly callable methods:

In addition, the ImageService.asmx class provides a public class, ImageInfo, which contains information about an image in the .\Images folder, including:

The client application calls the Browse method of the XML Web Service and displays a list of all the available images in a list box. As you select an item in the list box, the form displays a thumbnail image and information about the selected image. Double-clicking on the thumbnail (or clicking Display Image) displays the full image in a separate form. You can open as many image forms as you like. The image form (frmImage.vb) allows you to scale the image, or save it to a file.

Installation:

This is repeated from the ReadMe.htm file one level up. You do not need to repeat it if you have already completed these steps.

Because this example involves both a Windows client application and a Web Service application, its installation is a bit trickier than most samples. The client application, VB.NET How-To Web Service Graphics, includes a Web Reference to the Web Service exposed by the GraphicsServer project. Your goal is to create a new virtual directory named VB.NETHowToGraphicsServer that "points" to the WebService folder that was created when you installed this example.

In order to create the necessary IIS (Internet Information Server) project, follow these steps:

  1. From the Windows Control Panel, Administrative Tools menu, select Internet Information Services.
  2. Within the Internet Information Services applet, expand nodes in the treeview panel on the left, expanding Internet Information Services, your local computer, Web Sites, then Default Web Site.
  3. Right-click on Default Web Site, and select New, then Virtual Directory. Click Next to bypass the Welcome page.
  4. In the Virtual Directory Alias page, enter VB.NETHowToGraphicsServer. Click Next.
  5. In the Web Site Content Directory page, browse to the WebService folder within the sample you've installed, and select the WebService folder. Click Next.
  6. In the Access Permissions page, click Next to accept the default settings.
  7. Click Finish to complete the wizard.

Once you've added the new virtual directory, you should be able to load the  VB.NET How-To Web Service Graphics.sln file, in the Client folder, and then load and run the sample.

Featured Highlights

This sample calls two Web Service methods:

When you click the Retrieve Images on the main form, the code calls the Browse method, retrieves the array of ImageInfo objects, stores the array into a class variable, and adds the name of each available image to the list box (lstImages). As you select each image, code in the SelectedIndexChanged event handler displays selected properties of each image, along with the thumbnail image.

Double-click on the thumbnail, or click Display Image, and the sample loads a new instance ofr frmImage. This form displays the full image you selected, and allows you to display that image at 50%, 100%, or 200% of its original size, as well as allowing you to stretch the form (and the image) to any size. You can save the image to one of several different image formats (bmp, jpg, and so on).

Requirements

Requires the Trial or Release version of Visual Studio .NET Professional (or greater).

Running the Sample

Understanding the techniques involved in returning and consuming binary values from Web Services is simple, as long as you buy into the concept of using byte arrays on both ends. The .NET SOAP serializer handles the conversion to and from Base64 encoding, so you needn't worry about that, but you will need to convert to and from byte arrays. On the server, you'll find code in the ReadFile procedure that handles converting from a FileStream into a byte array, like this:

Dim fs As FileStream
' Read file and return contents
fs = File.Open(FilePath, FileMode.Open, FileAccess.Read)
Dim lngLen As Long = fs.Length
Dim abytBuffer(lngLen - 1) As Byte
fs.Read(abytBuffer, 0, lngLen)

On the client side, the code must convert from a byte array back into a Bitmap, using the following procedure:

Private Function GetImage(ByVal abyt() As Byte) As Bitmap
  ' Given an array of bytes, return an actual Bitmap
  ' object. This requires creating a new MemoryStream
  ' object based on the array of bytes, and then
  ' creating a new bitmap based on the memory stream.
  Return New Bitmap(New MemoryStream(abyt))
End Function

This code counts on the fact that you can initialize a MemoryStream object given a byte array, and can create a Bitmap given a MemoryStream. There are undoubtedly other ways to accomplish the same goal, but this is quick and easy.

Retrieving the thumbnail is simple, but requires a little trick. The GetThumbNailImage method of the Bitmap class allows you to pass it a file name and the dimensions of the thumbnail, but it also requires a callback procedure to handle cancelling the conversion. At this point, the .NET Framework doesn't actually use the callback, but you must supply it, and it must match this definition:

Private Function ThumbnailCallback() As Boolean 
  Return False
End Function

The method also includes a final parameter that must be IntPtr.Zero, at this time.

In addition, to get the "shape" of the thumbnail correct, the sample code adjusts the width of the thumbnail to match a fixed height:

Const THUMBNAIL_HEIGHT = 80
intWidth = bmp.Width
intHeight = bmp.Height
decRatio = intWidth / intHeight
Dim bmpTemp As Bitmap
bmpTemp = bmp.GetThumbnailImage(decRatio * THUMBNAIL_HEIGHT, THUMBNAIL_HEIGHT, _
 AddressOf ThumbnailCallback, IntPtr.Zero)
bmpTemp.Save(ms, Imaging.ImageFormat.Jpeg)

The remainder of the code in this demonstration handles the display of the image, the sizing of frmImage, and the saving of the image. For more information, read the source code and its comments.

Certainly, if you were to create an application like this one for commercial use, you'd want to investigate ways to optimize bandwidth. We've simply required a call to the Web Service method for each image you request, yet the example could optimize the behavior by caching images both on the client side (storing them in a temporary folder, perhaps, or in memory) and on the server side using output caching provided by ASP.NET. Instead, this demonstration focuses on handling binary files as return values from Web Services.

Last Update: 7 July 2002