0

I tried to make HTTP POST request with application/json in body to an external web-service from C# (.NET Core 2.2.104).

I've already read all similar questions in SO and wrote this code:

            SignXmlRequestDto requestBody = new SignXmlRequestDto(p12, model.SignCertPin, model.Data);
            string json = JsonConvert.SerializeObject(requestBody);

            var httpRequestMessage = new HttpRequestMessage
            {
                Method = HttpMethod.Post,
                RequestUri = ncanNodeUrl,
                Headers =
            {
                { HttpRequestHeader.ContentType.ToString(), "application/json" }
            },
                Content = new StringContent(JsonConvert.SerializeObject(json))
            };

            var response = await httpClient.SendAsync(httpRequestMessage);

            string responseString = await response.Content.ReadAsStringAsync();

I am getting an error from service, it says: "Invalid header Content-Type. Please set Content-Type to application/json". What is interesting here, if I simulate this request from Postman, then everything work well and I get successful response. enter image description here

Updated: as @Kristóf Tóth suggested, I modified my code to:

            var httpRequestMessage = new HttpRequestMessage
            {
                Method = HttpMethod.Post,
                RequestUri = ncanNodeUrl,
                Content = new StringContent(json, Encoding.UTF8, "application/json")
            };

            var response = await httpClient.SendAsync(httpRequestMessage);

            string responseString = await response.Content.ReadAsStringAsync();

but it still gives me the same error message.

Iskander Raimbaev
  • 1,322
  • 2
  • 17
  • 35
  • `HttpRequestHeader.ContentType.ToString()` ?? – Panagiotis Kanavos Mar 12 '19 at 09:00
  • @PanagiotisKanavos, it was suggested in this answer https://stackoverflow.com/a/53451542 – Iskander Raimbaev Mar 12 '19 at 09:01
  • Which wasn't accepted or upvoted, for a reason. `Content-Type` is a content header for starters. Either pass the content type in the `StringContent` constructor, or set it on the content object – Panagiotis Kanavos Mar 12 '19 at 09:05
  • Use Fiddler or another debugging proxy and capture what's actually being sent. Passing the content type in the StringContent constructor is how everyone posts JSON requests. How does the Postman request look like? How does your query differ? – Panagiotis Kanavos Mar 12 '19 at 09:12

2 Answers2

4

Content-Type is a content header. It should be set on the content, not the request itself. This can be done either using the StringContent(string,Encoding,string) constructor :

Content = new StringContent(JsonConvert.SerializeObject(json),Encoding.UTF8, "application/json")

or by setting the StringContent's Headers.ContentType property :

var content=new StringContent(JsonConvert.SerializeObject(json));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • Wow, second option solved my problem - setting the StringContent's Headers.ContentType property, it works. Now I wonder, why the fist one didn't work but the second one works? I thought both does the same action... – Iskander Raimbaev Mar 12 '19 at 09:14
  • @IskanderRaimbayev use Fiddler and check what's different. Postman can help you create an HTTP request by hand but can't show you what's actually being sent or received. Fiddler captures both – Panagiotis Kanavos Mar 12 '19 at 09:14
  • @IskanderRaimbayev which .NET version did you use? Did you add HttpClient through a NuGet package? Passing the content type in the constructor is very common so people would have noticed. *Maybe* there's an obscure combination of bugs though, eg in a specific HttpClient version or .NET Core runtime, but that would still be highly unlikely – Panagiotis Kanavos Mar 12 '19 at 09:19
  • I use .NET Core 2.2.104, and firstly tried to use the code from this answer: https://stackoverflow.com/a/10679340/6159500. – Iskander Raimbaev Mar 12 '19 at 09:24
2

This might be an encoding issue. You should use JsonContent not StringContent OR you can do something similar:

// Serialize into JSON String
var stringPayload = JsonConvert.SerializeObject(payload);

// Wrap JSON StringContent which then can be used by the HttpClient class
var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");
Kristóf Tóth
  • 791
  • 4
  • 19