如何在 ASP.Net MVC 2 中的 ViewUserControl 中封装 form/post/validation[/redirect]
简短版本:需要ViewUserControl(即登录表单)发布到自己并能够重定向(即成功登录),或返回带有验证摘要的原始视图(即主页/索引)并且不干扰其他视图ViewUserControls 在页面上。
另外,HomeController/Index 应该对登录表单的内部工作原理有最少的了解。理想情况下,Html.RenderAction("Login","User") 或类似的内容就足够了。
目前,卡在重定向上,给出“子操作不允许执行重定向操作”。我知道为什么,但想知道是否有办法解决,或者我应该这样做。
我想要实现的详细信息:
- 封装一个登录(或任何)表单以便在整个网站上重复使用
- 发帖给自己
- 当登录/验证失败时,显示带有验证摘要的原始页面
- (有些人可能会认为只发布到登录页面并在那里显示验证摘要;如果我想要实现的目标不可能实现,我就会走那条路)
- 登录成功后,重定向到/App/Home/Index
- 另外,想要:
- 坚持 PRG 原则
- 避免使用ajax
- 使登录表单(UserController.Login())尽可能封装;避免必须实现 HomeController.Login(),因为登录表单可能会出现在其他地方
除了重定向之外的所有内容都有效。到目前为止我的方法是:
Home/Index
包含登录表单:<%Html.RenderAction("Login","User");%>
用户/登录ViewUserControl
包括:
using(Html.BeginForm()){}
- 包含隐藏表单字段
"userlogin"="1"
public class UserController : BaseController {
...
[AcceptPostWhenFieldExists(FieldName = "userlogin")]
public ActionResult Login(UserLoginViewModel model, FormCollection form){
if (ModelState.IsValid) {
if(checkUserCredentials()) {
setUserCredentials()
return this.RedirectToAction<Areas.App.Controllers.HomeController>(x => x.Index());
}
else {
return View();
}
}
...
}
在以下情况下效果很好:ModelState 或用户凭据失败 - return View() 确实会屈服于 Home/Index并显示适当的验证摘要。
(我在同一页面上有一个注册表单,使用相同的结构。每个表单的验证摘要仅在提交该表单时显示。)
失败:ModelState 和用户凭据有效 - RedirectToAction<> () 给出以下错误:
“子操作不允许执行重定向操作。”
看起来在经典 ASP 时代,这个问题可以通过 Response.Buffer=True
来解决。现在有等效的设置或解决方法吗?
顺便说一句,正在运行:ASP.Net 4、MVC 2、VS 2010、开发/调试 Web 服务器
我希望所有这些都有意义。
那么,我有什么选择呢?或者我的方法哪里出了问题?蒂亚!
Short verion: need ViewUserControl (i.e., Login Form) to post to self and be able to redirect (i.e., on successful login), or return original View (i.e., Home/Index) with validation summary and not interfere with other ViewUserControls on the page.
Also, HomeController/Index should have minimal knowledge of Login Form's inner workings. Ideally, Html.RenderAction("Login","User"), or similar, is all that's required.
At the moment, stuck on redirect giving "Child actions are not allowed to perform redirect actions." I know why, but wondering if there is a way around, or another way I should be doing this.
Details of what I am trying to achieve:
- encapsulate a Login (or any) Form to be reused across site
- post to self
- when Login/validation fails, show original page with Validation Summary
- (some might argue to just post to Login Page and show Validation Summary there; if what I'm trying to achieve isn't possible, I will just go that route)
- when Login succeeds, redirect to /App/Home/Index
- also, want to:
- stick to PRG principles
- avoid ajax
- keep Login Form (UserController.Login()) as encapsulated as possible; avoid having to implement HomeController.Login() since the Login Form might appear elsewhere
All but the redirect works. My approach thus far has been:
Home/Index
includes Login Form:<%Html.RenderAction("Login","User");%>
User/Login ViewUserControl<UserLoginViewModel>
includes:
using(Html.BeginForm()){}
- includes hidden form field
"userlogin"="1"
public class UserController : BaseController {
...
[AcceptPostWhenFieldExists(FieldName = "userlogin")]
public ActionResult Login(UserLoginViewModel model, FormCollection form){
if (ModelState.IsValid) {
if(checkUserCredentials()) {
setUserCredentials()
return this.RedirectToAction<Areas.App.Controllers.HomeController>(x => x.Index());
}
else {
return View();
}
}
...
}
Works great when: ModelState or User Credentials fail -- return View() does yield to Home/Index and displays appropriate validation summary.
(I have a Register Form on the same page, using the same structure. Each form's validation summary only shows when that form is submitted.)
Fails when: ModelState and User Credentials valid -- RedirectToAction<>() gives following error:
"Child actions are not allowed to perform redirect actions."
It seems like in the Classic ASP days, this would've been solved with Response.Buffer=True
. Is there an equivalent setting or workaround now?
Btw, running: ASP.Net 4, MVC 2, VS 2010, Dev/Debugging Web Server
I hope all of that makes sense.
So, what are my options? Or where am I going wrong in my approach? tia!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我会选择可以放置在 MasterPage/_Layout 上的部分视图(例如“_Login.cshtml”或“_Login.ascx”)。在部分视图中,您编写一个表单标签,该标签发布到控制器上的操作(假设“AuthController”和操作“LogIn”)。记住您来自哪里
该操作可能如下所示:
当您成功验证用户身份时,将返回名为“Welcome.cshtml”/“Welcome.aspx”的视图,否则会从提交表单的位置重定向。
注意:引用者可能为空(例如,如果不是像 fiddler 这样的浏览器或脚本发出请求),因此还需要进行一些错误处理。
I would go with a partial View (e.g. "_Login.cshtml" or "_Login.ascx") that can be placed on the MasterPage/_Layout. Inside the partial View you write a form tag that posts to an Action on a Controller (lets say "AuthController" and the action "LogIn"). To remember where you came from
This is how the action could look like this:
When you successfully authenticated the user the view named "Welcome.cshtml"/"Welcome.aspx" is returned otherwise redirected from where the form was submitted.
Note: The referer could be null (e.g. if not a browser like fiddler or a script is making the request) so there is a bit of error handling left.
这是一个古老的问题,但这基本上与我现在正在做的事情完全相同,而且我的搜索仍然没有显示出符合所有条件的答案;我不明白为什么像这样完全封装登录过程如此困难,但也许我只是缺少一个清晰编写的示例。
我的解决方案效果很好,只需
使用旧标准
System.Web.HttpContext.Current.Response.Redirect(url, true);
在登录过程的控制器中
...。发布它是因为它有效,它保持封装,并且比我见过的 return-a-view-having-a-Javascript-redirect 解决方案稍微不那么可怕,但我仍然希望更好地了解如何实现这一点以更 MVC 的方式进行打包。
Ancient question, but this is basically exactly the same thing as I'm doing right now, and my searches have still revealed no answers that match all criteria; I don't see why it is so hard to have the login process completely encapsulated like this, but maybe I'm simply missing a clearly written example.
My solution, which works perfectly, is to simply use the old standard
System.Web.HttpContext.Current.Response.Redirect(url, true);
...in the controller for the login process.
Posting it because it works, it maintains encapsulation, and it's slightly less horrible than the return-a-view-containing-a-Javascript-redirect solution I've seen, but I'd still like a better idea of how to achieve this sort of packaging in a more MVC way.