Read POST Request body in Web API is adding an extra slash to '\t'

51 views Asked by At

We have a requirement in which for a certain rest call, we need to intercept the request before getting it to the controller and add something to the request body. I am able to do that using an authorization filter. The problem is, when I read the request using stream reader, it somehow adds an extra slash to '\t' (tab). That makes it '\t'. When the request gets to controller, due to this extra slash, it is treated as text instead of 'tab'.

Request Body

{
"myData": "This is some text \t more text"
}

Controller

[MyRequestConverter]
[HttpPost]
public virtual IActionResult myServiceAction([FromBody]myRequestModel myRequest)
{  
   // suppose print is something that writes the data to a file
   print(myRequest.myData);
}

Authorization Filter

public class MyRequestConverter : Attribute, IAsyncAuthorizationFilter
 {

     public MyRequestConverter() { }

     private async Task<string> GetRequestBodyAsTextAsync(HttpRequest request)
     {    
        
             var reqbody = "";
             request.EnableBuffering();
             request.Body.Seek(0, SeekOrigin.Begin);

             using (var reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true))
             {
                 reqbody = await @reader.ReadToEndAsync();
             }
             request.Body.Position = 0;

             return reqbody;

     }


     public async Task OnAuthorizationAsync(AuthorizationFilterContext filterContext)
     {
                var stream = request.Body;// currently holds the original stream                    

                var originalContent = await GetRequestBodyAsTextAsync(request);

                originalContent = AddSomethingToRequestBody(originalContent);

               var requestContent = new StringContent(originalContent, Encoding.UTF8, "application/json");
               stream = await requestContent.ReadAsStreamAsync();

                var requestData = Encoding.UTF8.GetBytes(originalContent);
                stream = new MemoryStream(requestData);

                filterContext.HttpContext.Request.Body = stream;

       }



 }

With 'MyRequestConverter', it prints (it treats \t as text due to that extra slash)

This is some text \t more text

Without 'MyRequestConverter', it prints (desired output - it has tab spacing)

This is some text (tab) more text

I did some search and looks like one option is to replace '\\t' with '\t' but is there any other solution to this problem ?

1

There are 1 answers

0
Ivan On

Use JsonDocument.Parse(originalContent) so it will be pause to the json again. and in the end it will be output like the desired output i.e. This is some text (tab) more text

Here is the test code

public async Task OnAuthorizationAsync(AuthorizationFilterContext filterContext)
{
    var request = filterContext.HttpContext.Request; // Correctly access the request
 
    // Retrieve the original content of the request body
    var originalContent = await GetRequestBodyAsTextAsync(request);
 
    // Parse the original content as JSON
    using (var jsonDoc = JsonDocument.Parse(originalContent))
    {
        // Clone the root element to modify
        JsonElement root = jsonDoc.RootElement.Clone();
 
        string newMyDataValue = ""; 
 
        // Check if "MyData" property exists and append the additional content
        if (root.TryGetProperty("myData", out JsonElement myData))
        {
            // Append additional content to the existing value
            newMyDataValue = myData.GetString() + " your additional content here";
        }
        else
        {
            // If "MyData" was not found, just use the additional content
            newMyDataValue = "your additional content here";
        }
 
        // Create a new JSON object with the modified "MyData"
        using (var stream = new MemoryStream())
        {
            using (var writer = new Utf8JsonWriter(stream))
            {
                writer.WriteStartObject();
                foreach (var property in root.EnumerateObject())
                {
                    // Write all the existing properties
                    property.WriteTo(writer);
                }
                // Overwrite the "MyData" property with the new value
                writer.WriteString("myData", newMyDataValue);
                writer.WriteEndObject();
            }
 
            // Convert the modified content back into a stream and replace the original request body
            var modifiedRequestBody = stream.ToArray();
            request.Body = new MemoryStream(modifiedRequestBody); // Set the modified stream as the request body
            request.ContentLength = modifiedRequestBody.Length; // Update the Content-Length header
        }
    }
}