【问题标题】:MVC Post Causes QueryString to Be Lost on Reload of Same ViewMVC Post 导致 QueryString 在重新加载相同视图时丢失
【发布时间】:2019-03-29 05:08:41
【问题描述】:

请让我解释一下设置。

我有一个更改密码控制器/操作和视图。 以下是我的帐户控制器中的操作签名:

public ActionResult ChangePassword(ChangePasswordMessageId? message)

[HttpPost]
public ActionResult ChangePassword(ChangePasswordViewModel model)

首次加载更改密码时,查询字符串中有一些数据。这是一个例子:

https://www.mywebsite.com/Account/ChangePassword?mobile=1

这是视图中的表单声明。

@using (Html.BeginForm("ChangePassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()

通过一个简单的提交按钮提交表单:

<div class="form-group">
  <div class="col-md-offset-2 col-md-4">
    <input type="submit" value="Change Password" class="btn btn-primary btn-block" />
  </div>
</div>

该表单有 3 个字段:当前密码、新密码和确认密码。 如果用户正确填写了所有数据,并通过了所有客户端验证,则表单可以正常工作。除了一个用例外,一切正常。

假设用户输入的旧密码值不正确。当我到达上面的 HTTPPOST ChangePassword 操作时,它将失败。这就是代码的样子。

[HttpPost]
            public ActionResult ChangePassword(ChangePasswordViewModel model)
            {   
                if (ModelState.IsValid)
                {
                    try
                    {
                        MembershipUser user = Membership.GetUser();
        //The NEXT line is the one that fails if they supply the wrong Old Password value.
        //The code then falls to the catch condition below.
                        bool changePassword = user.ChangePassword(model.OldPassword, model.NewPassword);
                        if (changePassword)
                        {
                            string path = Url.Action("ChangePassword", new { Message = ChangePasswordMessageId.ChangePasswordSuccess });
                            temp = Request.UrlReferrer.ToString();
                            pos = temp.IndexOf("?");
                            if (pos > 0) path += "&" + temp.Substring(pos + 1);
                            return RedirectToLocal(path);    
                       }
                        else
                        {
                            ModelState.AddModelError("", "Change Password failed.");
                        }
                    }
                    catch //(Exception ex)
                    {
                        ModelState.AddModelError("", "Change Password failed.");
                        //ModelState.AddModelError("", ex.Message);
                    }
                }

                // If we got this far, something failed, redisplay form
    //The original query string will be gone. The URLwill now only show
    //https://www.mywebsite.com/Account/ChangePassword
                return View(model);
            }

是否可以调用“返回视图(模型);”这样原始查询字符串仍然存在吗? 我需要在页面之间维护查询字符串。除了这个用例之外,我在任何地方都可以使用它。

谢谢!

【问题讨论】:

  • 在这种情况下为什么不使用 ajax 调用?
  • 谢谢。我实际上是这样想的并尝试了它。但是,这并不是将 HTML.BeginForm 更改为 AJAX.BeginForm 那么简单。默认情况下,当 HTTPPost 操作返回 View(model) 时,页面什么也不做。我将不得不编写更多代码来更新显示。我正在寻找一种更通用的解决方案,可以在任何可能发生这种情况的地方应用。

标签: c# asp.net asp.net-mvc asp.net-mvc-4 post


【解决方案1】:

如果有人仍在寻找此解决方案,请尝试不提供控制器和操作名称。

 @using (Html.BeginForm(null, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
    {
        @Html.AntiForgeryToken()

【讨论】:

    【解决方案2】:

    您可以这样做的一种方法是让您的Mobile 标志成为您的视图模型的一部分。并且,在您的 Get 控制器操作中,确保在填充 View Model 时从查询字符串中获取 Mobile 标志。

    在您的表单上,为您要回发的字段创建一个隐藏的输入字段。例如:

    @Html.Hidden(Model.Mobile)
    

    在发布时,Mobile 值将在您的ChangePasswordViewModel 中正确设置,因此您可以访问它。

    【讨论】:

      【解决方案3】:
      return RedirectToAction("Index", Request.QueryString.ToRouteValues());
      

      【讨论】:

      • “ToRouteValues”是你自己的扩展方法吗?
      【解决方案4】:

      我的代码在VB中,在视图中,创建一个辅助函数来将所有URL查询参数加载到表单中:

      @Functions
      Public Function GetRouteValues() As RouteValueDictionary
          Dim RouteValues As New RouteValueDictionary
          For Each Qstr As String In Request.QueryString
              RouteValues.Add(Qstr, Request.QueryString.GetValues(Qstr).FirstOrDefault)
          Next
          Return RouteValues
      End Function
      End Functions
      

      然后将表单头声明如下

      @Using (Html.BeginForm("MultipleHandler", "Files", GetRouteValues, FormMethod.Post))
      

      这样,您将查询字符串的集合传递给操作。

      在动作中,使用相同的功能:

      Private Function AllRouteVlaues() As RouteValueDictionary
              Dim RouteValues As New RouteValueDictionary
              For Each Qstr As String In Request.QueryString
                  RouteValues.Add(Qstr, Request.QueryString.GetValues(Qstr).FirstOrDefault)
              Next
              Return RouteValues
          End Function
      

      用法:

      Return RedirectToAction("Index", AllRouteVlaues)
      

      希望有帮助:)

      【讨论】:

        【解决方案5】:

        试试这个:

        using (Html.BeginForm("Action", "Controller",  new { Var1 = (string)ViewBag.Var1, Var2 = (string)ViewBag.Var2, Var3 = (string)ViewBag.Var3 }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
                            {
        

        【讨论】:

          【解决方案6】:

          您需要“以某种方式”在新请求中包含查询字符串参数。
          在路上将是以下(这也是 MS 在他们的示例中使用 ReturnUrl 的方式):

          public ActionResult ChangePassword(ChangePasswordMessageId? message. int mobile = 0)
          {
              // your code
              ViewBag.Mobile = mobile;
              return View();
          }
          [HttpPost]
          public ActionResult ChangePassword(ChangePasswordViewModel model, int mobile = 0)
          {
              // your code
              ViewBag.Mobile = mobile;
              return View(model);
          }
          

          和

          @using (Html.BeginForm("ChangePassword", "Account", FormMethod.Post, 
              new { @class = "form-horizontal", role = "form", mobile = @ViewBag.Mobile }))
          

          【讨论】:

          • 谢谢,我希望有一个通用的解决方案,这样我就不必在我的代码中找到所有可能发生这种情况的情况。
          • 您可以使用 Request.Url 并始终附加查询字符串,但这对我来说听起来很脏 - 也许在会话中保存此类设置?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-05-20
          • 2015-05-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-06-22
          • 1970-01-01
          相关资源
          最近更新 更多