我正在构建一个给定HttpContent对象的函数,它将发出请求并在失败时重试。但是我有例外,说发出请求后会丢弃HttpContent对象。无论如何,有没有要复制或复制HttpContent对象,以便我可以发出多个请求。
public HttpResponseMessage ExecuteWithRetry(string url, HttpContent content) { HttpResponseMessage result = null; bool success = false; do { using (var client = new HttpClient()) { result = client.PostAsync(url, content).Result; success = result.IsSuccessStatusCode; } } while (!success); return result; } // Works with no exception if first request is successful ExecuteWithRetry("http://www.requestb.in/xfxcva" /*valid url*/, new StringContent("Hello World")); // Throws if request has to be retried ... ExecuteWithRetry("http://www.requestb.in/badurl" /*invalid url*/, new StringContent("Hello World"));
(显然,我不会无限尝试,但是上面的代码本质上是我想要的)。
它产生这个异常
System.AggregateException: One or more errors occurred. ---> System.ObjectDisposedException: Cannot access a disposed object. Object name: 'System.Net.Http.StringContent'. at System.Net.Http.HttpContent.CheckDisposed() at System.Net.Http.HttpContent.CopyToAsync(Stream stream, TransportContext context) at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar) --- End of inner exception stack trace --- at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions) at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) at System.Threading.Tasks.Task`1.get_Result() at Submission#8.ExecuteWithRetry(String url, HttpContent content)
无论如何,有没有重复HttpContent对象或重复使用它?
代替实施包裹该重试功能的HttpClient,可以考虑构成HttpClient与HttpMessageHandler内部执行所述重试逻辑。例如:
HttpClient
HttpMessageHandler
public class RetryHandler : DelegatingHandler { // Strongly consider limiting the number of retries - "retry forever" is // probably not the most user friendly way you could respond to "the // network cable got pulled out." private const int MaxRetries = 3; public RetryHandler(HttpMessageHandler innerHandler) : base(innerHandler) { } protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { HttpResponseMessage response = null; for (int i = 0; i < MaxRetries; i++) { response = await base.SendAsync(request, cancellationToken); if (response.IsSuccessStatusCode) { return response; } } return response; } } public class BusinessLogic { public void FetchSomeThingsSynchronously() { // ... // Consider abstracting this construction to a factory or IoC container using (var client = new HttpClient(new RetryHandler(new HttpClientHandler()))) { myResult = client.PostAsync(yourUri, yourHttpContent).Result; } // ... } }