MVC表单无法提交,调用GET方法

4

我无法让表单调用控制器上的POST操作。

我的页面代码:

@model My.Models.ManageUserViewModel

@using (Html.BeginForm("Manage", "Account", FormMethod.Post, new { @id = "manageAccountFormHolder", @class = "form-horizontal col-sm-8 col-sm-offset-2 v-offset-4" }))
    {
        @Html.AntiForgeryToken()
        <h4 class="text-center">Change Password</h4>

        <div class="form-group">
            @Html.LabelFor(m => m.OldPassword, new { @class = "col-sm-3 control-label" })
            <div class="col-sm-9">
                @Html.PasswordFor(m => m.OldPassword, new { @class = "form-control" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(m => m.NewPassword, new { @class = "col-sm-3 control-label" })
            <div class="col-sm-9">
                @Html.PasswordFor(m => m.NewPassword, new { @class = "form-control" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-sm-3 control-label" })
            <div class="col-sm-9">
                @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
            </div>
        </div>

        <h4 class="text-center v-offset-4">Edit Personal Details</h4>

        <div class="form-group">
            @Html.LabelFor(m => m.FirstName, new { @class = "col-sm-3 control-label" })
            <div class="col-sm-4">
                @Html.TextBoxFor(m => m.FirstName, new { @class = "form-control", @placeholder = "First name" })
            </div>
            <div class="col-sm-5">
                @Html.TextBoxFor(m => m.LastName, new { @class = "form-control", @placeholder = "Last name" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(m => m.Mobile, new { @class = "col-sm-3 control-label" })
            <div class="col-sm-9">
                <input class="form-control" id="manageMobile" name="manageMobile" type="tel">
                @Html.TextBoxFor(m => m.Mobile, new { @class = "form-control", @placeholder = "First name" })
                <p class="help-block">For authorisation code. We will never share or display your mobile number.</p>
            </div>
        </div>

        <h4 class="text-center v-offset-4">Edit Address</h4>

        <div class="form-group">
            @Html.LabelFor(m => m.Address1, new { @class = "col-sm-3 control-label" })
            <div class="col-sm-2">
                @Html.TextBoxFor(m => m.Address1, new { @class = "form-control"})
            </div>
            <div class="col-sm-7">
                @Html.TextBoxFor(m => m.Address2, new { @class = "form-control" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(m => m.TownSuburb, new { @class = "col-sm-3 control-label" })
            <div class="col-sm-9">
                @Html.TextBoxFor(m => m.TownSuburb, new { @class = "form-control" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(m => m.StateRegion, new { @class = "col-sm-3 control-label" })
            <div class="col-sm-9">
                @Html.TextBoxFor(m => m.StateRegion, new { @class = "form-control" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(m => m.PostCode, new { @class = "col-sm-3 control-label" })
            <div class="col-sm-9">
                @Html.TextBoxFor(m => m.PostCode, new { @class = "form-control" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(m => m.Country, new { @class = "col-sm-3 control-label" })
            <div class="col-sm-9">
                @Html.TextBoxFor(m => m.Country, new { @class = "form-control" })
                @Html.HiddenFor(m => m.CountryIso, new { @class = "form-control" })
            </div>
        </div>

        <div class="text-center">
            <button class="btn btn-default" type="submit">Save Changes</button>
        </div>
    }

我的模型

public class ManageUserViewModel
{
    [Required]
    [DataType(DataType.Password)]
    [Display(Name = "Current password")]
    public string OldPassword { get; set; }

    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "New password")]
    public string NewPassword { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm New Password")]
    [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }

    [Required]
    [Display(Name = "Full Name")]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }

    [Required]
    [Display(Name = "Mobile Number")]
    public string Mobile { get; set; }

    [Display(Name = "Street Address")]
    public string Address1 { get; set; }

    public string Address2 { get; set; }

    [Display(Name = "City")]
    public string TownSuburb { get; set; }

    [Display(Name = "State")]
    public string StateRegion { get; set; }

    [Display(Name = "Postcode")]
    public string PostCode { get; set; }

    [Display(Name = "Country")]
    public string Country { get; set; }

    public string CountryIso { get; set; }
}

我的控制器操作

[HttpGet]
public ActionResult Manage(ManageMessageId? message)
{
    return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Manage(ManageUserViewModel model)
{
    //Save changes code here
    //Redirect
}

无法验证。如果我留下必填字段之一为空,将不会显示验证错误。

在 Fiddler 中,我看到表单正在将数据提交到服务器,但仍然调用 GET 方法?请参见下面的 Fiddler 原始数据,这仍然调用 GET 方法(我更新了模型以仅包含一个属性以使其更简单)。

POST https://localhost:44301/Account/Manage HTTP/1.1
Host: localhost:44301
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://localhost:44301/account/manage
Cookie: __RequestVerificationToken=xxxx..........
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 20

OldPassword=dfgdfgdg

1
@garethb - 你的代码完全没有问题,不需要做任何更改。你应该在浏览器控制台中查找错误。 - SBirthare
你试过改变输入类型为"submit"吗?- https://dev59.com/pnA65IYBdhLWcg3w9DmF#3543695 - Anuraj
@Anuraj - 是的,看下面发布的答案。 - garethb
@SBirthare - 是的,我试过了,但是出现了“找不到资源”的错误。当我将新命名的方法更改为允许GET时,它就可以正常找到了。所以问题只出现在发布方面! - garethb
@SBirthare - 谢谢,你的最后一条评论导致了一个“解决方案”。 - garethb
显示剩余8条评论
3个回答

9

问题已解决!如果有人能告诉我原因,因为我不知道(NFI)......

更改这行代码

@using (Html.BeginForm("Manage", "Account", FormMethod.Post, new { @id = "manageAccountFormHolder", @class = "form-horizontal col-sm-8 col-sm-offset-2 v-offset-4" }))

to

@using (Html.BeginForm())

我又来发帖了。耶,我是编码天才,居然花了4个小时才发布一个表格!有人想雇用我吗?

编辑:

经过进一步的挖掘,问题出在我们实现了小写路由。由于路由从/Account/Manage被重写为/account/manage,所以post动作找不到(尽管get动作可以找到)。Html.BeginForm()会将动作渲染成小写,而Html.BeginForm("Manage", "Account", FormMethod.Post, new{})则不会,因为我指定了驼峰式的动作和控制器。


奇怪...我能理解你的沮丧,编程有时候就是会遇到这种情况。也许其他人可以给出实际问题所在的提示? - SBirthare
在您最初的问题中,POST 请求无法正常工作的迹象是什么?例如,您是否收到了一个空白页面?在 ActionResult Manage(ManageUserViewModel model) 中是否设置了断点但未被触发? - Shaun Luttin
@ShaunLuttin - 我在post和get操作中都设置了断点,但只有get被触发了。Fiddler告诉我表单是从浏览器提交的。 - garethb
当您明确给出操作名称和控制器名称时,表单将发布到该特定控制器和操作。当您省略操作名称和控制器名称时,表单将发布到URL。这是我在这里看到的唯一区别。我猜您的控制器名称可能会出现问题。 - Manpreet Singh Dhillon
1
针对小写问题进行更正。请参见此处的答案,以了解如何仅将 GET URL 转换为小写,从而解决此问题:https://dev59.com/knNA5IYBdhLWcg3wpvpg - Savage

2

把你的按钮改成输入框

<input class="btn btn-default" type="submit" value="Save Changes" />

只需删除 Get,不要重命名任何内容。 - Mairaj Ahmad
是的,我先尝试了那个。那里出现了“找不到资源”的错误。所以它认识到这个动作只能是POST。之后尝试了更改名称。 - garethb
我复制了你的代码,它完美地运行着。 - Mairaj Ahmad
是的,我非常确定代码是稳定的。我感到很困惑。 - garethb
在 Fiddler 中显示的是 https,不应该是 http 吗? - Mairaj Ahmad
显示剩余2条评论

0
你使用了两种不同的BeginForm方法, 分别是: BeginForm(HtmlHelper, String, String, FormMethod, IDictionary), 这意味着...
@using (Html.BeginForm("Manage", "Account", FormMethod.Post, new {}))
{
    // Produces the following form element
    // <form action="/Account/Manage" action="post">
}

BeginForm(HtmlHelper)

假设你的/原始控制器/命名为AccountController,而/原始操作/命名为Manage,那么...

@using (Html.BeginForm())
{
    // Produces the following form element
    // <form action="/Account/Manage" action="post">
}

所以,它应该是可行的。这里是我创建的一个 Fiddle,用于尝试找出差异。


我本以为你的小样中表单操作应该是相反的?第二个表单操作具有索引操作,而我认为第一个应该具有。我的表单现在使用BeginForm(HtmlHelper)进行发布,但只要我使用BeginForm(HtmlHelper,String,String,FormMethod,IDictionary)而不改变任何其他内容,就会调用get。当我有时间时,我可能会深入研究这个问题! - garethb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接