Reputation: 131
I tried cloning the HttpResponseMessage
object and printing the response in a fire-and-forget async call. For this, I received The stream already consumed error.
Any leads are appreciated.
Logs
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: The stream was already consumed. It cannot be read again.
at System.Net.Http.HttpConnectionResponseContent.ConsumeStream()
at System.Net.Http.HttpConnectionResponseContent.SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken)
Sample Code
using System.Text;
using BookMyShow.Logging;
using Microsoft.Extensions.Http;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient();
builder.Services.ConfigureAll<HttpClientFactoryOptions>(options =>
{
options.HttpMessageHandlerBuilderActions.Add(messageHandlerBuilder =>
{
messageHandlerBuilder.AdditionalHandlers.Add(messageHandlerBuilder.Services.GetRequiredService<HttpRetentionHandler>());
});
});
builder.Services.AddTransient<HttpRetentionHandler>();
var app = builder.Build();
app.MapPost("/post", async (IHttpClientFactory httpClientFactory) =>
{
var httpClient = httpClientFactory.CreateClient();
string jsonPayload = @"{""title"": ""New Post"", ""body"": ""This is the body of the new post"", ""userId"": 1}";
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
using var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://jsonplaceholder.typicode.com/posts"),
Content = content
};
var response = await httpClient.SendAsync(request);
if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"Integration Service failed with error and Status Code: {response.StatusCode}");
}
string body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return Results.Ok(body);
});
app.Run();
public class HttpRetentionHandler : DelegatingHandler
{
public HttpRetentionHandler()
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var logReference = new Dictionary<string, object>();
try
{
HttpResponseMessage responseMessage = await base.SendAsync(request, cancellationToken);
HttpResponseMessage clonedResponse = await CloneAsync(responseMessage);
var responseText = new StringBuilder(clonedResponse.ToString());
responseText.Append('\n');
logReference["response"] = responseText.ToString();
Task.Run(async () => {
await PrintApiResponseAsync("print response", logReference, clonedResponse.Content, responseText);
}, cancellationToken);
return responseMessage;
}
catch (Exception)
{
throw;
}
}
async Task PrintApiResponseAsync(string name, Dictionary<string, object> logReference, HttpContent responseContent, StringBuilder responseText)
{
if (responseContent != null)
{
string content = await responseContent.ReadAsStringAsync();
responseText.Append(content);
logReference["response"] = responseText.ToString();
}
string text = JsonSerializer.Serialize(logReference, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(text);
}
private async Task<HttpResponseMessage> CloneAsync(HttpResponseMessage response)
{
var clone = new HttpResponseMessage(response.StatusCode);
if (response.Content != null)
{
using var ms = new MemoryStream();
await response.Content.CopyToAsync(ms);
ms.Position = 0;
clone.Content = new StreamContent(ms);
response.Content.Headers.ToList().ForEach(header =>
clone.Content.Headers.TryAddWithoutValidation(header.Key, header.Value));
}
response.Headers.ToList().ForEach(header =>
clone.Headers.TryAddWithoutValidation(header.Key, header.Value));
return clone;
}
}
Upvotes: 1
Views: 56