序列化 Web 的表单数据 Api put request MVC 5
Serialize form data for Web Api put request MVC 5
我有一个显示 class 记录的强类型 Razor 视图。此视图显示一个表单,用户可以使用该表单更新记录(一个下拉列表、几个复选框和几个文本框)。当用户通过更改控件的值修改字段时,ajax 调用会立即发送到 Web API 以更新该字段。以下 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()
后,它不会 return 预期的 JSON 字符串。相反,它发送一系列 name/value 对,如下所示:
[{"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; }
....
}
Razor 视图:
@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" })
....
}
您需要使用 .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
序列化 name/values 对。这意味着您的 PutPolicy
方法中的模型必须匹配。该方法需要
public IHttpActionResult PutPolicy(int id, PolicyViewModel model) // not AccessItemViewModel
如果方法参数不能改变,那么你的视图需要基于AccessItemViewModel
或者你需要使用AccessVM
属性的分部视图,这样你生成没有 "AccessVM" 前缀的名称属性。例如
_AccessVM.cshtml
@model AccessItemViewModel
@Html.HiddenFor(m => m.Id)
....
并在主视图中,使用@Html.Action()
或@Html.Partial()
生成其html
我有一个显示 class 记录的强类型 Razor 视图。此视图显示一个表单,用户可以使用该表单更新记录(一个下拉列表、几个复选框和几个文本框)。当用户通过更改控件的值修改字段时,ajax 调用会立即发送到 Web API 以更新该字段。以下 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()
后,它不会 return 预期的 JSON 字符串。相反,它发送一系列 name/value 对,如下所示:
[{"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; }
....
}
Razor 视图:
@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" })
....
}
您需要使用 .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
序列化 name/values 对。这意味着您的 PutPolicy
方法中的模型必须匹配。该方法需要
public IHttpActionResult PutPolicy(int id, PolicyViewModel model) // not AccessItemViewModel
如果方法参数不能改变,那么你的视图需要基于AccessItemViewModel
或者你需要使用AccessVM
属性的分部视图,这样你生成没有 "AccessVM" 前缀的名称属性。例如
_AccessVM.cshtml
@model AccessItemViewModel
@Html.HiddenFor(m => m.Id)
....
并在主视图中,使用@Html.Action()
或@Html.Partial()
生成其html