1

I'm a bit unsure on how to do my post request in C#. I have tried doing it in Postman and it works there without problem. I think my problem is json formatting. I construct my json with JObjects in the Newtonsoft library. When the code below is run, this is the output; {"accountreference":"XX","messages":"[{\r\n \"to\": \"+XXXXX\",\r\n \"body\": \"XXXXXXXX\"\r\n}]"} It is valid, but as you can see it contains linebreaks and escape characters. Upon posting it to the api I am using, I always get back a 400 bad request.

I've tried various serializers and techniques but not been able to get it working. I've also made sure that the Authroization header is correct, if it was incorrect the API should have said so in its return message. According to the developers of the API, this message should only happen if the body is incorrect. I've tried posting the string with linebreaks in Postman and that also yields 400. Is there a easy way to get rid of them?

var tmpObj = new JObject {{"to", to}, {"body", message}};

var jsonObj = new JObject
{
    {"accountreference", MessageConfiguration.Ref}, {"messages", "[" + tmpObj + "]"}
};

var json = jsonObj.ToString(Formatting.None);

var httpContent = new StringContent(json, Encoding.UTF8, "application/json");

var url = new Uri("www.xxxxxxxx/hjdhsf");
return await PostAsync(url, httpContent);


protected async Task<HttpResponseMessage> PostAsync(Uri endpoint, HttpContent content)
{
    using (var httpClient = NewHttpClient())
    {
        var result = await httpClient.PostAsync(endpoint, content);
        return result; //Statuscode is 400 here. 
    }
}

This valid json works in Postman:

{
    "accountreference":"XXXXX",
    "messages":[{
        "to":"XXXXX",
        "body":"XXX!"
    }]
}

Update:

According to answer, I tried this:

var body = new
{
    accountreference = MessageConfiguration.Ref,
    messages = new[]
    {
        new
        {
            to = to,
            body = message
        }
    }
};

var json = new JavaScriptSerializer().Serialize(body);

Now the json looks correct and I could even copy it from VS into postman and it worked. However my reqests in VS still returns 400.

Urb
  • 11
  • 1
  • 4
  • Is that your exact `to` and `body`? No characters like `@`? I'm guessing the `XXXXX` is just placeholder data? – Liam Dec 20 '18 at 16:19
  • Why don't you just create a class that represents the data you want to post, then serialize that via `JsonConvert.SerializeObject`? – mason Dec 20 '18 at 16:20
  • @Liam nope, no extra characters. The X's are just placeholder. I will try with an extra class. – Urb Dec 20 '18 at 16:22
  • 1
    Hold on your double encoding, `"[{\r\n \"to\": \"+XXXXX\",\r\n \"body\": \"XXXXXXXX\"\r\n}]"` is a sting, not json, notice the `"` at the beginning and the end – Liam Dec 20 '18 at 16:23
  • Note, that your message is **NOT** put as json object into your json data, but as a string representing the json object. I guess, that's why the request is not succeeding... –  Dec 20 '18 at 16:25
  • 1
    this line `"[" + tmpObj + "]"` creates a **string** with your json in it. Which you then json encode (again) That's the problem. Probably best to build the object as already suggested to fix this. – Liam Dec 20 '18 at 16:25

3 Answers3

2

You don't need to build up your JSON using JObject. You can either use anonymous classes or paste your JSON sample using Paste JSON as Classes. Based on your JSON sample an anonymous object would look like this.

var body = new
{
    accountrefrence = "XXXXX",
    messages = new[]
    {
        new
        {
            to = "XXXX",
            body = "XXX!"
        }
    }
}

And actual classes might look like this:

public class Rootobject
{
    public string accountreference { get; set; }
    public Message[] messages { get; set; }
}

public class Message
{
    public string to { get; set; }
    public string body { get; set; }
}
JSteward
  • 6,833
  • 2
  • 21
  • 30
  • This solution worked for me and creates the correct json output, however I still seem to experiene issues posting the request. – Urb Dec 20 '18 at 16:36
0

The easiest way to manage JSON serialization is to use objects instead of raw strings or trying to manually compose the output (as it looks like you're doing here).

As you're already using Newtonsoft libraries for it, it will be quite easy to do.

Frist thing would be to create an object that represents the data you want to send to the api. As stated in another answer here, you can simply do this by copying your sample JSON and in VS do a "Paste JSON as classes".

Most likely, the resulting classes will be something like:

public class Rootobject
{
    public string accountreference { get; set; }
    public Message[] messages { get; set; }
}

public class Message
{
    public string to { get; set; }
    public string body { get; set; }
}

What you can do now is a method that grabs your data and populates the properties of this objects. As you're not providing much details on what are you doing I will simply assume that it is possible for you to have a method that receives the string values somehow.

    public void ComposeAndSendJson(string accountReference, string toAddress, string messageBody)
    {
        RootObject whatIwanttoSend = new RootObject();
        Message messageComposed = new Message();

        messageComposed.to = toAddress;
        messageComposed.body = messageBody;

        whatIwanttoSend.accountReference = accountReference;

        //I'm doing a pretty bad aproach but it's just to ilustrate the concept
        whatIwanttoSend.messages.toList().Add(messageComposed);

        var jsonData = JsonConvert.SerializeObject(whatIwanttoSend);

        //As you're working on async, you may need to do some working on here. In this sample i'm just calling it in Sync. 
        var ApiResponse = PostAsync("YOURENDPOINT",jsonData).Result();

        //Do something else with the response ... 

    }


    protected async Task<Task<HttpResponseMessage> PostAsync(Uri endpoint, object payload)
    {
        using (var httpClient = NewHttpClient())
        {
            //You have to tell the API you're sending JSON data
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            //Execute your call
            var result = await httpClient.PostAsJsonAsync(endpoint, payload);

            //Basic control to check all went good.
            if (result.IsSuccessStatusCode)
            {
                return result;
            }

            //Do some management in case of unexpected response status here... 
            return result; //Statuscode is 400 here. 
        }
    }

I hope this sets you in the right path.

valvestater65
  • 130
  • 1
  • 5
  • Thanks. But where do you find the PostAsync method that accepts a string as a payload? I can only find one that accepts HttpContent. – Urb Dec 20 '18 at 16:59
  • My bad as i was coding in notepad :) Actually the HttpClient class has a PostAsJsonAsync method that accepts object as parameter. Let me edit the answer – valvestater65 Dec 20 '18 at 17:02
  • Alright, well I tried your suggestions here but my request still fails for some mysterious reason! – Urb Dec 20 '18 at 17:12
  • Still getting the 400 error? Or is it something different now? – valvestater65 Dec 20 '18 at 18:53
  • Its still 400 and according to the API docs it will return 400 when the request is malformed. It can be seen here: https://developers.esendex.com/api-reference#messagedispatcher I'm using the Message Dispatcher endpoint – Urb Dec 21 '18 at 06:40
  • I tried reading the contents after constructing it, like this: var str = httpContent.ReadAsStringAsync(); and it does look like the json string is escaped with backslashes. But isn't this beacause of C#? Surely they are omitted when the post is made with httpContent. – Urb Dec 21 '18 at 07:06
0

Found my answer here:

POSTing JsonObject With HttpClient From Web API

I had to add an additional header to my content, like this:

var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var result = client.PostAsync(url, content).Result;

I really wonder what is the point of specifying it in the StringContent constructor but ok.

Urb
  • 11
  • 1
  • 4