你可以在github阅读完整的设计文档,团队希望构建一个更加方便的独立发布的库,来在 HttpClient 和 System.Text.Json 使用,也可以在Blazor 中使用这些API。
这些初始化的工作已经由微软的 David Cantu 合并到项目,准备接下来的 Blazor,现在已经是.NET 5 BCL(基础库)的一部分,所以这是我为什么一直在提 System.Net.Http.Json,现在你可以在 Nuget 下载安装,接下来,我会探讨下支持的主要的API和使用场景。
使用 HttpClient 发送和接收Json数据下边的一些代码和示例我已经上传到了这里 https://github.com/stevejgordon/SystemNetHttpJsonSamples
这第一步是包添加到您的项目,你可以使用NuGet包管理器或者下边的命令行安装
dotnet add package System.Net.Http.Json 使用 HttpClient 获取Json数据让我们先看一个扩展方法HttpClient,这很简单
private static async Task<User> GetJsonHttpClient(string uri, HttpClient httpClient) { try { return await httpClient.GetFromJsonAsync<User>(uri); } catch (HttpRequestException) // Non success { Console.WriteLine("An error occurred."); } catch (NotSupportedException) // When content type is not valid { Console.WriteLine("The content type is not supported."); } catch (JsonException) // Invalid JSON { Console.WriteLine("Invalid JSON."); } return null; }在代码第5行,传入泛型调用 GetFromJsonAsync 来反序列化 Json 内容,方法传入一个uri地址,这是我们所需要的,我们操作了一个 Http Get请求到服务端,然后获取响应反序列化到 User 实体,这很简洁,另外上边有详细的异常处理代码,在各种条件下来抛出异常
跟最上面的代码一样,使用 EnsureSuccessStatusCode 来判断状态码是否成功,如果状态码在 200-299 之外,会抛出异常
并且这个库还会检查是不是有效的媒体类型,比如 application/json, 如果媒体类型错误,将抛出 NotSupportedException,这里的检查比我上边手动处理的代码更加完整,如果媒体类型不是 application/json,则会对值进行基于Span的解析, 所以 application/<something>+json 也是有效的格式
这种格式是现在经常使用的,另外一个例子,可以发现这个库对于标准和细节的处理,RFC7159 标准 定义一种携带机器可读的HTTP响应中的错误,比如 application/problem+json, 我手写的代码没有处理和匹配这些,因为 System.Net.Http.Json 已经做了这些工作
在内部,ResponseHeadersRead HttpCompletionOption 用来提升效率,我最近的文章有这个的介绍,这个库已经处理好了 HttpResponseMessage,使用这个Option是必需的
转码最后这个库的实现细节, 包括支持代码转换返回的数据,如果不是utf-8,utf-8应该在绝大多数情况下的标准,然而,如果 content-type 报头中包含的字符集标识不同的编码,将使用TranscodingStream 尝试反序列化成 utf-8
从HttpContent 处理Json在某些情况下,您可能想要发送请求的自定义 Header , 或者你想反序列化之前检查 Response Header,这也可以使用 System.Net.Http.Json 提供的扩展方法
private static async Task<User> GetJsonFromContent(string uri, HttpClient httpClient) { var request = new HttpRequestMessage(HttpMethod.Get, uri); request.Headers.TryAddWithoutValidation("some-header", "some-value"); using var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); if (response.IsSuccessStatusCode) { // perhaps check some headers before deserialising try { return await response.Content.ReadFromJsonAsync<User>(); } catch (NotSupportedException) // When content type is not valid { Console.WriteLine("The content type is not supported."); } catch (JsonException) // Invalid JSON { Console.WriteLine("Invalid JSON."); } } return null; } 发送Json数据最后一个示例我们使用 HttpClient 来发送Json数据,看一下下边我们的两种实现
private static async Task PostJsonHttpClient(string uri, HttpClient httpClient) { var postUser = new User { Name = "Steve Gordon" }; var postResponse = await httpClient.PostAsJsonAsync(uri, postUser); postResponse.EnsureSuccessStatusCode(); }第一个方法是使用 PostAsJsonAsync 扩展方法,把对象序列化成 Json 请求到服务端,内部会创建一个 HttpRequestMessage 和 序列化成内容流
还有一种情况需要手动创建一个 HttpRequestMessage, 也许包括自定义请求头,你可以直接创建 JsonContent
private static async Task PostJsonContent(string uri, HttpClient httpClient) { var postUser = new User { Name = "Steve Gordon" }; var postRequest = new HttpRequestMessage(HttpMethod.Post, uri) { Content = JsonContent.Create(postUser) }; var postResponse = await httpClient.SendAsync(postRequest); postResponse.EnsureSuccessStatusCode(); }