MVC 3 - 验证多行的值

时间:2012-07-12 19:00:16

标签: asp.net-mvc-3 validation

我有一个类似于此的MVC项目...

模型

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,如果它确实显示错误。

1 个答案:

答案 0 :(得分: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>
}

,最后一位是相应的编辑器模板,它将自动为Items集合的每个元素呈现,这样您甚至不需要编写for循环(~/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)