3

I am trying to make an service that posts some data to an API Endpoint using C# HttpClient. The code is as follows.

public class HttpClientService : IHttpClientService
{
    static HttpClient client = new HttpClient();

    public HttpClientService()
    {
        client.BaseAddress = new Uri("http://xx.xx.xx.xx/");
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    }

    public async Task<Uri> MakeLogEntry(CnsLog log)
    {
        HttpResponseMessage response = await client.PostAsJsonAsync("api/logs", log);
        return response.Headers.Location;
    }

}

The problem is that the end point returns error 411 Length Required. I have found that this is because my request doesn't have the content-length header set, which I found to be true when I inspected the request using Fiddler.

I have tried to set the content length header on the client in the constructor but the code doesn't compile after that. I'm stuck and would appreciate any help. Thanks

Isaac Roland
  • 43
  • 1
  • 6

2 Answers2

3

You don't want to set the Content-Length header on the client, especially since it's a static instance. You want to set it on the individual request.

PostAsJsonAsync is a nice shortcut that builds the HttpContent from a poco, builds the HttpRequestMessage from that content, and sends the POST request. Handy, but all that abstraction doesn't give you the opportunity to set request-level headers. So, you need to do a little more work to build/send the request:

var json = JsonConvert.SerializeObject(log);
var content = new StringContent(json, Encoding.UTF8, "application/json");
content.Headers.ContentLength = json.Length;
var response = await client.PostAsync("api/logs", content);
Todd Menier
  • 37,557
  • 17
  • 150
  • 173
  • 2
    `Content-Length` header must indicate the number of bytes, not characters ([RFC 2616 14.13](https://tools.ietf.org/html/rfc2616#section-14.13l)). So if you use `Encoding.UTF8` to encode the string, you'll need `Encoding.UTF8.GetByteCount(json)` instead of `json.Length`, which may or may not be the same depending on the string content. – Şafak Gür Jul 07 '20 at 11:07
0

Alternately you can use HttpWebRequest.

byte[] postBytes = Encoding.ASCII.GetBytes(log);
request.ContentLength = postBytes.Length;

Example of HttpWebRequest is as below:

ASCIIEncoding encoder = new ASCIIEncoding();
byte[] data = encoder.GetBytes(serializedObject); // a json object, or xml, whatever...

HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = data.Length;
request.Expect = "application/json";

request.GetRequestStream().Write(data, 0, data.Length);

HttpWebResponse response = request.GetResponse() as HttpWebResponse;
Habeeb
  • 7,601
  • 1
  • 30
  • 33
  • There is no need to abandon HttpClient just to set a request header. – Todd Menier Sep 18 '18 at 14:31
  • 1
    @Habeeb Thanks a bunch – Isaac Roland Sep 21 '18 at 07:03
  • Hi @IsaacRoland, Nice to hear it helped. Could you please mark it as the answer, so that it helps the community to find the answer fast. – Habeeb Sep 23 '18 at 05:06
  • Hi @IsaacRoland, in an above comment you have mentioned, "@ToddMenier I have tried this but it doesn't work." Hope you intended it for another answer. If so please remove it from here and add it for the respective comment. This will help the community and the future visitors. – Habeeb Sep 25 '18 at 12:15