如何设置 HttpClient (WinForms) 的默认 json 序列化设置

Lar*_*335 8 .net c# json.net winforms asp.net-web-api

我有一个使用 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);
Run Code Online (Sandbox Code Playgroud)

在客户端,我尝试了以下方法:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
    Formatting = Formatting.Indented,
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
    DateParseHandling = DateParseHandling.None
}.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
Run Code Online (Sandbox Code Playgroud)

当我显式使用 JsonConvert 时,这有效,例如:

var someVm = JsonConvert.DeserializeObject<SomeVm>(jsonString);
Run Code Online (Sandbox Code Playgroud)

但对于使用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.Nullable1[NodaTime.LocalDateTime]”时出错。路径“folderExpectedDate”,第 16 行,位置 45。 ---> System.ArgumentException:无法从 System.DateTime 强制转换或转换为 NodaTime.LocalDateTime。

请注意,在如上所述调用 DeserializeObject 时,导致上述异常的完全相同的 JSON 工作正常。

如何设置/修改 HttpClient 使用的默认序列化设置(我不想在每次调用中指定它 - 有数百个)?

Rez*_*aei 2

HttpContent扩展方法在 中定义,它们使用包含,和HttpContentExtensions的私有静态。MediaTypeFormatterCollectionJsonMediaTypeFormatterXmlMediaTypeFormatternew 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在应用程序启动时,您可以单点设置格式化程序:

var jsonFormatter = HttpClientDefaults.MediaTypeFormatters
    .OfType<JsonMediaTypeFormatter>().FirstOrDefault();

// Setup jsonFormatter, for example using jsonFormatter.SerializerSettings
Run Code Online (Sandbox Code Playgroud)

该设置将用于从 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>();
}
Run Code Online (Sandbox Code Playgroud)

  • 老兄,为什么`HttpClient`不允许全局配置这个,对吧?对于 `Content.ReadAsAsync` 来说,传递 json 转换器是“容易”的,但是对于 `client.PostAsJson` 则没有办法...通过反射设置对 `client.PostAsJson` 有效吗? (2认同)