Серьезный n00b, предупреждающий здесь; щадите!
Таким образом, я закончил Ужин Компьютерного фаната Учебное руководство MVC, и я нахожусь теперь в процессе преобразования приложения VB.NET на ASP.NET MVC использование программы Ужина Компьютерного фаната как своего рода грубый шаблон.
Я использую "IsValid / GetRuleViolations ()" шаблон для идентификации входа недействительного пользователя или значений, которые нарушают бизнес-правила. Я использую LINQ для SQL и использую в своих интересах "OnValidate ()" рычаг, который позволяет мне выполнять проверку и выдавать исключение приложения после попытки сохранить изменения в базе данных через класс CustomerRepository.
Так или иначе все работает хорошо, за исключением того, что к тому времени, когда значения формы достигают моего метода проверки, недопустимые типы были уже преобразованы в или существующее значение по умолчанию. (У меня есть свойство "StreetNumber", которое является целым числом, хотя я предполагаю, что это было бы проблемой для DateTime или любых других нестрок также.)
Теперь, я предполагаю, что UpdateModel () метод выдает исключение и затем изменяет значение потому что HTML. ValidationMessage отображен рядом с полем StreetNumber, но мой метод проверки никогда не видит исходный вход. Существует две проблемы с этим:
В то время как HTML. ValidationMessage действительно сигнализирует, что что-то неправильно, в HTML нет никакой соответствующей записи. ValidationSummary. Если бы я мог бы даже заставить сообщение об исключении разоблачать там указание на недопустимый бросок или что-то, что было бы лучше чем ничего.
Мой метод проверки, который находится в моем Клиенте частичный класс, никогда не видит исходный ввод данных пользователем, таким образом, я не знаю, является ли проблемой недостающая запись или недопустимый тип. Я не могу выяснить, как я могу сохранить свою логику проверки хорошей и аккуратной в одном месте и все еще получить доступ к значениям формы.
Я мог, конечно, записать некоторую логику в Представлении, которое обрабатывает ввод данных пользователем, однако который походит на полную противоположность того, что я должен делать с MVC.
Мне нужен новый шаблон проверки или есть ли некоторый способ передать исходные значения формы моему образцовому классу для обработки?
Код CustomerController
// POST: /Customers/Edit/[id]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues)
{
Customer customer = customerRepository.GetCustomer(id);
try
{
UpdateModel(customer);
customerRepository.Save();
return RedirectToAction("Details", new { id = customer.AccountID });
}
catch
{
foreach (var issue in customer.GetRuleViolations())
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
return View(customer);
}
Это было бы хорошей отправной точкой: Скотт Гу - ASP.NET MVC 2: Проверка модели
Но я бы сказал, что это плохо Практикуйтесь в привязке данных к объектам вашего домена.
Мой личный подход заключался бы в использовании моделей представления POCO с добавлением атрибутов проверки DataAnnotations для проверки (это упрощает подключение проверки на стороне клиента позже).Вы также можете создать собственные атрибуты ValidationAttributes для подключения к проверке привязки данных.
Если он действителен после привязки данных к вашему объекту POCO, передайте ему службу, которая выполняет более сложную бизнес-проверку. После того, как эта проверка пройдет, передайте ее другой службе (или той же службе), которая передает значения в объект вашего домена, а затем сохраняет их.
Я не знаком с шаблоном Linq to SQL GetRuleViolations, поэтому не стесняйтесь заменять один из моих шагов шаблоном, который подходит.
Я постараюсь объяснить это здесь.
Модель представления POCO:
public class EditCustomerForm
{
[DisplayName("First name")]
[Required(ErrorMessage = "First name is required")]
[StringLength(60, ErrorMessage = "First name cannot exceed 60 characters.")]
public string FirstName { get; set; }
[DisplayName("Last name")]
[Required(ErrorMessage = "Last name is required")]
[StringLength(60, ErrorMessage = "Last name cannot exceed 60 characters.")]
public string LastName { get; set; }
[Required(ErrorMessage = "Email is required")]
[RegularExpression(@"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
@"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
@".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$",
ErrorMessage = "Email appears to be invalid.")]
public string Email { get; set; }
}
Логика контроллера
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, EditCustomerForm editCustomerForm)
{
var editCustomerForm = CustomerService.GetEditCustomerForm(id);
return View(editCustomerForm);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, EditCustomerForm editCustomerForm)
{
try
{
if (Page.IsValid)
{
//Complex business validation that validation attributes can't handle
//If there is an error, I get this method to throw an exception that has
//the errors in it in the form of a IDictionary<string, string>
CustomerService.ValidateEditCustomerForm(editCustomerForm, id);
//If the above method hasn't thrown an exception, we can save it
//In this method you should map the editCustomerForm back to your Cusomter domain model
CustomerService.SaveCustomer(editCustomerForm, id)
//Now we can redirect
return RedirectToAction("Details", new { id = customer.AccountID });
}
//ServiceLayerException is a custom exception thrown by
//CustomerService.ValidateEditCusotmerForm or possibly .SaveCustomer
catch (ServiceLayerException ex)
{
foreach (var kvp in ex.Errors)
ModelState.AddModelError(kvp.Key, kvp.Value);
}
catch (Exception ex) //General catch
{
ModelState.AddModelError("*", "There was an error trying to save the customer, please try again.");
}
return View(editCustomerForm);
}
Ясно как грязь? Если вам нужны дополнительные разъяснения, просто дайте мне знать: -)
Опять же, это всего лишь мой подход. Вы могли бы просто подписаться на статью Скотта Гу, на которую я ссылался, а затем продолжить.
HTHs,
Чарльз