Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebAPI 2 [FromBody] parameter not getting set

I have what should be a VERY basic scenario ... one which I feel I have done 100 time before but for some reason it has decided to NOT work and waste my time on something trivial ...

I am using WebAPI with Attribute routes (love them).

I am trying to pass in two parameters, one from the Body and one from the Uri. They are both basic types ... one a Boolean and the other a Long sponsorID.

Pretty simple service signature ...

[HttpPut]
[Route("adminAPI/sponsors/{sponsorID:long}/Enable")]
public HttpResponseMessage EnableSponsor([FromBody]Boolean enabled, [FromUri] Int64 sponsorID)
{
    HttpResponseMessage ret = null;
    // does stuff and populates the response
    return ret;
}

Using Postman and Advanced REST Client and JQuery/Chrome I have been getting "Bad Request" errors ...

var request = function () {

    $.ajax({
        type: 'PUT',
        url: 'http://localhost:50865/adminAPI/Sponsor/23/Enable',
        data: { "enabled": true },
        contentType: "application/json"
    })
    .done(function (data, textStatus, jqXHR) {

        if ([200, 204, 304].indexOf(data.StatusCode) === -1) {

        } else {

        }
    })
    .fail(function (jqXHR, textStatus, errorThrown) {
    });
};

I am getting the following error ...

The parameters dictionary contains a null entry for parameter 'enabled' of non-nullable type 'System.Boolean' for method 'System.Net.Http.HttpResponseMessage EnableSponsorBanner(Boolean, Int64)' in 'WEB.Admin.api.SponsorAPIController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."

For some reason the [FromBody] parameter is not being passed along with the request, resulting in the error. When I make the parameter nullable the request goes through but, as expected the enabled argument is NULL?

I am beating my head against the wall ... any ideas?

SOLUTION

I tried simply removing the key from the Web Service call and had no success. Instead I created a Data Transfer Object (DTO) with the basic datatypes that I might send to a service individually. I can use this to pass this model to pass simple value references for this and any other requests made in the future.

//
// The Data Transfer Object
    public class APIValueTypes
    {
        public Boolean booleanValue { get; set; }

        public Int64 longValue { get; set; }

        public String stringValue { get; set; }

        public DateTime dateValue { get; set; }
    }

Since the Service knows what value it's looking for it can grab whatever value it requires.

[HttpPut]
[Route("adminAPI/sponsors/{sponsorID:long}/Enable")]
public HttpResponseMessage EnableSponsor([FromBody]APIValueTypes enabled, [FromUri] Int64 sponsorID)
{
    HttpResponseMessage ret = null;
    Boolean isEnabled = enabled.booleanValue;
    // does stuff and populates the response
    return ret;
}

CAVEAT

I have to confess at this time however that while I have it working in my REST tools, I have been unable to get it to work in my JQuery implementation. So while my post has been answered I am having another issue with JQuery ajax$ ... Even though I am sending in the DTO object the service method still receives a null instead of the object ... (another post I suspect ... - sigh)

var request = function () {

    $.ajax({
        type: 'PUT',
        url: 'http://localhost/adminAPI/Sponsor/23/Enable',
        data: { "booleanValue": false },
        contentType: "application/json",

    })
    .done(function (data, textStatus, jqXHR) {

        console.log(data);

        if ([200, 204, 304].indexOf(data.StatusCode) === -1) {

        } else {

        }
    })
    .fail(function (jqXHR, textStatus, errorThrown) {
    });
};

CAVEAT SOLUTION

I discovered that simply sending the JSON object as the data payload was not working. I had to "stringify" the data in order to get it to be serialized back to the APIValueTypes parameter datatype. So the call to the service from JQuery now looks like ... pay attention to the data assignment ...

var request = function () {

    $.ajax({
        type: 'PUT',
        url: 'http://localhost/adminAPI/Sponsor/23/Enable',
        data: JSON.stringify({ "booleanValue": false }),
        contentType: "application/json",

    })
    .done(function (data, textStatus, jqXHR) {

        console.log(data);

        if ([200, 204, 304].indexOf(data.StatusCode) === -1) {

        } else {

        }
    })
    .fail(function (jqXHR, textStatus, errorThrown) {
    });
};

I hope that someone can find this little journey useful and that when I forget it in 6 months this post will still be here to remind me as well!! Thanks again!

like image 594
Gary O. Stenstrom Avatar asked Dec 25 '22 09:12

Gary O. Stenstrom


2 Answers

You have this issue because you are not sending the data in the format at which ASP.Net Web API expect. ASP.net Web API need some special format when dealing value like string and value type (int, bool etc) parameter are marked with FromBody attribute.

Your ASP.Net Web API expect a primtiive type but you are sending an object { enabled: true } then it will not bind it to your enabled parameter which is not an object.

To make it work you must use the below code as data in your jQuery ajax request:

data: { "": true }

Notice that the property name is empty that will tell jQuery to send the data in this format =true. With that format, ASP.Net Web API can bind it to your boolean parameter.

To prevent that issue always use a ViewModel.

like image 101
CodeNotFound Avatar answered Jan 14 '23 07:01

CodeNotFound


I had the same problem and i deleted the key from the request and it has been set in my variable.

just remove the enabled like this:

var request = function () {
$.ajax({
    type: 'PUT',
    url: 'http://localhost:50865/adminAPI/Sponsor/23/Enable',
    data: { "": true },
    contentType: "application/json"
})
.done(function (data, textStatus, jqXHR) {

    if ([200, 204, 304].indexOf(data.StatusCode) === -1) {

    } else {

    }
})
.fail(function (jqXHR, textStatus, errorThrown) {
});

};

Or you can create a model like This:

    public class Model
    {
        public bool Enabled { get; set; }
    }

and then:

[HttpPut]
[Route("adminAPI/sponsors/{sponsorID:long}/Enable")]
public HttpResponseMessage EnableSponsor([FromBody]Model model, [FromUri] Int64 sponsorID)
{
    HttpResponseMessage ret = null;
    // does stuff and populates the response
    return ret;
}

Hope, It works for u.

like image 28
Mashtani Avatar answered Jan 14 '23 06:01

Mashtani