简体   繁体   中英

ASP.NET MVC Model binding doesn't work with AJAX GET but works with Post

I'm having a problem using the Jquery AJAX as a GET Request. For some reason the ASP.NET MVC model binder doesn't seem to be able to bind to my filter item. What happens is the action result is called but an empty object is created.

However if I change from HTTP Get to HTTP Post then it works. Why would that be? From what I understand it would be better to use GET as no data is changing on the server.

Here's a stripped down version of my code:

AJAX:

$.ajax({
    url: url,
    contentType: 'application/json',
    dataType: 'json',            
    type: "GET",
    data: "{'filter':" + ko.toJSON(model.filter) + "}",
    error: function (xhr, textStatus, errorThrown) {

    },
    success: function (returnedData) {

    }

ActionResult:

[HttpGet]
public virtual ActionResult Index(IFilter filter)
{
    ViewModel filteredViewModel = GetFilteredViewModel(filter);

    if (Request.IsAjaxRequest())
    {
        return toJSON(filteredViewModel );
    }

    return View(filteredViewModel );
}

Filter:

public class Filter: IFilter 
{    
   public Nullable<DateTime> LogDate { get; set; }        
   public Nullable<int> SpecificItem_ID { get; set; }
}

First, just to clear up misconceptions, POST doesn't mean change , necessarily. It's perfectly valid to request via POST when accessing a "function", for lack of a better word. For example:

# Request
POST /add-xy
{ "x": 2, "y": 2 }

# Response
200 OK
4

Nothing has "changed", but POST is still the most appropriate HTTP verb.

That said, there's a fundamental difference between GET and POST requests, namely the concept of a POST "body". A POST body can have a content type and therefore can be interpreted properly on the server-side as JSON, XML, etc. With GET, all you have is a querystring, which is just simply a string.

The problem you're having is that with GET, the filter "object" is just a string, and since a string does not implement IFilter the modelbinder can't bind it. However, via POST, the filter "object" is sent in the POST body with a proper content type. So, the modelbinder receives it as JSON, and maps the JSON object onto an implementation of IFilter .

The moral is that GET is only viable for simple requests -- with data that's pretty much only name-value pairs of simple types. If you need to transmit actual objects, you need to use POST.

I don't know why it was accepted, but the currently accepted answer is totally wrong.

ModelBinders don't bind the sent parameters if your object name is precisely filter . So change the name of the object and it will bind properly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM