How to do a form POST to an MVC 3 application and obtain the deserialized class?

时光怂恿深爱的人放手 提交于 2019-12-04 12:26:17

If you are posting it via AJAX with the content type set to JSON, then MVC 3 will be able to bind it properly in your controller action.

$.ajax({
    url: location.href, 
    type: "POST",
    data: ko.toJSON(viewModel),
    datatype: "json",
    contentType: "application/json charset=utf-8",
    success: function (data) { alert("success"); }, 
    error: function (data) { alert("error"); }
});

However, if like in your example, you want to do a normal form post that includes JSON, then you need to do some more work as MVC3 won't automatically bind it to your model, as the content type will be application/x-www-form-urlencoded.

Steve Sanderson has an older sample that demonstrates getting submitted JSON data to be bound properly in your controller action here: http://blog.stevensanderson.com/2010/07/12/editing-a-variable-length-list-knockout-style/

The gist of it is that he creates an attribute called "FromJson" that looks like:

public class FromJsonAttribute : CustomModelBinderAttribute
{
    private readonly static JavaScriptSerializer serializer = new JavaScriptSerializer();

    public override IModelBinder GetBinder()
    {
        return new JsonModelBinder();
    }

    private class JsonModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName];
            if (string.IsNullOrEmpty(stringified))
                return null;
            return serializer.Deserialize(stringified, bindingContext.ModelType);
        }
    }
}

Then, the action looks like:

    [HttpPost]
    public ActionResult Index([FromJson] IEnumerable<GiftModel> gifts)

Also, if you don't like having to use the attribute, then you can actually register a type to always use a certain model binder.

You could create a model binder that looks like:

public class JsonModelBinder: IModelBinder
{
    private readonly static JavaScriptSerializer serializer = new JavaScriptSerializer();

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName];
        if (string.IsNullOrEmpty(stringified))
            return null;
        return serializer.Deserialize(stringified, bindingContext.ModelType);
    }
}

Then, register it in global.asax.cs like:

ModelBinders.Binders.Add(typeof(DocumentModel), new JsonModelBinder());

Now, you would not need to use an attribute and your DocumentModel would be bound properly. This would mean that you would always be sending the DocumentModel via JSON though.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!