ASP.NET MVC: как я могу объяснить нарушение недопустимого типа конечному пользователю с помощью Html.ValidationSummary? - PullRequest
1 голос
/ 22 апреля 2010

Серьезное предупреждение n00b здесь; пожалуйста, помилуй!

Итак, я закончил Nerd Dinner MVC Tutorial , и сейчас я нахожусь в процессе преобразования приложения VB.NET в ASP.NET MVC с использованием программы Nerd Dinner как своего рода грубого шаблона.

Я использую шаблон «IsValid / GetRuleViolations ()», чтобы определить неверный ввод пользователя или значения, которые нарушают бизнес-правила. Я использую LINQ to SQL и использую ловушку OnValidate (), которая позволяет мне запускать проверку и генерировать исключение приложения при попытке сохранить изменения в базе данных через класс CustomerRepository.

В любом случае, все работает хорошо, за исключением того, что к тому времени, когда значения формы достигают моего метода проверки, недопустимые типы уже были преобразованы в значение по умолчанию или существующее значение. (У меня есть свойство "StreetNumber", которое является целым числом, хотя я думаю, что это будет проблемой для DateTime или любых других нестроковых значений.)

Теперь я предполагаю, что метод UpdateModel () генерирует исключение, а затем изменяет значение, потому что Html.ValidationMessage отображается рядом с полем StreetNumber, но мой метод проверки никогда не видит исходный ввод. Есть две проблемы с этим:

  1. Хотя Html.ValidationMessage действительно сигнализирует, что что-то не так, в Html.ValidationSummary нет соответствующей записи. Если бы я мог даже показать сообщение об исключении, указывающее на неверное приведение или что-то, что было бы лучше, чем ничего.

  2. Мой метод проверки, который находится в моем частичном классе Customer, никогда не видит исходный пользовательский ввод, поэтому я не знаю, является ли проблема отсутствующей записью или неверным типом. Я не могу понять, как сохранить правильную логику проверки в одном месте и при этом получить доступ к значениям формы.

Конечно, я мог бы написать некоторую логику в представлении, которое обрабатывает пользовательский ввод, однако это выглядит как полная противоположность тому, что я должен делать с 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);
    }

1 Ответ

2 голосов
/ 22 апреля 2010

Это было бы хорошей отправной точкой: Скотт Гу - ASP.NET MVC 2: Проверка модели

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

Мой личный подход заключается в использовании POCO моделей презентаций с атрибутами проверки DataAnnotations для проверки (это упрощает подключение проверки на стороне клиента в дальнейшем). Вы также можете создать свои собственные атрибуты ValidationAttributes, чтобы подключиться к проверке привязки данных.

Если он действителен после привязки данных к вашему объекту POCO, передайте ему услугу, которая выполняет более сложную проверку вашего бизнеса. После того, как проверка прошла успешно, передайте ее другой службе (или той же службе), которая передает значения в ваш объект домена и затем сохраняет ее.

Я не знаком с шаблоном GetRuleViolations Linq to SQL, поэтому не стесняйтесь заменить один из моих шагов тем шаблоном, где он подходит.

Я постараюсь объяснить это здесь.

Модель презентации 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
Charles

...