1

这里有严重的 n00b 警告;请怜悯!

所以我完成了Nerd Dinner MVC 教程,现在我正在使用 Nerd Dinner 程序作为一种粗略的模板,将 VB.NET 应用程序转换为 ASP.NET MVC。

我正在使用“IsValid / GetRuleViolations()”模式来识别无效的用户输入或违反业务规则的值。我正在使用 LINQ to SQL 并利用“OnValidate()”钩子,它允许我在尝试通过 CustomerRepository 类保存对数据库的更改时运行验证并引发应用程序异常。

无论如何,一切正常,除了当表单值到达我的验证方法时,无效类型已经转换为默认值或现有值。(我有一个整数的“StreetNumber”属性,尽管我认为这对于 DateTime 或任何其他非字符串也是一个问题。)

现在,我猜测 UpdateModel() 方法会引发异常,然后更改值,因为 Html.ValidationMessage 显示在 StreetNumber 字段旁边,但我的验证方法从未看到原始输入。这有两个问题:

  1. 虽然 Html.ValidationMessage 确实表明有问题,但 Html.ValidationSummary 中没有相应的条目。如果我什至可以让异常消息显示在那里,表明无效的演员阵容或总比没有好。

  2. 我的客户部分类中的验证方法永远不会看到原始用户输入,所以我不知道问题是缺少条目还是无效类型。我不知道如何在一个地方保持我的验证逻辑整洁,并且仍然可以访问表单值。

我当然可以在处理用户输入的视图中编写一些逻辑,但这似乎与我应该使用 MVC 做的完全相反。

我需要一个新的验证模式还是有什么方法可以将原始表单值传递给我的模型类进行处理?


客户控制器代码

    // 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);
    }

4

1 回答 1

2

这将是一个很好的起点:Scott Gu - ASP.NET MVC 2: Model Validation

但我建议将数据绑定到您的域对象是一种不好的做法。

我个人的方法是使用带有DataAnnotations 验证属性的POCO表示模型进行验证(这使得稍后连接客户端验证变得容易)。您还可以创建自己的 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);
}

清如泥?如果您需要更多说明,请告诉我:-)

同样,这只是我的方法。您可以先关注我首先链接到的 Scott Gu 的文章,然后再从那里开始。

HTH,
查尔斯

于 2010-04-21T23:48:35.877 回答