来自 HttpClient 的模型对象的 c# 生成 URL 编码查询



需要从 HttpClient 的模型对象构建 URL 编码查询

我的模型是

class SaveProfileRequest
{
public string gName { get; set; }
public string gEmail { get; set; }
public long gContact { get; set; }
public string gCompany { get; set; }
public string gDeviceID { get; set; }
public string Organization { get; set; }
public string profileImage { get; set; }
public string documentImagefront { get; set; }
public string documentImageback { get; set; }
}
SaveProfileRequest request = new SaveProfileRequest() { gName = name, gEmail = email, gContact = phonenumber, gCompany = company,
gDeviceID = deviceId, Organization = "", profileImage = "", documentImageback = "", documentImagefront = "" };
string response = await RequestProvider.PostAsync<string, SaveProfileRequest>(uri, request);

我有一个内容类型 JSON 的工作代码

content = new StringContent(JsonConvert.SerializeObject(data));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

其中数据类型为 TInput

content = new StringContent(System.Net.WebUtility.UrlEncode(JsonConvert.SerializeObject(data)));
content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

但没有锻炼

JsonConvert只生成 JSON 内容。对于 urlencoding 查询,您应该构造FormUrlEncodedContent的实例。作为构造函数参数,它需要KeyValuePair<string, string>的集合。所以主要的技巧是为模型对象构建这个集合。

为此,您可以使用反射。但是有一个基于 Json.net 的更简单的解决方案。这里描述了它,以下扩展方法是从该博客文章中复制/粘贴ToKeyValue()

public static class ObjectExtensions
{
public static IDictionary<string, string> ToKeyValue(this object metaToken)
{
if (metaToken == null)
{
return null;
}
JToken token = metaToken as JToken;
if (token == null)
{
return ToKeyValue(JObject.FromObject(metaToken));
}
if (token.HasValues)
{
var contentData = new Dictionary<string, string>();
foreach (var child in token.Children().ToList())
{
var childContent = child.ToKeyValue();
if (childContent != null)
{
contentData = contentData.Concat(childContent)
.ToDictionary(k => k.Key, v => v.Value);
}
}
return contentData;
}
var jValue = token as JValue;
if (jValue?.Value == null)
{
return null;
}
var value = jValue?.Type == JTokenType.Date ?
jValue?.ToString("o", CultureInfo.InvariantCulture) :
jValue?.ToString(CultureInfo.InvariantCulture);
return new Dictionary<string, string> { { token.Path, value } };
}
}

现在,您可以像以下方式轻松构建 url 编码的内容:

var keyValues = data.ToKeyValue();
var content = new FormUrlEncodedContent(keyValues);

您可以使用此简化版本

public static class URLExtensions
{
public static string ToKeyValueURL(this object obj)
{
var keyvalues = obj.GetType().GetProperties()
.ToList()
.Select(p => $"{p.Name} = {p.GetValue(obj)}")
.ToArray();
return string.Join('&',keyvalues);
}
}

这可以使用 Flurl 轻松完成(免责声明:我是作者),因为开箱即用地支持以下确切方案 - 将 .NET 对象的属性解析为 URL 编码的键值对:

using Flurl.Http;
var resp = await url.PostUrlEncodedAsync(data);

Flurl 在引擎盖下使用HttpClient,因此在上面的例子中,respHttpResponseMessage的一个实例,就像直接使用HttpClient进行调用一样。如果只需要响应正文,也可以将.ReceiveString()追加到调用中,或者如果需要 JSON 响应并需要T类型的匹配 .NET 对象,也可以.ReceiveJson<T>()追加到调用。

如果我可以扩展CodeFuller的答案,我想创建一些方便的方法,就像System.Net.Http.Json的HttpClient扩展一样。

就像你可以做PostAsJsonAsync()/PutAsJsonAsync()一样,我创建了这个简单的扩展类来添加到之前发布的类中:

public static class HttpClientExtensions
{
public static Task<HttpResponseMessage> PostAsFormUrlEncodedAsync<T>(this HttpClient httpClient, string? requestUri, T? content)
{
var dict = content?.ToKeyValue();
var formContent = dict is not null ? new FormUrlEncodedContent(dict) : null;
return httpClient.PostAsync(requestUri, formContent);
}
public static Task<HttpResponseMessage> PutAsFormUrlEncodedAsync<T>(this HttpClient httpClient, string? requestUri, T? content)
{
var dict = content?.ToKeyValue();
var formContent = dict is not null ? new FormUrlEncodedContent(dict) : null;
return httpClient.PutAsync(requestUri, formContent);
}
}

您可以像前面提到的HttpClient方法一样使用它:

var response = await httpClient.PostAsUrlEncodedAsync("api/customer", customer);

最新更新