Karmaşık bir tür göndermek için System.Net.HttpClient nasıl kullanılır?


102

Web API kullanarak çalışmak istediğim özel bir karmaşık türüm var.

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

Ve işte benim web API denetleyici yöntemim. Bu nesneyi şu şekilde göndermek istiyorum:

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

Ve şimdi System.Net.HttpClientyönteme çağrı yapmak için kullanmak istiyorum . Bununla birlikte, PostAsyncyönteme ne tür bir nesnenin aktarılacağından ve nasıl oluşturulacağından emin değilim . İşte bazı örnek müşteri kodları.

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

HttpContentNesneyi, web API'sinin anlayacağı şekilde nasıl oluşturabilirim ?


Nesnenizin XML serileştirilmiş sürümünü hizmet uç noktasına göndermeyi denediniz mi?
Joshua Drake

Yanıtlar:


132

Jenerik HttpRequestMessage<T>olmuştur kaldırıldı . Bu :

new HttpRequestMessage<Widget>(widget)

olacak artık işi No .

Bunun yerine, bu gönderiden , ASP.NET ekibi bu işlevi desteklemek için bazı yeni çağrılar ekledi :

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

Böylece, yeni kod ( Dunston'dan ) şöyle olur:

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
Evet, ama ya Widget sınıfına erişiminiz yoksa?
contactmatt

13
Yeni 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` listeleri?
Jaans

1
@Jaans Flurl.Http , üzerinden basit / kısa bir yol sağlar PostUrlEncodedAsync.
Todd Menier

16
Kullanabilmek için System.Net.Http.Formatting'e bir referans eklemeniz gerektiğini unutmayın PostAsJsonAsyncveyaPostAsXmlAsync
Pete

6
PostAsJsonAcync kullanmak için NuGet paketini Microsoft.AspNet.WebApi.Client ekleyin !!
Dennis

99

Bunun SendAsyncyerine yöntemi kullanmalısınız, bu, girdiyi hizmete serileştiren genel bir yöntemdir.

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

Somut bir sınıf oluşturmak istemiyorsanız, FormUrlEncodedContentsınıfla yapabilirsiniz.

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

Not: kimliğinizi null yapılabilir bir int ( int?) yapmanız gerekir


1
Bu, Widget nesnesini içeren derlemeye bir referansım olmayacağı harici bir projeden çağrılacak. Doğru özellikleri içeren anonim olarak yazılmış bir nesne oluşturmayı, bu yöntemi kullanarak serileştirmeyi ve bu şekilde geçirmeyi denedim, ancak 500 Dahili Sunucu Hatası alıyorum. Web api denetleyici yöntemine asla ulaşmaz.
indot_brad

Oh - o zaman xml veya json'u webapi hizmetine göndermeniz gerekiyor ve bu onu seri durumdan çıkaracak - aynı şeyi yapıyor, SendAsync, hizmet için nesneyi serileştiriyor
dunston

1
Az önce bir güncelleme yaptım - kodu
test ettim

8
"Genel olmayan tür 'System.Net.Http.HttpRequestMessage' tür bağımsız değişkenleriyle kullanılamaz" alıyorum. bu hala geçerli mi?
user10479

5
Evet, ilk çözüm artık çalışmıyor: aspnetwebstack.codeplex.com/discussions/350492
Giovanni B

74

Taşınabilir Sınıf Kitaplığı kullanıyorsanız, HttpClient'in PostAsJsonAsync yöntemine sahip olmayacağını unutmayın . Taşınabilir Sınıf Kitaplığı kullanarak bir içeriği JSON olarak göndermek için şunu yapmanız gerekir:

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 serileştirilmiş bir nesneden geldiğinde ve bu nesnenin bir özelliği yani. İçerik = "etki alanı \ kullanıcı", ardından \ iki kez kodlanacaktır. Bir kez argsAsJson'a serileştirildiğinde ve ikinci kez PostAsync contentPost yayınladığında. Çift kodlama nasıl önlenir?
Krzysztof Morcinek

3
Mükemmel @fabiano! Bu gerçekten işe yaradı. Bu tür projelerde bu iki ekstra argüman gereklidir.
Peter Klein

Çok iyi @PeterKlein! Bu bilgiyi web üzerindeki Microsoft belgelerinde bulamadım, bu yüzden aynı sorunu yaşayanlara yardımcı olabilir. Projem bu numara olmadan veri göndermiyor.
Fabiano


4

Diğer yanıtlarda belirtilen kolaylık yöntemlerini istiyorsanız, ancak taşınabilirliğe ihtiyacınız varsa (veya istemeseniz bile), Flurl [açıklama: ben yazarım] ' a göz atmak isteyebilirsiniz . O (ince) sarar HttpClientve Json.NET ve dahil olmak üzere bazı akıcı şeker ve diğer güzellikler, ekler bazı pişmiş-in yardımcıları test .

JSON olarak gönder:

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

veya URL kodlu:

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

Yukarıdaki her iki örnek de bir döndürür HttpResponseMessage, ancak Flurl sadece takip sırasına geçmek istiyorsanız diğer şeyleri döndürmek için uzatma yöntemleri içerir:

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

Flurl NuGet'te mevcuttur:

PM> Install-Package Flurl.Http

1

Birçok alternatifi araştırdıktan sonra API 2.0 sürümüne uygun başka bir yaklaşımla karşılaştım.

(VB.NET benim favorim, sooo ...)

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

İyi şanslar! Benim için bu işe yaradı (sonunda!).

Saygılarımızla, Peter


1
Bu, @Fabiano tarafından yukarıda verilen önerilerle işlerin gerçekleşmesini sağlar.
Peter Klein

2
VB.NET kimsenin favorisi değil :)
Lazy Coder

1

Bunu yapabileceğinizi düşünüyorum:

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

Benim gibi biri yukarıda anlatılanları gerçekten anlamadıysa, benim için çalışan kolay bir örnek veriyorum. URL'si " http://somesite.com/verifyAddress " olan bir web api'niz varsa , bu bir gönderme yöntemidir ve ona bir adres nesnesi iletmeniz gerekir. Bu API'yi kodunuzda aramak istiyorsunuz. Yapabilecekleriniz burada.

    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

Buradaki diğer cevaplara dayanarak bulduğum kod bu. Bu, karmaşık türleri alan ve yanıtlayan bir HttpPost içindir:

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

Bunun gibi bir servis çağrısı yapın:

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

Ve bunun gibi Servis yöntemi:

public HttpResponseMessage PutSaveActivationCode(ActivationCodes objAC)
{
}

PutAsJsonAsync, ağ üzerinden Serileştirme ve seriyi kaldırma ile ilgilenir


Bu, istendiği gibi bir POST değil, HTTP PUT mesajı gönderir. Diğerlerinin dediği gibi PostAsJsonAsync, gerekli verileri JSON'da bir POST olarak gönderecek.
Zhaph - Ben Duguid
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.