如何将一个对象传递给HttpClient.PostAsync并序列化为JSON主体?

yrdbyhpb  于 2022-11-19  发布在  其他
关注(0)|答案(8)|浏览(379)

我正在使用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做到这一点呢?谢谢。

xqk2d5yq

xqk2d5yq1#

你的问题的直接答案是:否。PostAsync方法的签章如下:
公共任务PostAsync(URI请求URI,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属性可能会有一些bad side effects,比如死锁,所以要小心。

5lhxktic

5lhxktic2#

您需要在请求主体中以原始字符串而不是FormUrlEncodedContent的形式传递数据。

var json = JsonConvert.SerializeObject(data); // or JsonSerializer.Serialize if using System.Text.Json

现在您需要做的就是将字符串传递给post方法。

var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); // use MediaTypeNames.Application.Json in Core 3.0+ and Standard 2.1+

var client = new HttpClient();
var response = await client.PostAsync(uri, stringContent);
4uqofj5v

4uqofj5v3#

新的.NET 5+解决方案:

在.NET 5中,引入了一个名为JsonContent的新类,它派生自HttpContentSee in Microsoft docs
该类包含一个名为Create()的静态方法,该方法接受任意对象作为参数,并且顾名思义,返回JsonContent的示例,然后可以将该示例作为参数传递给PostAsync方法。
用法:

var myObject = new
{
    foo = "Hello",
    bar = "World",
};

JsonContent content = JsonContent.Create(myObject);

await _httpClient.PostAsync("https://...", content);

更棒的是,您实际上可以使用新的PostAsJsonAsync扩展方法使其更加简洁-请参阅the docs for this。用法:

var myObject = new
{
    foo = "Hello",
    bar = "World",
};
await _httpClient.PostAsJsonAsync("https://...", myObject);

感谢@charlesthyer和@KonradViltersten指出这一点。

35g0bw71

35g0bw714#

一个简单的解决方案是从NuGet使用Microsoft ASP.NET Web API 2.2 Client
然后,您可以简单地执行此操作,它会将对象序列化为JSON,并将Content-Type头设置为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);
rmbxnbpk

rmbxnbpk5#

现在有一种更简单的方法来处理.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>();
06odsfpq

06odsfpq6#

@arad说得不错.其实我刚刚发现了这个扩展方法(.NET 5.0):
PostAsJsonAsync<TValue>(HttpClient, String, TValue, CancellationToken)
https://learn.microsoft.com/en-us/dotnet/api/system.net.http.json.httpclientjsonextensions.postasjsonasync?view=net-5.0开始
因此,现在可以:

var data = new { foo = "Hello"; bar = 42; };
var response = await _Client.PostAsJsonAsync(_Uri, data, cancellationToken);
mm5n2pyu

mm5n2pyu7#

您有两种选择,这取决于您编写的框架,如果您使用的是.Net 5,则可以只编写JsonContent.Create(yourObject);
或者创建一个扩展方法并在对象上调用它:

public static StringContent GetStringContent(this object obj)
{
    var jsonContent = JsonConvert.SerializeObject(obj);
    var contentString = new StringContent(jsonContent, Encoding.UTF8, "application/json");
    contentString.Headers.ContentType = new MediaTypeHeaderValue("application/json");

    return contentString;
}
pexxcrt2

pexxcrt28#

public static async Task<string> Post(string param, string code, string subject, string description)
    {
        object mydata = new
        {
            code = code,
            subject = subject,
            description = description
        };
        var myContent = JsonConvert.SerializeObject(mydata);
        var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
        var byteContent = new ByteArrayContent(buffer);
        byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

        using (HttpClient client = new HttpClient())
        {
            using (HttpResponseMessage res = await client.PostAsync(baseURL + param, byteContent))
            {
                Console.WriteLine("Nico", res);
                using (HttpContent content = res.Content)
                {
                    string data = await content.ReadAsStringAsync();
                    if (data != null) { return data; }
                }
            }
        }
        return string.Empty;
    }

在我的另一种形式

private async void button2_Click(object sender, EventArgs e) //POST
        {
            string param = "subject";
            string code = txtCode.Text; //NC101
            string subject = txtSubject.Text;
            string description = txtDescription.Text;
            var res = await RESTHelper.Post(param, code, subject, description);
            txtRes.Text = res;
        }

相关问题