2012-02-18 10 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プロパティを追加し、Response.Writeを呼び出す代わりにtrueに設定することをお勧めします。その後、単にあなたの部分図の上部にこれを追加します。あなたはまた、あなたのビューでにModelStateに取得することができますが、いくつかは、それはベストプラクティスではありません主張

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

。あなたが何かのためにあなたのモデルにプロパティを追加したくない場合は、あなたは自分のビューで見ることができるあなただけのこの操作を行うことができます。

@if (ViewData.ModelState.IsValid) 

もうnitpicky事は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; } 
    } 
... 

これは冗長に見えるかもしれませんがして価値が常にの努力ではありませんEntity Frameworkドメインモデルまたは変更が困難または不可能なその他のクラスを使用する場合は、考慮することをお勧めします。

+0

本当に良い点。 IsValidプロパティを作成することをお勧めします。 – SaltProgrammer

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

これは通常、決してうまくいかない。モデルには、ほとんどの場合、ユーザーに表示したくないデータがあります。今ではモデルのエディタだけではできません。あなたは送信過多や投稿時の転記のリスクを負います。私はそれが多くのマッピングだと知っていますが、私は通常、単純なビューモデルを持っている方が良いことを発見しました –

+0

追加のRegExp属性を使用することをお勧めします。 – SaltProgrammer

+0

CustomerModelに実際に注釈が必要なのは、まったく有効性をチェックするためですか?私はViewModelだけが要件属性を必要とすると思う。 –

2

私はMVCのハングを自分で取得していますが、私はこの同じトピックを昨日調査し、ViewModelにモデルオブジェクトを直接含めるべきではないという結論に達しました。だから私の理解は、CustomerViewModelに直接CustomerModelを含めることは悪い習慣になるということです。

代わりに、ViewModelに含めるCustomerModelの各プロパティを一覧表示する必要があります。その後、手動でCustomerViewModelにCustomerModelからデータをマップしたり、アクションメソッドのこの内部のようなコードの行を使用して自動的にそれをしないAutoMapperのようなツールを使用したいのいずれか:この場合

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

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

    return View(model); 
} 

、 Mapper.Mapは、ビューに渡すことができるCustomerViewModelを返します。

また、あなたのApplication_Startメソッドで次のように含める必要があります。一般的には

Mapper.CreateMap<CustomerModel, CustomerViewModel>(); 

私が仕事を得るためにAutoMapperはかなり簡単ました。フィールド名が一致したときに自動的に実行されます。ネストされていないオブジェクトやネストされたオブジェクトがある場合は、CreateMap行にこれらのマッピングを指定できます。だからあなたのCustomerModelではなく個々のプロパティのアドレスオブジェクトを使用している場合、あなたはこれを行うだろう:私はちょうど同様にMVCのまわりで私の頭を取得していて私が間違っている場合

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

を誰も私を修正してください。

関連する問題