Search code examples
c#.netjsonwcfwebrequest

Why do I get a bad request (code 400) with HttpWebReponse?


I am sending a simple json message to a WCF server application.

Json message:

{"Name":"Julian", "Id":123}

Client side code:

public string MakeRequest(string parameters)
{
        Console.WriteLine("parameters:" + parameters);

        var request = (HttpWebRequest)WebRequest.Create(EndPoint);
        request.Method = Method.ToString();
        request.ContentLength = 0;
        request.ContentType = ContentType;

        Console.WriteLine("request: " + request.Headers.ToString());

        if (PostData != null && Method == HttpVerb.POST)
        {
            var encoding = new UTF8Encoding();
            var bytes = ObjectToByteArray(PostData);
            request.ContentLength = bytes.Length;
            Console.WriteLine("Content length: " + request.ContentLength); 

            using (var writeStream = request.GetRequestStream())
            {
                writeStream.Write(bytes, 0, bytes.Length);
            }
        }

        try
        {
            using (var response = (HttpWebResponse)request.GetResponse())
            {
                var responseValue = string.Empty;

                if (response.StatusCode != HttpStatusCode.OK)
                {
                    var message = String.Format("Request failed. Received HTTP {0}", response.StatusCode);
                    throw new ApplicationException(message);
                }

                // grab the response
                using (var responseStream = response.GetResponseStream())
                {
                    if (responseStream != null)
                        using (var reader = new StreamReader(responseStream))
                        {
                            responseValue = reader.ReadToEnd();
                        }
                }

                return responseValue;
            }
        }
        catch (WebException exception)
        {
            string responseText;

            using (var reader = new StreamReader(exception.Response.GetResponseStream()))
            {
                responseText = reader.ReadToEnd();
                return responseText;
            }
        }

private byte[] ObjectToByteArray(object obj)
{
        if (obj == null)
            return null;
        BinaryFormatter bf = new BinaryFormatter();
        using (MemoryStream ms = new MemoryStream())
        {
            bf.Serialize(ms, obj);
            return ms.ToArray();
         }
}

Server side code:

 [WebInvoke(Method = "POST",
                ResponseFormat = WebMessageFormat.Json,
                RequestFormat =WebMessageFormat.Json,
                UriTemplate = "/postdata")]
    public Person PostData(Person data)
    {
        //Return new person with data inputted from json message
        return new Person()
        {
            Id = data.Id,
            Name = data.Name
        };
    }

Server's Config file

    <?xml version="1.0"?>
<configuration>
  <system.serviceModel>

  <services>
      <service name="WcfJsonRestService.Service1" behaviorConfiguration="Metadata">
      <host>
        <baseAddresses>
          <add baseAddress="http://localhost:8732/service1"/>
        </baseAddresses>
      </host>
          <endpoint address="http://localhost:8732/service1" 
                  binding="webHttpBinding" 
                  contract="WcfJsonRestService.IService1"/>
      </service>
    </services>

    <behaviors>
    <serviceBehaviors>
      <behavior name="Metadata">
        <serviceMetadata httpGetEnabled="true" policyVersion="Policy15"/>
        <serviceDebug includeExceptionDetailInFaults="true"/>
      </behavior>
    </serviceBehaviors>

    <endpointBehaviors>
          <behavior>
            <webHttp />
          </behavior>
      </endpointBehaviors>
    </behaviors>

  </system.serviceModel>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>

About the code:

  • (Client side) The input to the MakeRequest method is just the json data shown above.
  • (Client side) The Uri being posted to is just "localhost:8732/service1/postdata" (yes including http:// just can't include it here as it counts as a link and I can only have two apparently)
  • (Server side) The server code is an implementation of this solution I found at Code Project:

http://www.codeproject.com/Articles/167159/How-to-create-a-JSON-WCF-RESTful-Service-in-sec?fid=1614381&fr=1&df=90&mpp=25&prof=False&sort=Position&view=Normal&spc=Relaxed#xx0xx

What I've tried:

  • I've used Postman to POST a json message to the above uri and have received a response (for now it just returns a package with the same data) so I'm having a hard time finding any issues in the uri.
  • I've validated the json package with JSONLint.
  • I have added various try/catch blocks to get more error info but they all amount to protocol error/bad request error code 400.
  • I have also smashed things in my mind (it's cheaper and less alarming for my flatmate)

Current Output:

I get a bad request response from the server with no data.

Update 1:

I must have been getting the data conversion order wrong. Before I:

  • created Person object
  • converted Person object to json
  • passed json to MakeRequest method
  • (in MakeRequest) created WebRequest converting json to byte array

The first if-statement of the MakeRequest() method (Client side) has been updated with a code segment that makes the request with the json as is. I now get a protocol violation error when write.Flush() executes:

Updated client side code (MakeRequest method)

if (PostData != null && Method == HttpVerb.POST)
    {
        //var encoding = new UTF8Encoding();
        //var bytes = ObjectToByteArray(PostData);
        //request.ContentLength = bytes.Length;
        //Console.WriteLine("Content length: " + request.ContentLength); 

        //using (var writeStream = request.GetRequestStream())
        //{
        //    writeStream.Write(bytes, 0, bytes.Length);
        //}


        using (var streamWriter = new StreamWriter(request.GetRequestStream()))
        {
            streamWriter.Write(json);
            streamWriter.Flush();
            streamWriter.Close();
        }

        var httpResponse = (HttpWebResponse)request.GetResponse();
        using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
        {
            var result = streamReader.ReadToEnd();
        }

    }  

Update 2:

The protocol violation error from the streamWriter.Flush() call was because I hadn't set the request.ContentLenth. I have now set the Content.Length to json.Length and I now get this error:

System.ArgumentException: Stream was not readable

The image is a bit small but the error message reads:

"System.ArgumentException: Stream was not readable."

Solution

  • I think the problem was in the first lines of the try block. I attempt to read the response from the request object ... ehem ... Although I did try to read the response from the response object further down the damage was already done. I've included the working code below together with the commented out code that was causing the issue. I have marked the offending request.GetResponse() with **** as well as the correct response.GetResponseStream() which you'll be happy to hear, is now free to do its job.

    Hope this saves someone a lot of time!

    All the relevant parts of the MakeRequest method:

    var request = (HttpWebRequest)WebRequest.Create(EndPoint);
            request.Method = Method.ToString();
            request.ContentLength = 0;
            request.ContentType = ContentType;
    
    
            Console.WriteLine("request: " + request.Headers.ToString());
    
            if (PostData != null && Method == HttpVerb.POST)
            {
                Console.WriteLine("json length: " + json.Length);
                Console.WriteLine(json);
                request.ContentLength = json.Length;
                var encoding = new UTF8Encoding();             
    
                using (var streamWriter = new StreamWriter(request.GetRequestStream()))
                {
                    streamWriter.Write(json);
                    streamWriter.Flush();
                    streamWriter.Close();
                }
            }
    
            try
            {
                // ****    FIRST READ USING request.GetResponse()    ****
                //var httpResponse = (HttpWebResponse)request.GetResponse();
                //using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
                //{
                //    streamReader.ReadToEnd();
                //}
    
                using (var response = (HttpWebResponse)request.GetResponse())
                {
                    var responseValue = string.Empty;
    
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        var message = String.Format("Request failed. Received HTTP {0}", response.StatusCode);
                        throw new ApplicationException(message);
                    }
    
                    // grabs the response
                    using (var responseStream = response.GetResponseStream())
                    {
                        if (responseStream != null)
                            using (var reader = new StreamReader(responseStream))
                            {
                                //  ****    SECOND READ USING response.GetResponseStream()    ****
                                responseValue = reader.ReadToEnd();
                            }
                    }
                    return responseValue;
                }
            }