C# 如何使用System.Net.HttpClient发布复杂类型?

C# 如何使用System.Net.HttpClient发布复杂类型?,c#,asp.net-web-api,C#,Asp.net Web Api,我有一个自定义的复杂类型,我想使用Web API处理它 public class Widget { public int ID { get; set; } public string Name { get; set; } public decimal Price { get; set; } } 这是我的WebAPI控制器方法。我想这样发布此对象: public class TestController : ApiController { // POST /api

我有一个自定义的复杂类型,我想使用Web API处理它

public class Widget
{
    public int ID { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}
这是我的WebAPI控制器方法。我想这样发布此对象:

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

如何以web API能够理解的方式创建
HttpContent
对象?

您应该改用
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() );

注意:您需要将id设置为可为空的int(
int?

通用
HttpRequestMessage
已被删除。这:

new HttpRequestMessage<Widget>(widget)

请注意,如果您使用的是可移植类库,HttpClient将没有postsjsonasync方法。 要使用可移植类库将内容发布为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());

如果您想要其他答案中提到的便利方法类型,但需要可移植性(或者即使您不需要),您可能需要查看[披露:我是作者]。它(薄薄地)包装了
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();

在研究了许多替代方案之后,我发现了另一种方法,适用于API 2.0版本

(VB.NET是我的最爱,sooo…)

祝你好运!对我来说,这是成功的(最终!)

问候,,
彼得

我认为你可以做到这一点:

var client = new HttpClient();
HttpContent content = new Widget();
client.PostAsync<Widget>("http://localhost:44268/api/test", content, new FormUrlEncodedMediaTypeFormatter())
    .ContinueWith((postTask) => { postTask.Result.EnsureSuccessStatusCode(); });
var-client=new-HttpClient();
HttpContent=newwidget();
客户端。PostAsync(“http://localhost:44268/api/test,内容,新FormUrlEncodedMediaTypeFormatter())
.ContinueWith((postTask)=>{postTask.Result.EnsureSuccessStatusCode();});

拨打如下服务电话:

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)
{
}
服务方式如下:

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

这是我最后使用的代码,基于这里的其他答案。这适用于接收和响应复杂类型的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));
Task response=httpClient.PostAsJsonAsync(
strmyhttposturl,
新的MyComplexObject{Param1=Param1,Param2=Param2}).ContinueWith((postTask)=>postTask.Result.EnsureSessAccessStatusCode());
//调试:
//字符串s=response.Result.Content.ReadAsStringAsync().Result;
MyOtherComplexType moct=(MyOtherComplexType)JsonConvert.DeserializeObject(response.Result.Content.ReadAsStringAsync().Result,typeof(MyOtherComplexType));

如果像我这样的人真的不明白上面所说的是什么,我会给出一个简单的例子,这对我很有用。 如果您有一个url为“”的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;
    }
公共广播验证地址(地址)
{
this.client=新的HttpClient();
client.BaseAddress=新Uri(“http://somesite.com/");
client.DefaultRequestHeaders.Accept.Add(新的MediaTypeWithQualityHeaderValue(“应用程序/json”);
var urlParm=URL+“验证地址”;
response=client.PostAsJsonAsync(urlParm,address).Result;
var dataObjects=response.issucessstatuscode?response.Content.ReadAsAsync()。结果:null;
返回数据对象;
}

您是否尝试将对象的XML序列化版本提交到服务端点?这将从外部项目调用,在该项目中,我不会引用包含小部件对象的程序集。我尝试创建一个包含正确属性的匿名类型对象,使用此方法序列化它,并以这种方式传递它,但我得到一个500内部服务器错误。它从来不会命中web api控制器方法。哦-然后你需要将xml或json发布到webapi服务,它将对其进行反序列化-它也会这样做,SendAsync,正在序列化服务的对象。我刚刚做了一次更新-我已经测试了代码,但使用了一些更简单的代码,但我应该可以“非泛型类型'System.Net.Http.HttpRequestMessage'不能与类型参数一起使用”。这仍然有效吗?是的,第一个解决方案不再有效:是的,但是如果您无权访问Widget类怎么办?新的
HttpClient.PostasxxAsync(t值)方法很好,但是对于application/x-www-form-urlencoded格式的方法呢?有没有简单/快捷的方法呢?还是我们仍然需要创建详细的
KeyValuePair`列表?@Jaans通过
posterlencodedasync
提供了一种简单/快捷的方法。请注意,您需要添加对System.Net.Http.Formatting的引用才能使用
PostAsJsonAsync
PostAsXmlAsync
若要使用PostAsJsonAcync,请在argsAsJson来自序列化对象且该对象具有属性ie.Content=“domain\user”时添加NuGet包Microsoft.AspNet.WebApi.Client,则\将被编码两次。一次序列化为argsAsJson,第二次PostSync发布contentPost。如何避免双重编码?非常好@fabiano!这确实奏效了。这两个额外的参数在这类项目中是必要的。非常好@PeterKlein!我在网上的微软文档中找不到这些信息,因此这可以帮助其他人解决同样的问题。如果没有这个技巧,我的项目根本不会发送数据。请注意,您可能还必须将“application/json”添加到请求的Accept标头中,根据@Fabiano make things Occess.VB.NET给出的建议,这将发送HTTP PUT消息,而不是请求的帖子。正如其他人所说,
PostAsJsonAsync
将以JSON格式的POST发送所需数据。
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)
{
}
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));
    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;
    }