Asp.net mvc ASP.NET MVC:如何使用Html.ValidationSummary向最终用户解释无效类型冲突?

Asp.net mvc ASP.NET MVC:如何使用Html.ValidationSummary向最终用户解释无效类型冲突?,asp.net-mvc,validationsummary,Asp.net Mvc,Validationsummary,这里有严重的n00b警告;请宽恕我 因此,我完成了这项工作,现在正在将一个VB.NET应用程序转换为ASP.NETMVC,使用Nerd晚餐程序作为一种粗略的模板 我使用“IsValid/GetRuleViolations()”模式来识别无效的用户输入或违反业务规则的值。我使用LINQ to SQL,并利用“OnValidate()”钩子,该钩子允许我运行验证,并在尝试通过CustomerRepository类保存对数据库的更改时引发应用程序异常 无论如何,一切都很好,只是当表单值到达我的验证方法

这里有严重的n00b警告;请宽恕我

因此,我完成了这项工作,现在正在将一个VB.NET应用程序转换为ASP.NETMVC,使用Nerd晚餐程序作为一种粗略的模板

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

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

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

  • 虽然Html.ValidationMessage确实表示有问题,但Html.ValidationSummary中没有相应的条目。如果我甚至可以得到异常消息显示在那里,指示无效的强制转换或是比没有更好的东西

  • 我的客户分部类中的验证方法从未看到原始用户输入,因此我不知道问题是缺少条目还是无效类型。我不知道如何在一个地方保持我的验证逻辑整洁,并且仍然能够访问表单值

  • 我当然可以在视图中编写一些逻辑来处理用户输入,但是这似乎与我应该使用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);
        }
    

    这将是一个很好的起点:

    但我认为将数据绑定到域对象是一种不好的做法

    我个人的方法是使用带有todo验证的表示模型(这使得以后连接客户端验证变得很容易)。您还可以创建自己的ValidationAttributes,以连接到数据绑定验证中

    如果它在数据绑定到POCO对象后有效,则向它传递一个执行更复杂的业务验证的服务。验证通过后,将其传递给另一个服务(或同一个服务),该服务将值传输到域对象,然后保存它

    我不熟悉Linq到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);
    }
    
    [AcceptVerbs(HttpVerbs.Post)]
    公共操作结果编辑(int-id,editCustomerPerform editCustomerPerform)
    {
    var editCustomerPerform=CustomerService.geteditCustomerPerform(id);
    返回视图(EditCustomPerform);
    }
    [接受动词(HttpVerbs.Post)]
    公共操作结果编辑(int-id,editCustomerPerform editCustomerPerform)
    {
    尝试
    {
    如果(第页有效)
    {
    //验证属性无法处理的复杂业务验证
    //如果有错误,我会让这个方法抛出一个异常
    //以字典形式出现的错误
    CustomerService.ValidateEditCustomerPerform(编辑CustomerPerform,id);
    //如果上面的方法没有抛出异常,我们可以保存它
    //在这种方法中,您应该将editCustomerPerform映射回您的Cusomter域模型
    CustomerService.SaveCustomer(编辑CustomerPerform,id)
    //现在我们可以重定向了
    返回重定向到操作(“详细信息”,新的{id=customer.AccountID});
    }
    //ServiceLayerException是由
    //CustomerService.ValidateEditCustomerForm或可能的话.SaveCustomer
    捕获(ServiceLayerException ex)
    {
    foreach(变量kvp在ex.Errors中)
    AddModelError(kvp.Key,kvp.Value);
    }
    catch(Exception ex)//一般catch
    {
    AddModelError(“*”,“试图保存客户时出错,请重试。”);
    }
    返回视图(EditCustomPerform);
    }
    
    清晰如泥?如果您需要更多的澄清,请告诉我:-)

    再说一遍,这只是我的方法。你可以先看我链接的Scott Gu的文章,然后从那里开始

    HTHs,

    Charles

    哇,感谢您的详细回复!这将需要我一段时间来解析,但我一定会在沉浸其中后再查看。谢谢!您的帖子帮了我很大的忙!感谢您为我指明了正确的方向!