.Net-Core 控制器操作不会绑定模型中的子复杂类型

.Net-Core Controller action won't bind child complex type in model

这是我尝试绑定模型的操作:

    [HttpPost]
    public JsonResult SaveNewBusiness(NewBusinessVm newBusiness)
    {

    }

这是型号:

    public class NewBusinessVm 
    {
       public NewBusinessVm()
       {

       }

    public int ID { get; set; }
    public string Name { get; set; }
    public ImageViewModel MainImage { get; set; }
    public string Description { get; set; }
    public List<SelectListItem> CategorySelections { get; set; }
    public int CategoryID { get; set; }
    public List<SelectListItem> LocationSelections { get; set; }
    public string LocationStr { get; set; }
    public List<int> FacilitiesIDs { get; set; }
    public string GoogleAddress { get; set; }
    public string FriendlyAddress { get; set; }
    public string GooglePlaceID { get; set; }
    public string Lat { get; set; }
    public string Long { get; set; }
    public int MinPrice { get; set; }
    public int MaxPrice { get; set; }
}

无法绑定的有问题的 属性 是 MainImage:

  public class ImageViewModel
    {
        public bool IsParent { get; set; }
        public string FileName { get; set; }
        public List<ImageViewModel> ChildImages { get; set; }
        public int? ImageFamilyId { get; set; }
        public string ImageUrl { get; set; }
        public string Title { get; set; }
        public string Alt { get; set; }
        public string Width { get; set; }
        public string Height { get; set; }
        public string Sizes { get; set; }
        public bool IsThumbNail { get; set; }
        public int Bytes { get; set; }
        public DateTime CreateTime { get; set; }
    }

我将 MainImage 添加到数据中。 在客户端,我尝试了所有这 3 种方法:

        //#1
        var data = $form.serializeArray();
        data[data.length] = { name: "MainImage", value: mainImageObj };
        console.log(data);
        AjaxModule.Ajax(url, data, options);

        //#2
        var dataJson = JSON.stringify(data);
        console.log(dataJson);
        AjaxModule.Ajax(url, dataJson, options);

        //#3
        var data2 = $form.serialize();
        data2 += "&MainImage=" + JSON.stringify(mainImageObj);
        console.log(data2);
        AjaxModule.Ajax(url, data2, options);

第一个选项对象如下所示:

第二个选项:

[{"name":"Name","value":"BusinessName example"},{"name":"CategoryID","value":"80"},{"name":"Description","value":""},{"name":"GooglePlaceID","value":"ChIJy9AOJGrKM5QR23I19T-HKD0"},{"name":"Long","value":""},{"name":"Lat","value":""},{"name":"GoogleAddress","value":"La Posta, Cordoba, Argentina"},{"name":"FriendlyAddress","value":"Río Primero,La Posta"},{"name":"__RequestVerificationToken","value":"CfDJ8E3zPSvylsxAsVq_mjBa9qQxnItdTOHxZje0mUebkKW5pH2K2ZUkB_Flg3XJsUQh_8hxmqGvUJo_hLuQIz6xOiFR1Y5HCDeGmGGKFSM2h1cHGfGkr7SBkIkZr4ImqCDRiaaRmy0x1taJyFmcqRpXMVSBnBN5pcjWkqqNhuGYL09KKD2xFJwk1Tbhcyb7d2YEPw"},{"name":"MainImage","value":{"IsParent":true,"ImageUrl":"https://res.cloudinary.com/dzpwse6vo/image/upload/v1587727444/Businesses/44637/noyc0lpgto9t2p1j15kx.jpg","FileName":"Businesses/44637/noyc0lpgto9t2p1j15kx","Width":720,"Height":960,"CreateTime":"2020-04-24T11:24:04Z","Bytes":50450,"ChildImages":[{"IsParent":false,"ImageUrl":"https://res.cloudinary.com/dzpwse6vo/image/upload/c_crop,g_auto,h_350,q_auto,w_1600/v1587727444/Businesses/44637/noyc0lpgto9t2p1j15kx.jpg","FileName":"Businesses/44637/noyc0lpgto9t2p1j15kx","Width":720,"Height":350,"CreateTime":"2020-04-24T11:24:04Z","Bytes":21629},{"IsParent":false,"ImageUrl":"https://res.cloudinary.com/dzpwse6vo/image/upload/c_scale,q_auto,w_0.8/v1587727444/Businesses/44637/noyc0lpgto9t2p1j15kx.jpg","FileName":"Businesses/44637/noyc0lpgto9t2p1j15kx","Width":576,"Height":768,"CreateTime":"2020-04-24T11:24:04Z","Bytes":38069},{"IsParent":false,"ImageUrl":"https://res.cloudinary.com/dzpwse6vo/image/upload/c_scale,q_auto,w_0.6/v1587727444/Businesses/44637/noyc0lpgto9t2p1j15kx.jpg","FileName":"Businesses/44637/noyc0lpgto9t2p1j15kx","Width":432,"Height":576,"CreateTime":"2020-04-24T11:24:04Z","Bytes":25138},{"IsParent":false,"ImageUrl":"https://res.cloudinary.com/dzpwse6vo/image/upload/c_scale,q_auto,w_0.4/v1587727444/Businesses/44637/noyc0lpgto9t2p1j15kx.jpg","FileName":"Businesses/44637/noyc0lpgto9t2p1j15kx","Width":288,"Height":384,"CreateTime":"2020-04-24T11:24:04Z","Bytes":14803},{"IsParent":false,"ImageUrl":"https://res.cloudinary.com/dzpwse6vo/image/upload/c_scale,q_auto,w_0.2/v1587727444/Businesses/44637/noyc0lpgto9t2p1j15kx.jpg","FileName":"Businesses/44637/noyc0lpgto9t2p1j15kx","Width":144,"Height":192,"CreateTime":"2020-04-24T11:24:04Z","Bytes":5285,"IsThumbnail":true}]}}]

第三个选项:

Name=BusinessName%20example&CategoryID=80&Description=&GooglePlaceID=ChIJy9AOJGrKM5QR23I19T-HKD0&Long=&Lat=&GoogleAddress=La%20Posta%2C%20Cordoba%2C%20Argentina&FriendlyAddress=R%C3%ADo%20Primero%2CLa%20Posta&__RequestVerificationToken=CfDJ8E3zPSvylsxAsVq_mjBa9qQxnItdTOHxZje0mUebkKW5pH2K2ZUkB_Flg3XJsUQh_8hxmqGvUJo_hLuQIz6xOiFR1Y5HCDeGmGGKFSM2h1cHGfGkr7SBkIkZr4ImqCDRiaaRmy0x1taJyFmcqRpXMVSBnBN5pcjWkqqNhuGYL09KKD2xFJwk1Tbhcyb7d2YEPw&MainImage={"IsParent":true,"ImageUrl":"https://res.cloudinary.com/dzpwse6vo/image/upload/v1587727444/Businesses/44637/noyc0lpgto9t2p1j15kx.jpg","FileName":"Businesses/44637/noyc0lpgto9t2p1j15kx","Width":720,"Height":960,"CreateTime":"2020-04-24T11:24:04Z","Bytes":50450,"ChildImages":[{"IsParent":false,"ImageUrl":"https://res.cloudinary.com/dzpwse6vo/image/upload/c_crop,g_auto,h_350,q_auto,w_1600/v1587727444/Businesses/44637/noyc0lpgto9t2p1j15kx.jpg","FileName":"Businesses/44637/noyc0lpgto9t2p1j15kx","Width":720,"Height":350,"CreateTime":"2020-04-24T11:24:04Z","Bytes":21629},{"IsParent":false,"ImageUrl":"https://res.cloudinary.com/dzpwse6vo/image/upload/c_scale,q_auto,w_0.8/v1587727444/Businesses/44637/noyc0lpgto9t2p1j15kx.jpg","FileName":"Businesses/44637/noyc0lpgto9t2p1j15kx","Width":576,"Height":768,"CreateTime":"2020-04-24T11:24:04Z","Bytes":38069},{"IsParent":false,"ImageUrl":"https://res.cloudinary.com/dzpwse6vo/image/upload/c_scale,q_auto,w_0.6/v1587727444/Businesses/44637/noyc0lpgto9t2p1j15kx.jpg","FileName":"Businesses/44637/noyc0lpgto9t2p1j15kx","Width":432,"Height":576,"CreateTime":"2020-04-24T11:24:04Z","Bytes":25138},{"IsParent":false,"ImageUrl":"https://res.cloudinary.com/dzpwse6vo/image/upload/c_scale,q_auto,w_0.4/v1587727444/Businesses/44637/noyc0lpgto9t2p1j15kx.jpg","FileName":"Businesses/44637/noyc0lpgto9t2p1j15kx","Width":288,"Height":384,"CreateTime":"2020-04-24T11:24:04Z","Bytes":14803},{"IsParent":false,"ImageUrl":"https://res.cloudinary.com/dzpwse6vo/image/upload/c_scale,q_auto,w_0.2/v1587727444/Businesses/44637/noyc0lpgto9t2p1j15kx.jpg","FileName":"Businesses/44637/noyc0lpgto9t2p1j15kx","Width":144,"Height":192,"CreateTime":"2020-04-24T11:24:04Z","Bytes":5285,"IsThumbnail":true}]}

我尝试将签名更改为
public JsonResult SaveNewBusiness([FromBody]NewBusinessVm newBusiness)

还有:
public JsonResult SaveNewBusiness([FromForm]NewBusinessVm newBusiness)

除此属性外,所有属性均按预期绑定。 任何帮助,可能吗?

您的json格式不正确

您必须将 json 更改为此

{
  "MainImage": {
    "IsParent": true,
    "ImageUrl": "https://res.cloudinary.com/dzpws1e6vo/image/upload/v1587657844/Businesses/44637/q1lgkqgwpwp7zy1obtpwn.jpg",
    "FileName": "Businesses/44637/qlgkqgwpwp7zy11obtpwn",
    "Width": 960,
    "Height": 720,
    "CreateTime": "2020-04-23T16:04:04Z",
    "Bytes": 181783,
    "ChildImages": [{
        "IsParent": false,
        "ImageUrl": "https://res.cloudinary.com/dzpwse6vo/image/upload/c_crop,g_auto,h_350,q_auto,w_1600/v15876517844/Businesses/44637/qlgkqgwpwp7zy1o1btpwn.jpg",
        "FileName": "Businesses/44637/qlgkqgwpwp7z1y1obtpwn",
        "Width": 960,
        "Height": 350,
        "CreateTime": "2020-04-23T16:04:04Z",
        "Bytes": 78322
    }]
}

或者把输入模型改成这个

[HttpPost]
public JsonResult SaveNewBusiness(ImageViewModel imageViewModel)
{

}

你在这里混搭了东西。表单将作为 x-www-form-urlencoded 发送,它基本上只是字符串键值对。将 JSON 对象设置为其中一对的值不会导致 JSON 在以这种方式发送时被反序列化为对象,因为它不知道或以任何方式表明它是 JSON;它只是一个像任何其他字符串一样的字符串。此外,无论如何,这里的整个对象都不会绑定,因为 FromBody 需要类似 application/json 的东西,而不是 x-www-form-urlencoded。对于后者,您需要 FromForm.

如果您想接受 JSON,那么您需要使用 AJAX 发送 post(因为 HTML 表单无法执行那),你需要实际发送它编码为 JSON,而不是使用隐藏的输入和 JSON-like 字符串作为值。

如果您想通过表单继续post,那么您要么需要为主图像上的每个属性添加输入(而不是只输入一个以整个对象作为值的输入) ),否则你需要将它绑定到一个字符串 属性,然后手动返回并自己将其反序列化为一个对象。

通常当我 post 没有复杂对象的表单时,我会这样做:

var data = $form.serialize();
AjaxModule.Ajax(url, data, options);

但由于复杂的对象,我必须像这样操作以形成干净的 javascript 对象的输入:

    //#1 form elements into name:value object
    var data = $form.serializeArray();
    data[data.length] = { name: "MainImage", value: mainImageObj };

    //#2 Create a clean JS Object
    var myObj = {};
    for (var j = 0; j < data.length; j++) {
        myObj[data[j]["name"]] = data[j]["value"];
    }

    AjaxModule.Ajax(url, myObj, options);

有效! 谢谢 Partick(又名:poke)