C#を使用してサーバーにJSONを投稿する方法


269

これが私が使っているコードです:

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

これを実行していると、常に500内部サーバーエラーが発生します。

何が悪いのですか?


1
まず、投稿するデータがサーバーが期待するものであることを確認します。
LB

実際、私は無効なデータを投稿していたようです...
Arsen Zahray

作業を簡単にするために、jsonライブラリをビジュアルスタジオにも追加できます
Alireza Tabatabaeian 2013

@Arsen-不正な形式のデータでサーバーがクラッシュすることはありません。バグレポートを提出してください。
jww 2018

回答:


396

私がそれをやって、働いている方法は:

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

このタスクをより簡単な方法で実行するためのライブラリを作成しました。ここにあります:https : //github.com/ademargomes/JsonRequest

それが役に立てば幸い。


3
json文字列の行は次のようになるはずです。string json = "{\" user \ ":\" test \ "、" + "\" password \ ":\" bla \ "}"; \
Dream Lane

3
常に "application / json"を使用してください(他の理由でtext / jsonが必要な場合を除きます:entwicklungsgedanken.de/2008/06/06/…など)。クレディングは、stackoverflow.com / questions / 477816 /…に行きます。
Yaniv

34
streamWriter.Flush();と思ったでしょう。およびstreamWriter.Close(); usingブロック内にいるため、必要ありません。usingブロックの最後で、ストリームライターはとにかく閉じます。
ルチラ

1
JSONを手動で作成しないでください。JSONインジェクションを可能にする間違いを犯しやすいです。
フロリアン冬

5
@ user3772108 stackoverflow.com/a/16380064/2279059を参照してください。Newtonsoft JSON.NetなどのJSONライブラリを使用して、オブジェクトからJSON文字列をレンダリングするか、シリアル化を使用します。これは簡略化のためにここでは省略されていることを理解しています(単純化による利益は最小限です)が、構造化データ文字列(JSON、XMLなど)をフォーマットすることは、些細なシナリオでさえそれを実行し、人々にそのようなコードをコピーするように促すには危険すぎる。
フロリアン冬

149

Ademarのソリューションは、JavaScriptSerializerSerializeメソッドを利用してオブジェクトをJSONに暗黙的に変換することで改善できます。

さらに、およびをusing明示的に呼び出すことを省略するために、ステートメントのデフォルト機能を利用することが可能です。FlushClose

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

1
これと上のコードの違いは何ですか?何か不足していますか?
JMK

16
これは、JavaScriptSerializerのSerializeメソッドを使用して、手作りではなく有効なJSONを作成します。
ショーンアンダーソン

以下のJean Fの回答を参照してください-コメントにする必要があります。コンテンツタイプapplication/jsonが正しいことに注意してください。
Lucas

@SeanAnderson「リモートサーバーに接続できません」というエラーが発生し続けます。
ラルフガブ2015年

3
@LuzanBaralにはアセンブリが必要です:System.Web.Extensions
Norbrecht

60

HttpClientタイプは、より新しい実装であるWebClientHttpWebRequest

次の行を使用するだけです。

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

ここに画像の説明を入力してください

HttpClient複数回必要な場合は、1つのインスタンスのみを作成して再利用するか、新しいを使用することをお勧めしますHttpClientFactory


5
HttpClientについて少し注意しますが、一般的なコンセンサスは、それを破棄してはならないということです。IDisposableを実装していても、オブジェクトはスレッドセーフであり、再利用することを目的としています。stackoverflow.com/questions/15705092/...
ジャンF.

1
@JeanF。ちょっと入力ありがとうございます。すでに述べたように、インスタンスを1つだけ作成するか、を使用する必要がありHttpClientFactoryます。リンクされた問題のすべての回答を読んだわけではありませんが、ファクトリーについて言及していないため、更新する必要があると思います。
NtFreX 2018年

33

Seanの投稿に加えて、usingステートメントをネストする必要はありません。usingStreamWriter によって、ブロックの最後でフラッシュおよびクローズされるため、Flush()および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();
}

1
現在、この回答とショーンアンダーソンの回答はまったく同じです。ショーンが投稿を編集したためです。
ファザ

ねえ、これは素晴らしいです。ありがとう。でも、jsonに子ノードがある場合、どのようにデータを渡すのでしょうか。
user2728409

1
シリアライザーはjsonの子ノードを処理できます。有効なjsonオブジェクトを提供するだけで済みます。
David Clarke

14

非同期に呼び出す必要がある場合は、

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

    }

3
このソリューションVivekを投稿していただきありがとうございます。私たちのシナリオでは、この投稿で別の解決策を試してみましたが、同期投稿がスレッドをブロックしていると想定しているため、アプリケーションでSystem.Threading例外が発生しました。あなたのコードは私たちの問題を解決しました。
Ken Palmer

おそらくバイトに変換する必要がないことに注意してください。あなたは行うことができるはずpostStream.Write(postData);-とAPIに依存し、使用する必要がある場合がありますrequest.ContentType = "application/json";の代わりにtext/json
vapcguy


11

私は最近、JSONを投稿するはるかに簡単な方法を思いついたのですが、アプリのモデルから変換する追加のステップを備えています。値を取得して変換を行うには、コントローラーのモデル[JsonObject]を作成する必要があることに注意してください。

リクエスト:

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

モデル:

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

サーバ側:

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

6

このオプションは言及されていません:

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

2
このオプションは、.Net 4.5.2以降は使用できません。こちらをご覧くださいstackoverflow.com/a/40525794/2161568
Downhillski

上記のコメントに従って反対投票-これは利用できないため、おそらく回答を削除する必要があります。
NovaDev

1
誰もが最新バージョンの.netを使用しているわけではないため、これは有効な回答です。
Ellisan

4

これを実現するためのいくつかの異なるクリーンな方法は、次のようにHttpClientを使用することです。

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

4
便利PostAsJsonAsyncですが、.NET 4.5.2以降は使用できません。PostAsync代わりに使用してください。詳細はこちら
Zachary Keener 2017

通常、HttpClientは次のusingようなステートメントでは使用しないでください
p3tch 2018年

私はそれIDisposableが理由でインターフェースを実装していると思います
Dima Daron

4

警告!私はこの問題について非常に強い見解を持っています。

.NETの既存のWebクライアントは開発者にとって使いやすいものではありません。 WebRequestWebClientは、「開発者をさせる方法」の主な例です。冗長であり、操作が複雑です。C#での単純なPostリクエストだけが必要な場合。HttpClientはこれらの問題に対処する方法をいくつか備えていますが、それでも不十分です。その上、Microsoftのドキュメントは悪い…本当に悪い。あなたが技術的な言い訳のページやページをふるいにかけたくない限り。

救済のためのオープンソース。代替として、3つの優れたオープンソースの無料のNuGetライブラリがあります。よかった!これらはすべて十分にサポートされ、文書化されており、簡単に修正できます。非常に簡単に操作できます。

  • ServiceStack.Text高速、軽量、弾力性。
  • RestSharpシンプルなRESTおよびHTTP APIクライアント
  • Flurl-流暢で移植可能なテスト可能なHTTPクライアントライブラリ

それらの間には多くはありませんが、ServiceStack.Textにわずかなエッジを与えます…

  • Githubスターはほぼ同じです。
  • 未解決の問題&重要なことに、どれだけ早く問題が解決したか?ServiceStackは、最も早く問題を解決し、未解決の問題がないことで、この賞を受賞しました。
  • ドキュメンテーション?すべてに優れたドキュメントがあります。ただし、ServiceStackはそれを次のレベルに引き上げ、ドキュメントの「ゴールデンスタンダード」で知られています。

OK-では、ServiceStack.Text内のJSONのPostリクエストはどのように見えるのでしょうか?

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

これはコードの1行です。簡潔で簡単!上記を.NETのHttpライブラリと比較してください。


3

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

1

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

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

UFT8の代わりにASCIIを使用する


2
かなり悪い考えのように聞こえますが、何か不足していますか?
Cyber​​Fox 2017

JSONにはUTF8文字を含めることができますが、これはひどい考えのようです。
エイドリアン・スミス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.