如何为HTTPCLIENT设置默认的JSON序列化设置(WinForms)



我有一个使用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中定义,并且它们使用包含JsonMediaTypeFormatterXmlMediaTypeFormatternew 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>();
}

最新更新