如何为HttpClient(WinForms)设置默认的json序列化设置
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何为HttpClient(WinForms)设置默认的json序列化设置相关的知识,希望对你有一定的参考价值。
我有一个使用Web API后端的WinForms应用程序,我希望所有的HTTP请求/响应都使用特定的json SerializerSettings。在服务器端,只需在Global.asax.cs中执行此操作即可:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.DateParseHandling = DateParseHandling.None;
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
在客户端,我尝试了这个:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Formatting = Formatting.Indented,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
DateParseHandling = DateParseHandling.None
}.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
这在我明确使用JsonConvert时有用,例如:
var someVm = JsonConvert.DeserializeObject<SomeVm>(jsonString);
但是,对于使用HttpClient.GetAsync / PostAsAsync等的调用,它不会生效,从而导致异常:
将值2/24/2018 4:00:00 PM转换为类型'System.Nullable
1[NodaTime.LocalDateTime]'. Path 'folderExpectedDate', line 16, position 45. Newtonsoft.Json.JsonSerializationException: Error converting value 2/24/2018 4:00:00 PM to type 'System.Nullable
1 [NodaTime.LocalDateTime]'时出错。路径'folderExpectedDate',第16行,位置45. ---> System.ArgumentException:无法从System.DateTime转换或转换为NodaTime.LocalDateTime。
注意,在上面调用DeserializeObject时,导致上述异常的完全相同的JSON工作正常。
如何设置/修改HttpClient使用的默认序列化设置(我不想在每次调用中指定它 - 有几百个)?
这是我提出的目前似乎运作良好(为了我的目的)而且非常干净。
从服务器读取Json响应(基于:http://nodogmablog.bryanhogan.net/2017/10/httpcontent-readasasync-with-net-core-2/):
public static class HttpContentExtensions
{
public static async Task<T> ReadAsJsonAsync<T>(this HttpContent content, JsonSerializerSettings jsonSerializerSettings = null)
{
if (jsonSerializerSettings == null)
{
jsonSerializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
DateParseHandling = DateParseHandling.None
}.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
}
string json = await content.ReadAsStringAsync();
T value = JsonConvert.DeserializeObject<T>(json, jsonSerializerSettings);
return value;
}
}
用法:
var someVm = await response.Content.ReadAsJsonAsync<SomeVm>().ConfigureAwait(false);
对于Puts,Posts等:
//var response = await WebServiceUtil.HttpClient.PostAsJsonAsync("designSalesJob/new", designSalesJob).ConfigureAwait(false);
var response = await WebServiceUtil.HttpClient.PostAsync("designSalesJob/new", designSalesJob, HttpUtil.JsonFormatter).ConfigureAwait(false);
这是JsonFormatter实用程序方法(将重构上面的ReadAsJsonAsync也使用它):
public static class HttpUtil
{
public static JsonMediaTypeFormatter JsonFormatter => new JsonMediaTypeFormatter
{
SerializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
DateParseHandling = DateParseHandling.None
}.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb)
};
}
对此解决方案的反馈当然是受欢迎的......
HttpContent
扩展方法在HttpContentExtensions
中定义,它们使用包含MediaTypeFormatterCollection
,JsonMediaTypeFormatter
和XmlMediaTypeFormatter
的私有静态new FormUrlEncodedMediaTypeFormatter
。
这些扩展方法允许您传递MediaTypeFormatter
的自定义列表。它们使用您传递的格式化程序,或者如果您不传递任何格式化程序,它们将使用私有静态格式化程序集合。所以作为结论:
- 您可以创建格式化程序的静态列表并设置它们,并在每次要调用方法时将其传递给方法。
- 您可以选择使用反射设置
HttpContentExtensions
类的静态格式化程序集合。然后,这些扩展方法将始终使用该设置。
例
您可以创建一个公开DefaultMediaTypeFormatterCollection
的静态私有HttpContextException
属性的类:
public class HttpClientDefaults
{
public static MediaTypeFormatterCollection MediaTypeFormatters
{
get
{
var p = typeof(HttpContentExtensions).
GetProperty("DefaultMediaTypeFormatterCollection",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Static);
return (MediaTypeFormatterCollection)p.GetValue(null, null);
}
}
}
然后在启动应用程序时,您可以在一个点上设置格式化程序:
var jsonFormatter = HttpClientDefaults.MediaTypeFormatters
.OfType<JsonMediaTypeFormatter>().FirstOrDefault();
// Setup jsonFormatter, for example using jsonFormatter.SerializerSettings
该设置将用于从json反序列化的所有扩展方法,您无需更改调用这些方法的方式:
HttpClient client = new HttpClient();
var response = await client.GetAsync("http://localhost:58045/api/products/1");
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<Product>();
}
以上是关于如何为HttpClient(WinForms)设置默认的json序列化设置的主要内容,如果未能解决你的问题,请参考以下文章
如何为我的 HttpClient PostAsync 第二个参数设置 HttpContent?