Working with WCF Part Four – Data Contracts

Previous posts in this series:

After creating our service, our host and our client, we were able to get our Web Bagels business off the ground, and it’s become incredibly successful! And with success comes the need for growth. Among the requests from our legions of customers is to have better information being returned when they place their order. In this post I’ll show you how to use a Data Contract to accommodate those requests and explain the differences between the Data Contract serializer and the XML serializer.

Data, Data Everywhere

So far our service has used primitive types in both it’s method parameters and it’s return types. And there are times when that’s all you need. But what if you want to send more complex data? Consider the current implementation of our WebBagels service:

image

Up till now we’ve just been returning a confirmation number, and that’s been fine. But as our business has gotten more successful our customers have asked for a few more things. For one thing they would like to know when their bagels are going to be ready for pickup.  They would also like to know how much the bill is going to be.

So we’ve gone from having rather modest data needs to having some complex information that needs to be returned. WCF provides us with the ability to create Data Contracts, which are complex types that we have identified to WCF that we want to be serializable and have the ability to send and receive these types with WCF services. Let’s start by re-defining what we’re going to be returning.

Our clients have asked for the following information to be returned:

  • A confirmation number
  • A time that we can pick up our order
  • How much our order is going to cost.

At their core, Data Contracts are just classes that represent the data we want to send over the wire. To create a data contract to represent these bits of information, add a new class to the WebBagels project (the one our service contract and service implementation are in) and call it BagelOrderResponse.  Add a public property for each of these values to the BagelOrderReponse class. It should look a bit like this:

image

Now that we have a class to represent what we are going to be returning to our clients, we need to let WCF know that we want to be able to send this back as a response from our service. Like Service Contracts, Data Contracts are created by decorating classes with attributes, in this case the DataContract attribute. Add the DataContract attribute to the BagelOrderResponse class declaration:

image

WCF uses an opt-in model for all of it contracts. So, we’ll need to identify each member of our BagelOrderResponse class that we want serialized and sent to/from our service. We do this by decorating our properties with the DataMember attribute:

image

Now that we have our data contract we need to let our service and our service contract know about it. First, lets go back to the IBagelOrderService interface and change the definition of the PlaceOrder method to return an instance of our BagelOrderResponse data contract instead of an int:

image

Since we’ve changed the definition of this method in the interface, but not in our service implementation, our solution will not compile, let alone run. We’ll fix this by changing the method definition in the BagelOrderService implementation:

image

Now we just need to add some code to create, populate and return an instance of our BagelOrderResponse object:

image 

From a service stand point, that’s it! Although, when you compile you will see there is one issue with our custom client:

image

The proxy object for our custom client and our service implement the same contract. When we changed the service contract we broke this client. In truth, we broke all three clients, we just haven’t seen the breakage in the others yes since they implement a different version of the IBagelOrderService interface that we received as metadata from the service with we either ran SVCUTIL or used the “Add Service Reference…” functionality of Visual Studio. When we run these clients against our service they wont work.

Fixing the WebBagels.Client.SVCUTIL version of our client is simple; just re-run the SVCUTIL utility against the services metadata, which will re-write the proxy with the correct signature. To fix the proxy for the WebBagels.Client.Simple project you just need to right click the service reference in the project and from the context menu select “Update Service Reference”

image

Fixing the custom client is just as simple. All we need to do is update the PlaceOrder method of the BagelOrderServiceClient class in the proxy.cs file to return a BagelOrderResponse:

image

Now our solutions will compile. Before we get too worried out our client projects, we’re going to use the WCF test client. In order to make this easier, we need to switch back to using the WCF service host that is included with Visual Studio. If you’re remember we disabled this in a previous post. To re-enable it, right click on the WebBagels project (our WCF class library project) and click on the the WCF Options tab. Re-check the box marked “Start WCF Service Host when debugging another project in the same solution.”

image

Hit F5 to run the application. The WCF Test Client should open pointed at our Bagel Order service:

image

Go ahead and test the service with any data you choose. You should see the results returned at an instance of our data contract:

image

If you click on the XML tab you can see how our BagelOrderResponse object has been serialized as XML:

image

Let’s see how this works with our clients. In the properties for the WebBagels project, uncheck the box marked “Start WCF Service Host when debugging another project in the same solution”  and right click on the WebBagels.Host project and select “Debug | Start New Instance” item from the menu. Once the service is running, right click the WebBagels.Client.Custom project and select “Debug | Start New Instance” item. The client should display the message…

image

So it worked! Uh, kinda. To be honest, that message isn’t particularly helpful. Let’s make a few changes to the display logic in the Program.cs file of the WebBagels.Client.Custom project to give us a message that’s a bit more “human friendly.”

Since a data contract is just another class, from the client codes’ point of view, we should be able to just access the public properties of the object as if it were any other object. Let’s change our display logic a bit:

image

Now when we run the client, we should get something a bit more useful:

image

A Tale Of Two Serializers

When we decorate our response class with the Data Contact attribute, we are telling WCF to use the Data Contract serializer to convert our object into XML to be packaged into a SOAP message and, in this case, returned to the client of the service. If you’ve done any work with ASMX-based web services or any XML work in .NET you no doubt have made use of the .NET XML serializer. While these two serializers ultimately do the same thing, they go about it in different ways.

The Data Contract Serializer is specifically designed for WCF data contracts, and thus is the default for WCF services. The Data Contract serializer is an “opt-in” model, meaning you have to identify which fields you would like serialized. If you don’t mark a field with the DataMember attribute the WCF Data Contract serializer will ignore it.  The Data Contract serializer is very fast compared to the XML serializer. The cost associated with this speed is that the WCF Data Contract serializer does things one way; it’s way. The developer has very little control over how the XML is created and emitted. The Data Contract serializer optimizes it’s XML for speed.

As a corollary, the XML serializer is a general purpose serializer. It operations in an “opt-out”mode: the XML serializer will attempt to serialize every serializable public attribute on a class unless it is told to ignore it. While the XML serializer is not as fast as it’s WCF cousin, it makes up for it by giving the developer the ability to precisely control how data is serialized/deserialized into/from XML.

As mentioned, the Data Contractor is specifically designed for WCF, and is the default serializer. It’s fast and will suit 99% of your needs. If you need more control over how that XML is created, use the XML serializer. Each works will with WCF. An example of how to use the XML serializer will come in a future post.

In the next installment, we’ll look at the Data Contracts cousin, the Message Contract.

DotNetKicks Image
Print | posted on Friday, May 07, 2010 6:30 PM

Feedback

No comments posted yet.
Title  
Name
Email (never displayed)
Url
Comments   
Please add 5 and 2 and type the answer here: