Bagaimana cara mengirim JSON ke server menggunakan C #?

269

Berikut kode yang saya gunakan:

// 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;

Ketika saya menjalankan ini, saya selalu mendapatkan 500 kesalahan server internal.

Apa yang saya lakukan salah?

Arsen Zahray
sumber
1
Pertama, pastikan bahwa data yang Anda kirim sesuai dengan yang diharapkan server.
LB
sebenarnya, sepertinya saya memposting data yang tidak valid ...
Arsen Zahray
Untuk kemudahan pekerjaan Anda dapat menambahkan perpustakaan json ke studio visual Anda juga
Alireza Tabatabaeian
@ Arsen - Server tidak boleh macet dengan data cacat. Ajukan laporan bug.
jww

Jawaban:

396

Cara saya melakukannya dan berfungsi adalah:

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();
}

Saya menulis perpustakaan untuk melakukan tugas ini dengan cara yang lebih sederhana, ada di sini: https://github.com/ademargomes/JsonRequest

Semoga ini bisa membantu.

Ademar
sumber
3
Saya pikir garis string json harus: string json = "{\" user \ ": \" test \ "," + "\" password \ ": \" bla \ "}"; Sepertinya Anda melewatkan \
Dream Lane
3
Selalu gunakan "application / json" (kecuali untuk alasan lain teks / json diperlukan misalnya: entwicklungsgedanken.de/2008/06/06/… ). Pengreditan pergi ke: stackoverflow.com/questions/477816/… .
Yaniv
34
Saya akan berpikir streamWriter.Flush (); dan streamWriter.Close (); tidak perlu karena Anda berada di dalam blok menggunakan. Di akhir blok penggunaan, penulis aliran akan tetap menutup.
Ruchira
1
Jangan membangun JSON secara manual. Sangat mudah untuk membuat kesalahan yang memungkinkan untuk injeksi JSON.
Florian Winter
5
@ user3772108 Lihat stackoverflow.com/a/16380064/2279059 . Gunakan perpustakaan JSON, seperti Newtonsoft JSON.Net, dan render string JSON dari suatu objek, atau gunakan serialisasi. Saya mengerti bahwa ini dihilangkan di sini untuk kesederhanaan (meskipun keuntungan kesederhanaan minimal), tetapi memformat string data terstruktur (JSON, XML, ...) terlalu berbahaya untuk melakukannya bahkan dalam skenario sepele dan mendorong orang untuk menyalin kode tersebut .
Florian Winter
149

Solusi Ademar dapat ditingkatkan dengan leveraging JavaScriptSerializer's Serializemetode untuk memberikan konversi implisit dari objek untuk JSON.

Selain itu, dimungkinkan untuk memanfaatkan usingfungsionalitas default pernyataan untuk menghilangkan panggilan Flushdan 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
sumber
1
Apa perbedaan antara ini dan kode di atas, apakah saya melewatkan sesuatu?
JMK
16
Ini menggunakan metode Serialize JavaScriptSerializer untuk membuat JSON yang valid alih-alih membuatnya sendiri.
Sean Anderson
Lihat jawaban Jean F di bawah ini - harus menjadi komentar. Berhati-hatilah dengan jenis konten application/jsonyang benar.
Lucas
@SeanAnderson Saya terus mengalami "Tidak dapat terhubung ke server jauh" Kesalahan.
ralphgabb
3
@LuzanBaral Anda hanya perlu perakitan: System.Web.Extensions
Norbrecht
60

The HttpClientjenis adalah implementasi lebih baru daripada WebClientdan HttpWebRequest.

Anda cukup menggunakan baris berikut.

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"));
}

masukkan deskripsi gambar di sini

Ketika Anda membutuhkan HttpClientlebih dari sekali, disarankan untuk hanya membuat satu instance dan menggunakannya kembali atau gunakan yang baru HttpClientFactory.

NtFreX
sumber
5
Sedikit catatan pada HttpClient, konsensus umum adalah bahwa Anda tidak boleh membuangnya. Bahkan itu mengimplementasikan IDisposable objeknya adalah Thread-Safe dan dimaksudkan untuk digunakan kembali. stackoverflow.com/questions/15705092/...
Jean F.
1
@ JeanF. Hai, terima kasih atas masukannya. Seperti yang sudah saya catat sebelumnya, Anda hanya perlu membuat satu instance atau menggunakan HttpClientFactory. Saya tidak membaca semua jawaban dalam masalah terkait tetapi saya pikir ini perlu diperbarui karena tidak menyebutkan pabrik.
NtFreX
33

Lebih jauh ke pos Sean, tidak perlu menyarang pernyataan penggunaan. Oleh usingStreamWriter ia akan memerah dan ditutup pada akhir blok sehingga tidak perlu secara eksplisit memanggil metode Flush()dan Close():

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();
}
David Clarke
sumber
1
sekarang jawaban ini dan jawaban Sean Anderson persis sama, seperti Sean telah mengedit posnya.
faza
Hai, ini luar biasa. Terima kasih. Tapi bagaimana kita akan meneruskan data jika kita punya simpul anak di json kita?
user2728409
1
Serializer dapat menangani node anak di json - Anda hanya perlu memberikannya objek json yang valid.
David Clarke
14

Jika Anda perlu menelepon secara tidak sinkron maka gunakan

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
sumber
3
Terima kasih telah memposting solusi ini Vivek. Dalam skenario kami, kami mencoba solusi lain dalam posting ini, dan akhirnya melihat System.Threading pengecualian dalam aplikasi kami, karena apa yang saya anggap posting sinkron memblokir utas. Kode Anda memecahkan masalah kami.
Ken Palmer
Perhatikan bahwa Anda mungkin tidak perlu mengkonversi ke byte. Anda harus dapat melakukannya postStream.Write(postData);- dan tergantung pada API, mungkin harus menggunakan request.ContentType = "application/json";bukan text/json.
vapcguy
13

Jaga Jenis-Konten yang Anda gunakan:

application/json

Sumber:

RFC4627

Pos lainnya

Jean F.
sumber
11

Saya baru-baru ini datang dengan cara yang lebih sederhana untuk memposting JSON, dengan langkah tambahan mengkonversi dari model di aplikasi saya. Perhatikan bahwa Anda harus membuat model [JsonObject] untuk pengontrol Anda untuk mendapatkan nilai dan melakukan konversi.

Permintaan:

 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; }
}

Sisi server:

[HttpPut]     
public async Task<HttpResponseMessage> PutApi([FromBody]MyModel model)
{
    ...
    ... 
}
Dustin
sumber
6

Opsi ini tidak disebutkan:

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
sumber
2
Opsi ini tidak lagi tersedia sejak .Net 4.5.2. lihat di sini stackoverflow.com/a/40525794/2161568
Downhillski
Downvote per komentar di atas - karena ini tidak tersedia, mungkin harus menghapus jawabannya.
NovaDev
1
Itu bukan alasan yang bagus untuk menurunkan jawaban ini karena tidak semua orang menggunakan versi terbaru dari .net dan karenanya ini adalah jawaban yang valid.
Ellisan
4

Beberapa cara berbeda dan bersih untuk mencapai ini adalah dengan menggunakan HttpClient seperti ini:

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
sumber
4
Bermanfaat, namun PostAsJsonAsynctidak lagi tersedia sejak .NET 4.5.2. Gunakan PostAsyncsebagai gantinya. Lebih lanjut di sini
Zachary Keener
HttpClient umumnya tidak boleh digunakan dalam usingpernyataan seperti ini
p3tch
Saya pikir itu mengimplementasikan IDisposableantarmuka karena suatu alasan
Dima Daron
4

PERINGATAN! Saya memiliki pandangan yang sangat kuat tentang masalah ini.

Klien web .NET yang ada tidak ramah terhadap pengembang! WebRequest & WebClient adalah contoh utama "bagaimana menggagalkan pengembang". Mereka verbose & rumit untuk dikerjakan; ketika semua yang ingin Anda lakukan adalah permintaan Posting sederhana dalam C #. HttpClient melakukan beberapa cara dalam mengatasi masalah ini, tetapi masih gagal. Di atas semua itu, dokumentasi Microsoft buruk ... sangat buruk; kecuali jika Anda ingin menyaring halaman dan halaman dari uraian teknis.

Sumber terbuka untuk penyelamatan. Ada tiga sumber terbuka, perpustakaan NuGet gratis yang sangat baik sebagai alternatif. Untunglah! Ini semua didukung, didokumentasikan dan ya, mudah - koreksi ... super mudah - untuk bekerja dengannya.

  • ServiceStack.Text - cepat, ringan dan tangguh.
  • RestSharp - REST dan HTTP API Client sederhana
  • Flurl - pustaka klien HTTP yang lancar, portabel, dan dapat diuji

Tidak ada banyak di antara mereka, tapi saya akan memberikan ServiceStack.

  • Bintang - bintang Github kira-kira sama.
  • Buka Masalah & seberapa pentingkah masalah apa pun ditutup? ServiceStack menerima penghargaan di sini untuk resolusi masalah tercepat & tanpa masalah terbuka.
  • Dokumentasi? Semua memiliki dokumentasi yang bagus; namun, ServiceStack membawanya ke level berikutnya & dikenal dengan 'Standar Emas' untuk dokumentasi.

Oke - jadi seperti apa tampilan Permintaan Posting di JSON di dalam ServiceStack.Text?

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

Itu adalah satu baris kode. Ringkas & mudah! Bandingkan hal di atas dengan pustaka Http .NET.

Pemrograman dengan Mark
sumber
3

Saya akhirnya dipanggil dalam mode sinkronisasi dengan memasukkan .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
sumber
1

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

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

Gunakan ASCII bukan UFT8

pengguna3280472
sumber
2
Kedengarannya seperti ide yang sangat buruk, apakah saya melewatkan sesuatu?
CyberFox
JSON dapat berisi karakter UTF8, ini sepertinya ide yang buruk.
Adrian Smith