I am trying to get the request body in an ActionFilterAttribute.
The JSON value is always "". I am using .NET7.0 and I also added below code to Program.cs
.Use(async (context, next) =>
{
try
{
context.Request.EnableBuffering();
await next();
}
catch (Exception e)
{
}
.
.
.
The attribute code snippet:
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var expectedModel = context.ActionArguments.Values.FirstOrDefault();
if (expectedModel == null)
{
context.Result = new BadRequestObjectResult("Model empty.");
return;
}
var requestBodyStream = new MemoryStream();
await context.HttpContext.Request.Body.CopyToAsync(requestBodyStream);
requestBodyStream.Seek(0, SeekOrigin.Begin);
var json = await new StreamReader(requestBodyStream).ReadToEndAsync();
}
My controller method:
[HttpPost("scoring/add")]
[JsonModelValidationAttribute]
public async Task<IActionResult> AddScoringResult([FromBody] ScoreModel model)
{
//I am going to add logic.
}
I want to get the request body and compare the ScoreModel to check for any misspelled property. How to get the body from the request?
Classes and example:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
public class JsonModelValidationAttribute : ActionFilterAttribute
{
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var expectedModel = context.ActionArguments.Values.FirstOrDefault();
if (expectedModel == null)
{
context.Result = new BadRequestObjectResult("Model empty.");
return;
}
var requestBodyStream = new MemoryStream();
await context.HttpContext.Request.Body.CopyToAsync(requestBodyStream);
requestBodyStream.Seek(0, SeekOrigin.Begin);
var json = await new StreamReader(requestBodyStream).ReadToEndAsync();
Console.WriteLine(json);
}
}
ScoreModel
using System;
using System.Collections.Generic;
using System.Security.Principal;
namespace Scoring.Data.Custom;
public class ScoreModel
{
public int Id { get; set; }
public int Score { get; set; }
public string Name { get; set; }
}
Controller
using Scoring.Data.Custom;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace Scoring.API.Custom;
[ApiController]
public class ScoringController : ControllerBase
{
public ScoringController()
{
}
[HttpPost("scoring/add")]
[JsonModelValidationAttribute]
public async Task<IActionResult> AddScoringResult([FromBody] ScoreModel model)
{
return Ok(model);
}
}
After enabling buffering (do not forget that it should be placed early in the pipeline) you need to not forget to rewind the incoming stream (depending where along the pipeline you are you might need to rewind it before and/or after reading it). In this particular case the following will fix the issue:
Also I would recommend to dispose the created stream and do not forget to call
await next():