オブジェクトをHttpClient.PostAsyncに渡し、JSON本文としてシリアル化するにはどうすればよいですか?


93

私が使用しているSystem.Net.Http、私はウェブ上でいくつかの例を見つけました。私はPOSTリクエストを行うためにこのコードを作成することができました:

public static string POST(string resource, string token)
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri(baseUri);
        client.DefaultRequestHeaders.Add("token", token);

        var content = new FormUrlEncodedContent(new[]
        {
             new KeyValuePair<string, string>("", "")
        });

        var result = client.PostAsync("", content).Result;
        string resultContent = result.Content.ReadAsStringAsync().Result;
        return resultContent;
    }
 }

すべて正常に動作しています。しかし、POSTメソッドに3番目のパラメータであるdata。というパラメータを渡したいとします。データパラメータは次のようなオブジェクトです。

object data = new
{
    name = "Foo",
    category = "article"
};

作成せずにそれを行うにはどうすればよいKeyValuePairですか?私のphpRestAPIはjson入力を待つので、FormUrlEncodedContentrawjsonを正しく送信する必要があります。しかし、どうすればこれを行うことができMicrosoft.Net.Httpますか?ありがとう。


私があなたの質問を理解した場合、フォームエンコードされたコンテンツの代わりにJSONコンテンツを正しく送信したいですか(さらに、匿名型をJSONとしてそのコンテンツにシリアル化したいですか)?
CodingGorilla 2016

@CodingGorillayesは匿名型です。
IlDrugo 2016

3
将来の読者のための注意点として、使用していないusingためHttpClientaspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
maxshuty

2
なぜマイクロソフトからの注意using使用すべきではありません。HttpClient is intended to be instantiated once and reused throughout the life of an application. The following conditions can result in SocketException errors: Creating a new HttpClient instance per request. Server under heavy load. Creating a new HttpClient instance per request can exhaust the available sockets. docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/...
Ogglas

回答:


155

あなたの質問に対する正直な答えPostAsyncは次のとおりです。いいえ。メソッドのシグネチャは次のとおりです。

public Task PostAsync(Uri requestUri、HttpContent content)

だから、あなたが渡すことができている間objectPostAsync、それは型でなければなりませんHttpContentし、あなたの匿名型は、その基準を満たしていません。

ただし、達成したいことを達成する方法はいくつかあります。まず、匿名型をJSONにシリアル化する必要があります。このための最も一般的なツールはJson.NETです。そして、このためのコードは非常に簡単です。

var myContent = JsonConvert.SerializeObject(data);

次に、このデータを送信するためにコンテンツオブジェクトを作成する必要があります。オブジェクトを使用しByteArrayContentますが、必要に応じて別のタイプを使用または作成することもできます。

var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);

次に、コンテンツタイプを設定して、これがJSONであることをAPIに通知します。

byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

次に、フォームの内容を使用して、前の例と非常によく似たリクエストを送信できます。

var result = client.PostAsync("", byteContent).Result

ちなみに、.Resultここで行っているようにプロパティを呼び出すと、デッドロックなどの悪い副作用が発生する可能性があるため、これには注意が必要です。


わかりました、それは非常に明確です。この答えをありがとう。ただの質問:aPOST, PUT, DELETEが実行されると、通常はAPIが返さTRUEれ、メソッドをとして宣言しましたstringが、実行すると:return result;が得られます:Can't Convert HttpResponseMessage in string、メソッド宣言を変更する必要がありますか?他のクラスメソッドで後で逆シリアル化する必要があるため、文字列応答が必要です。
IlDrugo 2016

2
応答の本文を逆シリアル化する必要がある場合は、(を使用してresult.Content.ReadAsStringAsync())質問の方法で文字列を返すことでおそらく問題ありません。アプリケーションの構造によってはContent、ヘッダーを調べてconentタイプ(XMLやJSONなど)を判別する必要がある場合は、オブジェクトを直接返す方がよい場合があります。ただし、常にJSON(またはその他の形式)が返されることがわかっている場合は、応答の本文を文字列として返すだけで問題ありません。
CodingGorilla 2016

申し訳ありませんが、データがタイプの場合、これを行う必要がありStringContentますか?
MyDaftQuestions 2017

1
@MyDaftQuestions何を求めているのか正確にはわかりませんStringContentPostAsync、から派生しているため、直接に渡すことができますHttpContent
CodingGorilla 2017

@CodingGorilla、それ私が求めていものでした。ありがとう:)
MyDaftQuestions 2017

67

リクエスト本文のデータを、ではなく生の文字列として渡す必要がありますFormUrlEncodedContent。これを行う1つの方法は、JSON文字列にシリアル化することです。

var json = JsonConvert.SerializeObject(data); // or JsonSerializer.Serialize if using System.Text.Json

これで、文字列をpostメソッドに渡すだけで済みます。

var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); // use MediaTypeNames.Application.Json in Core 3.0+ and Standard 2.1+

var client = new HttpClient();
var response = await client.PostAsync(uri, stringContent);

stringContentですか?私の場合、stringContent値は"\"\""です。これは正しい値ですか?
R15

c#コードからvbの文字列結果を取得することは可能ですか?私は....それはかなり似ていますが分かった
gumuruh

42

簡単な解決策はMicrosoft ASP.NET Web API 2.2 ClientNuGetから使用することです。

次に、これを行うだけで、オブジェクトがJSONにシリアル化され、Content-Typeヘッダーがapplication/json; charset=utf-8次のように設定されます。

var data = new
{
    name = "Foo",
    category = "article"
};

var client = new HttpClient();
client.BaseAddress = new Uri(baseUri);
client.DefaultRequestHeaders.Add("token", token);
var response = await client.PostAsJsonAsync("", data);

2
間違いなくPostAsJsonAsyncを使用できます
Kat Lim Ruiz

25

.NET Standardまたはを使用したより簡単な方法があります.NET Core

var client = new HttpClient();
var response = await client.PostAsync(uri, myRequestObject, new JsonMediaTypeFormatter());

注:JsonMediaTypeFormatterクラスを使用するには、Microsoft.AspNet.WebApi.ClientNuGetパッケージをインストールする必要があります。このパッケージは、直接、またはなどの別のパッケージを介してインストールできますMicrosoft.AspNetCore.App

このの署名を使用HttpClient.PostAsyncすると、任意のオブジェクトを渡すことができJsonMediaTypeFormatter、シリアル化などが自動的に処理されます。

応答を使用HttpContent.ReadAsAsync<T>して、応答コンテンツを期待するタイプに逆シリアル化するために使用できます。

var responseObject = await response.Content.ReadAsAsync<MyResponseType>();

1
これはどのバージョンの.netを使用していますか?私のバージョンでは、System.Net.Http名前空間に「フォーマット」が見つかりません
TemporaryFix

1
@Programmatic先ほど述べたように、.NET Standardまたはを使用する必要があります.NET Core。多分あなたは使ってい.NET Frameworkますか?私のプロジェクトでは、JsonMediaTypeFormatterはここからロードされています:C:\ Program Files \ dotnet \ sdk \ NuGetFallbackFolder \ microsoft.aspnet.webapi.client \ 5.2.6 \ lib \ netstandard2.0 \ System.Net.Http.Formatting。 dll
Ken Lyon

1
@Programmaticこれらのプロジェクトタイプのいずれかを既に使用している場合は、NuGetパッケージを追加する必要がある可能性があります。自動的に含まれていたものを正確に忘れてしまいました。私の場合、Microsoft.AspNetCore.AppNuGetパッケージの一部として含まれていました。
ケン・リヨン

1
.NET Coreを使用していましたが、ソリューションが最新バージョンのc#言語を使用するように設定されていなかったと思います。更新して動作しました。ありがとう
TemporaryFix

1
@Programmaticどういたしまして。あなたがそれを動かしたと聞いてうれしいです!NuGetパッケージに関するメモを回答に追加しました。
ケン・リヨン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.