Recently, I started developing an API for my project. After some research, we decided to implement logging for each request and response of the API to track them effectively. 
For logging the posted request body, we need to read the request body. Additionally, there is a need for logging the response and the time it took for the request to process and return, enabling us to monitor our API's performance. 
 I decided to create a middleware for logging, but I don't know how to do that. If you're facing the same issue, read this article.

Logging Request Body and Response Body in ASP.NET Core API

To log the request body and response body in an ASP.NET Core API using middleware, let's take the OrderController as an example. We'll create a custom middleware that intercepts the request and response streams to log their content. 

Let's create a custom middleware to log the request body and response body in our ASP.NET Core API. We'll use the OrderController as an example.

1. Custom Middleware:

First, we'll create a custom middleware to intercept the request and response streams:

using System.IO;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;

    public class LoggingMiddleware
    {
        private readonly RequestDelegate _next;

        public LoggingMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            // Log the request body
            string requestBody = await ReadRequestBody(context.Request);
            Console.WriteLine("Request Body: " + requestBody);

            // Replace the response stream with a custom stream
            var originalResponseBody = context.Response.Body;
            var responseBodyStream = new MemoryStream();
            context.Response.Body = responseBodyStream;

            // Invoke the next middleware in the pipeline
            await _next(context);

            // Log the response body
            responseBodyStream.Seek(0, SeekOrigin.Begin);
            string responseBody = await new StreamReader(responseBodyStream, Encoding.UTF8).ReadToEndAsync();
            Console.WriteLine("Response Body: " + responseBody);

            // Copy the response back to the original stream and reset the position
            responseBodyStream.Seek(0, SeekOrigin.Begin);
            await responseBodyStream.CopyToAsync(originalResponseBody);
            context.Response.Body = originalResponseBody;
        }

        private async Task<string> ReadRequestBody(HttpRequest request)
        {
            request.EnableBuffering();
            using var reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true);
            var requestBody = await reader.ReadToEndAsync();
            request.Body.Seek(0, SeekOrigin.Begin);
            return requestBody;
        }
    }

2. Register Middleware:

Next, we'll register our custom middleware in the application startup:

 public void Configure(IApplicationBuilder app)
    {
        // Add the custom middleware to the pipeline
        app.UseMiddleware<LoggingMiddleware>();

        
    }

With this middleware , we'll be able to log the request body and response body for each request to our ASP.NET Core API.

2

Rreading the response body in ASP.NET Core 6, we use the HttpContext.Response.Body property, this property provides access to the response body stream, which we can read to obtain the response content. 

we first obtain the response body stream using HttpContext.Response.Body. We then save the current position of the response body stream to be able to reset it later. We seek to the beginning of the response body stream and read it as a string using a StreamReader with UTF-8 encoding and then finally, we reset the position of the response body stream to its original position before returning the response body string.



    using Microsoft.AspNetCore.Http;
    using System.IO;
    using System.Text;

    public async Task ReadResponseBody(HttpContext context)
    {
        // Get the response body stream
        Stream responseBody = context.Response.Body;

        // Save the current position of the response body stream
        long originalPosition = responseBody.Position;

        // Seek to the beginning of the response body stream
        responseBody.Seek(0, SeekOrigin.Begin);

        // Read the response body stream as a string
        using var reader = new StreamReader(responseBody, Encoding.UTF8);
        string responseBodyString = await reader.ReadToEndAsync();

        // Reset the position of the response body stream to its original position
        responseBody.Seek(originalPosition, SeekOrigin.Begin);

        return responseBodyString;
    }
    

Reading ASP.NET Core  Response.Body with Middleware

If we want to read the response body using middleware in ASP.NET Core , we can intercept the response stream within the middleware pipeline. Here's how we can achieve this:

First, let's create a custom middleware that will intercept the response:


    using Microsoft.AspNetCore.Http;
    using System.IO;
    using System.Text;
    using System.Threading.Tasks;

    public class ResponseReadingMiddleware
    {
        private readonly RequestDelegate _next;

        public ResponseReadingMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            // Capture the original response body stream
            var originalBodyStream = context.Response.Body;

            // Create a new memory stream to capture the response body
            using (var responseBody = new MemoryStream())
            {
                // Replace the original response body with the memory stream
                context.Response.Body = responseBody;

                // Call the next middleware in the pipeline
                await _next(context);

                // Reset the response body position and read the response
                responseBody.Seek(0, SeekOrigin.Begin);
                string responseBodyString = await new StreamReader(responseBody, Encoding.UTF8).ReadToEndAsync();

                // Log or process the response body as needed
                Console.WriteLine("Response Body: " + responseBodyString);

                // Copy the response body back to the original stream
                responseBody.Seek(0, SeekOrigin.Begin);
                await responseBody.CopyToAsync(originalBodyStream);
            }
        }
    }
    

Next, we need to register our middleware in the application startup:


    public void Configure(IApplicationBuilder app)
    {
        // Add the custom middleware to the pipeline
        app.UseMiddleware<ResponseReadingMiddleware>();

        
    }
    
3 I've been trying to write or set the HttpContext.Response.Body but to no avail. Most of the samples I found is using the Body.WriteAsync but the paramaters are different then the example. I tried converting my string to byte[] but the text doesn't show on my Response.Body. To write to HttpContext.Response.Body in .NET Core 6 or later, you can use the awaitable WriteAsync method of the Response.BodyStream property. 
using Microsoft.AspNetCore.Http;
using System.Text;
using System.Threading.Tasks;

public async Task WriteToResponseBody(HttpContext context)
{
    // Set the content type
    context.Response.ContentType = "text/plain";

    // Get the response body stream
    using var responseBody = context.Response.Body;

    // Convert the string to byte array
    byte[] byteArray = Encoding.UTF8.GetBytes("Hello, World!");

    // Write the byte array to the response body
    await responseBody.WriteAsync(byteArray, 0, byteArray.Length);
}
We first set the content type of the response to "text/plain". Then, we get the response body stream using the Response.Body property. We convert the string "Hello, World!" to a byte array using Encoding.UTF8.GetBytes.,we write the byte array to the response body using the WriteAsync method. Make sure to await this method call if it's within an asynchronous context, like within an endpoint handler in an ASP.NET Core application.