Search code examples
c#jsonasp.net-core-webapicustom-model-binder

How to read the raw json post body before hitting the controller in dot net c#?


I need to implement a [HttpPost] web api with same route/uri, but more than 10 different combinations of parameters in json body. In which some parameters are null in some case but required in another case. As I am migrating an already deployed project to dot net 6, I don't have the freedom to modify api routes.

I have planned to execute this requirement by reading entire json raw body data in a model binder, deserialize it and setting it to different model classes before hitting the controller. I assume that this method also helps me with model state validations, so that I need not perform any manual validations in controller or service.

Already existing code in java (Maven Web App Controller):

@PostMapping(produces = HttpUtilities.APPLICATION_JSON_UTF8_VALUE, consumes = HttpUtilities.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<HashMap<String, Object>> postForApproving(@RequestBody HashMap<String, Object> record,
        HttpServletRequest request) {

    RequestStore requestStore = (RequestStore) request.getAttribute("requestStore");

    logger.info("postForApproving({})", requestStore.toString());

    AuthorizationService.checkApiRole(requestStore, "postForApproving_" + entity_name, "Staff-Management");

    HashMap<String, Object> respBody = getService().postForApproving(requestStore, record);

    return new ResponseEntity<HashMap<String, Object>>(respBody, HttpUtilities.getResponseHeaders(requestStore),
            HttpStatus.CREATED);
}

And in the service the 'action' parameter in the request record is checked in else-if conditions and corresponding repository method is called for each situation.


Solution

  • Custom Model Binder:

    public class GetModelBindingContext : IModelBinder
    {
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            string json;
            using (var reader = new StreamReader(bindingContext.ActionContext.HttpContext.Request.Body, Encoding.UTF8))
                json = await reader.ReadToEndAsync();
    
            bindingContext.Result = ModelBindingResult.Success(json);
        }
    }
    

    Api Controller:

    [ApiController]
    public class ApproverDataController : ControllerBase
    {
        private readonly IApproverDataService _myService;
        private readonly IModelBinder _modelBinder;
    
        public MyController(IMyService myService)
        {
            _myService = myService;
        }
    
        [Route("rest/prd/v1/post_data/body")]
        [HttpPost]
        public async Task<IActionResult> PostForAction([FromBody][ModelBinder(BinderType = typeof(GetModelBindingContext))] string json)
        {
            dynamic requestBody = JsonConvert.DeserializeObject(json);
            return Ok("Success!");
        }
    }