WSDAPI 101 Part 5: Putting it all together to generate WS traffic

This is the fifth article in the WSDAPI 101 series. You'll learn the most by starting at the beginning, although it's not required to understand the content in this article.

Now that we know all about the pieces required in a device-oriented Web Services application, it's time to assemble all the pieces into a working application.  You can accomplish this with any number of commercial or free Web Services stacks, but the explanation today will focus on Windows' WSDAPI, since that's what I work on.

Step 1: Set up your environment
There are three things you'll need.

  • Visual Studio or another compiler.  This article will focus on VS2005 and VS2008.
  • The Windows SDK for the WSDAPI headers, libraries, and WsdCodeGen.  The Windows Server 2008 SDK is the most recent one released, and it will let you build 32-bit or 64-bit applications for Vista or Server 2008, both of which include WSDAPI.  You can use the new configuration tool to point your Visual Studio installation to the SDK.
  • A WSDL.  This one is a little tricky--you can either write one on your own, or you can find the WSDL for the application you're coding for.  We'll use the FileService sample WSDL included in the Windows SDK.

Step 2: Create a Visual Studio solution and projects
At this point, you should decide if you want to build a virtual device (and service), a client, or both.  The remainder of this guide assumes you'd like to build both--but if you're only interested in one, you can omit some steps to decrease your development time and decrease the total size of your code.

I typically build console applications (one each for the client and device), but nearly any C++ project is acceptable.

To use WSDAPI objects, simply #include <wsdapi.h> and link in wsdapi.lib, which contains some helper and factory functions.  WSDAPI.dll, which contains the bulk of the stack, will be loaded automatically at runtime.

Step 3: Generate some code
Use the WsdCodeGen tool (included in the SDK) to create the generated layer to customize the WSDAPI interfaces to your application.  We'll generate both client-side code and device-side code; the latter requires you to provide some information about the device's characteristics (below, in the second step).

  1. Generate a config file for WsdCodeGen.  In the same directory as FileService.wsdl, run "wsdcodegen.exe /generateconfig:all FileService.wsdl"
  2. Modify codegen.config to suit your application.  Look for a block of lines near the top of the config file that have values like, "### Sample Manufacturer ###"  Change these so your device will present a usable name.  Most of these fields are mandatory.
  3. Generate code.  Lastly, run "wsdcodegen.exe /generatecode codegen.config" to generate IDL, C++, and header files.

That's it!  All of the generated code is complete.  Add these files to your Visual Studio project.  You'll have to tweak the files somewhat to get them to compile (WsdCodeGen was originally intended for the build environment in the Windows Driver Kit).  This will be fixed in the future.

Step 4: Create a service
Steps 4 and 5 are only necessary if you want to build a virtual device and host a service.  If you're not interested, you can skip to step 6.

Open the IDL file and inspect the interfaces inside.  The base interface is the one you must implement--in the case of FileService.wsdl, it's called FileService, and it only inherits from IUnknown.  You must properly implement IUnknown in your service class, and must at least implement empty stubs for all service methods.

Step 5: Create a device host for your service
The service must live inside a container--in WSDAPI, this container is the IWSDDeviceHost.  Both the FileService and StockQuote samples demonstrate how to create and configure a host.  The important steps are:

  1. Create an XML context with WSDXMLCreateContext
  2. Register your XML names with this context by calling FileServiceRegisterNamespaces
  3. Create a device host with WSDCreateDeviceHost.  You'll need to choose an ID for your host--remember this for step 6.
  4. Set metadata by supplying two generated structures ("this model metadata" and "relationship metadata") and one hand-built structure ("this device metadata") to the SetMetadata method.
  5. Register the FileServicePortType with RegisterPortType
  6. Instantiate your service object and register it with RegisterService
  7. Start the host with ... Start!

Of course, always remember to Stop and Terminate the host when finished, and always remember to clean up variables and handle errors. 

It looks like a lot of work, but the pattern is the same for every host.  The device host emphasizes flexibility over simplicity, so simple applications like FileService are often a little more work than necessary, but these apps can grow easily with the extended support in the WSDAPI objects.

Step 6: Create a client
Thankfully, this is simpler than creating a device.

  1. Create a device proxy with WSDCreateDeviceProxy.  Specify the device ID you chose in the previous step.  Searching for devices available on the network is an advanced topic, and will be covered in another article.
  2. Get a service proxy by calling GetServiceProxyByType
  3. Create a FileServiceProxy and initialize it with the service proxy in the previous step
  4. Send messages (e.g., GetFileList)

Step 7: Compile and run
That's it!  Simply build the code, fire up the device, and then run the client program.

At first glance, this article looks pretty intimidating.  There are certainly a lot of steps--some of which are fairly involved.  But once you understand the pattern of generating code, building an app, and compiling it all together, authoring complex network applications that can communicate with actual devices becomes really straightforward.  Sure, it may be easier to write a simple socket program to do what the StockQuote or FileService samples demonstrate, but the pattern above can be applied to a WSDL of any complexity and the effort required is the same.  Letting Web Services handle the messaging allows you to focus on the logic above the messaging and, more importantly, the overall solution that the application presents.

I hope you've enjoyed WSDAPI 101.  I'll continue to touch on basic concepts for the lifetime of this journal, but I'm hoping that this guide has served to illustrate the architecture and steps behind Web Services applications written for devices.  If you've got questions that weren't answered here, please feel free to post a comment.