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

c#

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...
   }
   //...
}

这感觉有点hacky。使用老派的创建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
}

更新:处理空返回

遇到 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>();


以上是使用HttpClient.GetFromJsonAsync(),如何在没有额外SendAsync调用的情况下处理基于HttpStatusCode的HttpRequestException?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>