Ivan Krivyakov
Ivan Krivyakov

Reputation: 2058

How to return CSV OR JSON from a RESTful WCF call depending on a parameter?

Imagine I need to return a list of users, and the result must be in either CSV or JSON format.

/users?format=json returns JSON /users?format=csv returns CSV

I tried to implement it via a method that returns object:

// interface
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "users?format={format}", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[ServiceKnownType(typeof(List<UserInfo>))]
[ServiceKnownType(typeof(Stream))]
object GetUsers(string format);

The implementation returns either Stream or a list of users:

    public object GetUsers(string format)
    {
        if (format == null) format = "json";
        switch (format.ToLower())
        {
            case "json":
                return GetUsersJson(); // returns List<UserInfo>

            case "csv":
                return GetUsersCsv(); // returns MemoryStream

            default:
                return BadRequest("Invalid content format: " + format);
        }
    }

When I run this, JSON version works, but CSV version fails with a serialization exception:

System.Runtime.Serialization.SerializationException: Type 'System.IO.MemoryStream' with data contract name 'MemoryStream:http://schemas.datacontract.org/2004/07/System.IO' is not expected.

If I replace ServiceKnownType(typeof(Stream)) with ServiceKnownType(typeof(MemoryStream)), there is no exception, but the downloaded file contains JSON representation of a MemoryStream:

{"__identity":null,"_buffer":[78,97,109,...,0,0,0,0],"_capacity":256, "_expandable":true,"_exposable":true,"_isOpen":true,"_length":74, "_origin":0,"_position":74,"_writable":true}

This is not exactly what I had in mind when returning a stream :)

So, is there a way to return a Stream polymorphically, or do I have to use two different calls?

Upvotes: 0

Views: 1266

Answers (1)

Garett
Garett

Reputation: 16838

Your response format is set to WebMessageFormat.Json, which is why WCF is returning JSON. One way to achieve what you want is to use the WCF "Raw" programming model, which would mean changing the return type of the method to Stream. When this is done you are telling WCF that you want to control the response, and it will apply no formatting to the data. You can then use the the built in DataContractJsonSerializer (or any other serializer) to serialize the JSON string to the stream. Be sure to set the WebOperationContext.Current.OutgoingResponse.ContentType to an appropriate value in either case.

Upvotes: 1

Related Questions