A Simple Commerce Application

The Web File Share Application

This example will create a Web service that allows binary files to be transferred over HTTP and SOAP. Because SOAP leverages an XML-based method of encoding, you must represent method parameters and return values in a way that is conducive to XML.

In the preceding example, it was rather straightforward to encode the credit card number and the expiration date. In this example, the Web service will encode complex types that contain, among other things, binary data. As you will see, the .NET platform will handle the encoding and decoding for you. It will ensure that byte arrays are encoded so that they do not introduce special characters into the SOAP message that would invalidate the XML.

Before I go any further, I want to throw in a little disclaimer: There are more efficient ways of sending the content of a file over the Web than encoding it into a SOAP message. The purpose of this example is not to create a replacement for FTP; it is to demonstrate the power and flexibility of Web services and the robustness of the .NET platform.

Creating the WebFileShare Web Service

The WebFileShare Web service will expose two methods, ListFiles and GetFile. ListFiles is used to obtain a list of files that are available from the Web service, and GetFile will allow the client to retrieve the specified file.

First you create a Visual Studio .NET Web Service project using steps similar to those shown in the previous example: Open Visual Studio .NET, and create a new project. Set the project type to your language of choice, and select the Web Service template. Name your project WebFileShare, and set the location to a URL that points to the targeted Web server.

Change the name of the Service1.asmx file to WebDirectory.asmx. Right-click on WebDirectory.asmx, and choose View Code. Change the name of the Service1 class and its corresponding constructor to WebDirectory. Then modify the Inherits property in the ASMX header to point to the new class name.

Now that you have set up the Visual Studio .NET project, you will add the implementation to enable the client to request and retrieve files. First you need to create an alias for the System.IO namespace with the using keyword. Underneath the using statement that creates an alias for the System.Web.Services namespace, type the following statement:

using System.IO;

Next you define the WebFile structure, which encapsulates the contents of the file in addition to its metadata. The file structure contains the name of the file, the file's contents, and the file system attributes associated with the file.

Define the following structure immediately after the WebFileShare namespace is defined:

    public struct WebFile     {         public string    Name;         public byte[]    Contents;         public DateTime  CreationTime;         public DateTime  LastAccessTime;         public DateTime  LastWriteTime;     }

Next you need to create a number of methods within the WebFileShare class. These methods will be defined immediately before the example HelloWorld method.

The first method that must be defined returns a list of files available for download in the c:\Public directory. The list of files is returned as an array of strings. The .NET Framework will properly serialize the array for you.

        [WebMethod]         public string[] ListFiles()         {             return Directory.GetFiles("c:\\Public");         }

Next you create a GetFile method that allows the client to request a file. If the file is available, an instance of the WebFile structure should be sent back to the client. In this method, you use the System.IO.File object to obtain the necessary information about the file. You obtain a Stream object from the File object and write the contents of the stream into a byte array in the WebFile structure. You also set the CreationTime, LastAccessTime, and LastWriteTime fields to the values obtained from the associated static methods exposed by the File class.

        [WebMethod]         public WebFile GetFile(string fileName)         {             WebFile   webFile = new WebFile();             string    filePath = "c:\\Public\\" + fileName;             // Set the name of the file.             webFile.Name = fileName;                          // Obtain the contents of the requested file.             Stream s = File.Open(filePath, FileMode.Open);             webFile.Contents = new byte[s.Length];             s.Read(webFile.Contents, 0, (int)s.Length);             s.Close             // Retrieve the date/time stamps for the file.             webFile.CreationTime = File.GetCreationTime(filePath);             webFile.LastAccessTime = File.GetLastAccessTime(filePath);             webFile.LastWriteTime = File.GetLastWriteTime(filePath);             return webFile;         }

After the WebFile structure is initialized, it is sent back to the client. Once again, the .NET Framework performs the appropriate serialization. In this case, the instance of the structure is serialized, including its data. The Contents byte array is encoded into its Base-64 representation. Base-64 encoding maps each byte of the array into an alphanumeric character that can be contained within the XML document without introducing any invalid characters. In addition, the values of the Name, CreationTime, LastAccessTime, and LastWriteTime fields are serialized into the SOAP message.

In future chapters, I will discuss in detail how the .NET Framework encodes more complex data types such as structures, byte arrays, and enumerations. The important thing to realize is that the resulting message is 100 percent compliant with the industry-standard SOAP specification. Therefore, clients on other platforms, operating systems, or hardware can interact with your WebDirectory Web service.

Now that you have built the Web service, let's create a client for retrieving files through the WebFileSystem Web service.

Creating the WebFileUtil Program

Next you will create a console application to retrieve files from the WebFileShare Web service. This console application will accept at least two command-line arguments: a command specifying the action to take, and the name of the targeted file. You can optionally specify a third argument if you want to specify the name of the destination file. Otherwise, the default value is the original name of the file.

Start by opening Visual Studio .NET and selecting Create New Project. Set the project type to your language of choice, select the Console Application template, and name the project WebFileUtil, as shown here:

You can change the name of the Service1 file (with an extension based on the language you chose) to WebFileUtil and then delete the default implementation in WebFileUtil provided by Visual Studio .NET.

Next you add a Web reference to the WebDirectory Web service. Start the Web Reference Wizard by choosing Add Web Reference from the Project menu. In the Address text box, enter the URL of the server that hosts the Web service. Click on the link to the WebFileShare directory. The WebFileShare Web service will automatically be selected, as shown here:

Click the Add Reference button. Change the name of the new Web reference listed in Solution Explorer to WebFileShare.

Now that you have created and configured a Web reference, let's step through a C# implementation of WebFileUtil.

First you import the System.IO namespace into the project. This will simplify your code when you use the File class in the code below. You must also import the namespace of your Web reference, WebFileShare.

using System; using System.IO; using WebFileUtil.WebFileShare; namespace WebFileUtil {

You then change the name of the class from Class1 to a more descriptive name, WebFileUtil.

    public class WebFileUtil

Ensure that the program was passed the correct number of command-line arguments, and then initialize the source and destination variables.

    {         // Validate number of command-line arguments.         if(args.Length < 1   args.Length > 3)         {             DisplayUsage();             return 1;         }         // Initialize variables.         string source = args[1];         string destination = source;         if(args.Length == 3)             destination = args[2];

Next process the commands that were passed. The appropriate helper function will be called for the DIR or GET command:

        // Process command.         switch(args[0].ToUpper())         {             case "DIR":                 ListFiles();                 break;             case "GET":                 GetFile(source, destination);                 break;             default:                 DisplayUsage();                 break;         }         return 0;     }

Next create a ListFiles method to output to the console the list of files available from the Web service. To do this, create a WebDirectory object and a reference to an array of strings. Then set the reference to the array of strings equal to the return value from the WebDirectory.ListFiles method. Finally iterate through the array and write the name of each file out to the console.

    private static void ListFiles()     {         WebDirectory    webDir = new WebDirectory();         string[]        files;         files = webDir.ListFiles();         foreach(string file in files)         {             Console.WriteLine(file);         }         Console.WriteLine("\n{0} file(s) in directory.", files.Length);     }

To create the GetFile method that will retrieve the requested file and save it to the file system, you first create a new instance of the WebDirectory class and a reference to WebFile. Then you call the GetFile method on the WebDirectory object to retrieve the WebFile object. You open the destination file and use the stream class to write the byte array to the file. Finally you set the date/time stamps for the file to the values contained within the CreationTime, LastAccessTime, and LastWriteTime fields.

    private static void GetFile(string source, string destination)     {         WebDirectory    webDir = new WebDirectory();         WebFile         webFile = new WebFile();                      // Retrieve the requested file and then save it to disk.         webFile = webDir.GetFile(source);         // Save the retrieved Web file to the file system.         FileStream fs = File.OpenWrite(destination);         fs.Write(webFile.Contents, 0, webFile.Contents.Length);         fs.Close();         // Set the date/time stamps for the file.         File.SetCreationTime(destination, webFile.CreationTime);         File.SetLastAccessTime(destination, webFile.LastAccessTime);         File.SetLastWriteTime(destination, webFile.LastWriteTime);     }

Finally you create a DisplayUsage method to write the proper syntax for WebFileUtil to the console.

    private static void DisplayUsage()     {         Console.WriteLine("WebFile is used to retrieve files from the         WebDirectory Web service.");         Console.WriteLine("\nUsage:  WebFile command source [destination]");         Console.WriteLine("\tcommand     - Either DIR or GET.");         Console.WriteLine("\tsource      - The name of the file to          retrieve.");         Console.WriteLine("\tdestination - Optionally the name of the          destination file.");         Console.WriteLine("\nExamples:");         Console.WriteLine("\tWebFile GET somefile.exe");         Console.WriteLine("\tWebFile GET somefile.exe c:\temp");         Console.WriteLine("\tWebFile GET somefile.exe c:\temp\myfile.exe");     } }

Note that this example uses .NET types throughout. The Web service declared classes that exposed methods with strongly typed parameters and return values. For example, the WebFileShare Web service declared a WebFile struct. The client code uses the WebFile struct as if it were a native .NET type even though the messages are passed between the WebFileUtil client and the WebDirectory Web service in XML.

As a result, many of the rich features of Visual Studio .NET are available to the developer, such as IntelliSense and the ability to catch type mismatch errors at compile time. For example, the WebFile structure was available to the client with no loss in fidelity. If the client attempts to set the LastAccessTime field to a string, an error would be generated at compile time. This was accomplished because the WebFile structure was exposed in the WSDL file that is automatically generated by the ASP.NET runtime. Visual Studio .NET uses the information in the WSDL file to create a strongly typed proxy for the Web service.

As you might assume, the byte array had to be encoded in some fashion before it could be included in an XML document. However, the .NET infrastructure handled all of the encoding for you. The byte array was transformed into a Base-64-encoded string, placed into the SOAP message, sent across the wire, and then decoded back into a byte array. (I will cover Base-64 and other XML data types in Chapter 4.)



Building XML Web Services for the Microsoft  .NET Platform
Building XML Web Services for the Microsoft .NET Platform
ISBN: 0735614067
EAN: 2147483647
Year: 2002
Pages: 94
Authors: Scott Short

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net