2012-07-12 77 views
1

我有类似这样的MVC项目验证值...MVC 3 - 多行

型号

Public Class ItemDetails 

    Public Property SerialNo As Integer 
    Public Property Description As String 
    Public Property GroupNo As Integer 
    Public Property Price As String 
    Public Property Quantity As Integer 

End Class 

控制器

Function ListItems() As ActionResult 

    ' GetItems retrieves the items from the database 
    Dim i As List(Of ItemDetails) = ItemsRepository.GetItems 

    Return View(i) 

End Function 

查看

@ModelType List(Of MyApp.ItemDetails) 

@Using Html.BeginForm() 
    Dim RowNo As Integer 
    For i As Integer = 0 To Model.Count - 1 
     RowNo = i 

     @Html.HiddenFor(Function(model) model(RowNo).SerialNo) 
     @Html.LabelFor(Function(model) model(RowNo).Description) 
     @Html.HiddenFor(Function(model) model(RowNo).GroupNo) 
     @Html.LabelFor(Function(model) model(RowNo).Price) 
     @Html.TextBoxFor(Function(model) model(RowNo).Quantity) 
    Next 
End Using 

注意:这是从内存完成的,因此可能不完全准确。

正如你所看到的,这显示了一个项目列表。这些项目从数据库中检索。每个项目都有一个说明和一个组号。用户可以输入他们想要订购的每件物品的数量。

两个或更多项目可以在同一组中。例如,可能存在:组1中的项目1,组1中的项目2,组2中的项目3和组3中的项目4.

当用户单击提交时,我想验证每个组的否合并数量不超过10.因此,在上面的示例中,如果我为项目1输入数量为7,则项目2的数量必须为3或更少。

我可以很容易地验证客户端。

有关验证此服务器端(何处以及如何)的最佳方法是什么?

我需要为每个组的数量总和不超过10的总和的总和,如果它显示错误。

回答

3

我个人使用FluentValidation.NET进行这类任务。它允许您将给定视图模型的复杂验证规则定义到单独的图层中,以流畅的方式表达它们,它具有绝对的非凡和无缝的integration with ASP.NET MVC,并允许您单独使用unit test your validation logic

如果你不想使用第三方库,你总是可以写一个自定义的验证属性,并用它来装饰你的视图模型属性。您可以引入一个视图模型,该模型将包含ItemDetails作为属性的集合,然后使用您的自定义验证程序修饰此属性。

public class ItemDetails 
{ 
    public int SerialNo { get; set; } 
    public string Description { get; set; } 
    public int GroupNo { get; set; } 

    // Please take a note that I have allowed myself 
    // to use the decimal datatype for a property called 
    // Price as I was a bit shocked to see String in your code 
    public decimal Price { get; set; } 

    public int Quantity { get; set; } 
} 

public class MyViewModel 
{ 
    [EnsureMaxGroupItems(10, ErrorMessage = "You cannot have more than 10 items in each group")] 
    public IList<ItemDetails> Items { get; set; } 
} 

和验证属性本身:

[AttributeUsage(AttributeTargets.Property)] 
public class EnsureMaxGroupItemsAttribute : ValidationAttribute 
{ 
    public int MaxItems { get; private set; } 

    public EnsureMaxGroupItemsAttribute(int maxItems) 
    { 
     MaxItems = maxItems; 
    } 

    public override bool IsValid(object value) 
    { 
     var items = value as IEnumerable<ItemDetails>; 
     if (items == null) 
     { 
      return true; 
     } 

     return items 
      .GroupBy(x => x.GroupNo) 
      .Select(g => g.Sum(x => x.Quantity)) 
      .All(quantity => quantity <= MaxItems); 
    } 
} 

,最后你的控制器动作将与视图模型工作:

public ActionResult ListItems() 
{ 
    var model = new MyViewModel 
    { 
     Items = ItemsRepository.GetItems() 
    }; 
    return View(model); 
} 

[HttpPost] 
public ActionResult ListItems(MyViewModel model) 
{ 
    if (!ModelState.IsValid) 
    { 
     return View(model); 
    } 

    ... 
} 

和它旁边相应的强类型的视图:

@model MyViewModel 
@Html.ValidationSummary() 
@using (Html.BeginForm()) 
{ 
    @Html.EditorFor(x => x.Items) 
    <button type="submit">Go go go</button> 
} 

最后一点是,它会自动被渲染为项目集合中的每个元素,让你甚至都不需要编写循环对应的编辑器模板(~/Views/Shared/EditorTemplates/ItemDetails.cshtml):

@model ItemDetails 
@Html.HiddenFor(x => x.SerialNo) 
@Html.LabelFor(x => x.Description) 
@Html.HiddenFor(x => x.GroupNo) 
@Html.LabelFor(x => x.Price) 
@Html.TextBoxFor(x => x.Quantity) 
+0

谢谢,我会给这个早上试试。看起来它会对我很好。注意:价格栏是小数(我只是从内存中输入)。 – 2012-07-12 19:50:29

+0

感谢验证属性为我完美工作。我只需要弄清楚现在是否有可能使客户端验证正确工作。例如,如果我对Quantity有Required属性,这将验证客户端。我有jQuery来验证Group No,但不知道如何让它像Required属性那样不显眼地工作。 – 2012-07-13 10:50:00

+0

@cw_dev,您需要使'EnsureMaxGroupItemsAttribute'实现IClientValidatable接口,然后为此规则编写一个自定义的不显眼的适配器。 – 2012-07-13 11:24:24