Click here to Skip to main content
15,884,176 members
Articles / Web Development / ASP.NET

Redirect and Post JSON Object in ASP.NET MVC

Rate me:
Please Sign up or sign in to vote.
4.96/5 (13 votes)
14 May 2014CPOL5 min read 71.9K   587   16   4
The article is about how to post json data to ASP.NET MVC action and be redirected to that page.

Introduction

I want to be short as much as I can by stating the problem, possible solutions and cleanest solution that I am sharing with you here, so I will be descriptive and straight forward to the point as much as I can.

Problem

Simply what I wanted is to submit a JSON object from one page to another as a POST and be redirected to that page, and I wanted that to happen by having the JSON object as a parameter for my controller post action. Please note that we are doing this from one page to another (from one controller action to another controller action).

Below is my destination page or controller action:

C#
[HttpPost] 
public ActionResult SubmitOrder(OrderViewModel vmOrder)
{ 
    //Process the vmOrder if wanted
    return View(vmOrder); 
}  

Now imagine that my source page or controller action has the following JavaScript snippet of which we want to submit the vmOrder to the destination.

C#
function CollectOrderDetails(){
var order = new Object();
//Fill order data
//Submit the order object to destination page after serializing it 
(e.g. ../MyApplication/SubmitOrder)  
//====>JSON.stringify(order) 
}  

Possible Solutions

Now to do a submit here (POST), I have two options:

  1. Use Ajax: Simply I can just use jquery.post or jquery.ajax (with the verb POST of course) and content-type "application/json", and here the serialized order object will be sent to the destination controller action and ASP.NET MVC will automatically de-serialize the json object into OrderViewModel.

    The problem here is that it's AJAX !! which means the response will be back in the xhr object of the Ajax call, and therefore no redirect has occurred.

    So we managed to send the object, serialize it with no effort but we couldn't get a response that represents the new page with a redirect.

  2. Use ajax and inject the response into the document: It's the same as the previous one, except that when the response gets back from the xhr object (which in this case will be a full HTML response that represents the destination page), we inject it in the document.

    Of course this option is bad, why? Because first of all, it will return the HTML and JavaScript yes but it will not be parsed, and actually we are still on the source page (URL will remain on the source) and we displayed the destination page only.

    This option is best fit when you want to deal with partial views, or when you deal with pages that return static content with no script tags included to be parsed.

  3. Use a dynamic form submission: This method is known for us, and it's the best of all, you create a form element in JavaScript, and create a hidden HTML input element, serialize the order object and store it in the hidden field, append the hidden input element to the form and submit it.
JavaScript
var form = document.createElement("form");
<pre>var input = document.createElement("input");
input.setAttribute("type", "hidden") ;
input.setAttribute("name", "XOrder") ;  
input.setAttribute("value", JSON.stringify(order)); 
form.appendChild(input);
document.body.appendChild(form);
form.submit();

Now here what we did is that we serialized the object into JSON and sent it to the destination action controller BUT the action controller parameter (OrderViewModel vmOrder) will be NULL, why? Simply because MVC received the HTTP request as an html/text request not as JSON, remember that when we used Ajax we specified that the content type is application/json and that helped us to send the data (payload) to the destination and MVC was able to recognize the payload from the content-type as JSON and therefore de-serialize it to OrderViewModel. The case here is different, this is a normal form submission and you can read data in ASP.NET (server side) by iterating over this.Request.Form, which will hold all inputs (hidden or non-hidden of course). Remember too that using form submission, you can't specify JSON as the content type as it's not supported by the browsers.

Best Solution

Ok .. Now what I wanted is: NOT AJAX, normal form submission (POST of course) and I wanted the parameter of the controller action to automatically deserialize to my view model parameter (OrderViewModel).

To do this, I knew I had to understand more of Model Binders in ASP.NET MVC, model binders simply translate HTTP requests coming to MVC controllers into objects and terms the controller can understand and deal with easily, and in many times it uses conventions to accomplish that.

So what I wanted is a custom binder that will receive my serialized JSON object from the hidden field and automatically convert it to my parameter in the controller action without worrying about that nasty workload.

Below is the code:

C#
public class JsonModelBinder : DefaultModelBinder
{
    public  override BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    try
    {
        var strJson = controllerContext.HttpContext.Request.Form[bindingContext.ModelName];
        if(string.IsNullOrEmpty(strJson))
        {
            return null;
        }
        else
        {
            JavaScriptSerializer serializer = new JavasScriptSerializer();
            var model = serializer.Deserialize(strJson, bindingContex.ModelType);
            var modelMetaData = ModelMetadataProviders.Current
                        .GetMetadataForType(()=>model, bindingContext.ModelType);
            var validator= ModelValidator
                        .GetModelValidator(modelMetaData, controllerContext);
            var validationResult = validator.Validate(null);
            foreach(var item in validationResult)
            {
                bindingContext.ModelState
                            .AddModelError(itrem.MemberName, item.Message);
            }
            return model;
         }
    }
    catch(Exception ex)
    {
            bindingContext.ModelState.AddModelError(bindingContext.ModelType.Name, ex.Message);
    }
}

Now the above is a model binder that inherits the default model binder of MVC, without going into details we need to use that in the correct place in order to get the JSON object as a parameter for the controller action.

MVC already has a support for that in several ways and I think the cleanest one without changing the default behaviour you have in your application is through .NET Attributes. MVC already has a class CustomModelBinderAttribute which we can inherit from and use our custom model binders.

C#
public class JsonBinderAttribute : CustomModelBinderAttribute
{
    public overried IModelBinder GetBinder()
    {
        return new JsonModelBinder(); 
    }  
}  

And now what you will be doing is two things:

First: Add JsonBinder attribute to the parameter on the destination controller action:

C#
[HttpPost] 
public ActionResult SubmitOrder([JsonBinder]OrderViewModel vmOrder)
{     
    //Process the vmOrder if wanted    
    return View(vmOrder); 
}   

Second: When you send the data from JavaScript, set the name of the hidden field as the name of the parameter:

C#
var form = document.createElement("form");
var input = document.createElement("input");
input.setAttribute("type", "hidden") ;
input.setAttribute("name", "vmOrder") ;
input.setAttribute("value", JSON.stringify(order));
form.appendChild(input);
document.body.appendChild(form);
form.submit(); 

Points of Interest

Why to set the name of the hidden field as the name of the parameter? Because we want to have some kind of convention based mapping in between the sender and the receiver, name of the parameter is the most obvious clear choice.

Summary

Hopefully that was helpful, I believe this is the second time I want something almost similar in concept of posting data and redirecting in the same time, and the first time I posted an article about 4 years ago .. here is the link to it: http://www.codeproject.com/Articles/37539/Redirect-and-POST-in-ASP-NET.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Jordan Jordan
Samer is a Computer and Digital Electronics Engineer who lives in Abu Dhabi UAE, worked on a fair number of personal projects as part of fun or freelancing, mostly related to integration between hardware and software (e.g Security Systems, Sensors, Cameras, Bluetooth ... etc), which gave him a powerful knowledge in this area and the ability to invent various complex designs to adhere for external elements effect those systems.

Through his career path he worked on a fair number of enterprise projects with well known software companies, which showed him the various aspects of an enterprise applications.

You may contact Samer through his e-mail: SamerX@outlook.com or Twitter: SamerX as well.

Comments and Discussions

 
QuestionDid anyone get this to work? Pin
Member 131669679-Aug-19 5:14
Member 131669679-Aug-19 5:14 
SuggestionThe model binder is required just because you pass a set of values as a single value. Pin
Theo Bebekis20-Apr-16 4:47
Theo Bebekis20-Apr-16 4:47 
QuestionRedirect from within Controller method Pin
Rev Kev15-May-14 10:06
Rev Kev15-May-14 10:06 
AnswerRe: Redirect from within Controller method Pin
Samer Aburabie15-May-14 10:41
Samer Aburabie15-May-14 10:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.