102

我有一个想要使用 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方法,以及如何构造它。这是一些示例客户端代码。

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以 Web API 可以理解的方式创建对象?

4

9 回答 9

134

泛型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() );
于 2013-02-05T18:42:08.623 回答
99

您应该改用该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该类进行创建

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

于 2012-04-24T20:04:17.077 回答
76

请注意,如果您使用的是可移植类库,则 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());
于 2014-04-15T22:21:25.910 回答
4

如果您想要其他答案中提到的便利方法类型但需要可移植性(或者即使您不需要),您可能需要查看Flurl [披露:我是作者]。它(薄薄地)包装HttpClient了 Json.NET 并添加了一些流利的糖和其他好东西,包括一些烘焙测试助手

以 JSON 格式发布:

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

或 URL 编码:

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
于 2014-07-30T18:49:48.343 回答
1

在研究了很多替代方案后,我遇到了另一种方法,适用于 API 2.0 版本。

(VB.NET 是我最喜欢的,所以……)

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

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

问候,彼得

于 2014-08-10T18:27:34.433 回答
1

我认为你可以这样做:

var client = new HttpClient();
HttpContent content = new Widget();
client.PostAsync<Widget>("http://localhost:44268/api/test", content, new FormUrlEncodedMediaTypeFormatter())
    .ContinueWith((postTask) => { postTask.Result.EnsureSuccessStatusCode(); });
于 2015-03-27T12:38:36.717 回答
1

如果像我这样的人并不真正理解以上所有内容,我会举一个对我有用的简单示例。如果你有一个 url 为“ http://somesite.com/verifyAddress ”的 web api,它是一个 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;
    }
于 2017-10-24T19:36:35.407 回答
0

这是我根据此处的其他答案得出的代码。这适用于接收和响应复杂类型的 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));
于 2017-01-26T14:56:41.947 回答
-1

像这样拨打服务电话:

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 负责网络上的序列化和反序列化

于 2016-08-31T19:17:25.270 回答