使用HttpClient.GetFromJsonAsync(),如何在没有额外SendAsync调用的情况下处理基于Ht



System.Net.Http.JsonHttpClient扩展方法(如GetFromJsonAsync()(极大地简化了从web API检索json对象的例程代码。使用它很愉快。

但由于它的设计方式(直接返回反序列化对象(,它不会生成任何HttpResponseMessage以供检查,从而允许我基于HttpStatusCode执行自定义操作。

相反,非成功状态代码会导致HttpRequestException,它似乎不提供任何公开强类型HttpStatusCode的属性。相反,状态代码包含在异常的Message字符串本身中。

编辑:.NET 5.0添加了HttpRequestException.StatusCode属性,因此现在可以在调用GetFromJsonAsync时对其进行检查

//下方的旧帖子

所以我一直在做这样的事情:

try
{
var cars = await httpClient.GetFromJsonAsync<List<Car>>("/api/cars");
//...
}

catch (HttpRequestException ex)
{
if (ex.Message.Contains(HttpStatusCode.Unauthorized.ToString()))
{
//Show unauthorized error page...
}
//...
}

这感觉有点古怪。使用创建HttpRequestMessage并调用SendAsync的老派方法,我们自然有机会检查响应的HttpResponseMessage.StatusCode。将其中一些代码添加回System.Net.Http.Json中会破坏使用一行代码的方便目的。

如有任何建议,我们将不胜感激。

您可以使用:

// return HttpResponseMessage
var res= await httpClient.GetAsync<List<Car>>("/api/cars")
if (res.IsSuccessStatusCode)
var cars = res.Content.ReadFromJsonAsync<List<Car>>();
else
// deal with the HttpResponseMessage directly as you used to

我使用这样的基类:

using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;

namespace MyProject.ClientAPI
{
public abstract class ClientAPI
{
protected readonly HttpClient Http;
private readonly string BaseRoute;
protected ClientAPI(string baseRoute, HttpClient http)
{
BaseRoute = baseRoute;
Http = http;
}
protected async Task<TReturn> GetAsync<TReturn>(string relativeUri)
{
HttpResponseMessage res = await Http.GetAsync($"{BaseRoute}/{relativeUri}");
if (res.IsSuccessStatusCode)
{
return await res.Content.ReadFromJsonAsync<TReturn>();
}
else
{
string msg = await res.Content.ReadAsStringAsync();
Console.WriteLine(msg);
throw new Exception(msg);
}
}

protected async Task<TReturn> PostAsync<TReturn, TRequest>(string relativeUri, TRequest request)
{
HttpResponseMessage res = await Http.PostAsJsonAsync<TRequest>($"{BaseRoute}/{relativeUri}", request);
if (res.IsSuccessStatusCode)
{
return await res.Content.ReadFromJsonAsync<TReturn>();
}
else
{
string msg = await res.Content.ReadAsStringAsync();
Console.WriteLine(msg);
throw new Exception(msg);
}
}
}
}

然后从派生类中,我们回到一行

public class MySpecificAPI : ClientAPI
{
public MySpecificAPI(HttpClient http) : base("api/myspecificapi", http) {}

public async Task<IEnumerable<MyClass>> GetMyClassAsync(int ownerId)
{
try
{
return GetAsync<IEnumerable<MyClass>>($"apiMethodName?ownerId={ownerId}");
}
catch (Exception e)
{
// Deal with exception
}
}

// repeat for post
}

更新:处理NULL返回

遇到WebAPI返回null的有效场景后,行:

return await res.Content.ReadFromJsonAsync<TReturn>();

将引发Json反序列化错误。

为了解决这个问题,我们需要检测NoContent响应(204(并相应地处理:

if (res.StatusCode == HttpStatusCode.NoContent)
return default(TReturn);
else if (res.IsSuccessStatusCode)
return await res.Content.ReadFromJsonAsync<TReturn>();

我刚刚发现.NET 5.0实际上向HttpRequestException类添加了StatusCode属性!

https://github.com/dotnet/runtime/pull/32455

https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httprequestexception.statuscode?view=net-5.0

最新更新