.NET HttpClient 如何在 POST 请求中添加查询字符串和 JSON 主体

13

我如何设置 .NET HttpClient.SendAsync() 请求以包含查询字符串参数和 JSON 主体(在 POST 的情况下)?

// Query string parameters
var queryString = new Dictionary<string, string>()
{
    { "foo", "bar" }
};

// Create json for body
var content = new JObject(json);

// Create HttpClient
var client = new HttpClient();
client.BaseAddress = new Uri("https://api.baseaddress.com/");

var request = new HttpRequestMessage(HttpMethod.Post, "something");
// Setup header(s)
request.Headers.Add("Accept", "application/json");
// Add body content
request.Content = new StringContent(
    content.ToString(),
    Encoding.UTF8,
    "application/json"
);

// How do I add the queryString?

// Send the request
client.SendAsync(request);

我看到的每一个例子都建议设置

request.Content = new FormUrlEncodedContent(queryString)

但是这样我会失去在request.Content中初始化JSON body的操作。


HttpRequestMessage有一个RequestUri属性;使用它来添加查询字符串(你可能需要创建一个新的Uri对象并将RequestUri设置为该对象)。 - Heretic Monkey
@MikeMcCaughan 我确实研究了这个问题,并发现重新设置 RequestUri 属性,加上我的端点 + 查询字符串信息,会覆盖我在 HttpClient 对象上全局设置的 HttpClient.BaseAddress。但是这条路线引导我找到了我正在寻找的解决方案。 - Kevin R
3个回答

34

我最终找到了Microsoft.AspNetCore.WebUtilities.QueryHelpers.AddQueryString(),这正是我需要的。 这使我能够添加查询字符串参数而无需手动构建字符串(并担心转义字符等问题)。

注意:我正在使用ASP.NET Core,但相同的方法也可通过Microsoft.Owin.Infrastructure.WebUtilities.AddQueryString()获得

新代码:

// Query string parameters
var queryString = new Dictionary<string, string>()
{
    { "foo", "bar" }
};

// Create json for body
var content = new JObject(json);

// Create HttpClient
var client = new HttpClient();
client.BaseAddress = new Uri("https://api.baseaddress.com/");

// This is the missing piece
var requestUri = QueryHelpers.AddQueryString("something", queryString);

var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
// Setup header(s)
request.Headers.Add("Accept", "application/json");
// Add body content
request.Content = new StringContent(
    content.ToString(),
    Encoding.UTF8,
    "application/json"
);

// Send the request
client.SendAsync(request);

1
我不明白。所以foo=bar已经是一个查询字符串..(键/值对); 然后你又添加了另一个查询字符串something="foo=bar",其中键=key,值="foo=bar"? - joedotnot
4
在这个上下文中,“something”将作为URI的一部分添加到“BaseAddress”中。因此,最终的URI将是https://api.baseaddress.com/something?foo=bar - Kevin R

2
我可以建议您使用RestSharp来实现此目的。它基本上是HttpWebRequest的包装器,可以轻松地组合URL和请求参数,并将结果反序列化回来。
以下是该网站上的示例:
var client = new RestClient("http://example.com");

var request = new RestRequest("resource/{id}", Method.POST);
request.AddParameter("name", "value"); // adds to POST or URL querystring based on Method
request.AddUrlSegment("id", "123"); // replaces matching token in request.Resource

// easily add HTTP Headers
request.AddHeader("header", "value");

// add files to upload (works with compatible verbs)
request.AddFile(path);

// execute the request
IRestResponse response = client.Execute(request);

1
这是误导性的。RestSharp不是HttpClient的包装器。HttpClient允许传递DelegatingHandler进行身份验证和重试逻辑。RestSharp的结构完全不同,需要单独安装Polly来处理重试逻辑。 - Gabriel Garrett
是的,它实际上是基于 HttpWebRequest 的。我只是意味着它是在 .Net 类的基础上进行封装的。我会更改文本。 - Ilya Chernomordik

-5

这很简单,对我很有效:

responseMsg = await httpClient.PostAsJsonAsync(locationSearchUri, new { NameLike = "Johnson" });

请求体的格式如下:{ NameLike:"Johnson" }

1
这并没有回答如何将查询字符串和JSON主体添加到同一POST请求的问题。 - Pyritie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接