.net HttpClient 与自定义 JsonConverter

Posted

技术标签:

【中文标题】.net HttpClient 与自定义 JsonConverter【英文标题】:.net HttpClient with custom JsonConverter 【发布时间】:2012-12-17 13:54:13 【问题描述】:

我正在使用 .NET 的 HttpClient 向 WebAPI 发出请求,该 WebAPI 返回一些 JSON 数据,需要在客户端进行一些自定义反序列化。为此,我创建了自己的JsonConverter,但我不知道如何让ReadAsAsync<T> 方法获取转换器的存在。

我现在已经解决了我的问题,方法是使用ReadAsStringAsync 读取响应,然后将该字符串传递给JsonConvert.DeserializeObject,但似乎应该有一个更优雅的解决方案。

这是我的代码:

public PrefsResponse GetAllPrefs(string sid) 
    HttpClient client = CreateHttpClient(null, sid);
    var response = client.GetAsync("api/sites/" + sid).Result;

    // TODO : find a way to hook custom converters to this...
    // return response.Content.ReadAsAsync<PrefsResponse>().Result;

    var stringResult = response.Content.ReadAsStringAsync().Result;

    return JsonConvert.DeserializeObject<PrefsResponse>(stringResult, new PrefClassJsonConverter());

这是我能做的最好的,还是有更优雅的方法?

这里也是我创建 HttpClient 的地方,如果我需要连接它的话:

        private HttpClient CreateHttpClient(CommandContext ctx, string sid) 
        var cookies = new CookieContainer();

        var handler = new HttpClientHandler 
            CookieContainer = cookies,
            UseCookies = true,
            UseDefaultCredentials = false
        ;

        // Add identity cookies:
        if (ctx != null && !ctx.UserExecuting.IsAnonymous) 
            string userName = String.Format("0 (1)", ctx.RequestingUser.UserName, ctx.UserExecuting.Key);
            cookies.Add(new Cookie(__userIdCookieName, userName));
            cookies.Add(new Cookie(__sidCookieName, sid));
            cookies.Add(new Cookie(__hashCookieName,
                                   GenerateHash(userName, Prefs.Instance.UrlPrefs.SharedSecret)));
        

        var client = new HttpClient(handler) 
            BaseAddress = _prefServerBaseUrl
        ;

        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));



        return client;
    

【问题讨论】:

【参考方案1】:

您可以将带有转换器列表的JsonSerializerSettings 传递给JsonMediaTypeFormatterReadAsAsync&lt;T&gt; 将使用它:

var obj = await result.Content.ReadAsAsync<refsResponse>(
    new[] new JsonMediaTypeFormatter 
          SerializerSettings = new JsonSerializerSettings  
              Converters = new List<JsonConverter> 
                //list of your converters
               
              
          
    );

【讨论】:

我不知道 JSON.Net 有它自己的转换器概念!所以现在我们有了三样东西可以做同样的工作。派生的 HttpContent 类、派生的 MediaTypeFormatters 和派生的 JsonConverter.... 这就是我要找的。最终,我将使用我最初拥有的内容,因为我还需要在磁盘上缓存响应,以防将来请求发生故障转移。 太棒了!我需要自定义一些其他 JSON.NET 设置,而这对我来说是缺失的部分:) @filip-w 有没有办法让备用序列化程序成为默认值(即不必作为参数传入)? 在 WebAPi 中配置全局 json 转换器很容易,但在客户端应用程序中,使用 HttpClient 我找不到简单的方法。问题是关于阅读响应,但是POSTing 请求呢?我必须应用 2 个自定义格式化程序,我该怎么做?【参考方案2】:

您可能想使用HttpClient.GetStringAsync Method (String)

var response = client.GetStringAsync("api/sites/" + sid);
return JsonConvert.DeserializeObject<PrefsResponse>(response.Result, new  PrefClassJsonConverter());

或者你到底想要什么更优雅?

【讨论】:

这绝对比将大量嵌套初始化器传递给Content.ReadAsAsync() 更优雅。唯一的缺点可能是将流读入一个字符串,这对于不是很大的 json 数据包来说已经足够了。在代码退出代码编辑器窗口后,我以这种方式更改了我的代码,并且没有任何格式可以帮助它。【参考方案3】:

我能够使用以下内容将自定义 JsonConverter 添加到 HttpClient 的默认格式化程序:

MediaTypeFormatterCollection formatters = new MediaTypeFormatterCollection(); 
formatters.JsonFormatter.SerializerSettings.Converters.Add(new MyCustomConverter());


var result = response.Content.ReadAsAsync<T>(formatters).Result;

这似乎允许您将自定义转换器添加到默认转换器。

【讨论】:

使用httpclient.PostAsJson()时会怎样?如何传递自定义格式化程序?

以上是关于.net HttpClient 与自定义 JsonConverter的主要内容,如果未能解决你的问题,请参考以下文章

Json.net 从 HTTPClient 结果反序列化 DateTime

HttpClient请求头自定义

opsworks rails.env 与自定义 json rails_env 不匹配

使用 System.Net.Http.Json 简化 HttpClient 的使用

.NET 3.1 中来自 HTTPClient 的 SendAsync 中的对象循环 Json

使用 .NET 4.0 任务模式使用 HTTPClient .ReadAsAsync 将 JSON 反序列化为数组或列表