Bir nesneyi HttpClient.PostAsync'e nasıl iletirim ve JSON gövdesi olarak serileştiririm?


94

Ben kullanıyorum System.Net.Http, ben web üzerinde çeşitli örnekler gördük. Bir POSTistekte bulunmak için bu kodu oluşturmayı başardım :

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

hepsi iyi çalışıyor. Ancak POSTyönteme üçüncü bir parametrenin, adı verilen bir parametrenin geçirilmesini istediğimi varsayalım data. Veri parametresi şuna benzer bir nesnedir:

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

bunu oluşturmadan nasıl yapabilirim KeyValuePair? Benim php RestAPIböylece, bir json girişi beklemek FormUrlEncodedContentgöndermelidir rawdoğru json. Ama bunu nasıl yapabilirim Microsoft.Net.Http? Teşekkürler.


Sorunuzu anlarsam, doğrudan form kodlu içerik yerine JSON içeriği göndermek mi istiyorsunuz (ve uzantı olarak anonim türünüzün o içeriğe JSON olarak serileştirilmesini istiyorsunuz)?
CodingGorilla

@CodingGorilla evet anonim bir tür.
IlDrugo

3
Gelecekteki okuyucular için bir yan not usingolarak HttpClient,. aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
maxshuty

2
Microsoft'tan neden usingkullanılmaması gerektiğine ilişkin not: 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

Yanıtlar:


155

Sorunuzun doğrudan cevabı şudur: Hayır. PostAsyncYöntemin imzası aşağıdaki gibidir:

public Task PostAsync (Uri requestUri, HttpContent içeriği)

Eğer geçebilir süre Yani, bir objectkarşı PostAsyncbunun türünde olmalıdır HttpContentve anonim türü bu kriterlere uygun değildir.

Ancak, başarmak istediğiniz şeyi başarmanın yolları vardır. İlk olarak, anonim türünüzü JSON olarak serileştirmeniz gerekir, bunun için en yaygın araç Json.NET'tir . Ve bunun kodu oldukça önemsiz:

var myContent = JsonConvert.SerializeObject(data);

Ardından, bu verileri göndermek için bir içerik nesnesi oluşturmanız gerekecek ByteArrayContent, bir nesne kullanacağım , ancak isterseniz farklı bir tür kullanabilir veya oluşturabilirsiniz.

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

Ardından, API'nin bunun JSON olduğunu bilmesini sağlamak için içerik türünü ayarlamak istersiniz.

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

Daha sonra form içeriği ile talebinizi önceki örneğinize çok benzer şekilde gönderebilirsiniz:

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

Bir yan not olarak, .Resultburada yaptığınız gibi mülkiyeti aramak, kilitlenme gibi bazı kötü yan etkilere neden olabilir , bu yüzden buna dikkat etmek istersiniz.


Tamam, çok açık. Bu cevap için teşekkürler. Sadece bir soru: a POST, PUT, DELETEyapıldığında, genellikle API dönüşü TRUE, yöntemi olarak ilan ettim string, ancak yaptığımda: return result;şunu alırım:, Can't Convert HttpResponseMessage in stringyöntem bildirimini değiştirmeli miyim? Dize yanıtına ihtiyacım var çünkü başka bir sınıf yönteminde daha sonra serisini kaldırmam gerekecek.
IlDrugo

2
Yanıt gövdesinin seri halini kaldırmanız gerekiyorsa, dizeyi sorunuzdaki gibi döndürmeniz (kullanarak result.Content.ReadAsStringAsync()) muhtemelen yeterli olacaktır. Uygulama Contentyapınıza bağlı olarak, içerik türünün (ör. XML veya JSON) ne olduğunu belirlemek için başlıkları incelemeniz gerekiyorsa nesneyi doğrudan döndürmeniz daha iyi olabilir . Ancak, her zaman JSON (veya başka bir format) döndüreceğini biliyorsanız , yanıt gövdesini bir dize olarak döndürmek yeterli olacaktır.
CodingGorilla

Sorduğum için özür dilerim, ancak veri türü ise bunu yapmanız gerekir StringContentmi?
MyDaftQuestions

1
@MyDaftQuestions Ne istediğinizden tam olarak emin değilim, ancak kaynaklandığı için StringContentdoğrudan ' a geçebilirsiniz . PostAsyncHttpContent
CodingGorilla

@CodingGorilla, sorduğum şey buydu. Teşekkür ederim :)
MyDaftQuestions

67

Verilerinizi istek gövdesinde değil, ham dizge olarak iletmeniz gerekir FormUrlEncodedContent. Bunu yapmanın bir yolu, onu bir JSON dizesi halinde serileştirmektir:

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

Şimdi yapmanız gereken tek şey dizeyi post yöntemine iletmektir.

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

Nedir stringContent? Benim durumumda stringContentdeğer "\"\"". Bu doğru değer mi?
R15

c # kodunuzdan vb'deki dizi sonucunu elde etmek mümkün müdür? oldukça benzer olduğunu
öğrendim

42

Basit bir çözüm kullanmaktır Microsoft ASP.NET Web API 2.2 Clientgelen Nuget .

Daha sonra bunu basitçe yapabilirsiniz ve bu, nesneyi JSON'a serileştirir ve Content-Typebaşlığı şu şekilde ayarlar 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
kesinlikle PostAsJsonAsync kullanmak için var
Kat Lim Ruiz

26

Artık .NET Standardveya ile daha basit bir yol var .NET Core:

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

NOT:JsonMediaTypeFormatter Sınıfı kullanmak için , Microsoft.AspNet.WebApi.Clientdoğrudan veya Microsoft.AspNetCore.App.

Bu imzayı kullanarak HttpClient.PostAsyncherhangi bir nesneye geçebilirsiniz ve JsonMediaTypeFormatterotomatik olarak serileştirme ile ilgilenir.

HttpContent.ReadAsAsync<T>Yanıtla, yanıt içeriğini beklediğiniz türe göre seri durumdan çıkarmak için kullanabilirsiniz :

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

1
bu hangi .net sürümünü kullanıyor?
TemporaryFix

1
@Programmatic .NET Standardveya .NET Corebahsettiğim gibi kullanmanız gerekiyor . Belki kullanıyorsun .NET Framework? Projemde, JsonMediaTypeFormatter buradan yükleniyor: 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 Bu proje türlerinden birini zaten kullanıyorsanız, fazladan bir NuGet paketi eklemeniz gerekebilir. Benim için otomatik olarak hangisinin dahil edildiğini tam olarak unutuyorum. Benim durumumda, Microsoft.AspNetCore.App NuGet paketinin bir parçası olarak dahil edildi.
Ken Lyon

1
.NET Core kullanıyordum, ancak çözümümün c # dilinin en son sürümünü kullanacak şekilde ayarlandığını sanmıyorum. Güncelledim ve işe yaradı. Teşekkür ederim
TemporaryFix

1
@Programmatic Hoş geldiniz. Çalıştığını duyduğuma sevindim! NuGet paketi ile ilgili cevabıma bir not ekledim.
Ken Lyon
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.