Doing a Web Service the Right Way

Doing a Web Service the Right Way

Old forum URL: forums.lhotka.net/forums/t/2463.aspx


ltgrady posted on Friday, March 02, 2007

I tried this over at asp.net forums and didn't get a response.

We had a quick and dirty web service we had to create on the fly for a client.  Lots of dynamic sql typed right into our .cs file, loading and returning XmlDataDocuments. It worked, but it was nothing we were happy with.

Since then we've gotten our system working properly.  All our asp.net pages are running using CSLA objects.  So now we're re-writing our web service and we want to do it right. We're pretty new to web services and our clients will be using asp.net, php, and java stuff.  So we want as much interoperability as possible.

So for simple scalar type methods we're just returning the value.  Like a int or a String.  For Search Results, lists of Brands, and other more complex items we've created a custom class in our web service, then we call our business object and transfer the data from our biz object to our data transfer object ad return that object.  We're passing our security credentials to the service inside the SOAP header.

We are also trying to pass our parameters in using objects.  For instance our SearchResults had about 10 criteria fields.  An ArrayList of brands, an ArrayList of Categories, FromPrice, ToPrice, etc..  These were being passed in each with its own parameters, however, now we have an object with these properties that we pass in.  We made this change after reading Rocky's web service chapter again.  This way if we change anything in the future we don't have to have GetSearchResults2, GetSearchResultsEx, or other things like that. 

So right now our objects are just simple, basic classes that we pass back to the consumer.  I'll include an example below.  I know I'm missing something here.  When my consumers begin working with my web service what defines the classes for them?  How do they take what I give them and easily use it as a object, and also know how to form the object they need to pass back to me? What am I missing?  In order for this to be as generic and usable by as many platforms as possible, I know there is something else I need to do.  Is it XSD?  If so, does someone have a quick example of what the output below may look like?  Also, is this something I should code by hand or is there a tool or process to simplify this?

EDIT NOTE:  After reading through XSD tutuorial it seems pretty clear I should do this for my docs.  I'm still not sure though how my cosumers see these definitions before they use service though?

We're working on our input objects now but this would be what's being returned from one of our main Web Service Methods:

 <?xml version="1.0" encoding="utf-8" ?>

- <ArrayOfAnyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns=http://webservices.ourcompany.net>
- <anyType xsi:type="SResult">
  <_Product_ID>041be....6eb</_Product_ID>
  <_Brand_Name>Brand X</_Brand_Name>
  <_Brand_ID>adaee....ab4</_Brand_ID>
  <_Prd_Model>PHL-200</_Prd_Model>
  <_Prd_ShortName>Widget 200</_Prd_ShortName>
  <_Prd_SalesCopy>The new and improved Widget.</_Prd_SalesCopy>
  <_Prd_C_QuotedPrice>25.9900</_Prd_C_QuotedPrice>
  <_MSRP>42.9900</_MSRP>
  <_Prd_Status>1</_Prd_Status>
  </anyType>
- <anyType xsi:type="SResult">
  <_Product_ID>a46a5...a40</_Product_ID>
  <_Brand_Name>Brand X</_Brand_Name>
  <_Brand_ID>adaee....ab4</_Brand_ID>
  <_Prd_Model>PHL-300</_Prd_Model>
  <_Prd_ShortName>Widget 300</_Prd_ShortName>
  <_Prd_SalesCopy>The even newer and more improved Widget.</_Prd_SalesCopy>
  <_Prd_C_QuotedPrice>64.9900</_Prd_C_QuotedPrice>
  <_MSRP>75.9900</_MSRP>
  <_Prd_Status>1</_Prd_Status>
  </anyType>
  </ArrayOfAnyType>

RockfordLhotka replied on Friday, March 02, 2007

The point of web services is that you don't know what your clients are doing. You don't know if they put this result into an object, or if they parse the XML directly or something else. And, frankly, you shouldn't care.

What you should care about, is whether you are expessing your message structure through your WSDL, because that's what gives the consumer the flexibility to do what they want.

Let's face it. Most web service consumer technologies do represent results as some sort of object or object-like-thing. And they get the shape of that object from the WSDL description - actually the XSD in the WSDL.

In many cases, especially if you are accepting/returning simple DTO types like I show in the book, Visual Studio will create perfectly acceptable WSDL on your behalf.

If it does not, then you are in for more work. The general solution is to create the XSD yourself, then merge it into the WSDL and use it to create your DTO objects. There's a command line tool provided by Microsoft that creates DTOs based on XSD/WSDL.

Christian Weyer has done a lot of work in this area, and I think he has some tools to help with this XSD approach. It is often called contract-first design.

Copyright (c) Marimer LLC