1

我有一个类似于此的 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 或更少。

我可以轻松地验证这个客户端。

验证此服务器端的最佳方法是什么(在哪里以及如何)?

对于每个组号,我需要合计 Quantity 的组合值不超过 10,如果它确实显示错误。

4

1 回答 1

3

我个人使用FluentValidation.NET来完成这类任务。它允许您将给定视图模型的复杂验证规则定义到单独的层中,以流畅的方式表达它们,它与 ASP.NET MVC 具有绝对奇妙的无缝集成,并允许您对验证逻辑进行独立的单元测试.

如果您不想使用第三方库,您可以随时编写自定义验证属性并用它装饰您的视图模型属性。您可以引入一个视图模型,该模型将包含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)
于 2012-07-12T19:02:02.670 回答