I want to send the exact same request more than once, for example:
HttpClient client = new HttpClient(); HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, "http://example.com"); await client.SendAsync(req, HttpCompletionOption.ResponseContentRead); await client.SendAsync(req, HttpCompletionOption.ResponseContentRead);
Sending the request for a second time will throw an exception with the message:
The request message was already sent. Cannot send the same request message multiple times.
Is their a way to "clone" the request so that I can send again?
My real code has more variables set on the HttpRequestMessage
than in the example above, variables like headers and request method.
An HttpRequestMessage object can only be used one time; future attempts to use the same object throw an exception.
SendAsync(HttpRequestMessage) Send an HTTP request as an asynchronous operation. SendAsync(HttpRequestMessage, HttpCompletionOption) Send an HTTP request as an asynchronous operation.
I wrote the following extension method to clone the request.
public static HttpRequestMessage Clone(this HttpRequestMessage req) { HttpRequestMessage clone = new HttpRequestMessage(req.Method, req.RequestUri); clone.Content = req.Content; clone.Version = req.Version; foreach (KeyValuePair<string, object> prop in req.Properties) { clone.Properties.Add(prop); } foreach (KeyValuePair<string, IEnumerable<string>> header in req.Headers) { clone.Headers.TryAddWithoutValidation(header.Key, header.Value); } return clone; }
Here is an improvement to the extension method proposed by @drahcir. The improvement is to ensure the content of the request is cloned as well as the request itself:
public static HttpRequestMessage Clone(this HttpRequestMessage request) { var clone = new HttpRequestMessage(request.Method, request.RequestUri) { Content = request.Content.Clone(), Version = request.Version }; foreach (KeyValuePair<string, object> prop in request.Properties) { clone.Properties.Add(prop); } foreach (KeyValuePair<string, IEnumerable<string>> header in request.Headers) { clone.Headers.TryAddWithoutValidation(header.Key, header.Value); } return clone; } public static HttpContent Clone(this HttpContent content) { if (content == null) return null; var ms = new MemoryStream(); content.CopyToAsync(ms).Wait(); ms.Position = 0; var clone = new StreamContent(ms); foreach (KeyValuePair<string, IEnumerable<string>> header in content.Headers) { clone.Headers.Add(header.Key, header.Value); } return clone; }
Edit 05/02/18: here's Async version
public static async Task<HttpRequestMessage> CloneAsync(this HttpRequestMessage request) { var clone = new HttpRequestMessage(request.Method, request.RequestUri) { Content = await request.Content.CloneAsync().ConfigureAwait(false), Version = request.Version }; foreach (KeyValuePair<string, object> prop in request.Properties) { clone.Properties.Add(prop); } foreach (KeyValuePair<string, IEnumerable<string>> header in request.Headers) { clone.Headers.TryAddWithoutValidation(header.Key, header.Value); } return clone; } public static async Task<HttpContent> CloneAsync(this HttpContent content) { if (content == null) return null; var ms = new MemoryStream(); await content.CopyToAsync(ms).ConfigureAwait(false); ms.Position = 0; var clone = new StreamContent(ms); foreach (KeyValuePair<string, IEnumerable<string>> header in content.Headers) { clone.Headers.Add(header.Key, header.Value); } return clone; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With