Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC Api Controller confusion with JSON.stringify

I know how to post to Umbraco's Api Controller, that's not the issue.

Question:

Let us say that we have (2) Api methods:

    [HttpPost]
    public string Test1(string time, string activityType)
    {
        return time;
    }

    [HttpPost]
    public string Test2(SomeModel model)
    {
        return model.SomeProperty;
    }

On the first method/ajax call, if I stringify the "time" and "activityType", I get this error:

url: '/Umbraco/api/SomeApi/Test1',
type: 'POST',
dataType: 'json',
data: JSON.stringify({time: '10', activityType: 'test'}),

UmbracoApiController - No HTTP resource was found that matches the request URI


Instead, I have to append the (2) parameters as a querystring, and it works. However, in the 2nd Api method, I have a model, and I can use the stringify method for JSON, and it works.

Why? Is this the same with regular MVC as well??


We have (2) ajax calls, and these both work:

// you can see that I have to append via querystring in this instance
$.ajax({
        url: '/Umbraco/api/SomeApi/Test1?time=' + time + '&activityType=' + activityType,
        type: 'POST',
        dataType: 'json',
        data: '',
        // doesn't work ****
        // url: '/Umbraco/api/SomeApi/Test1',
        // data: JSON.stringify({time: '10', activityType: 'test'}),
        // **********************
        processData: false,
        async: false,
        contentType: 'application/json; charset=utf-8',
        complete: function (data) {
            var test= $.parseJSON(data.responseText);
            console.log(test);
        },
        error: function (response) {
            console.log(response.responseText);
        }
    });

var post = {
   SomeProperty : 'test',
   AnotherProperty: 'blahblah'
};

$.ajax({
        url: '/Umbraco/api/SomeApi/Test2',
        type: 'POST',
        dataType: 'json',
        data: JSON.stringify(post),
        processData: false,
        async: false,
        contentType: 'application/json; charset=utf-8',
        complete: function (data) {
            var test= $.parseJSON(data.responseText);
            console.log(test);
        },
        error: function (response) {
            console.log(response.responseText);
        }
    });
like image 815
Rob Scott Avatar asked Jun 22 '26 18:06

Rob Scott


2 Answers

WebAPI's model binder looks in the query string by default when binding "simple" types like strings. This is different from MVC. Use the [FromBody] attribute to tell it that it should look in the request body instead.

public string Test1([FromBody]string time, [FromBody]string activityType)

Edit: It turns out that WebAPI reads the body as a stream instead of caching it like in MVC. That means [FromBody] can only be applied to one parameter. You will need to either pass one in the URI and one in the body or create a complex type that contains both of your parameters.

like image 128
Britton Avatar answered Jun 25 '26 09:06

Britton


This behaviour is by design and well documented

  • If the parameter is a “simple” type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string. (More about type converters later.)
  • For complex types, Web API tries to read the value from the message body, using a media-type formatter.

To force Web API to look in the body for simple types, you can decorate the parameters with the [FromBody] attribute e.g.

public string Test1([FromBody]string time, [FromBody]string activityType)
like image 26
James Avatar answered Jun 25 '26 10:06

James



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!