Создаем ValidationService для веб-сайта на ASP.NET MVC

суббота, 3 октября 2009, Bobasoft

Для примера будем использовать Validation Application Block из библиотеки Microsoft Enterprise Lilbrary 4.1, его можно скачать

Как будет реализована валидация:

Чтобы наш веб-сайт не зависел от самой реализации валидации, нам нужно это все обобщить. Для этого нужно будет создать интерфейс, от которого будет наследоваться класс, который будет производить валидацию данных. Также, мы должны сами придумать в каком виде будет возвращаться результат этой проверки. И потом нам будет уже не важно, кто и как реализую саму валидацию, мы будет работать только с интерфейсом… который умеет делать то что нам нужно.. и возвращает нам результат точно в том виде, который мы определили.

Работаем с проектом Core.

Дальнейшая работа будет производиться по этому пути: Infrastructure/ValidationService.

Результат проверки:

Когда мы проверяем некий объект на правильность данных, в случае не прохождения ее, результат может содержать в себе несколько ошибок, но их можно привести к определенному виду.

Так каждая ошибка должна будет содержать в себе такие данные:

  • Key – имя параметра, для которого произошла ошибка.
  • Message – описание этой ошибки.

И также нам понадобиться объект, который будет содержать набор этих ошибок – он и будет нашим результат валидации.

И так, создадим сначала класс ошибки: файл “RuleViolation.cs”

public class RuleViolation
{
	public RuleViolation(string key, string message)
	{
		Key = key;
		Message = message;
	}

	public string Key { get; private set; }
	public string Message { get; private set; }
}

Дале создаем класс ответа валидационного процесса: файл: “ValidationServiceResult.cs”

public class ValidationServiceResult
{
	public ValidationServiceResult(IEnumerable errors)
	{
		_errors = new List(errors.Count());
		if (errors != null)
			_errors.AddRange(errors);
	}

	/// 
	/// if therer no error - return True
	/// 
	public bool IsValid
	{
		get
		{
			return (_errors.Count == 0);
		}
	}

	public IEnumerable Errors
	{
		get { return _errors.AsReadOnly(); }
	}

	private List _errors;
}

Он будет хранить все ошибки которые произошли во время валидации.

-------------------------------------------------------

Далее создадим интерфейс валидационного сервиса: файл: “IValidationService.cs”

public interface IValidationService
{
	/// 
	/// Так мы просто можем узнать иль объект валидный
	/// 
	bool IsValid(T instance);

	/// 
	/// Возвращает результат валидации, в определеной нами форме
	/// 
	ValidationServiceResult Validate(T instance);
}

На данном этапе у нас вот такой проект:

Работаем с проектом DomainModel.

Теперь давайте создадим репозитарий который будет управлять данными, и сам класс данных.

Класс данных: создадим файл “Person.cs” в каталоге DomainObject

public class Person
{
	public string Name { get; set; }
	public string Email { get; set; }
}

И репозитарий только с одним методом:

файл: “PersonRepository.cs” в каталоге Repositories.

using DomainModel.DomainObjects;
using Core.Infrastructure.ValidationService;

public class PersonRepository
{
	private IValidationService _validationService;

	public void Save(Person person)
	{
		/// TODO: проверить или person содержит правельные данных
		/// если да, то сохранить гдето,
		/// если нет, то выкинуть исключение содержащее результат валидации
	}
}

Также нам нужно будет добавить в References текущего проекта (DomainObject) бибилиотеку dll из Core проекта.

Если все сделали правельно… сейчас должно все скомпилироватся.

Работаем с проектом EnterprizeLibrary.

Для начала добавим в References сборку Enterprise Library Validation Application Block (Microsoft.Practices.EnterpriseLibrary.Validation.dll). А также сборку из проекта Core.

Теперь в каталоге ValidationService создадим класс, который будет реализовать интерфейс IValidationService. В этом примере, он какраз и будет производить проверку обьектов, и возвращать соответствующий результат.

using Microsoft.Practices.EnterpriseLibrary.Validation;
using Core.Infrastructure.ValidationService;

public class ValidationService : IValidationService
{
	public bool IsValid(T target)
	{		
		Validator personValidator = ValidationFactory.CreateValidator();
		ValidationResults results = personValidator.Validate(target);

		return results.IsValid;
	}

	public ValidationServiceResult Validate(T target)
	{
		Validator personValidator = ValidationFactory.CreateValidator();
		ValidationResults results =  personValidator.Validate(target);

		List errors = new List();

		foreach (var result in results)
			errors.Add(new RuleViolation(result.Key, result.Message));

		return new ValidationServiceResult(errors);
	}
}

В этом классе мы использум функциональность валидации обьектов, которую предоставляет Майкрософт. В IsValid функции все довольно ясно, мы валидирем обьект, дальше обращаемся к обьект Майкрософта ValidationResults, к свойству IsValid, которое возращает True если объект валидный.

А вот ф-ция Validate должна возврать набор ошибок, в определном нами формате, поэтому, нам нужно пербрать каждую ошибку валидации в results объекте, и создать соответствующую ошибку RuleViolation для нашего ValidationServiceResult.

Теперь мы можем проверить любой обьект на правельность введенных данных.

Вернемся к нашему PersonRepository.

Модифицируем метод Save(…) чтобы он уже умел проверять объект и вслучае нахождения хотя бы одной ошибки, бросать исключение.

public void Save(Person person)
{
	if (!_validationService.IsValid(person))
		throw new Exception();

	// TODO: Save person to somewhere
}

А также сделаем так, чтобы при создании этого репозитория создавался нужный нам _validationService:

using DomainModel.DomainObjects;
using Core.Infrastructure.ValidationService;
using EnterpriseLibrary.ValidationService;

public class PersonRepository
{
	private IValidationService _validationService = new ValidationService();

	public void Save(Person person)
	{
		if (_validationService.IsValid(person))
			throw new Exception();

		// TODO: Save person to somewhere
	}
}

Также нам нужно будет добавить dll проекта EnterprizeLibrary.

На текущий момент у нас вот такой проект:

Теперь перейдем к проекту HelloValidation:

Создадим контроллер: PersonController в каталоге “Controllers”.

using DomainModel.Repositories;
using DomainModel.DomainObjects;
using Core.Infrastructure.ValidationService;
using EnterpriseLibrary.ValidationService;

public class PersonController : Controller
{
	private PersonRepository _repository;

	public PersonController()
	{
		_repository = new PersonRepository();
	}

	/// 
	/// Вызовется когда пользователь 
	/// запросит страницу /Person/Validation 
	/// из строки браузера
	/// 
	/// 
    [AcceptVerbs(HttpVerbs.Get)]
	public ViewResult Validation()
	{
		return View();
	}

	/// 
	/// Вызовется когда пользователь
	/// введет данные в форму и нажмет кнопку Submit
	/// 
	/// 
	[AcceptVerbs(HttpVerbs.Post)]
	public ActionResult Validation(Person person)
	{
		try
		{
			// Пытаемся сохранить объект person
			_repository.Save(person);

			/// В случае удачного сохраниея, перенаправляем 
              /// пользователя на главную страницу
			return RedirectToAction("Index", "Home");
		}
		catch (System.Exception ex)
		{
			/// Обьект не прошел процеса валидации
			/// Вызовем функцию валидировщика, чтобы узнать какие ошибки были

			ValidationServiceResult result = 
                  new ValidationService().Validate(person);

			/// и дальше запишем эти все ошибки в ModelState, 
			/// чтобы они потом показались на экране
			foreach (var error in result.Errors)
				ModelState.AddModelError(error.Key, error.Message);

			return View(person);
		}
	} 
}

И нужно будет добавить все три dll остальных проектов в решении:

Core.dll, EnterpriseLibrary.dll, DomainModel.dll.

Теперь создадим View для нашого котроллера:

Выставим вот такие настройки:

Студия нам создаст какраз то что нужно)))))

Теперь мы можем запустить проект, зайти по адрессу /Person/Validation ввести данные на нажать кнопку Save… и мы увидем что сразу перенаправимя на главную странницу, даже если мы ввели неверные данные… или вообще ничего не ввели…

Это потому-что мы еще не добавили логику проверки.

Вернемся к нашему классу Person в проекте DomainModel. И воспользуемя тем, что нам предлагает майкрософт: добавим атриббуты валидации для каждого из свойств: (сначала также добавим сборку Microsoft.Practices.EnterpriseLibrary.Validation.dll, о которой упоминалось ранее, в текущий проект DomainModel)

using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;

public class Person
{
	[StringLengthValidator(1, 25, 
MessageTemplate = "Имя должно содержать от {3} до {5} символов")]
	public string Name { get; set; }

	[RegexValidator(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", 
MessageTemplate = "Invalid E-mail address")]
	public string Email { get; set; }
}

Перезапускаем проект… и О Чудо!)) при вводе неправельных данных, нам отображается ошибка:

А когда вы введете правельные данные, то будет перенаправление на главную страницу…

Теперь, если мы захотим изменить проверку валидации: добавить или удалит какието условия, нам нужно будет только изменить класс Person. А если мы захотим вообще переделать алгоритм проверки, мы можем слекостью подменить ValidationService на другой)))…

-------------------------------------------------------------

Многие вещи тут упускались, ради упрощения примера. Так например репозиторий не должен создавать сам обьект валидации… его нужно передавать в конструктор с помощью IoC.

Надейюсь этот пост вам помог)))... Замечания и предложения приветствуются)))

WBR,

Bobasoft

Компании из статьи


Microsoft Украина


Сайт:
http://www.microsoft.com/ukr/ua/

Microsoft Украина Украинское подразделение компании Microsoft.

Ищите нас в интернетах!

Комментарии

Свежие вакансии