2012-07-12 58 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