如何使用System.Net.HttpClient发布一个复杂的types?

我有一个自定义的复杂types,我想使用Web API。

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

这是我的Web 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方法的对象types,以及如何构造它。 这里是一些示例客户端代码。

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

如何以Web API可以理解的方式创buildHttpContent对象?

通用HttpRequestMessage<T>已被删除 。 这个 :

 new HttpRequestMessage<Widget>(widget) 

不再工作

相反, 从这篇文章中 ,ASP.NET团队已经包含了一些新的调用来支持这个function:

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

所以,新代码( 来自邓斯顿 )变成:

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

您应该使用SendAsync方法,这是一种通用的方法,将input序列化到服务

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

如果你不想创build具体的类,你可以使用FormUrlEncodedContent

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

注意:你需要把你的id设为一个可空的int( int?

请注意,如果您使用的是可移植类库,则HttpClient将不具有PostAsJsonAsync方法 。 要使用可移植类库发布内容为JSON,您将必须这样做:

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

如果你想在其他答案中提到的便利方法的types,但需要可移植性(或者即使你不这样做),你可能想检查Flurl [披露:我是作者]。 它(简单地)包装了HttpClient和Json.NET,并添加了一些stream利的糖和其他好东西,包括一些烘焙testing助手 。

作为JSON发布:

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

或URL编码:

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

上面的两个例子都返回一个HttpResponseMessage ,但是Flurl包含了用于返回其他内容的扩展方法,如果你只想切换到chase:

 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 

在调查了许多替代scheme之后,我遇到了另一种适用于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 

祝你好运! 对我来说,这个解决了(最终!)。

问候,彼得

我认为你可以这样做:

 var client = new HttpClient(); HttpContent content = new Widget(); client.PostAsync<Widget>("http://localhost:44268/api/test", content, new FormUrlEncodedMediaTypeFormatter()) .ContinueWith((postTask) => { postTask.Result.EnsureSuccessStatusCode(); }); 

这是我根据其他答案在这里结束的代码。 这是一个HttpPost接收和复杂types的响应:

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

如果像我这样的人真的不明白上面所说的是什么,我就举个简单的例子来帮助我。 如果你有一个网站的API是“ http://somesite.com/verifyAddress ”,这是一个后期的方法,它需要你传递一个地址对象。 你想在你的代码中调用这个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; } 

拨打这样的服务电话:

 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负责通过networking进行序列化和反序列化