locked
WCF REST Service that accepts arbitrary JSON data into a Stream RRS feed

  • Question

  • I want to create WCF REST Service that accepts arbitrary JSON data into a Stream, so that I can decode/parse myself into different data structures depending on the situation.

    Here is a sample JSON body that I send in the request

    {"intMemAvailableMax": 240, "intProjectRevision": 5, "blnCharging": 1, "intBatteryLevel": 80, "strUUID": "786234yugjhg4", "intMemAvailable": 105, "intDeviceId": 6170, "strIPAddr": "10.1.5.101", "strDescription": "A stream test"}

    This what I have tried.

    (I have also tried WebMessageBodyStyle.Bare)

    [OperationContract]
            [WebInvoke(Method = "POST",
                    RequestFormat = WebMessageFormat.Json,
                    ResponseFormat = WebMessageFormat.Json,
                    BodyStyle = WebMessageBodyStyle.Wrapped,
                    UriTemplate = "DeviceHeartbeat/")]
            string DeviceHeartbeat(Stream s);

    The client always has a http 400/404 error. If I remove the Stream parameter, the Client request works, but but the service has no Stream parameter to receive the stream in. On further reading I found that I can read the JSON into a string using:-

                string JSONstring = OperationContext.Current.RequestContext.RequestMessage.ToString();

    However, the string is not JSON, but an XML representation.

    Is there a way to get a Stream or the JSON?

    Then I could use JsonSerializer to Deserialize<T>(jsonReader) to T of my choosing on the fly.


    Gadgetman Stewart

    Wednesday, April 5, 2017 2:55 PM

Answers

  • For getting a Stream of body, you need to set {"Content-Type":"text/plain"} for the request instead of application/json.

    Here is a simple code:

    //Service Contract
            [OperationContract]
            [WebInvoke(Method = "POST",
                    RequestFormat = WebMessageFormat.Json,
                    ResponseFormat = WebMessageFormat.Json,
                    BodyStyle = WebMessageBodyStyle.Wrapped,
                    UriTemplate = "PostJsonBody/")]
            string PostJsonBody();
    //Service implementation
            public string PostJsonBody()
            {
                var inputStream = OperationContext.Current.RequestContext.RequestMessage.GetBody<Stream>();
                var sr = new StreamReader(inputStream, Encoding.UTF8);
                var str = sr.ReadToEnd();            
                return "Hello JSON Body";
            }

    Request in PostMan

    POST /WCFRest/RestService.svc/PostJsonBody HTTP/1.1
    Host: localhost
    Authorization: Basic di10YXpob0Bob3RtYWlsLmNvbTplRFdBUkQ5MDExMjE=
    Content-Type: text/plain
    Cache-Control: no-cache
    Postman-Token: d27820ba-31bb-4738-010f-aa321a1d1dfd
    
    {"intMemAvailableMax": 240, "intProjectRevision": 5, "blnCharging": 1, "intBatteryLevel": 80, "strUUID": "786234yugjhg4", "intMemAvailable": 105, "intDeviceId": 6170, "strIPAddr": "10.1.5.101", "strDescription": "A stream test"}



    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, April 6, 2017 3:17 AM

All replies

  • For getting a Stream of body, you need to set {"Content-Type":"text/plain"} for the request instead of application/json.

    Here is a simple code:

    //Service Contract
            [OperationContract]
            [WebInvoke(Method = "POST",
                    RequestFormat = WebMessageFormat.Json,
                    ResponseFormat = WebMessageFormat.Json,
                    BodyStyle = WebMessageBodyStyle.Wrapped,
                    UriTemplate = "PostJsonBody/")]
            string PostJsonBody();
    //Service implementation
            public string PostJsonBody()
            {
                var inputStream = OperationContext.Current.RequestContext.RequestMessage.GetBody<Stream>();
                var sr = new StreamReader(inputStream, Encoding.UTF8);
                var str = sr.ReadToEnd();            
                return "Hello JSON Body";
            }

    Request in PostMan

    POST /WCFRest/RestService.svc/PostJsonBody HTTP/1.1
    Host: localhost
    Authorization: Basic di10YXpob0Bob3RtYWlsLmNvbTplRFdBUkQ5MDExMjE=
    Content-Type: text/plain
    Cache-Control: no-cache
    Postman-Token: d27820ba-31bb-4738-010f-aa321a1d1dfd
    
    {"intMemAvailableMax": 240, "intProjectRevision": 5, "blnCharging": 1, "intBatteryLevel": 80, "strUUID": "786234yugjhg4", "intMemAvailable": 105, "intDeviceId": 6170, "strIPAddr": "10.1.5.101", "strDescription": "A stream test"}



    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, April 6, 2017 3:17 AM
  • Thanks - {"Content-Type":"text/plain"}  did the trick - I have tested this in my code and it works.

    It is a pity that my clients (Android Apps) have to specify {"Content-Type":"text/plain"} 

    One would think that as the client is sending JSON, {"Content-Type":"application/json"} would be correct?

    I prefer not to change the client - anyway around this?



    Gadgetman Stewart

    Thursday, April 6, 2017 4:57 AM
  • If so, I suggest you try to loop through the below xml document which gets from "OperationContext.Current.RequestContext.RequestMessage.ToString()", and write the node name and value to json string.

    <root type="object">
      <intMemAvailableMax type="number">240</intMemAvailableMax>
      <intProjectRevision type="number">5</intProjectRevision>
      <blnCharging type="number">1</blnCharging>
      <intBatteryLevel type="number">80</intBatteryLevel>
      <strUUID type="string">786234yugjhg4</strUUID>
      <intMemAvailable type="number">105</intMemAvailable>
      <intDeviceId type="number">6170</intDeviceId>
      <strIPAddr type="string">10.1.5.101</strIPAddr>
      <strDescription type="string">A stream test</strDescription>
    </root>


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, April 6, 2017 7:21 AM