0

I am using .Net Core API 2.1 I have this in my Controller:

[Route("Invoke")]
        [HttpPost]
        public IActionResult Invoke(Student studentDetails)
        {
            DetailsResponse objResponse;
            if(ModelState.IsValid)
                {
                  objResponse= GetDetails(studentDetails);
                }
              return OK(objResponse);  
        }

I am trying to invoke the Invoke action method from Postman with the request body as

{"student": {"name":"John Doe", "age":18, "country":"United States of America"}}

This object is always null in the controller. If i try to invoke the action method from Postman with the request body as

{"name":"John Doe", "age":18, "country":"United States of America"}

Here the object has the data and is working fine. My question is to invoke the action with the root node like shown below

{"student": {"name":"John Doe", "age":18, "country":"United States of America"}}

Is there any possibility to achieve this?

Rabia Basri
  • 21
  • 1
  • 5

3 Answers3

0

depending on your framework you can use

public IActionResult Invoke([FromBody]Student studentDetails)

What will happen is that model binding will try and map the json to the class you have specified.

Walter Verhoeven
  • 3,867
  • 27
  • 36
0

The thing is that Your second attempt fully mimics your Student class, that is why it is mapped to the Student.

{"name":"John Doe", "age":18, "country":"United States of America"}

If You want to receive an object with field "student" populated with Student json, You can create another class StudentWrapper or InvokeParameters or something like that with Student field.

But You better not to do it if You don't really need it. Usually it is not necessarily and should be omitted. It is only useful if You receive to have several models like Student in Your API action.

satma0745
  • 667
  • 1
  • 7
  • 26
0

{"name":"John Doe", "age":18, "country":"United States of America"}

This is the acceptable json for model Student in your default JsonInputFormatter.What you want to pass is an unacceptable json for Student,you need to custom JsonInputFormatter to meet your requirement:

public class CustomJsonInputFormatter : JsonInputFormatter
{
    public CustomJsonInputFormatter(ILogger logger, JsonSerializerSettings serializerSettings, ArrayPool<char> charPool, ObjectPoolProvider objectPoolProvider, MvcOptions options, MvcJsonOptions jsonOptions) : base(logger, serializerSettings, charPool, objectPoolProvider, options, jsonOptions)
    {

    }
    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
    {
        var request = context.HttpContext.Request;
        using (var reader = new StreamReader(request.Body))
        {
            string content = await reader.ReadToEndAsync();
            JObject jo = JObject.Parse(content);
            Student student = jo.SelectToken("student", false).ToObject<Student>();
            return await InputFormatterResult.SuccessAsync(student);
        }
    }
}

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        var serviceProvider = services.BuildServiceProvider();
        var jsonInputLogger = serviceProvider.GetRequiredService<ILoggerFactory>().CreateLogger<CustomJsonInputFormatter>();
        var jsonOptions = serviceProvider.GetRequiredService<IOptions<MvcJsonOptions>>().Value;
        var charPool = serviceProvider.GetRequiredService<ArrayPool<char>>();
        var objectPoolProvider = serviceProvider.GetRequiredService<ObjectPoolProvider>();

        var customJsonInputFormatter = new CustomJsonInputFormatter(
                    jsonInputLogger,
                    jsonOptions.SerializerSettings,
                    charPool,
                    objectPoolProvider,
                    options,
                    jsonOptions
            );
        options.InputFormatters.Insert(0, customJsonInputFormatter);
    }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    //services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

Result: enter image description here

Another way:

{"student": {"name":"John Doe", "age":18, "country":"United States of America"}}

This json is acceptable for the following model:

public class Student
{
    public int Age { get; set; }
    public string Name { get; set; }
    public string Country { get; set; }
}

public class Test
{
    public Student student { get; set; }
}

Action:

[HttpPost]
public IActionResult Invoke(Test studentDetails)
{
   //...
}
Rena
  • 30,832
  • 6
  • 37
  • 72