Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC 3 - posting complex JSON model to action

I am trying to post the following JSON data to an Action method on my controller...

{
"Id": "0",
"VendorId": "5",
"FirstName": "g",
"LastName": "g",
"Sex": "m",
"DateOfBirth": "",
"Address": "",
"City": "",
"State": "",
"PostCode": "",
"Country": "",
"Email": "",
"AirportCity": "s",
"AirportState": "s",
"CurrencyCode": "1",
"UsTaxId": "",
"ForeignTaxId": "",
"GstNumber": "",
"TaxExemptCalifornia": false,
"TaxExemptCanada": false,
"DateContracted": "",
"DateTerminated": "",
"TerminationStatus": "",
"FirstSeminarDate": "",
"FirstOnsiteDate": "",
"LastSeminarDate": "",
"DateCertified": "",
"CertificationCall": "",
"CertificationMaterials": "",
"FacultyTrainer": "",
"PassportIssued": "",
"PassportExpired": "",
"TnVisa": false,
"BrochurePermission": false,
"Phones": [{
        "Id": 0,
        "Type": "cell",
        "Number": "222-333-4444",
        "IsPrimary": false
    }, {
        "Id": 0,
        "Type": "home",
        "Number": "333-444-5555",
        "IsPrimary": false
    }
]

}

With the significant part in this case being the "Phones" property toward the end. FYI: I obtained this JSON string that I have posted here by calling JSON.stringify(profileData) in the javascript console. In profileData is an actual object.

Here is the ajax call which is making the post...

$.ajax({
    url: '/Trainer/SaveProfile',
    type: 'POST',
    dataType: 'json',
    success: function (data) {
        //...
    },
    error: function (jqXHR, textStatus, errorThrown) {
        //...
    },
    data: profileData
});

With profileData being the JSON that I have posted above.

Here is the method signature for the Action I am calling with the AJAX post...

[HttpPost]
public ActionResult SaveProfile(TrainerEditModel model)

Here is TrainerEditModel (Sorry it's so big)...

public class TrainerEditModel
{
    public TrainerEditModel()
    {
        Phones = new List<Phone>();
    }

    [Display(Name = "Trainer Id")]
    public Int32 Id { get; set; }

    [Display(Name = "Vendor Id")]
    [Required(ErrorMessage = "Vendor ID is required.")]
    public Int32? VendorId { get; set; }

    [Display(Name = "First Name")]
    [Required(ErrorMessage = "First Name is required.")]
    public String FirstName { get; set; }

    [Display(Name = "Last Name")]
    [Required(ErrorMessage = "Last Name is required.")]
    public String LastName { get; set; }

    public String Address { get; set; }

    public String City { get; set; }

    public String State { get; set; }

    [Display(Name = "Postal Code")]
    public String PostCode { get; set; }

    public String Country { get; set; }

    [DataType(DataType.EmailAddress, ErrorMessage = "Must be a valid email address.")]
    public String Email { get; set; }

    [Display(Name = "Airport City")]
    [Required(ErrorMessage = "Airport City is required.")]
    public String AirportCity { get; set; }

    [Display(Name = "Airport State")]
    [Required(ErrorMessage = "Airport State is required.")]
    public String AirportState { get; set; }

    [Display(Name = "Currency Code")]
    [Required(ErrorMessage = "Currency Code is required.")]
    public String CurrencyCode { get; set; }

    [Display(Name = "US Tax Id")]
    [RegularExpression(@"^\d{3}-\d{2}-\d{4}$|^\d{2}-\d{7}$", ErrorMessage = "US Tax Id must be a valid Social Security Number or Tax ID.")]
    public String UsTaxId { get; set; }

    [Display(Name = "Foreign Tax Id")]
    public String ForeignTaxId { get; set; }

    [Display(Name = "Tax Exempt California")]
    public Boolean TaxExemptCalifornia { get; set; }

    [Display(Name = "Tax Exempt Canada")]
    public Boolean TaxExemptCanada { get; set; }

    [Display(Name = "GST Number")]
    public String GstNumber { get; set; }

    [Display(Name = "Gender")]
    [Required(ErrorMessage = "Gender is required.")]
    public String Sex { get; set; }

    [Display(Name = "Date of Birth")]
    [DataType(DataType.Date, ErrorMessage = "Must be a valid date.")]
    public DateTime? DateOfBirth { get; set; }

    [Display(Name = "Date Contracted")]
    [DataType(DataType.Date, ErrorMessage = "Must be a valid date.")]
    public DateTime? DateContracted { get; set; }

    [Display(Name = "Date Terminated")]
    [DataType(DataType.Date, ErrorMessage = "Must be a valid date.")]
    public DateTime? DateTerminated { get; set; }

    [Display(Name = "Termination Status")]
    public String TerminationStatus { get; set; }

    [Display(Name = "First Seminar Date")]
    [DataType(DataType.Date, ErrorMessage = "Must be a valid date.")]
    public DateTime? FirstSeminarDate { get; set; }

    [Display(Name = "First On Site Date")]
    [DataType(DataType.Date, ErrorMessage = "Must be a valid date.")]
    public DateTime? FirstOnsiteDate { get; set; }

    [Display(Name = "Last Seminar Date")]
    [DataType(DataType.Date, ErrorMessage = "Must be a valid date.")]
    public DateTime? LastSeminarDate { get; set; }

    [Display(Name = "Date Certified")]
    [DataType(DataType.Date, ErrorMessage = "Must be a valid date.")]
    public DateTime? DateCertified { get; set; }

    [Display(Name = "Certification Call")]
    public DateTime? CertificationCall { get; set; }

    [Display(Name = "Certification Materials")]
    public DateTime? CertificationMaterials { get; set; }

    [Display(Name = "Faculty Trainer")]
    public String FacultyTrainer { get; set; }

    [Display(Name = "Passport Issued")]
    public DateTime? PassportIssued { get; set; }

    [Display(Name = "Passport Expired")]
    public DateTime? PassportExpired { get; set; }

    [Display(Name = "TN Visa")]
    public Boolean TnVisa { get; set; }

    [Display(Name = "Brochure Permission")]
    public Boolean BrochurePermission { get; set; }

    public List<Phone> Phones { get; set; }
}

And here is the Phone object which is used in the generic list...

public class Phone : IHaveAnId
{
    public Int32 Id { get; set; }
    public String Type { get; set; }
    public String Number { get; set; }
    public Boolean IsPrimary { get; set; }

    public virtual Trainer Trainer { get; set; }
}

So, here is the issue. The HTTP Post is successfully reaching the Action method and all the properties except for Phones are mapping correctly. The List object is even being populated with the correct number of Phone objects, but they all have default values on all their fields of null or 0 or false. So I'm not sure what I'm doing wrong, but when I try to populate a List in a Model from a JSON array I'm getting a List of the correct number of blank objects.

Any ideas what I'm doing wrong here?

like image 241
jdavis Avatar asked Apr 11 '12 16:04

jdavis


1 Answers

Try setting the proper content type and make sure that you are sending a real JSON request (using the JSON.stringify method):

var profileData = {"Id":"0","VendorId":"5","FirstName":"g","LastName":"g","Sex":"m","DateOfBirth":"","Address":"","City":"","State":"","PostCode":"","Country":"","Email":"","AirportCity":"s","AirportState":"s","CurrencyCode":"1","UsTaxId":"","ForeignTaxId":"","GstNumber":"","TaxExemptCalifornia":false,"TaxExemptCanada":false,"DateContracted":"","DateTerminated":"","TerminationStatus":"","FirstSeminarDate":"","FirstOnsiteDate":"","LastSeminarDate":"","DateCertified":"","CertificationCall":"","CertificationMaterials":"","FacultyTrainer":"","PassportIssued":"","PassportExpired":"","TnVisa":false,"BrochurePermission":false,"Phones":[{"Id":0,"Type":"cell","Number":"222-333-4444","IsPrimary":false},{"Id":0,"Type":"home","Number":"333-444-5555","IsPrimary":false}]}

$.ajax({
    url: '/Trainer/SaveProfile',
    type: 'POST',
    dataType: 'json',
    contentType: 'application/json',
    data: JSON.stringify({ model: profileData }),
    success: function (data) {
        //...
    },
    error: function (jqXHR, textStatus, errorThrown) {
        //...
    }
});

The JSON.stringify is natively built into modern browsers but if you need to support legacy browsers you could include the json2.js script to your page.

like image 112
Darin Dimitrov Avatar answered Oct 19 '22 03:10

Darin Dimitrov