Как передать объект HttpClient.PostAsync и сериализовать как тело JSON?
Я использую 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
, параметр под названием data
. Параметр data представляет собой такой объект:
object data = new
{
name = "Foo",
category = "article"
};
как я могу это сделать без создания KeyValuePair
? Мой php RestAPI
ждет ввода json, поэтому FormUrlEncodedContent
должен правильно отправить raw
json. Но как я могу сделать это с помощью Microsoft.Net.Http
? Спасибо.
Ответы
Ответ 1
Прямой ответ на ваш вопрос: Нет. Подпись для метода PostAsync
выглядит следующим образом:
public Task PostAsync (Uri requestUri, контент HttpContent)
Итак, хотя вы можете передать object
в PostAsync
, он должен иметь тип HttpContent
, а ваш анонимный тип не соответствует этим критериям.
Однако есть способы выполнить то, что вы хотите выполнить. Во-первых, вам нужно будет сериализовать ваш анонимный тип в JSON, наиболее распространенным инструментом для этого является Json.NET. И код для этого довольно тривиален:
var myContent = JsonConvert.SerializeObject(data);
Затем вам нужно будет создать объект содержимого для отправки этих данных, я буду использовать объект ByteArrayContent
, но вы могли бы использовать или создать другой тип, если хотите.
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);
Затем вы хотите установить тип содержимого, чтобы API знал, что это JSON.
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
Затем вы можете отправить свой запрос, очень похожий на ваш предыдущий пример, с содержимым формы:
var result = client.PostAsync("", byteContent).Result
На стороне примечания, вызов свойства .Result
, как вы здесь, может иметь некоторые плохие побочные эффекты, такие как мертвая блокировка, поэтому вы хотите быть осторожно с этим.
Ответ 2
Вам нужно передать ваши данные в теле запроса в виде необработанной строки, а не FormUrlEncodedContent
. Один из способов сделать это - сериализовать его в строку JSON:
var json = JsonConvert.SerializeObject(data);
Теперь все, что вам нужно сделать, это передать строку методу post.
var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json");
var client = new HttpClient();
var response = await client.PostAsync(uri, stringContent);
Ответ 3
Простым решением является использование Microsoft ASP.NET Web API 2.2 Client
от NuGet.
Затем вы можете просто сделать это, и он будет сериализовать объект в JSON и установить заголовок Content-Type
в application/json; charset=utf-8
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);
Ответ 4
Там теперь более простой способ с .NET Standard
или .NET Core
:
var client = new HttpClient();
var response = await client.PostAsync(uri, myRequestObject, new JsonMediaTypeFormatter());
ПРИМЕЧАНИЕ. Чтобы использовать класс JsonMediaTypeFormatter
, вам необходимо установить пакет Microsoft.AspNet.WebApi.Client
NuGet, который можно установить напрямую или через другой, такой как Microsoft.AspNetCore.App
.
Используя эту подпись HttpClient.PostAsync
, вы можете передать любой объект, и JsonMediaTypeFormatter
автоматически позаботится о сериализации и т.д.
С ответом вы можете использовать HttpContent.ReadAsAsync<T>
для десериализации содержимого ответа к типу, который вы ожидаете:
var responseObject = await response.Content.ReadAsAsync<MyResponseType>();