如何在ASP.NET Core中将HTTP响应干净地传播到类型化HTTP客户端的使用者

时间:2019-07-13 04:59:13

标签: c# asp.net .net asp.net-core .net-core

在ASP.NET Core中,是否存在一种将成功的对象或状态代码和响应主体传播给typed HTTP client的使用者的好方法?

提供以下API服务:

public class TestApiService
{
    private readonly HttpClient _httpClient;

    public TestApiService(HttpClient httpClient)
    {
        httpClient.BaseAddress = new Uri("https://localhost:5000");
        _httpClient = httpClient;
    }

    public async Task<string> GetVersion()
    {
        var response = await _httpClient.GetAsync("/api/v1/version");

        if (response.IsSuccessStatusCode)
        {
            return await response.Content.ReadAsStringAsync();
        }

        return null;
    }
}

通过以下方式在DI容器中注册:

services.AddHttpClient<TestApiService>();

如果响应成功或响应失败,我想从string方法返回TestApiService.GetVersion()值。返回状态代码和响应正文。

似乎无法执行以下操作:

public async Task<string> GetVersion()
{
    var response = await _httpClient.GetAsync("/api/v1/version");

    response.EnsureSuccessStatusCode();

    return await response.Content.ReadAsStringAsync();
}

并获得理想的结果,因为从HttpRequestException抛出的HttpResponseMessage.EnsureSuccessStatusCode()不包括状态码或响应正文。

在GitHub上有一个open issue,但我不确定它是否会很快实现。

虽然ActionResult确实存在,但实际上似乎是用于控制器层的,所以我不确定在这里使用它是否适合该类的使用,或者是否有更好的方法来获取所需的类结果吗?

应该可以创建自己的异常类,然后将其从服务中抛出,但是如果要使用某种内置机制,我真的想避免这种情况。

1 个答案:

答案 0 :(得分:1)

删除response.EnsureSuccessStatusCode(),这基本上是在检查状态,如果不是200,则抛出异常。考虑使用response.IsSuccessStatusCode或手动检查响应状态代码。两种方法都可以防止引发您不想要的异常。

if (HttpStatusCode.Ok == response.StatusCode)
{
   // Read your result
}
else if ( // handle the specific failure case was it a 404 or a 401)
{
  string value = await response.Content?.ReadAsStringAsync();
  // Read your failed result
  return $"{response.StatusCode} {value}".Trim()";
}

下一个问题是如何处理服务的失败者并将其传达给服务的被呼叫者?您是否希望服务对客户端应用程序不透明?

由于您的代码仅返回字符串,因此您是否考虑过返回其他内容,例如包含对象{Success = true | false,Error =“”,ErrorCode = 1234,Data =“ value”},或者只是抛出一个适当的异常来传达故障的性质。例如。您可能要抛出适当的异常,例如TestApiException,其中TestApiException可能带有ErrorCode或您需要的任何内容。