POST数据中不包含MVC 3远程验证表单按钮

时间:2011-06-17 13:46:28

标签: asp.net-mvc asp.net-mvc-3

我有一个ASP.NET MVC3应用程序,并在我的一个模型类上进行远程验证。我发现如果在提交表单之前打开该模型的编辑视图并且远程验证例程不是被调用(由于没有编辑带有远程验证的字段),该按钮被单击为POST表单包含在发送到Action方法的请求数据中。

如果在表单发布之前调用远程验证例程 IS - 单击该按钮以提交POST中包含的 IS 表单。

我需要知道在服务器上调用Action时单击了哪个按钮,以便我可以确定用户是否单击了UPDATE或CANCEL。

如果我从模型中删除远程验证,表单每次都会正确提交。

为什么在表单提交之前未调用远程验证时,用于提交表单的按钮会从表单发布中排除。

感谢 迈克尔

以下是一些示例代码:

@model Channel
<script src="@Url.Content("~/Scripts/jquery-1.6.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
<fieldset>
    <legend>Edit Channel</legend>

    @Html.HiddenFor(model => model.ChannelGUID)


    <div class="editor-label">Name</div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Name)
        @Html.ValidationMessageFor(model => model.Name)
    </div>

    <div class="editor-label">Description</div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Description)
        @Html.ValidationMessageFor(model => model.Description)
    </div>

    <div class="editor-label">Channel Code</div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Code)
        @Html.ValidationMessageFor(model => model.Code)
    </div>

    <p>
        <button type="submit" name="updateCommand" value="Update">Update</button>
        <button type="submit" class="cancel">Cancel</button>
    </p>
</fieldset>
}

这是行动

[HttpPost]
public ActionResult Edit(string updateCommand, Channel channel)
{
    if (updateCommand != null)
    {
     //update clicked
    }
    else
    {
     //cancel clicked
    }

这是模型属性Code

的远程属性
[Remote("IsChannelCodeUnique", "Channel", AdditionalFields = "ChannelGUID", ErrorMessage = "code must be unique")]

3 个答案:

答案 0 :(得分:4)

我遇到了同样的问题。我在一个有两个提交输入的表单中添加了远程验证,并且单击了提交按钮的值,并不总是已经发布了。

虽然其他答案提供了解决方法,但我深入研究并回答了您提出的实际问题:“为什么用于提交表单的按钮会在远程验证时从表单帖子中排除在表单提交之前不会调用。“

我知道Javascript Submit does not include the Submit Button Value。因此,我试图发布禁用javascript。验证无效,但我的提交价值已过帐。我假设jquery.validate.js跳入并发送程序化提交。确实如此。这就是使用jquery.validate.js 1.9.0,未压缩的:

  1. 加载页面时,在第942行,使用远程方法扩展验证器,使用 stopRequest 原型在第735行扩展验证器。
  2. 当输入字段第一次失去焦点,之后输入焦点或提交表单时,验证就会发生。
  3. 验证后,将调用 stopRequest 方法。
  4. 单击提交输入时,会以某种方式抑制提交。在第56行中有一个语句event.preventDefault();,但这仅在调试模式下调用。无论如何,单击提交时以及执行远程验证后,将调用 stopRequest 方法。
  5. 当表单有效时,将调用第742行:$(this.currentForm).submit();,这是一个程序化提交,不会发布提交的值。这就是我无法确定单击了哪个提交按钮的原因。
  6. 仔细查看验证扩展的方式,我在第59行找到了一个处理程序的定义,它似乎旨在克服一些类似的问题:它添加了一个隐藏的输入,其中包含提交按钮的名称和值它处理。但是,在我的情况下,validator.settings.submitHandlervalidator.submitButton都没有定义,因此永远不会调用此代码。

    如果在这种情况下添加了这个隐藏字段会很好,因为MVC不会知道也不关心发布值的输入类型,控制器上的post操作只能使用该值。

    <强>加成 我对此问题的解决方法是为提交的单击函数添加处理程序:

    $('input[type="submit"]').click(function () {
        var hidden = $("<input type='hidden'/>").attr("name", this.name).val(this.value).appendTo($(this).closest("form"));
    });
    

    隐藏字段已创建,因此我不必依赖具有正确名称的隐藏字段。 您可以为您的提交提供相同的名称,并测试该值,或者为它们指定不同的名称并测试是否存在post参数。 当然,您还需要使用尚未使用的表单字段名称。

答案 1 :(得分:0)

我尝试将取消按钮更改为链接(使用操作链接)并使用jQuery UI来设置表单上的链接和提交按钮的样式以使其看起来相同。这避免了我点击的按钮未包含在POST数据中的问题。现在,当调用操作时,我不需要确定单击的按钮以查看用户是否按下取消。

答案 2 :(得分:0)

我们创建了一个自定义的ActionMethodSelectorAttribute,因此无需编写if else或switch语句来决定单击哪个按钮。这是自定义类:

public class AcceptParameterAttribute : ActionMethodSelectorAttribute
{
    public string Name { get; set; }

    public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
    {
        var req = controllerContext.RequestContext.HttpContext.Request;

        return req.Form[this.Name] != null;
    }
}

此属性根据单击的按钮名称选择要执行的方法。以下是用法:

[HttpPost]
[ActionName(ActionNameEditUser)]
[AcceptParameter(Name = "save")]
public ActionResult Save()
{
    // put your code here
}

[HttpPost]
[ActionName(ActionNameEditUser)]
[AcceptParameter(Name = "cancel")]
public ActionResult Cancel()
{
    // put your code here
}

相应地命名按钮的所有内容,我们完成了:

<button name="save">Save</button>
<button name="cancel">Cancel</button>