我正在编写一个REST,它使用Polly弹性策略调用另一个REST。我第一次得到了可以正常工作的后备策略,但是第二次触发它会抛出一个错误:
System.IO.StreamHelpers.ValidateCopyToArgs(Stream source, Stream destination, int bufferSize)
System.IO.MemoryStream.CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
System.IO.Stream.CopyToAsync(Stream destination)
ProxyBase.HttpResponseMessageResult.ExecuteResultAsync(ActionContext context) in HttpResponseMessageResult.cs
+ await stream.CopyToAsync(context.HttpContext.Response.Body);
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0<TFilter, TFilterAsync>(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)HttpResponseMessageResult类是客户端在回退处理程序中返回的HttpResponseMessage到控制器方法所期望的IActionResult的自定义转换器。下面是抛出异常的方法的代码:
context.HttpContext.Response.StatusCode = (int)_responseMessage.StatusCode;
using (var stream = await _responseMessage.Content.ReadAsStreamAsync())
{
await stream.CopyToAsync(context.HttpContext.Response.Body);
await context.HttpContext.Response.Body.FlushAsync();
}我的政策是:
var fallbackPolicy = Policy<HttpResponseMessage>.Handle<Exception>()
.OrResult(r => r.StatusCode == System.Net.HttpStatusCode.RequestTimeout)
.FallbackAsync(
GetFailoverResponse(fallbackUrl),
(ct,cx) => {
HttpClient client = new HttpClient();
return client.GetAsync(fallbackUrl + ct.Result.RequestMessage.RequestUri.AbsolutePath);
});
clientBuilder.AddPolicyHandler(fallbackPolicy);我第二次检查返回的HttpResponseMessage是否新鲜--它是唯一的,当我添加一个随机参数时,我可以看到queryString是不同的。
我还尝试将实际的失败调用直接替换为回退调用(即将Polly从等式中提取出来)--就像这样,它工作得很好,因此,出于某种原因,polly用一个封闭的流来传递HttpResponseMessage。
发布于 2020-05-12 10:40:19
这个问题似乎与(Ab)使用FallbackAsync方法的第二个参数有关:它的目的是在返回回退结果之前运行,而不是生成结果本身,这就是我在上面代码的坏版本中所做的。
该方法具有不同的过载,但它们大多支持两个参数,并且精确数据类型不同: fallbackResult和onFallbackAsync。在这个中断的示例中,我返回一个静态fallbackResult作为备份,即使我的onFallbackAsync委托返回任务。我(错误的)理解是,这将是将由策略返回的HTTP响应。显然,在引擎盖下,它实际上是返回静态响应,在第二次使用时,它的流已经被读取了。
解决方案是使用第一个参数的另一个重载,该重载不会返回静态HttpResponseMessage,而是将HTTP上下文传递给可以执行回退HTTP请求的lambda,如下所示:
var fallbackPolicy = Policy<HttpResponseMessage>.Handle<Exception>()
.OrResult(r => r.StatusCode == System.Net.HttpStatusCode.RequestTimeout)
.FallbackAsync(
(res, cx, ct) => {
HttpClient client = new HttpClient();
return client.GetAsync(fallbackUrl + res.Result.RequestMessage.RequestUri.AbsolutePath);
},
(ct, cx) =>
{
return Task.CompletedTask;
});https://stackoverflow.com/questions/61703707
复制相似问题