Answers:
EnsureSuccessStatusCode
当您不想以任何特定方式处理失败案例时,的惯用法是简洁地验证请求的成功。当您要快速建立客户端原型时,这特别有用。
当您决定要以特定方式处理故障案例时,请勿执行以下操作。
var response = await client.GetAsync(...);
try
{
response.EnsureSuccessStatusCode();
// Handle success
}
catch (HttpRequestException)
{
// Handle failure
}
抛出一个异常只是为了立即捕获它,这没有任何意义。的IsSuccessStatusCode
属性HttpResponseMessage
就是为此目的而存在的。而是执行以下操作。
var response = await client.GetAsync(...);
if (response.IsSuccessStatusCode)
{
// Handle success
}
else
{
// Handle failure
}
(int)response.StatusCode
(见msdn.microsoft.com/en-us/library/...)
我不喜欢SecureSuccessStatusCode,因为它不会返回任何有意义的信息。这就是为什么我创建自己的扩展程序的原因:
public static class HttpResponseMessageExtensions
{
public static async Task EnsureSuccessStatusCodeAsync(this HttpResponseMessage response)
{
if (response.IsSuccessStatusCode)
{
return;
}
var content = await response.Content.ReadAsStringAsync();
if (response.Content != null)
response.Content.Dispose();
throw new SimpleHttpResponseException(response.StatusCode, content);
}
}
public class SimpleHttpResponseException : Exception
{
public HttpStatusCode StatusCode { get; private set; }
public SimpleHttpResponseException(HttpStatusCode statusCode, string content) : base(content)
{
StatusCode = statusCode;
}
}
可以在此处找到Microsoft的sureSuccessStatusCode的源代码
基于SO链接的同步版本:
public static void EnsureSuccessStatusCode(this HttpResponseMessage response)
{
if (response.IsSuccessStatusCode)
{
return;
}
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
if (response.Content != null)
response.Content.Dispose();
throw new SimpleHttpResponseException(response.StatusCode, content);
}
我不喜欢IsSuccessStatusCode的地方在于它不是“很好”的可重用的。例如,在网络出现问题时,您可以使用诸如polly之类的库来重复请求。在那种情况下,您需要您的代码引发异常,以便波莉或其他库可以处理它。
EnsureSuccessStatusCode
。您总是要处置response.Content
(因为即使在该return;
语句之后,总会始终调用它),它会破坏内容以供进一步阅读。原始实现仅在状态代码未指示成功结果时才处理内容。
await response.Content.ReadAsStringAsync()
查询然后再查询if (response.Content != null)
HttpRequest
呼叫,并配置策略以处理某些异常和某些HttpResponseCode
。请参阅此处的Polly自述文件中
response.Content
当刚刚调用了一个方法时,怎么可能为null?
当我不想在同一方法上处理Exception时,可以使用GuaranteeSuccessStatusCode。
public async Task DoSomethingAsync(User user)
{
try
{
...
var userId = await GetUserIdAsync(user)
...
}
catch(Exception e)
{
throw;
}
}
public async Task GetUserIdAsync(User user)
{
using(var client = new HttpClient())
{
...
response = await client.PostAsync(_url, context);
response.EnsureSuccesStatusCode();
...
}
}
GetUserIdAsync上引发的异常将在DoSomethingAsync上处理。
以下是我建议的解决方案。唯一的缺陷是,由于ASP.NET Core框架资源管理器位于框架内部,因此我无法直接重用Microsoft的国际化消息字符串,因此我仅在此处使用逐字英语消息文字。
ConfigureTestContainer<T>
response.EnsureSuccessStatusCode();
并让服务器处理它即可。Content
在检查状态之前读取属性。在某些情况下这可能是不希望的,其中之一就是效率低下。using (var requestMessage = new HttpRequestMessage(HttpMethod.Post, "controller/action"))
{
using (var response = await HttpClient.SendAsync(requestMessage))
{
var content = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode2(content);
var result = JsonConvert.DeserializeObject<ResponseClass>(content);
}
}
public static class HttpResponseMessageExtensions
{
public static void EnsureSuccessStatusCode2(this HttpResponseMessage message, string content = null)
{
if (message.IsSuccessStatusCode)
return;
var contentMessage = string.IsNullOrWhiteSpace(content) ? string.Empty : $"Content: {content}";
throw new HttpRequestException(string.Format(
System.Globalization.CultureInfo.InvariantCulture,
"Response status code does not indicate success: {0} ({1}).{2}",
(int)message.StatusCode,
message.ReasonPhrase,
contentMessage)
);
}
}