Answered Custom JSON serialization in WCF REST 3.5

  • Tuesday, May 20, 2008 9:42 PM
     
     
    Hi all,

    I was hoping to get some help with some custom JSON serialization in WCF REST services. Some of my the types i am trying to return from my WCF REST service have strict JSON serialization standards they need to follow which goes beyond the scope of the customization offered by the DataContract. So, I have the JSON serialization logic implemented in a ToJSON(...) method on the type.

    How can I return the output of the ToJSON(...) function instead of the default .net JSON serializer? I tried returning the custom serialized JSON as a string but that puts the JSON output within quotes. How can I leverage the extensibility of the WCF REST serialization framework to return the custom JSON generated by the function.

    Thank You,
    Vish

All Replies

  • Wednesday, May 21, 2008 4:04 AM
     
     Answered

    You can use the WCF REST "raw" programming model to return exactly what you want. The post at http://blogs.msdn.com/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-web.aspx, it explains how to use that mode.

  • Wednesday, May 21, 2008 5:22 AM
     
     

    Hi Carlos,

     

    Thank you that worked for me. I had actually tried returning a Stream earlier. But I was writing the string to the stream using a StreamWriter. And weirdly that does not work. The response is empty. Any ideas as to why? But anyway using the UTF8 encoder like you did in your application works fine for me right now. Thank you. I appreciate your time for the response.

     

    Thank You,

    Vish

     

  • Wednesday, May 21, 2008 1:39 PM
     
     

    One reason why the response might have been empty with the StreamWriter is that the writer hadn't flushed the data to the stream (sometimes it buffers some data for performance reasons). If you call StreamWriter.Flush it should write the data to the underlying stream.

     

    Glad to have helped Smile

  • Wednesday, May 21, 2008 1:44 PM
     
     

    Hi Carlos,

     

    I did flush the stream. But still had no luck with the response. That was very weird. Does encoding have anything to do with it?

     

    Thank You,

    Vish

     

  • Thursday, May 22, 2008 12:35 AM
     
     

    Hi Carlos,

     

    The problem I was having with using StreamWriter to write to a memorystream and then it was, Not only did I have to flush the StreamWriter but I also had to reset the position on the MemoryStream to 0.

     

    Thank You,

    Vish

     

  • Thursday, July 24, 2008 8:54 AM
     
     

    Hi Carlos

    In continuation to the above

    Is it possible to prompt the user with a File Download Box on the browser using the approach above.

    I am returning a Memory Stream from the Service. I am also setting the Content-Disposition and Content-Type headers in the WebOperationContext.

    Still the File Download box is not prompted.

    The same works from a normal ASP.Net page. I have checked the headers using Fiddler and they are the same.

    Is there anything else I need to do to enable the File Download box prompt?

     

    Thanks in advance

    Regards

    Vikas Manghani

     

     

  • Thursday, July 24, 2008 6:57 PM
     
     Answered

    That should just work. I just used this simple .svc file, and it just worked. What is the problem you're seeing?

     

    <%@ServiceHost language=c# Debug="true" Service="MyTest.Service" Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory" %>
    namespace MyTest
    {
     using System;
     using System.IO;
     using System.ServiceModel;
     using System.ServiceModel.Web;
     using System.Text;

     [ServiceContract(Namespace = "")]
     public interface ITest
     {
      [OperationContract, WebGet]
      Stream GetData();
     }

     [ServiceBehavior(IncludeExceptionDetailInFaults = true, Namespace = "")]
     public class Service : ITest
     {
      public Stream GetData() {
       WebOperationContext.Current.OutgoingResponse.ContentType = "application/json";
       WebOperationContext.Current.OutgoingResponse.Headers.Add("Content-Disposition", "attachment; filename=MyFile.json");
       string jsonResponse = "{\"a\":123,\"b\":[false, true, false],\"c\":{\"foo\":\"bar\"}}";
       MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonResponse));
       return ms;
      }
     }
    }

  • Friday, July 25, 2008 6:19 AM
     
     

    Hi Carlos

    The problem I face is that I need to return a file to the user (similar to Response.TransmitFile(Filename) in ASP.Net). The user should see a prompt on the browser to download the file.

    The code I am trying to use is this:

     

    public Stream DownloadFile()

    {

    //Read File bytes into a byte array

    byte[] bytes = ReadFile(filepath);

     

    MemoryStream ms = new MemoryStream(bytes);

    ms.Position = 0;

    WebOperationContext.Current.OutgoingResponse.ContentType = "application/octet-stream";

    WebOperationContext.Current.OutgoingResponse.Headers.Add("Content-Disposition", "attachment; filename=1.doc");

     

    return ms;

    }

    This doesnt result in any prompt, though from what I read, the Content-Disposition header should force the browser to display a prompt.

     

    Thanks again

    Regards

    Vikas

  • Friday, July 25, 2008 9:15 AM
     
     

    Hi Carlos

    Just a small thing - when I submit an HTML form with Action= URL of WCF service, it works fine. The file gets downloaded.

     

    But If I use xmlHttpRequest thus:

     

    var url = Service1.svc/DownloadFile;

    xmlHttp.Open("POST",url,false);

    xmlHttp.send();

     

    I am not able to get the download box to appear. So it seems that the problem is not with the service but the client i.e. Javascript code.

     

    I even tried the same with an HTTPHandler and that too exhibited the same behavior. The ASHX Handler prompts a download box if it is invoked due to a form submit, but not when invoked using xmlHttpRequest.send(),

     

    Thanks and regards

    Vikas Manghani

     

  • Saturday, July 26, 2008 5:08 AM
     
     

    The behavior from the client of showing a Save As box when facing a Content-Disposition header is not mandatory (look at the RFC for more details). When a browser receives a response with that it will what you expect and prompt with the save file dialog.

     

    When you're using XmlHttpRequest, however, you're essentially taking control over the behavior of the client (as the client now is your Javascript code, which happens to be running inside the browser). The response will be handed over to the callback for xmlHttp, and it's the callback's responsibility to interpret it the way you intend.

  • Monday, July 28, 2008 5:17 AM
     
     

    Hi Carlos

    You are right. I was thinking on similar lines and was hoping that there can be some way for xmlHttpRequest to handover the response to the browser  I dont think it is possible though.

    For now, I have used a dummy form submit to simulate the request.

    My main concern was however the WCF service, which now works as expected

     

    Thanks a lot for your help

    Regards

    Vikas

     

     

  • Saturday, September 06, 2008 6:08 PM
     
     
    Hi,

    the Stream hack works fine to send raw content to the client, but what is its conceptual reason ?
    In fact returning a Stream breaks the business logic : a business operation has a prototype and the technical implementation, here WCF, forces to break this prototype to adapt to the technical constraints.

    Wouldn't it have been more easy and supple to extend the "WebMessageFormat" to add a "Any" value for example, allowing the code to be business interface compliant ?

    Is an other way planned to obtain the same effect but in a more natural fashion ?

    Thanks to all for your answers.