我有一个使用Web API后端的Winforms应用程序,我希望所有HTTP请求/响应都使用特定的JSON Serializertings。在服务器端,只需在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 pm to类型 '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 to 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);
用于推杆,帖子等:
//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
中定义,并且它们使用包含JsonMediaTypeFormatter
,XmlMediaTypeFormatter
和new FormUrlEncodedMediaTypeFormatter
的私有静态MediaTypeFormatterCollection
。
那些扩展方法,允许您通过MediaTypeFormatter
的自定义列表。他们使用您通过的格式器,或者如果您不通过任何格式器,他们将使用私人静态格式化器集合。因此结论:
-
您可以创建一个格式化器的静态列表并设置它们,并在每次要调用方法时将其传递到方法。
-
您可以选择使用反射设置
HttpContentExtensions
类的静态格式集合。然后,设置将始终由这些扩展方法使用。
示例
您可以创建一个公开HttpContextException
的静态私有DefaultMediaTypeFormatterCollection
属性的类:
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>();
}