WCF - let the client choose the return format
Asked Answered
A

4

7

I'm trying to learn some WCF on my own. I have C#/ASP.net knowledge but I am new to WCF. I am using Visual Studio 2010 to develop some apps while I learn.

I developed a small web service which acts as the backend for a TODO/Task manager where a user can create/delete/edit new events; it's all very simple and basic.

My questions are the following:

  1. Is there a way to let the client choose the return format he wants (e.g. xml/json/rdf) without writing new operation contracts?
  2. How can I see on the client the exact message the Web Service sends to me (so that I can check if it's for instance a json representation or an xml message).
Acquit answered 2/6, 2012 at 0:31 Comment(0)
B
3

The way web browsers choose response formats from web sites is via content negotiation, and in particular through the use of the Accept and Content-Type HTTP headers.

For example, if your client requires a JSON-formatted response, it would send the server an HTTP request that looks something like this:

GET /resource HTTP/1.0
User-Agent: YourClient 1.0
Accept: application/json

The server, in turn, would respond with an HTTP packet like this:

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 20

{ "type" : "json" }

WCF is unfortunately not equipped to handle content negotiation out of the box, but there is a really nice third-party library that enables it without too much work called WcfRestContrib. Their documentation describes the (quite simple) steps you have to take to make it work. To sum it up, you have to

  1. decorate your service class according to the content types you wish to support,
  2. decorate the methods you wish to be content negotiation-aware, and
  3. return a serializable business object from that method.

As for your second question, Fiddler is a fine choice for testing both the client and the server.

Bookkeeper answered 2/6, 2012 at 1:40 Comment(1)
I'll give WcfRestContrib a look later today and get back to you.Acquit
O
9

When you create a REST service with WCF, content negotiation is supported.

You simply need to set automaticFormatSelectionEnabled to true on the endpoint.

See also: WCF Web HTTP Formatting

Olathe answered 27/9, 2012 at 11:15 Comment(1)
I just found the above Microsoft documentation link myself after a painful 2 hours of searching. This answer needs more love and attention as it trumps all others.Bloodroot
B
3

The way web browsers choose response formats from web sites is via content negotiation, and in particular through the use of the Accept and Content-Type HTTP headers.

For example, if your client requires a JSON-formatted response, it would send the server an HTTP request that looks something like this:

GET /resource HTTP/1.0
User-Agent: YourClient 1.0
Accept: application/json

The server, in turn, would respond with an HTTP packet like this:

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 20

{ "type" : "json" }

WCF is unfortunately not equipped to handle content negotiation out of the box, but there is a really nice third-party library that enables it without too much work called WcfRestContrib. Their documentation describes the (quite simple) steps you have to take to make it work. To sum it up, you have to

  1. decorate your service class according to the content types you wish to support,
  2. decorate the methods you wish to be content negotiation-aware, and
  3. return a serializable business object from that method.

As for your second question, Fiddler is a fine choice for testing both the client and the server.

Bookkeeper answered 2/6, 2012 at 1:40 Comment(1)
I'll give WcfRestContrib a look later today and get back to you.Acquit
B
1

My experience is that WCF isn't great in this area. MVC is a big improvement with its concept of "Action Results" which let you return whatever you want for a given endpoint. (And supposedly the new "Web API" will be a marriage of WCF and MVC features.)

That said, the easiest WCF way to let the client choose the response format, is to specify a Stream return type, and serialize the result according to the requirement.

So declare the method like this, and use the your serializer(s) of choice for JSON and XML.

[OperationBehavior]
[WebGet()]
public Stream SomeOperation(string format)
{
    string test = "Hello world";
    string encodedResult;
    if (format.ToLower() == "xml") {
        // serialize as XML (eg, XML Serializer)
        HttpContext.Current.Response.ContentType = "text/xml";
    }
    else if (format.ToLower() == "json") {
        // serialize as JSON (eg, Newtonsoft Json)
        HttpContext.Current.Response.ContentType = "application/json";
    }
    var ms = new MemoryStream(Encoding.UTF8.GetBytes(encodedResults));
    return ms;
}

For your second question, I'd recommend using a free tool like Fiddler to inspect the raw HTTP response from the server.

Basset answered 2/6, 2012 at 0:47 Comment(4)
Thanks for mentioning Fiddler. Will test it out. I didn't really get what you meant with "specify a string return type, and serialize the result according to the requirement"? You mean make all my contracts return string and handle the serialization myself or?Acquit
@Acquit yeah, that's what I meant. I'll update the answer with a bit more detail.Basset
Thank you for adding a code example; it's more clear now. But doesn't coding everything the way you suggest prevent me from taking advantage of all the custom data types a proxy would provide? I would also have to parse the reply from the WebService instead of having objects ready out of the box?Acquit
@Acquit yes, that is a definite limitation of this approach. You couldn't generate that nifty one-click client proxy with all the deserialization built in.Basset
B
1

Instead of going for a SOAP based service you can try REST model. The new way of creating REST or HTTP services using MS technologies is using Web API that will be available ASP.NET MVC 4.

Advantages of REST:

  1. Content Negotiation - The client can specify the data-type(JSON, XML..) through the Accept-Type parameter in the Request header.

  2. Use HTTP methods explicitly

  3. Directory structure-like URIs

and more..

Bornite answered 2/6, 2012 at 5:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.