ASP.Net MVC 部分视图保持其模型状态?

发布于 2024-09-06 01:18:36 字数 1138 浏览 8 评论 0原文

这可能又是一个新手问题。

当我创建 ASP.NET MVC2 应用程序时,会创建一个带有操作登录的帐户控制器,如下所示:

[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
   if (ModelState.IsValid)
   {
      if (MembershipService.ValidateUser(model.UserName, model.Password))
      {
         FormsService.SignIn(model.UserName, model.RememberMe);
         if (!String.IsNullOrEmpty(returnUrl))
         {
            return Redirect(returnUrl);
         }
         else
         {
           return RedirectToAction("Index", "Home");
         }
       }
       else
       {
          ModelState.AddModelError("", "The user name or password provided is incorrect.");
       }
     }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

现在,我不想有登录页面,我希望将登录控件作为更大页面的一部分。因此,我将 Login.aspx 更改为 Login.ascx,并将其与 Html.RenderPartial 或 Html.RenderAction 集成到我的主视图中。

如果登录成功,两者都会发挥作用。如果不是,那就

return View(model)

杀了我。 我想要的是返回到我的主页(称为主页/索引),但带有部分视图的错误信息。

return RedirectToAction("Index", "Home")

显然是行不通的。

提示?

This is probably again a newbie question.

When I create an ASP.NET MVC2 application, an Account Controller with an Action LogIn is created like this:

[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
   if (ModelState.IsValid)
   {
      if (MembershipService.ValidateUser(model.UserName, model.Password))
      {
         FormsService.SignIn(model.UserName, model.RememberMe);
         if (!String.IsNullOrEmpty(returnUrl))
         {
            return Redirect(returnUrl);
         }
         else
         {
           return RedirectToAction("Index", "Home");
         }
       }
       else
       {
          ModelState.AddModelError("", "The user name or password provided is incorrect.");
       }
     }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

Now, I don't want to have a login page, I want to have login controls as part of a bigger page. So, I changed Login.aspx to Login.ascx and I am integrating it in my main view either with Html.RenderPartial or Html.RenderAction.

Both works like a charm if the login is successfull. If it is not, the

return View(model)

is killing me.
What I want is to go back to my main page (call it Home/Index) but with the error information of the partial view.

return RedirectToAction("Index", "Home")

Obviously doesn't work.

Hints?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

聽兲甴掵 2024-09-13 01:18:36

这当然不是一个新手问题,我已经在网上搜索了这个问题的答案,到目前为止,我发现的最佳解决方案隐藏在本教程中 此处。这就是达林·迪米特洛夫 (Darin Dimitrov) 在阿贾克斯更新中所建议的。我将总结该链接的重要部分以及为什么这不容易修复: /

基于奇怪的情人的 Ajax 刷新

ajax 刷新的解决方案几乎取决于以下功能(奇怪的情人使用ControllerContext 但它对我来说不存在,所以我有 ControllerExtension):

ControllerExtension.RenderPartialViewToString(this,"mypartial", (object)model)

这个函数负责获取模型 + 模型状态并将部分视图重新呈现为 html 字符串。然后,您可以获取该字符串并将其以 json 对象形式发送回某些 javascript 以刷新视图。我使用了jquery,它看起来像这样,

$(document).ready(function () {
    var partialViewUpdate = function (e) {
            e.preventDefault(); //no postback
            var partialDiv = $(this).parent(".partial");
            $.post($(this).attr("action"),
                   $(this).serialize(),
                   function (json) {
                   if (json.StatusCode != 0) {
                       // invalid model, return partial 
                       partialDiv.replaceWith(json.Content);
                   }
                   else if (json.Content != null && json.Content != "") {
                       window.location.replace(data.Content);
                   };
           });

    $(".partial").find("form")
                 .unbind('submit')
                 .live("submit", partialViewUpdate);
};

Jquery解释:

  1. 查找包含我的部分(class =“partial”)的div并找到该div中的表单
  2. 解除与该表单的任何其他“提交”事件的绑定(我得到了一些奇怪的双重提交错误,直到我取消绑定)。
  3. 使用“live”,这样一旦内容被替换,它就会再次重新绑定。
  4. 一旦我们进入函数partialViewUpdate...
  5. 阻止表单完成提交,以便全部由ajax处理。
  6. 获取包含我的部分的 div(稍后将使用它)
  7. 通过从表单 $(this).attr("action") 获取它来设置 jquery post url
  8. 获取表单(即我们的模型)并将其序列化为控制器function, $(this).serialize()
  9. 创建处理ajax返回值的函数。
  10. 我使用我自己的个人 json 对象,其中 StatusCode 1 是错误的。因此,如果情况不好,那么我会采用 Content 中的内容,这是 RenderPartialViewToString 给我的字符串,我只需替换包含我的部分的 div 的内容。

为什么它不能正常“正常工作”

因此,部分部分不能仅与模型状态验证一起使用的原因是您无法通过 POST 返回 View(model),因为 MVC 将解决该问题到部分视图 (login.ascx) 的路由地址,而不是部分嵌入的位置 (index.aspx)。

您也不能使用 RedirectAction(),因为这会将其发送到 (index.aspx) 控制器函数,这相当于清除所有内容并刷新 index.aspx 页面。但是,如果您使用 Chino 和 Thabaza 建议的 ActionFilter,那么当刷新页面并且再次触发 login.ascx 控制器功能时,它将获取该临时数据。然而,如果刷新页面导致客户端代码(例如弹出模式)出现麻烦(即,如果刷新弹出窗口就消失了),则此方法不起作用。

说不是这样的

我更希望它“只是有效”,所以如果有人知道正确/更好的方法,请分享它!我仍然觉得 Ajax 刷新和 ActionFilter 解决方案不是一种干净的方法,因为它几乎使它看起来像带有表单的部分视图,如果没有某种“技巧”就不可能使用。

This is certainly not a newbie question and I have combed up and down the web for an answer to this problem and so far the best solution I've found was kind of hidden in this tutorial here. This is what Darin Dimitrov was suggesting with the Ajax refresh. I'll summarize the important parts of that link and why this isn't easily fixed : /

Ajax refresh based on weird lover

The solution with the ajax refresh pretty much hinges on the following function (weird lover uses ControllerContext but it didn't exist for me so I have ControllerExtension):

ControllerExtension.RenderPartialViewToString(this,"mypartial", (object)model)

This function is what takes your model + modelstate and rerenders your partial view into an html string. You can then take that string and send it back in a json object to some javascript to refresh the view. I used jquery and it looks like this,

$(document).ready(function () {
    var partialViewUpdate = function (e) {
            e.preventDefault(); //no postback
            var partialDiv = $(this).parent(".partial");
            $.post($(this).attr("action"),
                   $(this).serialize(),
                   function (json) {
                   if (json.StatusCode != 0) {
                       // invalid model, return partial 
                       partialDiv.replaceWith(json.Content);
                   }
                   else if (json.Content != null && json.Content != "") {
                       window.location.replace(data.Content);
                   };
           });

    $(".partial").find("form")
                 .unbind('submit')
                 .live("submit", partialViewUpdate);
};

Jquery explanation:

  1. Look up the div that contains my partial (class="partial") and find the form within that div
  2. Unbind any other "submit" events with that form (I got some strange double submit bug until I did that unbind).
  3. use "live" so that once the content is replaced it rebinds again
  4. Once we enter the function partialViewUpdate...
  5. Prevent the form from finishing the submit so that it can all be handled by ajax.
  6. fetch the div that contains my partial (will use this later)
  7. Setup the jquery post url by taking it from the form, $(this).attr("action")
  8. Take the form (i.e. our model) and serialize it for the controller function, $(this).serialize()
  9. Create the function that will handle the ajax return value.
  10. I use my own personal json object, where a StatusCode 1 is bad. So if it's bad then I take what's in Content, this is the string that RenderPartialViewToString gave me, and I just replace the contents of the div that contains my partial.

Why it doesn't "just work" normally

So the reason the partials' don't just work with modelstate validation is that you can't return View(model) with the POST because MVC will resolve that to the route address of the partial view (login.ascx) instead of where the partial is embedded (index.aspx).

You also can't use RedirectAction() because that will send it to (index.aspx) controller function, which is the equivalent of clearing everything and refreshing the index.aspx page. However if you use that ActionFilter suggested by Chino and Thabaza then when your page is refreshed and the login.ascx controller function is fired off again it will pick up that tempdata. This however doesn't work if refreshing the page causes a hassle with client-side code such as popup modals (i.e. if you refresh your popup is gone).

Say it aint so

I would prefer if it "just worked" so if anyone knows the correct/better way of doing this pleaaaase share it! I still feel that the Ajax refresh and ActionFilter solutions are not a clean way of doing it because it almost makes it look like partial views with forms are impossible to use without some sort of "trick".

流绪微梦 2024-09-13 01:18:36

是的,redirecttoaction,但在临时数据中提供错误消息,因此您应该执行类似的操作

TempData["errorMsg"] = "incorrect values provided";
return RedirectToAction("Index", "Home")

当然,在主索引中,您应该有一个显示消息

<%= html.Encode(TempData["errorMsg"]) %>

EDIT 的 div
我看到您想要维护可能存在问题的模型状态,但您可以做的是在索引操作中传递模型状态或在临时数据中传递模型状态对象。然后您可以做的是检查对象中是否存在模型状态错误以及检查字段并将错误添加到正确的字段。

Yeah redirecttoaction but provide an error message with it in the tempdata so you should do something like this

TempData["errorMsg"] = "incorrect values provided";
return RedirectToAction("Index", "Home")

Of course in the main index you should have a div that displays the message

<%= html.Encode(TempData["errorMsg"]) %>

EDIT
I see you want to maintain the modelstate that might be a problem but what you could do is pass the modelstate in the index action or pass the modelstate object in the tempdata. What you can do then is check if a there are modelstate errors in the object and if there are check the field and add the error to the right field.

小情绪 2024-09-13 01:18:36

您可以显式指定要返回的视图:

return View("~/Views/Home/Index.aspx", model);

这样,将保留错误信息并呈现正确的视图。

You could explicitly specify the view to return:

return View("~/Views/Home/Index.aspx", model);

This way error information will be preserved and correct view rendered.

哭泣的笑容 2024-09-13 01:18:36

看看实践#13 博客。当您以 PRG(Post-Redirect-Get)风格进行编码时,此方法可以很好地传递模型状态信息。您只需要创建几个操作过滤器,并根据需要将它们应用到您的获取和发布操作。

Take a look at practice #13 on this blog. This method works well to pass modelstate information when you're coding in the PRG (Post-Redirect-Get) style. You'll just need to create a couple of action filters and apply them to your get and post actions as appropriate.

情绪失控 2024-09-13 01:18:36

使用 Ajax.BeginForm 时我遇到了同样的问题,我需要返回部分视图,但所有模型状态错误都消失了。
诀窍是将 Ajax.BeginForm 部分隔离到单独的视图,并在另一个包含视图的 UpdateTargetId div 内渲染此视图。

这样,您可以在出现模型错误时返回带有模型错误的视图模型,或者仅显示您选择的一些成功消息(如果有)。
这是一个很棒、详细的解释:
http://xhalent。 wordpress.com/2011/02/05/using-unobtrusive-ajax-forms-in-asp-net-mvc3/

I had the same issue when used Ajax.BeginForm, where i needed to return a partial view, but all the modelstate errors were gone.
what does the trick is to isolate the Ajax.BeginForm part to a separate View, and RenderPartial this view within the UpdateTargetId div in another, containing view.

This way you can return the viewmodel with the model errors when you have them, or else just show some success message of your choice (if any).
here is a great, detailed explanation:
http://xhalent.wordpress.com/2011/02/05/using-unobtrusive-ajax-forms-in-asp-net-mvc3/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文