【问题标题】:Serialize form data for Web Api put request MVC 5为 Web Api put request MVC 5 序列化表单数据
【发布时间】:2016-09-16 09:42:04
【问题描述】:

我有一个显示类记录的强类型 Razor 视图。这个视图显示了一个用户可以用来更新记录的表单(一个下拉菜单、几个复选框和几个文本框)。当用户通过更改控件的值来修改字段时,会立即向 Web API 发送 ajax 调用以更新该字段。以下 Ajax 调用工作正常:

$(document).ready(function () {
    $(this).on("change", function (e) {
        var editRecordURL = $("#editRecordURL").val();
        var key = $("#AccessVM_Id").val();
        var mode = $("#AccessVM_AccessMode").val();
        var failLim = $("#AccessVM_LoginFailLimit").val();
        var cap = $("#AccessVM_PwdWCap").is(':checked');
        ...
        var rec = {
            Id: key,
            AccessMode: mode,
            LoginFailLimit: failLim,
            PwdWCap: cap,
            ....
        };

        $.ajax({
            type: "PUT",
            url: editRecordURL,
            data: JSON.stringify(rec),
            contentType: 'application/json; charset=utf-8',
            success: function (msg) {
                bootbox.alert("Success: Record updated successfully!");
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                bootbox.alert("Error: " + errorThrown);
            }
        });
    });
});

但是,我想让这个函数更通用,以便可以将其重用于其他表单(尤其是那些需要更新更多数据的表单)。理想情况下,rec 对象将像这样填充:

var rec = $("#form").serializeArray();

很遗憾,这不起作用,因为在 rec 上应用 JSON.stringify() 后,它不会返回预期的 JSON 字符串。相反,它会发送一系列名称/值对,如下所示:

[{"name":"__RequestVerificationToken","value":"qVedWHJ6HIrqtLJpTxp4m5D2ehZ_AdjCOvQtz4Jyzlg0cdocsWqcTCiE2jzIEB7UsJPwuSZeZF7y1GsluHNrNCDV1wrHjU1UJO5vMMGTLB41"},{"name":"AccessVM.Id","value":"1"},{"name":"AccessVM.AccessMode","value":"1"},{"name":"AccessVM.LoginFailLimit","value":"10"},{"name":"AccessVM.PwdWCap","value":"true"},{"name":"AccessVM.PwdWCap","value":"false"},{"name":"AccessVM.PwdWNum","value":"true"},{"name":"AccessVM.PwdWNum","value":"false"},{"name":"AccessVM.PwdWSC","value":"true"},{"name":"AccessVM.PwdWSC","value":"false"},{"name":"AccessVM.PwdMinLen","value":"6"},{"name":"AccessVM.PwdMaxLen","value":"25"},{"name":"AccessVM.PwdChange","value":"90"},{"name":"AccessVM.PwdPrevUsedLimit","value":"10"}]

那么我该如何解决这个问题,使字符串看起来像:

[{"AccessVM.Id": 1, "AccessVM.AccessMode": 1, "AccessVM.LoginFailLimit": 10, "AccessVM.PwdWCap": true, "AccessVM.PwdWNum": true, "AccessVM.PwdWSC": false, "AccessVM.PwdMinLen": 6, "AccessVM.PwdMaxLen": 25, "AccessVM.PwdChange": 90, "AccessVM.PwdPrevUsedLimit": 10}]

Web API 控制器:

public class PoliciesController : ApiController
{
    ....
    // PUT: api/policies/1
    [ResponseType(typeof(void))]
    public IHttpActionResult PutPolicy(int id, AccessItemViewModel polDto)
    {
        ....
    }
    ....
}

查看模型

public class PolicyViewModel
{
    public AccessItemViewModel AccessVM { get; set; }
    ....
}

public class AccessItemViewModel
{
    public int Id { get; set; }
    public int AccessMode { get; set; }  
    public int LoginFailLimit { get; set; } 
    public bool PwdWCap { get; set; }   
    ....
}

剃刀视图:

@model App.Web.ViewModels.PolicyViewModel
....
@using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary("", new { @class = "text-danger" })
    <input type="hidden" id="editRecordURL" value="@Model.ExtraVM.EditRecordUrl" />
    @Html.LabelFor(m => m.AccessVM.AccessMode, new { @class = "col-xs-5" })
    @Html.HiddenFor(m => m.AccessVM.Id)
    @Html.DropDownListFor(m => m.AccessVM.AccessMode, new SelectList(Model.AccessModes, "Mode", "Description"), null, new { @class = "input-sm col-xs-7" })
    @Html.LabelFor(m => m.AccessVM.LoginFailLimit, new { @class = "col-xs-9" })
    @Html.DropDownListFor(m => m.AccessVM.LoginFailLimit, new SelectList(Model.LoginLimits, "LoginFailLimit", "Value"), null, new { @class = "input-sm col-xs-3" })
    @Html.LabelFor(m => m.AccessVM.PwdWCap, new { @class = "col-xs-11" })
    @Html.CheckBoxFor(m => m.AccessVM.PwdWCap, new { @class = "input-xs col-xs-1" })
    ....
}

【问题讨论】:

  • 这是$("#form").serialize()(不是.serializeArray())并删除contentType: 'application/json; charset=utf-8',并且不要字符串化(只使用data: $("#form").serialize(),
  • 这不起作用(我收到错误“未找到”),因为它创建了一个键和值的查询字符串,如下所示:AccessVM.Id=1&AccessVM.AccessMode=1&AccessVM.LoginFailLimit=1&AccessVM.PwdWCap =false&AccessVM.PwdWNum=false&AccessVM.PwdWSC=false&AccessVM.PwdMinLen=3... Web API 端点期望将“策略”类型的对象发送给它(这意味着 JSON 对象)。但是如果我能以某种方式把这个字符串变成一个 JSON 对象,那就太好了!
  • 你是什么Policy 模型。如果它包含一个名为AccessVM 的复杂属性,其中包含属性IdAccessMode 等,它将很好地绑定。并显示部分视图和控制器(根据你所说的正常工作,那么POST方法中的模型与视图中的模型不一样(应该是)
  • 从技术上讲,没有“发布”方法,但出于我们的目的,您可以这样想。视图是强类型的(基于 API 接收的相同模型)。我遇到的问题是以正确的格式获取对象。有关详细信息,请参阅我编辑的问题...
  • 您视图中的模型是PolicyViewModel,因此您发布到的方法中的参数需要是PolicyViewModel(不是AccessItemViewModel

标签: jquery asp.net-mvc asp.net-mvc-5 serializearray webapi2


【解决方案1】:

您需要使用.serialize()(不是.serializeArray(),它不能与您的bool 属性和DefaultModelBinder 一起正常工作)并删除contentType 选项,以便它使用默认的application/x-www-form-urlencoded; charset=UTF-8 并且不要对数据进行字符串化。 Yoru 脚本应该是

$.ajax({
    type: "PUT",
    url: editRecordURL,
    data: $('form').serialize(),
    success: function (msg) {

但是,您视图中的模型是 PolicyViewModel,并且您基于该模型生成表单控件,因此 .serialize() 函数将为 PolicyViewModel 序列化名称/值对。这意味着 PutPolicy 方法中的模型必须匹配。方法需要

public IHttpActionResult PutPolicy(int id, PolicyViewModel model) // not AccessItemViewModel

如果方法参数无法更改,那么您的视图需要基于AccessItemViewModel 或者您需要为AccessVM 属性使用部分视图,以便生成不带“AccessVM”前缀的`name 属性。例如

_AccessVM.cshtml

@model AccessItemViewModel
@Html.HiddenFor(m => m.Id)
....

并在主视图中,使用@Html.Action()@Html.Partial() 生成其html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 1970-01-01
    • 1970-01-01
    • 2020-02-29
    • 2016-06-26
    相关资源
    最近更新 更多