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

注: これはメモリから行われるため、完全に正確ではない可能性があります。

ご覧のとおり、これによりアイテムのリストが表示されます。項目はデータベースから取得されます。各アイテムには説明とグループ番号があります。ユーザーは、注文したい各アイテムの数を入力できます。

2 つ以上のアイテムを同じグループに含めることができます。たとえば、グループ 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 に答える