# .NET API: capture original message body

**Date:** 2021-03-11  
**Author:** Kees C. Bakker  
**Categories:** .NET / C#  
**Original:** https://keestalkstech.com/net-api-capture-original-message-body/

![.NET API: capture original message body](https://keestalkstech.com/wp-content/uploads/2021/03/markus-spiske-gnhxvdGmGG8-unsplash-scaled.jpg)

---

Sometimes you just need to record the original message that was submitted to your API. My colleague [Onno Pierik](https://www.linkedin.com/in/onno-pierik-062a577/) and I encountered such an event. We needed to record the original submitted SOAP message (body) and submit it (under certain conditions) to another service. To be honest: most of the scenarios I've seen so far end up with memory problems, so use with caution!

## Recording middleware

We've found a [nice piece of code](https://github.com/DigDes/SoapCore/blob/develop/src/SoapCore/SoapEndpointMiddleware.cs#L210-L214) that can replace the original body of a request with a new memory stream:

```cs
//Reload the body to ensure we have the full message
var memoryStream = new MemoryStream((int)httpContext.Request.ContentLength.GetValueOrDefault(1024));
await httpContext.Request.Body.CopyToAsync(memoryStream).ConfigureAwait(false);
memoryStream.Seek(0, SeekOrigin.Begin);
httpContext.Request.Body = memoryStream;
```

Let's turn the code into a piece of middleware:

```cs
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

public class RecorderMiddleware 
{
    private readonly RequestDelegate _next;

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

    public async Task Invoke(HttpContext httpContext)
    {
        var ms = new MemoryStream((int)httpContext.Request.ContentLength.GetValueOrDefault(1024));
            
        await httpContext.Request.Body.CopyToAsync(ms).ConfigureAwait(false);
        ms.Seek(0, SeekOrigin.Begin);

        httpContext.Items.Add("recording", Encoding.UTF8.GetString(ms.ToArray()));
        ms.Seek(0, SeekOrigin.Begin);

        httpContext.Request.Body = ms;

        await _next(httpContext);
    }
}
```

We save the recording as an UTF-8 string into the `HttpContext` object for later use.

## Startup

We need to set up 2 things in our `Startup` class. The first thing is the ability for a controller to access the HTTP accessor. The second thing is to add the `RecorderMiddleware` to the HTTP pipeline. Make sure to add it to the proper place, before any controller has accessed the request.

```cs
public void ConfigureServices(IServiceCollection services)
{
	// { ... } rest of the services
	services.AddHttpContextAccessor();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
	app.UseMiddleware<RecorderMiddleware>();
	// { ... } rest the middleware
}
```

## Retrieval

When you inject an `IHttpContextAccessor httpContextAccessor` into your controller, you can retrieve the recorded message by the following code:

```cs
string recording = "";

if(httpContextAccessor.HttpContext.Items.TryGetValue("recording", out var r))
{
	recording = (string) r;
}
```

## Final thoughts

Be careful on what to record and what not to record. Some messages might be too big for a string or cause other problems.
