295

Here's the code I'm using:

// create a request
HttpWebRequest request = (HttpWebRequest)
WebRequest.Create(url); request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";


// turn our request string into a byte stream
byte[] postBytes = Encoding.UTF8.GetBytes(json);

// this is important - make sure you specify type this way
request.ContentType = "application/json; charset=UTF-8";
request.Accept = "application/json";
request.ContentLength = postBytes.Length;
request.CookieContainer = Cookies;
request.UserAgent = currentUserAgent;
Stream requestStream = request.GetRequestStream();

// now send it
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();

// grab te response and print it out to the console along with the status code
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string result;
using (StreamReader rdr = new StreamReader(response.GetResponseStream()))
{
    result = rdr.ReadToEnd();
}

return result;

When I'm running this, I'm always getting 500 internal server error.

What am I doing wrong?

jww
  • 83,594
  • 69
  • 338
  • 732
Arsen Zahray
  • 21,834
  • 46
  • 119
  • 205

13 Answers13

442

The way I do it and is working is:

var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://url");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";

using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
    string json = "{\"user\":\"test\"," +
                  "\"password\":\"bla\"}";

    streamWriter.Write(json);
}

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

I wrote a library to perform this task in a simpler way, it is here: https://github.com/ademargomes/JsonRequest

Hope it helps.

xbrady
  • 1,613
  • 13
  • 23
Ademar
  • 5,166
  • 1
  • 15
  • 23
  • 3
    I think the json string line should be: string json = "{\"user\":\"test\"," + "\"password\":\"bla\"}"; It looks like you are missing a \ – Dream Lane Feb 26 '13 at 17:00
  • 3
    Always use "application/json" (unless for some other reason text/json is needed for example: http://www.entwicklungsgedanken.de/2008/06/06/problems-with-internet-explorer-and-applicationjson/). Creding goes to: http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type. – Yaniv May 09 '15 at 21:43
  • 35
    I would've thought the streamWriter.Flush(); and streamWriter.Close(); is not necessary as you are inside a using block. At the end of the using block, stream writer will close anyway. – Ruchira Jan 19 '16 at 00:04
  • Hi @Albert it should as long as WebRequest is set to a https API/Site, please check this: http://stackoverflow.com/questions/10389808/using-https-and-httpwebrequest – Ademar May 26 '16 at 09:34
  • Short question: Why use `Close` when in `using` ? – Felix D. Jun 01 '16 at 07:19
  • 1
    Don't build JSON manually. It is easy to make mistakes that allow for JSON injection. – Florian Winter Feb 27 '17 at 14:08
  • @FlorianWinter How to build the JSON instead? – user3772108 Oct 24 '17 at 08:32
  • 6
    @user3772108 See https://stackoverflow.com/a/16380064/2279059. Use a JSON library, such as Newtonsoft JSON.Net, and render the JSON string from an object, or use serialization. I understand that this was omitted here for simplicity (although the simplicity gain is minimal), but formatting structured data strings (JSON, XML, ...) is too dangerous to do it even in trivial scenarios and to encourage people to copy such code. – Florian Winter Oct 25 '17 at 08:37
  • Using `async` methods where there are available is a good thing to do if you are in an async context. One other thing that I would want to point out is use of `var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://url");` why would you want to create a `WebRequest` instance and then parse it to `HttpWebRequest` while you have a method `CreateHttp`? Saves you from parsing the object. e.g `var httpWebRequest = WebRequest.CreateHttp("http://url");` – Jamshaid K. Aug 18 '19 at 14:39
  • I have followed the code,but it does not seem to post the json with the request. The method writes data to a table and the values are passed as null. Am I missing something? When I debug the string json does have a value. – jlh3302 Jan 06 '20 at 14:35
  • Maybe more usings are needed? For the request: `HttpWebRequest` doesn't need it, but `request.GetRequestStream()` and `streamWriter` should each have their own using. Similar for the response: `request.GetResponse()`, `response.GetResponseStream()` and `StreamReader(responseStream)` each should have using IMO. – jws Apr 16 '20 at 21:19
  • The only thing that finally helped. Thanks a lot – bolt Apr 23 '21 at 14:58
159

Ademar's solution can be improved by leveraging JavaScriptSerializer's Serialize method to provide implicit conversion of the object to JSON.

Additionally, it is possible to leverage the using statement's default functionality in order to omit explicitly calling Flush and Close.

var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://url");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";

using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
    string json = new JavaScriptSerializer().Serialize(new
                {
                    user = "Foo",
                    password = "Baz"
                });

    streamWriter.Write(json);
}

var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
    var result = streamReader.ReadToEnd();
}
Sean Anderson
  • 24,467
  • 26
  • 112
  • 219
84

The HttpClient type is a newer implementation than the WebClient and HttpWebRequest.

You can simply use the following lines.

string myJson = "{'Username': 'myusername','Password':'pass'}";
using (var client = new HttpClient())
{
    var response = await client.PostAsync(
        "http://yourUrl", 
         new StringContent(myJson, Encoding.UTF8, "application/json"));
}

When you need your HttpClient more than once it's recommended to only create one instance and reuse it or use the new HttpClientFactory.

NtFreX
  • 7,449
  • 1
  • 34
  • 57
  • 5
    A little note on HttpClient, the general consensus is that you should not dispose it. Even it implements IDisposable the object is Thread-Safe and meant to be reused. https://stackoverflow.com/questions/15705092/do-httpclient-and-httpclienthandler-have-to-be-disposed – Jean F. Nov 14 '18 at 23:07
  • 1
    @JeanF. Hey Thanks for the input. As I have allready noted you should only create one instance or use the `HttpClientFactory`. I did not read all answers in the linked issue but I think it needs updating as it doesn't mention the factory. – NtFreX Nov 15 '18 at 08:03
35

Further to Sean's post, it isn't necessary to nest the using statements. By using the StreamWriter it will be flushed and closed at the end of the block so no need to explicitly call the Flush() and Close() methods:

var request = (HttpWebRequest)WebRequest.Create("http://url");
request.ContentType = "application/json";
request.Method = "POST";

using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
    string json = new JavaScriptSerializer().Serialize(new
                {
                    user = "Foo",
                    password = "Baz"
                });

    streamWriter.Write(json);
}

var response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
        var result = streamReader.ReadToEnd();
}
Lynn
  • 8,876
  • 38
  • 66
David Clarke
  • 12,002
  • 8
  • 80
  • 105
15

If you need to call is asynchronously then use

var request = HttpWebRequest.Create("http://www.maplegraphservices.com/tokkri/webservices/updateProfile.php?oldEmailID=" + App.currentUser.email) as HttpWebRequest;
            request.Method = "POST";
            request.ContentType = "text/json";
            request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);

private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
    {
        HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
        // End the stream request operation

        Stream postStream = request.EndGetRequestStream(asynchronousResult);


        // Create the post data
        string postData = JsonConvert.SerializeObject(edit).ToString();

        byte[] byteArray = Encoding.UTF8.GetBytes(postData);


        postStream.Write(byteArray, 0, byteArray.Length);
        postStream.Close();

        //Start the web request
        request.BeginGetResponse(new AsyncCallback(GetResponceStreamCallback), request);
    }

    void GetResponceStreamCallback(IAsyncResult callbackResult)
    {
        HttpWebRequest request = (HttpWebRequest)callbackResult.AsyncState;
        HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(callbackResult);
        using (StreamReader httpWebStreamReader = new StreamReader(response.GetResponseStream()))
        {
            string result = httpWebStreamReader.ReadToEnd();
            stat.Text = result;
        }

    }
Vivek Maskara
  • 1,035
  • 10
  • 25
  • 3
    Thanks for posting this solution Vivek. In our scenario we tried another solution in this post, and wound up seeing System.Threading exceptions in our application, due to what I assume were synchronous posts blocking threads. Your code solved our problem. – Ken Palmer Nov 22 '16 at 16:02
  • Note that you probably don't have to convert to bytes. You should be able to do `postStream.Write(postData);` - and depending on the API, might have to use a `request.ContentType = "application/json";` instead of `text/json`. – vapcguy Apr 22 '20 at 05:19
13

Take care of the Content-Type you are using :

application/json

Sources :

RFC4627

Other post

Community
  • 1
  • 1
Jean F.
  • 1,735
  • 17
  • 16
11

I recently came up with a much simpler way to post a JSON, with the additional step of converting from a model in my app. Note that you have to make the model [JsonObject] for your controller to get the values and do the conversion.

Request:

 var model = new MyModel(); 

 using (var client = new HttpClient())
 {
     var uri = new Uri("XXXXXXXXX"); 
     var json = new JavaScriptSerializer().Serialize(model);
     var stringContent = new StringContent(json, Encoding.UTF8, "application/json");
     var response = await Client.PutAsync(uri,stringContent).Result;
     ...
     ...
  }

Model:

[JsonObject]
[Serializable]
public class MyModel
{
    public Decimal Value { get; set; }
    public string Project { get; set; }
    public string FilePath { get; set; }
    public string FileName { get; set; }
}

Server side:

[HttpPut]     
public async Task<HttpResponseMessage> PutApi([FromBody]MyModel model)
{
    ...
    ... 
}
Dustin
  • 637
  • 7
  • 16
7

This option is not mentioned:

using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("http://localhost:9000/");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    var foo = new User
    {
        user = "Foo",
        password = "Baz"
    }

    await client.PostAsJsonAsync("users/add", foo);
}
Centro
  • 3,502
  • 1
  • 21
  • 29
  • 2
    This option is no longer available since .Net 4.5.2. see here http://stackoverflow.com/a/40525794/2161568 – Downhillski Dec 03 '16 at 00:58
  • 1
    Thats not a good reason to downvote this answer since not everyone uses the latest versions of .net and therefore this is a valid answer. – Ellisan Aug 06 '18 at 09:02
5

Some different and clean way to achieve this is by using HttpClient like this:

public async Task<HttpResponseMessage> PostResult(string url, ResultObject resultObject)
{
    using (var client = new HttpClient())
    {
        HttpResponseMessage response = new HttpResponseMessage();
        try
        {
            response = await client.PostAsJsonAsync(url, resultObject);
        }
        catch (Exception ex)
        {
            throw ex
        }
        return response;
     }
}
Dima Daron
  • 510
  • 6
  • 19
  • 4
    Helpful, however `PostAsJsonAsync` is no longer available since .NET 4.5.2. Use `PostAsync` instead. More [here](https://stackoverflow.com/a/34594919/4461141) – hbd Jul 17 '17 at 19:02
  • HttpClient generally shouldn't be used in a `using` statement like this – p3tch Oct 31 '18 at 14:04
  • I think it implements `IDisposable` interface for a reason – Dima Daron Nov 08 '18 at 14:50
  • This works in .net core 2.1, and is a very clean option. If you inject your httpClient, this becomes a 1 line json Post. – Alex-v-s Aug 06 '20 at 00:50
5

WARNING! I have a very strong view on this subject.

.NET’s existing web clients are not developer friendly! WebRequest & WebClient are prime examples of "how to frustrate a developer". They are verbose & complicated to work with; when all you want to do is a simple Post request in C#. HttpClient goes some way in addressing these issues, but it still falls short. On top of that Microsoft’s documentation is bad … really bad; unless you want to sift through pages and pages of technical blurb.

Open-source to the rescue. There are three excellent open-source, free NuGet libraries as alternatives. Thank goodness! These are all well supported, documented and yes, easy - correction…super easy - to work with.

There is not much between them, but I would give ServiceStack.Text the slight edge …

  • Github stars are roughly the same.
  • Open Issues & importantly how quickly any issues closed down? ServiceStack takes the award here for the fastest issue resolution & no open issues.
  • Documentation? All have great documentation; however, ServiceStack takes it to the next level & is known for its ‘Golden standard’ for documentation.

Ok - so what does a Post Request in JSON look like within ServiceStack.Text?

var response = "http://example.org/login"
    .PostJsonToUrl(new Login { Username="admin", Password="mypassword" });

That is one line of code. Concise & easy! Compare the above to .NET’s Http libraries.

Mark
  • 1,905
  • 18
  • 22
4

I finally invoked in sync mode by including the .Result

HttpResponseMessage response = null;
try
{
    using (var client = new HttpClient())
    {
       response = client.PostAsync(
        "http://localhost:8000/....",
         new StringContent(myJson,Encoding.UTF8,"application/json")).Result;
    if (response.IsSuccessStatusCode)
        {
            MessageBox.Show("OK");              
        }
        else
        {
            MessageBox.Show("NOK");
        }
    }
}
catch (Exception ex)
{
    MessageBox.Show("ERROR");
}
lgturrez
  • 41
  • 1
3

I find this to be the friendliest and most concise way to post an read JSON data:

var url = @"http://www.myapi.com/";
var request = new Request { Greeting = "Hello world!" };
var json = JsonSerializer.Serialize<Request>(request);
using (WebClient client = new WebClient())
{
    var jsonResponse = client.UploadString(url, json);
    var response = JsonSerializer.Deserialize<Response>(jsonResponse);
}

I'm using Microsoft's System.Text.Json for serializing and deserializing JSON. See NuGet.

Yosef Bernal
  • 680
  • 4
  • 17
1

var data = Encoding.ASCII.GetBytes(json);

byte[] postBytes = Encoding.UTF8.GetBytes(json);

Use ASCII instead of UFT8

user3280472
  • 127
  • 1
  • 4