Reputation: 6255
How can I pass dynamic
data with an AJAX
call to an MVC
Controller
?
Controller
:
public JsonResult ApplyFilters(dynamic filters){
return null;
}
The AJAX
call:
$(':checkbox').click(function (event) {
var serviceIds = $('input[type="checkbox"]:checked').map(function () {
return $(this).val();
}).toArray();
//alert(serviceIds);
$.ajax({
type: 'GET',
url: '/home/ApplyFilters',
data: JSON.stringify({
name: serviceIds
}),
contentType: 'application/json',
success: function (data) {
alert("succeeded");
},
error: function (err, data) {
alert("Error " + err.responseText);
}
});
//return false;
});
Ideally would be that the filters
would contain the serviceIds
as a property
For example like this: filters.ServiceIds
.
I got another filter for a date range and that one would be added like so: filters.DateRange
.
And server side get the filter as a dynamic
object in the ApplyFilters()
Upvotes: 5
Views: 6681
Reputation: 1907
Ad far as i know the default ASP MVC model binder cannot accomplish such a thing.
Fortunately there are numerous solutions, here are two of them :
1. Here is the first one, it converts your JSON data into a IDictionary<string, object>
instance before passing it to your controller action. You would end up with :
public JsonResult ApplyFilters(IDictionary<string, object> filters)
{
return null;
}
2. The second approach enables your controller action to receive a JsonValue instance. Making your action looks like this one :
public JsonResult ApplyFilters([DynamicJson]JsonValue filters)
{
return null;
}
3. Based on the previous tutorials, you could create your own custom model binder returning a dynamic object. The following code has been taken from the first proposal and modified to generate a dynamic object. It is just to illustrate the idea, don't use it as is :
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
return null;
}
controllerContext.HttpContext.Request.InputStream.Position = 0;
using (var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream))
{
var json = reader.ReadToEnd();
if (string.IsNullOrEmpty(json))
{
return null;
}
dynamic result = new ExpandoObject();
var deserializedObject = new JavaScriptSerializer().DeserializeObject(json) as IDictionary<string, object>;
if (deserializedObject != null)
{
foreach (var item in deserializedObject)
{
((IDictionary<string, object>)result).Add(item.Key, item.Value);
}
}
return result;
}
}
These solutions rely on building a custom model binder to handle this particuliar scenario :
ModelBinders.Binders.Add
or using a dedicated attribute (CustomModelBinderAttribute).Upvotes: 7