ASP.NET MVC:返回Redirect和ViewData

时间:2022-03-11 18:17:55

I have a login box in my MasterPage. Whenever the login information is not correct, I valorize ViewData["loginError"] to show the error message to the user.

我的MasterPage中有一个登录框。每当登录信息不正确时,我都会对ViewData [“loginError”]进行定值,以向用户显示错误消息。

Login is an action of the UserController, so the form that contains the login has action = "/User/Login".

Login是UserController的一个动作,因此包含登录的表单有action =“/ User / Login”。

As a user can try to log in from any page, in case of success I redirect him to his personal page, but in case of error I want him to stay on the very same page where he tried to login. I've found that this works:

由于用户可以尝试从任何页面登录,如果成功,我会将他重定向到他的个人页面,但如果出现错误,我希望他留在他尝试登录的同一页面上。我发现这有效:

return Redirect(Request.UrlReferrer.ToString());

but it seems that, as I'm not returning a proper view, the data on ViewData is lost, so I cannot show the error message.

但似乎,由于我没有返回正确的视图,ViewData上的数据丢失了,所以我无法显示错误消息。

Any suggestion on how to solve this and similar problems?

关于如何解决这个问题和类似问题的任何建议?

Thanks

谢谢

5 个解决方案

#1


14  

You probably want to use the TempData property, this will be persisted across to the next HTTP request.

您可能希望使用TempData属性,这将持久保存到下一个HTTP请求。

#2


2  

Why not handle the login via AJAX instead a full post? You could easily supply the status, a redirect URL, and any error messages via JSON.

为什么不通过AJAX处理登录而不是完整的帖子?您可以通过JSON轻松提供状态,重定向URL和任何错误消息。

public ActionResult Logon( string username, string password )
{
     ...

     // Handle master page login
     if (Request.IsAjaxRequest())
     {
          if (success)
          {
              return Json( new { Status = true, Url = Url.Action( "Index", "Home" ) } );
          }
          else
          {
              return Json( new { Status = false, Message = ... } );
          }
     }
     else // handle login page logon or no javascript
     {
          if (success)
          {
              return RedirectToAction( "Index", "Home" );
          }
          else
          {
              ViewData["error"] = ...
              return View("Logon");
          }
      }
  }

Client-side

客户端

  $(function() {
      $('#loginForm input[type=submit]').click( function() {
          $('#loginError').html('');
          $.ajax({
             url: '<%= Url.Action("Logon","Account") %>',
             dataType: 'json',
             type: 'post',
             data: function() { return $('#loginForm').serialize(); },
             success: function(data,status) {
                 if (data.Status) {
                     location.href = data.Url;
                 }
                 else {
                     $('#loginError').html( data.Message );
                 }
             }
          });
          return false;
      });
  });

#3


1  

Normally for most web sites, when user fail to authenticate (due to password or so), it will go to another page which help the user with (like password retrieve, or ask the user to sign up) which is rare to stay in the very same page. I think you can re-consider that you really need the navigation that you are using.

通常对于大多数网站,当用户无法进行身份验证时(由于密码等),它将转到另一个页面,帮助用户(如密码检索,或要求用户注册),这很少留在非常相同的页面。我想你可以重新考虑一下你真的需要你正在使用的导航。

OK, one solution if you really want to stick to your model, is that you can attach the login error to the URL. For example, http://www.example.com/index.aspx?login_error=1 indicates that error occurs, and you can use BEGIN_REQUEST (or HTTP Module) to capture this, and tell the model state about the error:

好的,如果你真的想坚持你的模型,一个解决方案就是你可以将登录错误附加到URL。例如,http://www.example.com/index.aspx?login_error = 1表示发生错误,您可以使用BEGIN_REQUEST(或HTTP模块)捕获此错误,并告知模型状态错误:

ModelState.AddModelError(...);

BTW, add model error is actually a more proper way to inform the view about any error rather than using ViewState (this is similar to throwing exception vs returning an integer about the execution result in old days).

顺便说一句,添加模型错误实际上是一种更恰当的方式来通知视图有关任何错误而不是使用ViewState(这类似于抛出异常vs返回关于过去执行结果的整数)。

While using AJAX to login (as suggested by tvanfosson) is perfectly achievable and it sometimes excel in user experience, classic full-post is still inreplacable (consider some user will disable javascript, or even on my dump WM6 handset that doesn't support javascript).

虽然使用AJAX登录(由tvanfosson建议)是完全可以实现的,它有时在用户体验方面表现优异,但经典的全帖仍然是不可替代的(考虑一些用户将禁用javascript,甚至在我的转储WM6手机上不支持javascript )。

#4


1  

I'm confused. Doesn't

我很困惑。不

return View();

just return the current page back to you?

只需将当前页面返回给您?

So in your case, when login fails, set your viewdata and call return View();

所以在你的情况下,当登录失败时,设置你的viewdata并调用return View();

i.e.

if (!FailedLogin) {
  //Go to success page
}else{
  //Add error to View Data or use ModelState to add error
  return View();
}

Are you using the [Authorize] decorator? The MVC login process auto prompts with the login page and then returns you to the controller action you were trying to execute. Cuts down on a lot of redirecting.

你在使用[授权]装饰器吗? MVC登录过程会自动提示登录页面,然后返回您尝试执行的控制器操作。削减了很多重定向。

#5


1  

The following example would hopefully help you out in resolving this issue:

以下示例有望帮助您解决此问题:

View.aspx

View.aspx

<%= Html.ValidationSummary("Login was unsuccessful. Please correct the errors and try again.") %>
<% using (Html.BeginForm()) { %>
    <div>
        <fieldset>
            <legend>Account Information</legend>
            <p>
                <label for="username">Username:</label>
                <%= Html.TextBox("username") %>
                <%= Html.ValidationMessage("username") %>
            </p>
            <p>
                <label for="password">Password:</label>
                <%= Html.Password("password") %>
                <%= Html.ValidationMessage("password") %>
            </p>
            <p>
                <%= Html.CheckBox("rememberMe") %> <label class="inline" for="rememberMe">Remember me?</label>
            </p>
            <p>
                <input type="submit" value="Log On" />
            </p>
        </fieldset>
    </div>
<% } %>

AccountController.cs

AccountController.cs

private bool ValidateLogOn(string userName, string password)
{
    if (String.IsNullOrEmpty(userName))
    {
        ModelState.AddModelError("username", "You must specify a username.");
    }
    if (String.IsNullOrEmpty(password))
    {
        ModelState.AddModelError("password", "You must specify a password.");
    }
    if (!MembershipService.ValidateUser(userName, password))
    {
        ModelState.AddModelError("_FORM", "The username or password provided is incorrect.");
    }
    return ModelState.IsValid;
}

You won't be able capture the information added in ViewData after Redirect action. so the right approach is to return the same View() and use ModelState for errors as mentioned by "xandy" as well.

在重定向操作后,您将无法捕获ViewData中添加的信息。所以正确的方法是返回相同的View()并使用ModelState进行错误,如“xandy”所述。

Hope this would give u a head start with form validation.

希望这会让您在表单验证方面领先一步。

#1


14  

You probably want to use the TempData property, this will be persisted across to the next HTTP request.

您可能希望使用TempData属性,这将持久保存到下一个HTTP请求。

#2


2  

Why not handle the login via AJAX instead a full post? You could easily supply the status, a redirect URL, and any error messages via JSON.

为什么不通过AJAX处理登录而不是完整的帖子?您可以通过JSON轻松提供状态,重定向URL和任何错误消息。

public ActionResult Logon( string username, string password )
{
     ...

     // Handle master page login
     if (Request.IsAjaxRequest())
     {
          if (success)
          {
              return Json( new { Status = true, Url = Url.Action( "Index", "Home" ) } );
          }
          else
          {
              return Json( new { Status = false, Message = ... } );
          }
     }
     else // handle login page logon or no javascript
     {
          if (success)
          {
              return RedirectToAction( "Index", "Home" );
          }
          else
          {
              ViewData["error"] = ...
              return View("Logon");
          }
      }
  }

Client-side

客户端

  $(function() {
      $('#loginForm input[type=submit]').click( function() {
          $('#loginError').html('');
          $.ajax({
             url: '<%= Url.Action("Logon","Account") %>',
             dataType: 'json',
             type: 'post',
             data: function() { return $('#loginForm').serialize(); },
             success: function(data,status) {
                 if (data.Status) {
                     location.href = data.Url;
                 }
                 else {
                     $('#loginError').html( data.Message );
                 }
             }
          });
          return false;
      });
  });

#3


1  

Normally for most web sites, when user fail to authenticate (due to password or so), it will go to another page which help the user with (like password retrieve, or ask the user to sign up) which is rare to stay in the very same page. I think you can re-consider that you really need the navigation that you are using.

通常对于大多数网站,当用户无法进行身份验证时(由于密码等),它将转到另一个页面,帮助用户(如密码检索,或要求用户注册),这很少留在非常相同的页面。我想你可以重新考虑一下你真的需要你正在使用的导航。

OK, one solution if you really want to stick to your model, is that you can attach the login error to the URL. For example, http://www.example.com/index.aspx?login_error=1 indicates that error occurs, and you can use BEGIN_REQUEST (or HTTP Module) to capture this, and tell the model state about the error:

好的,如果你真的想坚持你的模型,一个解决方案就是你可以将登录错误附加到URL。例如,http://www.example.com/index.aspx?login_error = 1表示发生错误,您可以使用BEGIN_REQUEST(或HTTP模块)捕获此错误,并告知模型状态错误:

ModelState.AddModelError(...);

BTW, add model error is actually a more proper way to inform the view about any error rather than using ViewState (this is similar to throwing exception vs returning an integer about the execution result in old days).

顺便说一句,添加模型错误实际上是一种更恰当的方式来通知视图有关任何错误而不是使用ViewState(这类似于抛出异常vs返回关于过去执行结果的整数)。

While using AJAX to login (as suggested by tvanfosson) is perfectly achievable and it sometimes excel in user experience, classic full-post is still inreplacable (consider some user will disable javascript, or even on my dump WM6 handset that doesn't support javascript).

虽然使用AJAX登录(由tvanfosson建议)是完全可以实现的,它有时在用户体验方面表现优异,但经典的全帖仍然是不可替代的(考虑一些用户将禁用javascript,甚至在我的转储WM6手机上不支持javascript )。

#4


1  

I'm confused. Doesn't

我很困惑。不

return View();

just return the current page back to you?

只需将当前页面返回给您?

So in your case, when login fails, set your viewdata and call return View();

所以在你的情况下,当登录失败时,设置你的viewdata并调用return View();

i.e.

if (!FailedLogin) {
  //Go to success page
}else{
  //Add error to View Data or use ModelState to add error
  return View();
}

Are you using the [Authorize] decorator? The MVC login process auto prompts with the login page and then returns you to the controller action you were trying to execute. Cuts down on a lot of redirecting.

你在使用[授权]装饰器吗? MVC登录过程会自动提示登录页面,然后返回您尝试执行的控制器操作。削减了很多重定向。

#5


1  

The following example would hopefully help you out in resolving this issue:

以下示例有望帮助您解决此问题:

View.aspx

View.aspx

<%= Html.ValidationSummary("Login was unsuccessful. Please correct the errors and try again.") %>
<% using (Html.BeginForm()) { %>
    <div>
        <fieldset>
            <legend>Account Information</legend>
            <p>
                <label for="username">Username:</label>
                <%= Html.TextBox("username") %>
                <%= Html.ValidationMessage("username") %>
            </p>
            <p>
                <label for="password">Password:</label>
                <%= Html.Password("password") %>
                <%= Html.ValidationMessage("password") %>
            </p>
            <p>
                <%= Html.CheckBox("rememberMe") %> <label class="inline" for="rememberMe">Remember me?</label>
            </p>
            <p>
                <input type="submit" value="Log On" />
            </p>
        </fieldset>
    </div>
<% } %>

AccountController.cs

AccountController.cs

private bool ValidateLogOn(string userName, string password)
{
    if (String.IsNullOrEmpty(userName))
    {
        ModelState.AddModelError("username", "You must specify a username.");
    }
    if (String.IsNullOrEmpty(password))
    {
        ModelState.AddModelError("password", "You must specify a password.");
    }
    if (!MembershipService.ValidateUser(userName, password))
    {
        ModelState.AddModelError("_FORM", "The username or password provided is incorrect.");
    }
    return ModelState.IsValid;
}

You won't be able capture the information added in ViewData after Redirect action. so the right approach is to return the same View() and use ModelState for errors as mentioned by "xandy" as well.

在重定向操作后,您将无法捕获ViewData中添加的信息。所以正确的方法是返回相同的View()并使用ModelState进行错误,如“xandy”所述。

Hope this would give u a head start with form validation.

希望这会让您在表单验证方面领先一步。