2012-02-18 43 views
7

我剛開始使用ViewModels。你們可以看看這段代碼,看看我是否遵循最佳做法?有什麼不尋常的東西嗎?你會以不同的方式進行驗證嗎?ASP.NET MVC中的ViewModel實現 - 此代碼是否是最佳實踐?

對不起,如果代碼很冗長(有太多的零件)。我試圖讓它儘可能容易理解。

謝謝!

模型

public class CustomerModel 
    { 
    [Required(ErrorMessage="Primer nombre!")] 
    public string FirstName { get; set; } 

    [Required(ErrorMessage="Segundo nombre!")] 
    public string LastName { get; set; } 

    [Required(ErrorMessage="Edad")] 
    public int? Age { get; set; } 

    public string State { get; set; } 
    public string CountryID { get; set; } 

    [Required(ErrorMessage="Phone Number")] 
    public string PhoneNumber { get; set; } 
    } 

視圖模型

public class CustomerViewModel 
    { 
    public CustomerModel Customer { get; set; } 

    public string Phone1a { get; set; } 
    public string Phone1b { get; set; } 
    public string Phone1c { get; set; } 
    } 

控制器

public ActionResult Index() 
    { 
     CustomerViewModel Customer = new CustomerViewModel() 
     { 
     Customer = new CustomerModel(), 
     }; 


     return View(Customer); 
    } 


    [HttpPost] 
    public ActionResult Index(CustomerViewModel c) 
    { 

     //ModelState.Add("Customer.PhoneNumber", ModelState["Phone1a"]); 

     // Let's manually bind the phone number fields to the PhoneNumber properties in 
     // Customer object. 
     c.Customer.PhoneNumber = c.Phone1a + c.Phone1b + c.Phone1c; 

     // Let's check that it's not empty and that it's a valid phone number (logic not listed here) 
     if (!String.IsNullOrEmpty(c.Customer.PhoneNumber)) 
     { 
     // Let's remove the fact that there was an error! 
     ModelState["Customer.PhoneNumber"].Errors.Clear(); 
     } // Else keep the error there. 

     if (ModelState.IsValid) 
     { 
     Response.Write("<H1 style'background-color:white;color:black'>VALIDATED</H1>"); 
     } 
     return View("Index", c); 
    } 

    } 

V iew

@model MVVM1.Models.CustomerViewModel 

@using (Html.BeginForm("Index", "Detail")) 
{ 
    <table border="1" cellpadding="1" cellspacing="1"> 
    <tr> 
     <td>@Html.LabelFor(m => m.Customer.FirstName)</td> 
     <td> 
     @Html.TextBoxFor(m => m.Customer.FirstName) 
     @Html.ValidationMessageFor(m => m.Customer.FirstName) 
     </td> 
    </tr> 
    <tr> 
     <td>@Html.LabelFor(m => m.Customer.LastName)</td> 
     <td> 
     @Html.TextBoxFor(m => m.Customer.LastName) 
     @Html.ValidationMessageFor(m => m.Customer.LastName) 
     </td> 
    </tr> 
    <tr> 
     <td>@Html.LabelFor(m => m.Customer.Age)</td> 
     <td> 
     @Html.TextBoxFor(m => m.Customer.Age) 
     @Html.ValidationMessageFor(m => m.Customer.Age) 
     </td> 
    </tr> 

    <tr> 
     <td>@Html.LabelFor(m => m.Customer.PhoneNumber)</td> 
     <td width="350"> 
     @Html.TextBoxFor(m => m.Phone1a, new { size="4", maxlength="3" }) 
     @Html.TextBoxFor(m => m.Phone1b) 
     @Html.TextBoxFor(m => m.Phone1c) 
     <div> 
     @Html.ValidationMessageFor(m => m.Customer.PhoneNumber) 
     </div> 
     </td> 
    </tr> 
    <tr> 
     <td></td> 
     <td> 
     <input type="submit" value="Submit" /></td> 
    </tr> 
    </table> 
} 

回答

2

有一件事情是這樣的:

if (ModelState.IsValid) 
    { 
    Response.Write("<H1 style'background-color:white;color:black'>VALIDATED</H1>"); 
    } 
    return View("Index", c); 

記住視圖模式有利於將數據傳遞到您的控制器和回到你的模型。我建議你爲視圖模型添加一個IsValid屬性,然後將其設置爲true而不是調用Response.Write。然後,只需添加到您的局部視圖的頂部:

@if (Model.IsValid) 
{ 
    <H1 style'background-color:white;color:black'>VALIDATED</H1> 
} 

您也可以到ModelState中在你的觀點,但有人會說,是不是最佳做法。但是,如果你不想將屬性添加到模型的東西,你可以在你的視圖中看到你可以這樣做:

@if (ViewData.ModelState.IsValid) 

另一個挑剔的是MVC驗證屬性是使用通常用於在UI上驗證。該驗證可以在其他領域重用,但在某些情況下是不理想的。另外,您可能無法始終修改域模型。因此,讓我所有的UI驗證在一個地方,我通常包在我看來,我的模型域模型,所以你得到的東西是這樣的:

public class CustomerViewModel      
{      
    public CustomerModel Customer { get; set; } 

    [Required(ErrorMessage="Primer nombre!")]       
    public string FirstName 
    { 
     get { return Customer.FirstName; } 
     set { Customer.FirstName = value; } 
    } 
... 

這似乎是多餘的,是不是永遠值得的努力但在使用實體框架域模型或其他難於或不可能修改的類時,考慮一下是一個好習慣。

+0

真的好點。關於創建一個IsValid屬性的好主意。 – SaltProgrammer 2012-02-21 01:40:20

1

我會說你的ViewModel實現是非常標準的。您正在使用ViewModel作爲視圖和域模型之間的中間對象。這是一個很好的做法。

我唯一厭倦的是你如何處理模型錯誤,並且你的ViewModel應該有一些屬性。例如,你可能想使用RegularExpressionAttribute類:

,在跳出我
public class CustomerViewModel 
    { 
    public CustomerModel Customer { get; set; } 

    [RegularExpression(@"^\d{3}$")] 
    public string Phone1a { get; set; } 
    [RegularExpression(@"^\d{3}$")] 
    public string Phone1b { get; set; } 
    [RegularExpression(@"^\d{4}$")] 
    public string Phone1c { get; set; } 
    } 
+2

最後,這通常不會解決。模型幾乎總是會讓您不想向用戶顯示數據。你現在不能僅僅爲模型做編輯,而且你會冒着過帳的風險,並在提交時發佈。我知道這是很多映射,但我發現通常使用'簡單'查看模型更好 – 2012-02-18 03:59:44

+0

使用其他RegExp屬性的好主意。 – SaltProgrammer 2012-02-21 01:41:28

+0

CustomerModel實際上是否需要註釋來檢查合法性?我認爲只有ViewModel需要Requirement屬性。 – 2012-03-11 21:14:20

2

我剛剛得到了MVC的竅門,但我昨天研究了這個相同的主題,並得出結論,不應該直接在ViewModel中包含模型對象。所以我的理解是,將您的CustomerModel直接包含在CustomerViewModel中是一種不好的做法。

相反,您希望列出您希望包含在ViewModel中的CustomerModel中的每個屬性。然後你要麼想從CustomerModel數據手動映射到CustomerViewModel或使用像AutoMapper一個工具,它可以自動進行用一行代碼像這裏面的操作方法:

public ViewResult Example() 
{ 
    // Populate/retrieve yourCustomer here 
    Customer yourCustomer = new CustomerModel(); 

    var model = Mapper.Map<CustomerModel, CustomerViewModel>(yourCustomer); 

    return View(model); 
} 

在這種情況下, Mapper.Map將返回一個可以傳遞給View的CustomerViewModel。

您還需要在您的Application_Start方法如下:

Mapper.CreateMap<CustomerModel, CustomerViewModel>(); 

總的來說,我發現AutoMapper很容易去上班。當字段名稱匹配時它是自動的,如果它們不匹配,或者您有嵌套的對象,則可以在CreateMap行中指定這些映射。所以,如果你CustomerModel使用的地址對象,而不是單獨的屬性,你可以這樣做:

Mapper.CreateMap<CustomerModel, CustomerViewModel>() 
    .ForMember(dest => dest.StreetAddress, opt => opt.MapFrom(src => src.Address.Street)); 

請人糾正我,如果我錯了,因爲我剛開始我的周圍MVC頭爲好。