skip to Main Content

Is it possible to implement follow:
I have a controller, that contains several methods and using as API. For GET requests I can just send params in url query and use it in a method body, but for POST method I just get json object in a FromBody param and need to parse it at start of every method. Is it possible to handle it somehow?

    public class AppServiceController : Controller
    {
    [HttpPost]
    public ApiMethodResponse TestPost(string p1, int p2, double p3)
    {
// Use p1, p2, p3 parsed from post body json here
    }
    }

POST body Json sample:

{
    "p1": "test value",
    "p2": "2",
    "p3": "2.3"
}

UPD
Thanks for the answers, it is interesting info for me, but I have many methdos in my controller and they have different signatures, so I need to create model for every method. In DrJay method it looks even complex becuase I additionaly need to determine model by json structure.
So I return to my question: is it possible to parse JSON and get it’s values in method params (like in GET)?

3

Answers


  1. Chosen as BEST ANSWER

    Thanks, guys, for your answers, they get me a clue. So, I achive what I need.

    [HttpPost]
    public ApiMethodResponse TestPost(
        [ModelBinder(typeof(JsonModelBinder))] string p1,
        [ModelBinder(typeof(JsonModelBinder))] int p2,
        [ModelBinder(typeof(JsonModelBinder))] double p3)
    {
        //TODO Use params here
    }
        
    public class JsonModelBinder : IModelBinder
    {
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var bodyResult = await bindingContext.HttpContext.Request.BodyReader.ReadAsync();
            using (var ms = new MemoryStream(bodyResult.Buffer.ToArray()))
            {
                using (var sr = new StreamReader(ms))
                {
                    var body = sr.ReadToEnd();
                    var jsonObj = JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(body);
                    var value = jsonObj.GetValue(bindingContext.FieldName);
                    var result = value == null
                        ? GetDefault(bindingContext.ModelType)
                        : bindingContext.ModelType.IsValueType
                            ? Convert.ChangeType(value, bindingContext.ModelType)
                            : value.ToObject(bindingContext.ModelType);
                    bindingContext.Result = ModelBindingResult.Success(result);
                }
            }
        }
    
        private static object GetDefault(Type type) => type.IsValueType ? Activator.CreateInstance(type) : null;
    }
    

    Test JSON:

    {
        "p": "test value",
        "p2": 23,
        "p3": 23.4
    }
    

  2. Yes, you can do this by creating a custom model binder in ASP.NET Core.
    This custom model binder will automatically parse the JSON body and bind the parameters to the action method:
    Create a custom model binder:

    Csharp

        using System;
    using System.IO;
    using System.Text.Json;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc.ModelBinding;
    
    public class JsonModelBinder : IModelBinder
    {
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }
    
            try
            {
                using (StreamReader reader = new StreamReader(bindingContext.HttpContext.Request.Body))
                {
                    string bodyText = await reader.ReadToEndAsync();
    
                    if (!string.IsNullOrEmpty(bodyText))
                    {
                        var options = new JsonSerializerOptions
                        {
                            PropertyNameCaseInsensitive = true // To make property names case-insensitive
                        };
    
                        object model = JsonSerializer.Deserialize(bodyText, bindingContext.ModelType, options);
                        bindingContext.Result = ModelBindingResult.Success(model);
                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex.Message);
            }
    
            bindingContext.Result = ModelBindingResult.Failed();
        }
    }
    

    Register the custom model binder in your startup.cs file:

    Csharp

        using Microsoft.Extensions.DependencyInjection;
    
    public void ConfigureServices(IServiceCollection services)
    {
        // ...
        services.AddControllers(options =>
        {
            options.ModelBinderProviders.Insert(0, new BinderTypeModelBinderProvider(typeof(JsonModelBinder)));
        });
        // ...
    }
    

    Use the custom model binder in your action method:

    Csharp

    public class AppServiceController : Controller
    {
        [HttpPost]
        public ApiMethodResponse TestPost([ModelBinder(typeof(JsonModelBinder))] YourModelClass model)
        {
            // Use model.p1, model.p2, model.p3 parsed from the JSON body here
        }
    }
    

    Obviously replace YourModelClass with the class that represents the structure of your JSON input data.

    Login or Signup to reply.
  3. Try something like the below.

    ‘PostData’ represents the structure of the JSON object. Adding the [FromBody] attribute tells it to automatically bind the JSON data, in the request body, to the PostData object. You can then access the properties of the PostData object (postData.p1, postData.p2, postData.p3) within your method.

    using Microsoft.AspNetCore.Mvc;
    
    public class AppServiceController : Controller
    {
        [HttpPost]
        public ApiMethodResponse TestPost([FromBody] PostData postData)
        {
            // Use postData.p1, postData.p2, postData.p3 here
        }
    }
    
    public class PostData
    {
        public string p1 { get; set; }
        public int p2 { get; set; }
        public double p3 { get; set; }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search