Как использовать System.Net.HttpClient для публикации сложного типа?
У меня есть настраиваемый сложный тип, с которым я хочу работать с использованием Web API.
public class Widget
{
public int ID { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
И вот мой метод API веб-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();
});
Как создать объект HttpContent таким образом, чтобы веб-API его понял?
Ответы
Ответ 1
Общий HttpRequestMessage<T>
был удален. Это:
new HttpRequestMessage<Widget>(widget)
будет больше работать.
Вместо этого из этого сообщения команда 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() );
Ответ 2
Вместо этого вы должны использовать метод 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
class
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();
});
Примечание: вам нужно сделать свой идентификатор нулевым int (int?
)
Ответ 3
Обратите внимание, что если вы используете портативную библиотеку классов, HttpClient не будет иметь метод PostAsJsonAsync.
Чтобы опубликовать контент как JSON с использованием Portable Class Library, вам нужно будет сделать это:
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());
Ответ 4
Если вы хотите, чтобы типы методов удобства, упомянутые в других ответах, но нуждались в переносимости (или даже если вы этого не сделали), вы можете проверить Flurl [раскрытие: я автор]. Он (тонко) обертывает HttpClient
и Json.NET и добавляет немного свободного сахара и других полезных свойств, в том числе некоторые испеченные помощники .
Опубликовать как JSON:
var resp = await "http://localhost:44268/api/test".PostJsonAsync(widget);
или URL-encoded:
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
Ответ 5
После изучения множества альтернатив, я столкнулся с другим подходом, подходящим для версии API 2.0.
(VB.NET - мой любимый, 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
Удачи! Для меня это получилось (в конце концов!).
С уважением,
Питер
Ответ 6
Я думаю, вы можете это сделать:
var client = new HttpClient();
HttpContent content = new Widget();
client.PostAsync<Widget>("http://localhost:44268/api/test", content, new FormUrlEncodedMediaTypeFormatter())
.ContinueWith((postTask) => { postTask.Result.EnsureSuccessStatusCode(); });
Ответ 7
Это код, с которым я столкнулся, основываясь на других ответах здесь. Это для 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));
Ответ 8
В случае, если кто-то вроде меня действительно не понимает, о чем идет речь выше, я даю простой пример, который работает на меня.
Если у вас есть веб-api, который url " http://somesite.com/verifyAddress", это метод post, и вам нужно передать ему адресный объект, Вы хотите называть это 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;
}
Ответ 9
Сделайте вызов службы следующим образом:
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 заботится о сериализации и десериализации по сети