2016-04-14 18 views
22

Używam System.Net.Http, znalazłem kilka przykładów w Internecie. Udało mi się stworzyć ten kod dokonać POST żądanie:Jak przekazać obiekt do HttpClient.PostAsync i serializować jako ciało JSON?

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

wszystko działa poprawnie. Ale załóżmy, że chcę przekazać trzeci parametr do metody POST, param o nazwie data. Param danych jest obiektem tak:

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

jak mogę to zrobić bez tworzenia KeyValuePair? Mój php RestAPI czekać na wejście json, więc FormUrlEncodedContent powinien wysłać poprawnie Json raw. Ale jak mogę to zrobić z Microsoft.Net.Http? Dzięki.

+0

Jeśli dobrze rozumiem pytanie, chcesz wysłać zawartość JSON zamiast formie zakodowanej treści prawo (i przez rozszerzenie chcesz, aby twój anonimowy typ był serializowany jako JSON do tej treści)? – CodingGorilla

+0

@CodingGorilla yes to anonimowy typ. – IlDrugo

Odpowiedz

39

Prosta się odpowiedź na Twoje pytanie brzmi: Nie Podpis dla metody PostAsync jest następujący:

zadania publicznego PostAsync (URI requestUri, HttpContent treści)

Tak więc, choć możesz przekazać object do PostAsync musi to być typ HttpContent, a Twój anonimowy typ nie spełnia tych kryteriów.

Istnieją jednak sposoby na osiągnięcie tego, co chcesz osiągnąć. Najpierw będziesz musiał serializować swój anonimowy typ do JSON, najczęściej używanym narzędziem jest Json.NET. A kod na to dość banalne:

var myContent = JsonConvert.SerializeObject(data); 

Dalej, trzeba będzie zbudować treści przedmiotu wysłać te dane, będę używać ByteArrayContent obiekt, ale można użyć lub utworzyć inny typ, jeśli chciał .

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

Następnie należy ustawić typ zawartości, aby interfejs API wiedział, że jest to JSON.

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

Następnie można wysłać zamówienie bardzo podobny do poprzedniego przykładu z treścią formularza:

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

Na marginesie, nazywając właściwość jak robisz tutaj może mieć jakieś bad side effects.Result takie jak martwe blokowanie, więc chcesz być ostrożny z tym.

+0

OK, jest bardzo jasne. Dziękuję za tę odpowiedź. Tylko pytanie: kiedy wykonywane jest 'POST, PUT, DELETE', zwykle API zwraca' TRUE', deklarowałem metodę jako 'string', ale kiedy robię:' return result; 'otrzymuję:' Can not Konwertuj HttpResponseMessage w ciągu znaków', czy powinienem zmienić deklarację metody? Potrzebuję odpowiedzi łańcuchowej, ponieważ będę potrzebował deserializować ją w innej metodzie klasy. – IlDrugo

+1

Jeśli potrzebujesz deserializować treść odpowiedzi, to zwracanie łańcucha w sposób jaki masz w swoim pytaniu (używając 'result.Content.ReadAsStringAsync()') jest prawdopodobnie w porządku. W zależności od struktury aplikacji, lepiej jest zwrócić obiekt 'Content' bezpośrednio, jeśli zajdzie potrzeba sprawdzenia nagłówków, aby określić, jaki jest typ elementu (np. XML lub JSON). Ale jeśli ** wiesz ** zawsze będzie zwracać JSON (lub inny format), to właśnie zwracanie treści odpowiedzi w postaci łańcucha powinno być w porządku. – CodingGorilla

+0

Mam to, dziękuję :) – IlDrugo

6

Musisz przekazać swoje dane w treści żądania jako surowy ciąg zamiast FormUrlEncodedContent. Jednym ze sposobów, aby to zrobić jest serializować go na ciąg JSON:

var json = JsonConvert.SerializeObject(data); 

Teraz wszystko co musisz zrobić, to przekazać ciąg do metody postu.

var stringContent = new HttpStringContent(json, 
         UnicodeEncoding.Utf8, 
         "application/json"); 

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

Należy zauważyć, że 'HttpStringContent' jest klasą środowiska wykonawczego Windows, która może nie zawsze być dostępna. Zobacz sekcję Wymagania [tutaj] (https://msdn.microsoft.com/en-us/library/windows/apps/windows.web.http.httpstringcontent.aspx). – CodingGorilla

+0

Tak, ponieważ jest to przenośna biblioteka klas. – IlDrugo

4

Prostym rozwiązaniem jest użycie Microsoft ASP.NET Web API 2.2 Client z NuGet.

Następnie można po prostu to zrobić i będzie to serializacji obiektu do JSON i ustawić Content-Type nagłówek do 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);