none
Error checking start element of object -- 400 Bad Request RRS feed

  • Question

  • This post is similar to http://social.msdn.microsoft.com/Forums/vstudio/en-US/50013919-6ac1-4b12-a6f8-f09387f21b26/why-is-my-wcf-json-web-service-expecting-xml, but not the same.  I get the "Error checking start element" before my code can start.

    I have a statements service -- it picks up statements from an E-Learning module:  The request can either be OPTIONS or POST.  I've got the OPTIONS part working, since the request is null in that case, but with the POST, it always fails with a bad request.  Note that the RequestFormat = WebMessageForm.Json, and that's what Content-Type is set to.

    [DataContract]
    public class Data_In
    {
       [DataMember]
       public string registration, Authorization, statementId, content;
    }

    [OperationContract, WebInvoke(Method = "*", UriTemplate = "/statements/", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]

    public string statements(Data_In theStatement)

    It gets through the OPTIONS, but on the subsequent POST, I always get a bad request.  I got tracing going and here’s what I get:

    There was an error checking start element of object of type FBSService.FBSService+Data_In. Encountered unexpected character 'r'.  Note that ‘r’ is the first character of Data_In (the r in registration).

    So this indicates that the request isn't JSON, and it's probably not.  I would think the request would have name value pairs separated by a ":".  [unless Fidder is somehow changing things, which I doubt.]  Using Fiddler output, the request looks like:

    statementId=e3b49e17%2D754c%2D4b51%2Dae63%2Da94a7d50b13c&registration=you&Content%2DType=application%2Fjson&content=%7B%22context%22%3A%7B%22registration%22%3A%22you%22%2C%22contextActivities%22%3A%7B%22grouping%22%3A%7B%22id%22%3A%226h4QeKoJbYF%5Fcourse%5Fid%22%7D%2C%22parent%22%3A%7B%22id%22%3A%226h4QeKoJbYF%5Fcourse%5Fid%22%7D%7D%7D%2C%22verb%22%3A%22attempted%22%2C%22actor%22%3A%7B%22name%22%3A%5B%22Frank%20Siegel%22%5D%2C%22mbox%22%3A%5B%22mailto%3Afrank%40fbs419%2Ecom%22%5D%7D%2C%22object%22%3A%7B%22id%22%3A%226h4QeKoJbYF%5Fcourse%5Fid%22%2C%22definition%22%3A%7B%22name%22%3A%7B%22und%22%3A%22%22%7D%2C%22type%22%3A%22Course%22%2C%22description%22%3A%7B%22und%22%3A%22%22%7D%7D%7D%7D&Authorization=me

    But the weird thing is that there is another company that does the same thing.  When I go into Fiddler and look at their output, their request looks the same as mine, and they also declare the Content-Type as application/json.  I do notice that theirs starts out with the Content-Type, i.e.

    Content%2DType=application%2Fjson&statementId= etc., etc

    But that's the only difference.  But theirs works great; their request doesn't look like JSON either.  Of course, I have no idea what kind of statements service they have. 

    We both do exactly the same things, like:

    Access-Control-Allow-Origin: *
    Access-Control-Allow-Methods: GET,HEAD,PUT,POST,OPTIONS,DELETE

    We also do exactly the same thing for Access-Control-Allow-Headers and Access-Control-Expose-Headers

    Is this some kind of web.config thing?  I don't have control over the request, as it comes in from the E-Learning module. How can I rectify this situation?

    Thanks


    Wednesday, September 18, 2013 12:16 AM

Answers

  • Hi,

    Since the request body is not JSON, you cannot use WebMessageFormat.Json or DataContractJsonSerializer. The input looks like application/x-www-form-urlencoded. WCF doesn't stand by it out of box. So it is needed to use Stream as the input parameter, and manually parse the request body.
     
    [OperationContract, WebInvoke(Method = "*", UriTemplate = "/statements/")]
    public string statements(Stream theStatement)
    You can use StreamReader to read the stream, which gives you a string. Then you can parse the string and create the Data_In object manually. Please refer to http://msdn.microsoft.com/en-us/library/cc656724.aspx for a sample on how to make a WCF REST service accept arbitrary request (not specific to this scenario).

      >>  So is there anything that can be done here, since I can't control the request coming in?

    From my experience, you can also use ASP.NET Web API, which is the recommended technology to build REST services. It supports application/x-www-form-urlencoded out of box. Please check http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-1 for a sample.

    Best Regards,

    Ming Xu


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    • Marked as answer by fbs419 Friday, September 20, 2013 3:34 PM
    Friday, September 20, 2013 8:45 AM

All replies

  • Hi fbs419,

    The default value of WebMessageBodyStyle is Bare, so do you try pass something like

    { ”Name“: "Micheal", ”Gender“: "Female" } 

    If you have set WebMessageBodyStyle as Wrapped somewhere, you need pass something like

    {"Customer": {”Name“: "Micheal", ”Gender“: "Female" } }

    In addtion, you can use JSON.stringify to converts a JavaScript value to a JavaScript Object Notation (JSON) string. A reference for your information.

    #ASMX ScriptService mistake – Invalid JSON primitive

    http://encosia.com/asmx-scriptservice-mistake-invalid-json-primitive/

    And also check if formats of quote do the trick as mentioned in this post.

    Hope this can help you.

    Best Regards.


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Wednesday, September 18, 2013 12:23 PM
    Moderator
  • Hi.  Thanks for the reply.  Those are good threads, and I've learned a lot.  But as I've said, I don't really have control over the request that comes in -- it's done by the E-Learning module.  So when you say:

    so do you try pass something like  ”Name“: "Micheal", ”Gender“: "Female" }

    I don't really have any control over that.  What comes in is what I showed in the Fiddler output above.  I'm sure that if I wrote a test client that passed in the format you mentioned, it would work fine.  My problem is the request is made by someone else.

    But there has to be a way to do this, since the other company's request is in the same format, yet their service works.

    Is there something in the DataContract that I can change?

    I've tried something like:
    [DataContract]
    public class Data_In
    {
       [DataMember(Name = "registration", EmitDefaultValue = false)]
       public string registration { get; set; }
       [DataMember(Name = "Authorization", EmitDefaultValue = false)]
       public string Authorization { get; set; }
       etc., etc.
    }

    but I've been getting the same error.  Somehow I need to get the correct format before the service gets invoked.   Thanks.

     


    Wednesday, September 18, 2013 5:18 PM
  • Any help here?  Again, the main problem is that when the E-Learning client sends a request to my service endpoint, I get a 400, but when the same client sends essentially the same request to another service endpoint (and I don't know anything about that service), it works fine.

    The E-Learning stuff is invoked by a URL like:

    http://somestory.html?endpoint=myservice&Authorization=someauth?registration=somereg?activity_id=someid?&actor={ "name" : ["foo"], "mbox" : ["bar"] }

    When I change the endpoint to their service endpoint, it all works great.

    According to Fiddler, when my service is called by the E-Learning module, the request is something like:

    statementId=something&registration=something&Content%2DType=application%2Fjson&Authorization=whatever&content=whatever

    and I get:

    There was an error checking start element of object of type FBSService.FBSService+Data_In. Encountered unexpected character 's' 

    since statementId is the first thing in the request, so that's the 's'.

    When their endpoint is used, Fiddler says the request is something like:

    Content%2DType=application%2Fjson&statementId=something&registration=something&Authorization=whatever&content=whatever

    Note that the only difference is that they have Content-Type first.  Could this be it??? [I kind of doubt it, but don't know.]  If so, how do I get that at the beginning?  Neither of these requests look like JSON, but theirs works.

    I've tried webHttpBinding instead of basic, I've changed the data contract to use individual wrapped fields, but nothing works.  Note that I'm not using interface files -- I have it set up with Factory="System.ServiceModel.Activation.WebServiceHostFactory".  I doubt that has anything to do with it.

    So is there anything that can be done here, since I can't control the request coming in?

    Thanks again


    Thursday, September 19, 2013 4:56 PM
  • Hi,

    Since the request body is not JSON, you cannot use WebMessageFormat.Json or DataContractJsonSerializer. The input looks like application/x-www-form-urlencoded. WCF doesn't stand by it out of box. So it is needed to use Stream as the input parameter, and manually parse the request body.
     
    [OperationContract, WebInvoke(Method = "*", UriTemplate = "/statements/")]
    public string statements(Stream theStatement)
    You can use StreamReader to read the stream, which gives you a string. Then you can parse the string and create the Data_In object manually. Please refer to http://msdn.microsoft.com/en-us/library/cc656724.aspx for a sample on how to make a WCF REST service accept arbitrary request (not specific to this scenario).

      >>  So is there anything that can be done here, since I can't control the request coming in?

    From my experience, you can also use ASP.NET Web API, which is the recommended technology to build REST services. It supports application/x-www-form-urlencoded out of box. Please check http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-1 for a sample.

    Best Regards,

    Ming Xu


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    • Marked as answer by fbs419 Friday, September 20, 2013 3:34 PM
    Friday, September 20, 2013 8:45 AM
  • Does the fiddler reults show any cookies in the HTTP headers.  Is a certificate used?  Is the same version of IE browser installed?  There is something different in the headers that is causing the problem.  Make sure you delete the cookies between tests.  Compare you IE browser settings with the other company.

    jdweng

    Friday, September 20, 2013 8:58 AM
  • Thank you Ming Xu and jdweng.  There are no cookies in the headers.  But -- Ming Xu was right -- not declaring a WebMessageFormat, and using a Stream did the trick.  I am now able to get the request correctly and process it as I see fit.

    THANK YOU -- you made my day.

    Friday, September 20, 2013 3:34 PM