8

I am trying to submit JSON to a MVC action. What I want is to take the JSON object and then access it's data. The number of JSON fields will vary each time so I need a solution that will handle all cases.

This is my POST to my action, address could have 3 fields or 20 it will vary on each post.

Update: I'll go into a little more detail. I'm trying to use the LinkedIn API, I'll be sent a JSON which will look like the JSON at the end of this page : link. I need to create an Action which will accept this JSON which will vary for every person.

var address =
    {
        Address: "123 rd",   
        City: "Far Away",
        State: "Over There"           
    };


    $.ajaxSetup({ cache: false });
    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "/Account/GetDetails/",
        data: JSON.stringify(address),
        dataType: "json",
        success: function () {

            alert("Success from JS");
        }
    });

This is my action in MVC, I need to be apply to take whatever JSON object is passed and access its fields.

 [HttpPost]
    public ActionResult GetDetails(object address)
    {         
        //address object comes in as null            

        @ViewBag.Successs = true;

        return View();

    }
Sam Axe
  • 33,313
  • 9
  • 55
  • 89
Eilimint
  • 307
  • 1
  • 3
  • 11

9 Answers9

5

I don't believe nobody saying this so I will try. Have your code like this

 public class Personal
 {
      public string Address { get; set; }
      public string City { get; set; }
      public string State { get; set; }
      //other properties here
 }

[HttpPost]
public ActionResult GetDetails(Personal address)
{         
    //Should be able to get it.            

    @ViewBag.Successs = true;

    return View();

}

In general, you can add those possible properties into the class Personal (or whatever you can name it). But according to linkedin API, you will need a tool to generate the data class due to its complexity. I think xsd.exe can help if you can get xsd file for that (or you can even generate xsd file from xml)

Tae-Sung Shin
  • 20,215
  • 33
  • 138
  • 240
  • this does not answer the question at all. You are essentially just answer the question "How do I Create a Custom Model to Bind to an Controller?" – Adam Hess Apr 21 '16 at 21:37
4
  1. Remove data: JSON.stringify(address) with data: address

  2. Action method

    [HttpPost]
    public ActionResult GetDetails(string Address, string City, string State, string PropName)
    {         
       //access variable here
    }
    

As you have said your data object may contain 20 props, to avoid creating 20 parameters, you can use formscollection like below

[HttpPost]
public ActionResult GetDetails(FormCollection address)
{        
      string city= address["city"] ;
      string anotherPro=address["prop"];          
}
Amir Ismail
  • 3,865
  • 3
  • 20
  • 33
Praveen Prasad
  • 31,561
  • 18
  • 73
  • 106
  • My code above was just a test I was trying, here is a link to the JSON I'll be receiving [link](https://developer.linkedin.com/application-response-data-structure). Scroll down to see how the JSON looks. It will be send as JSON from LinkedIn so I've no control as to how I receive it. I just need to create an Action to accept it. – Eilimint Aug 12 '11 at 16:46
  • if youre removing 'stringify' then what you're sending is NOT Json - it's just form parameters. – Simon_Weaver Dec 16 '12 at 01:13
2

Not sure if this will work (never done this myself), but you could try the following signature:

public ActionResult LinkedIn(dynamic address)

I'm actually quite interested myself to see what will happen then. Or, as suggested in the comment by Kristof Claes, use a FormCollection.

Second, when things like this happen, always check whether the browser actually sends the data you expected to the server. IE9 and Chrome support this out of the box, otherwise you can use a tool like Fiddler.

EDIT: Just tried for myself with a dynamic parameter and that doesn't work.. The runtime type of the parameter is object so everything you submitted is lost. You'd better use FormCollection.

Ronald Wildenberg
  • 31,634
  • 14
  • 90
  • 133
1

I believe you can use a FormCollection for this.

public ActionResult LinkedIn(FormCollection address)
{
    var street = address["street"];
    ...
    return View();
}
Kristof Claes
  • 10,797
  • 3
  • 30
  • 42
  • I'll go into a little more detail. I'm trying to use the LinkedIn API, I'll be sent a JSON which will look like the JSON at the end of this page : [link](https://developer.linkedin.com/application-response-data-structure). I need to create an Action which will accept this JSON which will vary for every person. – Eilimint Aug 12 '11 at 16:30
1

Might just be a typo, but you are calling GetDetails ActionResult, but yet your code is LinkedIn ?

Tim B James
  • 20,084
  • 4
  • 73
  • 103
1

You need to wrap your JSON object in the name of parameter you are expecting in your action method. Something like this:

var data = { address: { address: '123 Test Way', city: 'Parts Unknown', state: 'TX' } };


$.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "/Account/GetDetails/",
        data: JSON.stringify(data),
        dataType: "json",
        success: function () {

            alert("Success from JS");
        }

Then in your action method, do this:

public ActionResult GetDetails(dynamic address) {}
Malevolence
  • 1,857
  • 12
  • 9
1

My take is all the answers are sort of right.

As your don't know the number of things you're sending, use formcollection on the server. But also remove the stringfy from the ajax call. These means the data will be sent using www-encoding.

If you wnat to send n address objects, change the mvc action parameter to an array of address objects and use stringfy.

Simon Halsey
  • 5,459
  • 1
  • 21
  • 32
  • I'll go into a little more detail. I'm trying to use the LinkedIn API, I'll be sent a JSON which will look like the JSON at the end of this page : [link](https://developer.linkedin.com/application-response-data-structure). I need to create an Action which will accept this JSON which will vary for every person. – Eilimint Aug 12 '11 at 16:27
  • This might help? http://stackoverflow.com/questions/2849872/using-dynamic-as-type-of-mvc-strongly-typed-view – Simon Halsey Aug 12 '11 at 16:33
  • I got the FormCollection to work but only by removing the stringfy and sending the data as a string. However I won't have any control in how the data is sent. I'll just have to accept it as a JSON from LinkedIn – Eilimint Aug 12 '11 at 16:37
  • when you're calling the mvc action, you've already got the response json from LinkedIn. You could send this as a string & process it on the server. – Simon Halsey Aug 12 '11 at 17:18
1

This is how I do it. I have a MyProject.Model.Entities and I serialize them in by using [ParamSerializationFilter] attribute on the given action method.

Full code here: https://gist.github.com/3b18a58922fdd8d5a963

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (!Enum.GetNames(typeof(AllowedMethods)).Any(n => n == filterContext.HttpContext.Request.HttpMethod))
            throw new InvalidOperationException("Invalid Request: HttpMethod");

        foreach (var param in filterContext.ActionDescriptor.GetParameters())
        {
            if (ModelTypes.Contains(param.ParameterType))
            {
                if ((filterContext.HttpContext.Request.ContentType ?? string.Empty) == ("application/json"))
                {
                    filterContext.ActionParameters[param.ParameterName] =
                        JsonSerializer.DeserializeFromStream(param.ParameterType, filterContext.HttpContext.Request.InputStream);
                }
                else if (filterContext.HttpContext.Request.ContentType.Contains("xml"))
                {
                    filterContext.ActionParameters[param.ParameterName] =
                    XmlSerializer.DeserializeFromStream(param.ParameterType, filterContext.HttpContext.Request.InputStream);
                }
            }
        }
    }
Anuj
  • 3,134
  • 13
  • 17
0

You're doing too much work! You can pass the JSON Literal directly to the server and access the elements via the action method parameters, like this:

var address =
    {
        Address: "123 rd",   
        City: "Far Away",
        State: "Over There"           
    };


    $.ajaxSetup({ cache: false });
    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "/Account/GetDetails/",
        data: address,
        dataType: "json",
        success: function () {

            alert("Success from JS");
        }
    });

[HttpPost]
    public ActionResult LinkedIn(string Address, string City, string State)
    {                    
        // now you have everything you want as params
        @ViewBag.Successs = true;

        return View();

    }

Note: This will only work if your action params are named the exact same as your JSON Literal attributes.

slandau
  • 23,528
  • 42
  • 122
  • 184
  • But the requirement was that the number of parameters could vary from 3 to 20. Instead of using a 20-parameter action method, I'd rather use a `FormCollection`. You're correct when saying that it is unnecessary to transform the JSO literal to a string. – Ronald Wildenberg Aug 12 '11 at 14:48
  • If I use Action params it will work but if I have 20 + parameter things get messy, this will probably grow to even more in the future. Also if the JSON literals sent to me where to change then my code will fall apart. – Eilimint Aug 12 '11 at 15:01