Я работал над этой проблемой и думаю, что нашел достойное решение. Вот мои надуманные бизнес-требования. Создайте экран входа, который не обновляется при отправке формы. Если пользователь не может войти в систему, отобразите сообщение для пользователя. Имя пользователя и пароль должны быть введены. Имя пользователя не может содержать пробелов. Если пользователь не вводит имя пользователя или пароль, отображается ошибка.
Вот некоторые технические требования. Валидация должна использовать аннотацию данных в модели. Проверка должна быть СУХОЙ (не повторять себя). Проверка на стороне клиента должна проверять имя пользователя и пароль перед отправкой данных. Json должен быть возвращен клиенту с любыми ошибками, которые могли быть обнаружены на сервере.
Вот модели. Первый - это LoginModelView. Он имеет два свойства: имя пользователя и пароль. Оба свойства имеют атрибуты аннотации данных. Эти атрибуты будут использоваться при проверке на стороне клиента и на стороне сервера. ErrorModelView будет использоваться для возврата результатов входа в систему с любыми ошибками, которые могли быть идентифицированы.
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
namespace TestClientSideValidation.Models
{
public class LoginModelView
{
[Required(ErrorMessage = "UserName Is Required")]
[RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")]
[StringLength(12, MinimumLength = 3)]
public string UserName { get; set; }
[Required(ErrorMessage = "Password Is Required")]
[StringLength(20, MinimumLength = 3)]
public string Password { get; set; }
public bool RememberMe { get; set; }
}
public class ErrorModelView
{
public bool IsLogInSuccessful { get; set; }
public List<Error> Errors { get; set; }
}
public class Error
{
public string Key { get; set; }
public List<string> Messages { get; set; }
}
}
Класс AccountServices имитирует проверку учетных данных для входа в хранилище данных. Сначала мы проверяем, действительно ли текущее состояние модели. Если он недействителен, то нет причин для доступа к хранилищу данных. Если состояние модели действительно, проверьте учетные данные для входа в хранилище данных. Если учетные данные неверны, добавьте Ошибка в ModelState.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using TestClientSideValidation.Models;
namespace TestClientSideValidation.Services
{
public static class AccountServices
{
public static void ValidateLogin(ModelStateDictionary modelState, LoginModelView loginModelView)
{
if (modelState.IsValid) //If modelState is Invalid there is not reason tho check the login is valid
{
if (loginModelView.UserName != "Admin" || loginModelView.Password != "Password")
{
modelState.AddModelError("_FORM", "The username or password provided is incorrect.");
}
}
}
}
}
Контроллер содержит два действия, Login и JsonLogin. Действие входа очень просто; создайте пустую LoginViewModel и передайте его представлению Login.
LoginJson выполняет большую часть нашей работы в этом приложении. Первоначально переданный LoginModelView проверяется на соответствие AccountSerices.Validation, которое мы создали ранее. Затем ModelState проверяется. Если состояние режимов недопустимо, переместите данные из ModelState в ErrorModelView. Прости меня за LINQ, я знаю, это довольно некрасиво. Может быть, я сделаю рефакторинг или еще что-нибудь. Кроме того, для ModelViewError.IsLogInSuccessful установлено значение false. Затем мы отправляем обратно представление модели, используя метод Json, для сериализации данных в Json.
Если все верно, FormsAuthenticationTicket создан, установите для ErrorModelView.IsLogInSuccessful значение true и верните Json обратно клиенту.
using System.Web;
using System.Web.Mvc;
using TestClientSideValidation.Models;
using TestClientSideValidation.Services;
using System.Web.Security;
using System;
using System.Linq;
namespace TestClientSideValidation.Controllers
{
public class AccountController : Controller
{
public ActionResult Login()
{
LoginModelView loginModelView = new LoginModelView();
return View(loginModelView);
}
[System.Web.Mvc.OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public virtual JsonResult LoginJson(LoginModelView loginModelView)//Share Model
{
ErrorModelView modelView = new ErrorModelView();
AccountServices.ValidateLogin(ModelState, loginModelView);
if (!ModelState.IsValid)
{
modelView.Errors = (from d in
(from ms in ModelState
where ms.Value.Errors.Count > 0
select ms
).ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray())
select new Error
{
Key = d.Key,
Messages = d.Value.ToList()
}).ToList();
modelView.IsLogInSuccessful = false;
return Json(modelView, JsonRequestBehavior.AllowGet);
}
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket
(
1,
loginModelView.UserName,
DateTime.Now,
DateTime.Now.AddDays(30),
loginModelView.RememberMe,
loginModelView.UserName.ToString()
);
string encTicket = FormsAuthentication.Encrypt(authTicket);
this.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
modelView.IsLogInSuccessful = true;
return Json(modelView, JsonRequestBehavior.AllowGet);
}
}
}
Последняя часть этого примера отображает представление и принимает возвращаемый JSON из контроллера действий. Первая строка идентифицирует строго типовую модель LoginModelView. Этот режим является тем, который мы создали ранее и который включает атрибуты UserName и Passwords и Validation. Чтобы валидация и вызовы Ajax работали, нам нужно включить несколько файлов JavaScript. Если вы перейдете к концу этого блока кода, вы заметите, что мы вызываем Ajax.BeginForm при отправке страницы. Это вызовет действие LoginJson и передаст значения в форме. Также следующая функция JavaScript, которую я объявил ранее в этом блоке кода, также будет запускаться в определенные моменты процесса; Только OnSuccess имеет код. В этом примере @ Html.TextBoxFor и @ Html.ValidationMessageFor совершают магию. Вот тут и начинается проверка на стороне клиента.
Когда Json переустанавливается из действия LoginJson, запускается функция JavaScript OnSucces. При наличии ошибок вызывается функция DisplayErrors, которая просматривает ошибки и добавляет их в блок ошибок. Если ошибок нет, предупредите пользователя об успешном входе.
@model TestClientSideValidation.Models.LoginModelView
<html>
<head>
<title>Login</title>
<script src="/Scripts/jquery-1.4.4.min.js" type="text/javascript"></script>
@*This is need for validation*@
<script src="/Scripts/jquery.validate.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js" type="text/javascript"></script>
@*This is need for validation Ajax.BeginForm*@
<script src="/Scripts/jquery.unobtrusive-ajax.js" type="text/javascript"></script>
<script type="text/javascript">
function OnSuccess(e) {
if (e.IsLogInSuccessful) {
ClearErrors();
alert("You logged in");
}
else {
ClearErrors();
DisplayErrors(e.Errors);
}
}
function OnFailure(e) {
}
function OnComplete(e) {
}
function DisplayErrors(errors) {
for (error in errors) {
for (message in errors[error].Messages) {
if (message != null && message != "") {
$("#Errors").append(errors[error].Messages[message]);
}
}
}
}
function ClearErrors() {
$("#Errors").text("");
}
</script>
</head>
<body>
<div>
<div id="Errors"></div>
@using (Ajax.BeginForm("LoginJson", new AjaxOptions { HttpMethod = "Post", OnFailure = "OnFailure", OnSuccess = "OnSuccess", OnComplete = "OnComplete" }))
{
<div>
@Html.LabelFor(m => m.UserName)
@Html.TextBoxFor(m => m.UserName)
@Html.ValidationMessageFor(m => m.UserName)
</div>
<div>
@Html.LabelFor(m => m.Password)
@Html.TextBoxFor(m => m.Password)
@Html.ValidationMessageFor(m => m.Password)
</div>
<input type="submit" id="loginDialog_submitForm" value="Submit Form" />
}
</body>
</html>
Во-первых, извините за расширенный пример. Но, надеюсь, это поможет некоторым людям. Или, если есть лучший или другой способ сделать это, некоторые ответят.
Таким образом, это решает основную проблему, когда все правила проверки находятся в одном месте. Я также считаю, что мы выполняем надуманные бизнес / технические требования.
Я пытался сделать это очень просто, и с этим есть много способов улучшить это, но я считаю, что это отличное начало. В настоящее время я использую это с пользовательским интерфейсом JQuery, делая представление частичным и отображая его в модальном диалоговом окне.
Опять же, я надеюсь, что это поможет людям.
Обновление
Убедитесь, что в файле web.config
указано следующее
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
BarDev