REST/POX client with WCF
The most remarkable thing in WCF is its extensibility. The Indigo team did a really great work providing hooks almost everywhere, that allows to customize all behaviors in every step of the communication framework.
In this example I created a client behavior that communicates with a REST/POX service. Clemens Vasters have an excelent series of articles on how to create REST/POX services with WCF. There is also two articles here and there in MSDN but what I don’t like about it is that you loose the type safe contracts, having to deal with Message class in order to send a request or decode the response.
What I did to avoid this problem is use a series of extension points in order to customize the request and response messages. In the example I used the del.icio.us API.
These are the WCF hooks I’ve implemented:
- IEnpointBehavior: attaches the message inspector and also configures itself as an operation behavior in every contract operation.
- IOperationBehavior: configures the message formatter.
- IClientMessageInspector: customizes the request message suppressing the body, changing the HTTP method and headers, and setting the query string previously created by the message formatter. This is done setting an instance of
HttpRequestMessagePropertyin the message properties. This is later used by the HTTP channel. - IClientMessageFormatter: This implements both the request and response customizations. In the
SerializeRequestmethod, it creates the query string and attach it as a property in an empty message. This is later used by the message inspector to create the final request. It also uses theActionvalue of theOperationContractto use as the relative URI. In theDeserializeReplymethod, the received message is deserialized as a plain XML using theXmlSerializer.
Once the behavior is attached to the client endpoint, the contract methods can be defined as:
[OperationContract(Action = "/v1/posts/recent")] PostsResponse GetRecentPosts(string tag, int? count);
That makes a request to the address defined in the Action, with two arguments (tag and count) in the query string.
IMPORTANT NOTE: Take special care in the usage of this example. It doesn’t take into account any of the important notes about the del.icio.us api usage, and you can be throttled. Use under your own risk. Again, this is just an example.
In order to use this example, first you have to provide your del.icio.us username and password to WCF, setting it in the Program.cs.
There is a number of things to improve. For example, right now it only supports GET requests. It should also handle POST method serializing the arguments as a POX request. Also, the query string arguments formatting should be customizable.
Download the sources: WcfRestPox.zip
Posted: May 13th, 2007 under .NET, WCF.
Comments: 9
Comments
Comment from Frank-Leonardo Quednau
Time: July 18, 2007, 11:04 am
Greetings!
I enjoyed reading through your item and your project works well. I have been looking into setting up something similar with facebook.
However, I am quite stuck with the fact that most requests need to be POSTed. That in itself may be alright, but the body sent has nothing to do with XML. Wherever I look at WCF’s body properties I hit XMlSerializers and similar objects. Do you think there is any way to send a message whose body is not XML?
Comment from Juan Wajnerman
Time: July 18, 2007, 9:58 pm
Frank, in order to customize the POST content, you should create a custom MessageEncoder. The message encoder is responsible of serialize the message on the wire.
In fact, what you have in the message is the XML infoset. That is an abstract representation of the objects, and that is created by the message formatters.
So, the big picture can be something like this:
typed object >– FORMATTER –> message (xml infoset) >– ENCODER –> XML or any other representation
At the same time, remember that the output of the encoder should be supported and will be encapsulated by the transport channel. In the case of a http transport, that means the body of the http request.
Hope you find this useful.
Thanks for reading!
Juan
Comment from Frank-Leonardo Quednau
Time: August 8, 2007, 6:20 am
Hi Juan,
I wasn’t even sure my comment got through, as your underlying DB didn’t respond that day…anyway, back then I found the necessary step by writing an encoder and got it working…hence no need to POST XML with WCF! So far I have only documented the web sites I came across, but I will be writing about the Text Encoder business in the days to come on my site. Thanks again for your helpful post!
Comment from Greg Sojalski
Time: September 20, 2007, 3:16 pm
Juan,
Great article.
So if one had to do a post of a large xml doc to a REST service, what modifications does one have to make to this code? Obviously changing a GET to a POST, but how does SerializeRequest change? Any details or info would be greatly appreciated.
Comment from jwajnerman
Time: September 29, 2007, 2:39 pm
Greg, basically you have to return a non empty Message from SerializeRequest method. You can use other overloads of Message.CreateMessage for that. For example, creating a custom BodyWriter.
Apart from that you just have to change the verb and set the SuppressEntityBody to ‘true’ in the BeforeSendRequest method and you are done.
Then you’ll have to think about how to make it more flexible and support either GET or POST requests, how to specify it. For example you can parse the Action to be something like “GET /foor” or “POST /bar”. Also, if you want to mix query string arguments with request body, which argument(s) will be used for the body and which ones for the query string? You can assume the first one for the body, or use attributes, etc… All this stuff depends on your requirements and your creativity ;-).
Comment from Greg Sokalski
Time: October 2, 2007, 2:08 pm
Thanks Greg.
So my requirement is to have a WCF service that my internal .NET apps can call and pass in an object graph that the service needs to deserialize into xml and post it to another external RESTful service which in turn will send me reply xml then I would need to serialize and send back to the consumer.
I’m assuming, correct me if I’m wrong, I construct a normal WCF service with a defined service and data contracts. Tnen inside my service contract, I would need to deserialize the data into xml (1. any place this should be done or just simply inside the business logic?). Once I have the raw xml, I can then utilize my custom RestPoxBehavior while calling the RESTful service, where inside of it (like yours), I set the method to POST, SuppressEntityBody to true (2. what do I do with headers, properties? I don’t really understand that part). Then in the SerializeRequest, I use my custom BodyWriter (3. a. do I simply create a message with my raw xml? b. do I set any specific Message properties?).
Lastly, in the DeserializeReply, 4. is that the place where I deserialize the xml received from the ReSTful service?
I apologize if any questions seem odd but I’m new and hopefully you can guide me in the right direction.
Appreciate your help.
Comment from Matt
Time: November 3, 2007, 2:26 am
Hi Juan,
I’ve spent all day trying to figure out how to parse xml data that I am posting to my wcf service.
Here is what the operation contract looks like
[OperationContract, WebInvoke]
XmlElement GetAsXml();
I want to parse the xml that is included in the Post Request Body.
Any ideas on how I would do that.
Comment from Matt
Time: November 3, 2007, 2:30 am
Some more info that i forgot to add. I am simulating a client POST request by using fiddler to send xml data in the request body. I always get the same response:
HTTP/1.1 415 Unsupported Media Type
I’ve tried setting the RequestFormat in the WebInvoke Attribute as RequestFormat=WebMessageFormat.Xml
but that didnt make any difference.
Thanks
Matt
Pingback from Juan Wajnerman » REST/POX client with WCF 3.5
Time: December 1, 2007, 6:56 pm
[...] time ago I wrote a post about how to create REST clients using WCF and taking advantage of its extensibility to obtain a [...]
Write a comment