System.Net.HttpClientを使用して複合型を投稿する方法


102

Web APIを使用して操作したいカスタムの複合型があります。

public class Widget
{
    public int ID { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

そして、これが私のWeb APIコントローラメソッドです。このオブジェクトを次のように投稿したい:

public class TestController : ApiController
{
    // POST /api/test
    public HttpResponseMessage<Widget> Post(Widget widget)
    {
        widget.ID = 1; // hardcoded for now. TODO: Save to db and return newly created ID

        var response = new HttpResponseMessage<Widget>(widget, HttpStatusCode.Created);
        response.Headers.Location = new Uri(Request.RequestUri, "/api/test/" + widget.ID.ToString());
        return response;
    }
}

そして今、私System.Net.HttpClientはメソッドを呼び出すために使用したいと思います。ただし、どのタイプのオブジェクトをPostAsyncメソッドに渡すか、またどのように作成するかはわかりません。クライアントコードの例を以下に示します。

var client = new HttpClient();
HttpContent content = new StringContent("???"); // how do I construct the Widget to post?
client.PostAsync("http://localhost:44268/api/test", content).ContinueWith(
    (postTask) =>
    {
        postTask.Result.EnsureSuccessStatusCode();
    });

HttpContentWeb APIが理解できる方法でオブジェクトを作成するにはどうすればよいですか?


オブジェクトのXMLシリアル化バージョンをサービスエンドポイントに送信してみましたか?
ジョシュアドレイク

回答:


132

ジェネリックHttpRequestMessage<T>削除れました。この :

new HttpRequestMessage<Widget>(widget)

長く仕事をNO

代わりに、この投稿から、ASP.NETチームには、この機能をサポートするためのいくつかの新しい呼び出しが含まれています。

HttpClient.PostAsJsonAsync<T>(T value) sends application/json
HttpClient.PostAsXmlAsync<T>(T value) sends application/xml

したがって、新しいコード(dunstonから)は次のようになります。

Widget widget = new Widget()
widget.Name = "test"
widget.Price = 1;

HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:44268");
client.PostAsJsonAsync("api/test", widget)
    .ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode() );

1
でも、ウィジェットクラスにアクセスできない場合はどうでしょうか。
contactmatt 2013年

13
新しいHttpClient.PostAsXXXAsync<T>( T value ) methods are great, but what about one for application/x-www-form-urlencoded format? Is there a simple / short way for that or do we still need to create elaborate KeyValuePair`リスト?
Jaans 2013年

1
@Jaans Flurl.Httpはを介してシンプルな/短い方法を提供しますPostUrlEncodedAsync
トッドメニア2014

16
あなたが使用できるようにSystem.Net.Http.Formattingへの参照を追加する必要がありますPostAsJsonAsyncPostAsXmlAsync
ピート

6
PostAsJsonAcyncを使用するには、NuGetパッケージMicrosoft.AspNet.WebApi.Clientを追加します!!
Dennis

99

SendAsync代わりにメソッドを使用する必要があります。これは、サービスへの入力をシリアル化する汎用メソッドです

Widget widget = new Widget()
widget.Name = "test"
widget.Price = 1;

HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:44268/api/test");
client.SendAsync(new HttpRequestMessage<Widget>(widget))
    .ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode() );

あなたは具象クラスを作成したくない場合は、あなたがそれを作ることができますFormUrlEncodedContentクラス

var client = new HttpClient();

// This is the postdata
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("Name", "test"));
postData.Add(new KeyValuePair<string, string>("Price ", "100"));

HttpContent content = new FormUrlEncodedContent(postData); 

client.PostAsync("http://localhost:44268/api/test", content).ContinueWith(
    (postTask) =>
    {
        postTask.Result.EnsureSuccessStatusCode();
    });

注:IDをnull許容のint(int?)にする必要があります


1
これは外部プロジェクトから呼び出されますが、ウィジェットオブジェクトを含むアセンブリへの参照はありません。正しいプロパティを含む匿名で型付けされたオブジェクトを作成し、このメソッドを使用してシリアル化して、その方法で渡そうとしましたが、500内部サーバーエラーが発生します。Web APIコントローラメソッドにヒットすることはありません。
indot_brad 2012

ああ-その後、xmlまたはjsonをwebapiサービスにポストする必要があり、それはそれを逆シリアル化します-同じことをします、SendAsyncは、サービスのオブジェクトをシリアル化しています
dunston

1
更新を行いました-コードをテストしましたが、いくつかの単純なコードを使用していますが、動作するはずです
dunston 2012

8
「ジェネリックでない型 'System.Net.Http.HttpRequestMessage'は型引数では使用できません」を取得しています。これはまだ有効ですか?
user10479 2012年

5
ええ、最初のソリューションはもう機能しません:aspnetwebstack.codeplex.com/discussions/350492
Giovanni B

74

ポータブルクラスライブラリを使用している場合、HttpClientにはPostAsJsonAsyncメソッドがないことに注意してください。ポータブルクラスライブラリを使用してコンテンツをJSONとして投稿するには、次のようにする必要があります。

HttpClient client = new HttpClient();
HttpContent contentPost = new StringContent(argsAsJson, Encoding.UTF8, 
"application/json");

await client.PostAsync(new Uri(wsUrl), contentPost).ContinueWith(
(postTask) => postTask.Result.EnsureSuccessStatusCode());

argsAsJsonがシリアル化されたオブジェクトからのものであり、このオブジェクトにプロパティがある場合。Content = "domain \ user"の場合、\は2回エンコードされます。1回はargsAsJsonにシリアル化され、2回目はPostAsyncがcontentPostをポストするときです。二重エンコーディングを回避する方法は?
Krzysztof Morcinek 2014

3
素晴らしい@fabiano!これで本当にうまくいきました。このタイプのプロジェクトでは、これら2つの追加の引数が必要です。
Peter Klein、

とても良い@PeterKlein!Web上のMicrosoftのドキュメント内でこの情報を見つけることができなかったので、これは同じ問題を持つ他の人を助けることができます。私のプロジェクトは、このトリックなしではデータを送信しません。
Fabiano 2014年


4

他の回答に記載されている種類の便利なメソッドが必要だが移植性が必要な場合(または必要でない場合でも)、Flurlをチェックすることをお勧めます [開示:私は作成者です]。それは(薄い)HttpClientJson.NETをラップして、焼き付けられたテストヘルパーを含むいくつかの流暢な砂糖と他のグッズを追加します

JSONとして投稿:

var resp = await "http://localhost:44268/api/test".PostJsonAsync(widget);

またはURLエンコード:

var resp = await "http://localhost:44268/api/test".PostUrlEncodedAsync(widget);

上記の例はどちらもHttpResponseMessageを返しますが、追跡するだけの場合は、Flurlに他のものを返す拡張メソッドが含まれています。

T poco = await url.PostJsonAsync(data).ReceiveJson<T>();
dynamic d = await url.PostUrlEncodedAsync(data).ReceiveJson();
string s = await url.PostUrlEncodedAsync(data).ReceiveString();

FlurlはNuGetで利用できます。

PM> Install-Package Flurl.Http

1

多くの代替案を調査した後、API 2.0バージョンに適した別のアプローチに出くわしました。

(VB.NETは私のお気に入りです、すごい...)

Public Async Function APIPut_Response(ID as Integer, MyWidget as Widget) as Task(Of HttpResponseMessage)
    Dim DesiredContent as HttpContent = New StringContent(JsonConvert.SerializeObject(MyWidget))
    Return Await APIClient.PutAsync(String.Format("api/widget/{0}", ID), DesiredContent)
End Function

幸運を!私にとってこれはうまくいきました(最後に!)。

よろしく、ピーター


1
これは、@ Fabianoによる上記の提案と相まって、物事を起こします。
Peter Klein

2
VB.NETはお気に入りではありません:)
Lazy Coder 2016年

1

私はこれを行うことができると思います:

var client = new HttpClient();
HttpContent content = new Widget();
client.PostAsync<Widget>("http://localhost:44268/api/test", content, new FormUrlEncodedMediaTypeFormatter())
    .ContinueWith((postTask) => { postTask.Result.EnsureSuccessStatusCode(); });

1

私のような人が上記のすべてが何を話しているのか本当に理解していない場合のために、私は私のために働いている簡単な例を挙げます。URLが「http://somesite.com/verifyAddress」であるWeb APIがある場合、それはポストメソッドであり、アドレスオブジェクトを渡す必要があります。このAPIをコードで呼び出します。ここであなたができること。

    public Address verifyAddress(Address address)
    {
        this.client = new HttpClient();
        client.BaseAddress = new Uri("http://somesite.com/");
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        var urlParm = URL + "verifyAddress";
        response = client.PostAsJsonAsync(urlParm,address).Result;
        var dataObjects = response.IsSuccessStatusCode ? response.Content.ReadAsAsync<Address>().Result : null;
        return dataObjects;
    }

0

これは、ここでの他の回答に基づいて、私が巻き込んだコードです。これは、複合型を受信して​​応答するHttpPost用です。

Task<HttpResponseMessage> response = httpClient.PostAsJsonAsync(
                       strMyHttpPostURL,
                       new MyComplexObject { Param1 = param1, Param2 = param2}).ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
                    //debug:
                    //String s = response.Result.Content.ReadAsStringAsync().Result;
                    MyOtherComplexType moct = (MyOtherComplexType)JsonConvert.DeserializeObject(response.Result.Content.ReadAsStringAsync().Result, typeof(MyOtherComplexType));

-1

次のようなサービスを呼び出します。

public async void SaveActivationCode(ActivationCodes objAC)
{
    var client = new HttpClient();
    client.BaseAddress = new Uri(baseAddress);
    HttpResponseMessage response = await client.PutAsJsonAsync(serviceAddress + "/SaveActivationCode" + "?apiKey=445-65-1216", objAC);
} 

そして、このようなサービスメソッド:

public HttpResponseMessage PutSaveActivationCode(ActivationCodes objAC)
{
}

PutAsJsonAsyncは、ネットワークを介したシリアライゼーションとデシリアライゼーションを処理します


これは、要求されたPOSTではなく、HTTP PUTメッセージを送信します。他の人が言っているPostAsJsonAsyncように、JSONのPOSTとして必要なデータを送信します。
Zhaph-Ben Duguid 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.