2011-10-30 47 views
34

我很好奇人們構建ViewModel的各種方式,以及他們爲什麼選擇這種方法。你如何填充/驗證你的ViewModels?

我可以在這裏想到幾種方法:

-1。注入庫 - 控制器將模型和映射加載到ViewModel。在這裏,ViewModel的構造函數可以採用各種集合來爲ex設置。在選擇列表中,例如:

 

public CustomerController(ISomeRepository repository) 
{ 
    _repository = repository; 
} 

public ActionResult Create() 
{ 
    CustomerCreateViewModel model = new CustomerCreateViewModel(_repository.GetShipTypes, 
                   _repository.GetStates); 
.. 
.. 
} 
 

-2。 ViewModelBuilder - 在控制器中注入或實例化一個注入庫的實例。通過一些所謂的像

>var orderViewModel = orderViewModelBuilder.WithStates().Build(orderId);

,或者

var orderViewModel = orderViewModelBuilder.WithStates().Build(orderId);

-3。直接在控制器(無需代碼 - 其凌亂)

-4。返回域模型,控制器則映射或視圖模型的一些其他服務(注射或沒有)(任何人都這樣做,以返回未明確指定的視圖模型/注意到作爲一個視圖模型生成器類?)


public JobCreateViewModel BuildJobCreateViewModel(int parentId) 
{ 
    JobCreateViewModel model = new JobCreateViewModel(); 
    model.JobStatus = _unitOfWork.JobRepository.GetJobStatuses(); 
    model.States=_unitOfWork.StateRepository.GetAll(); 
    return model; 
} 

現在在回程中 - 關於驗證視圖模型 - 您是從基礎ViewModel類繼承以進行標準驗證,還是在所有ViewModel之間複製驗證(例如數據註釋屬性),還是僅僅依靠服務器端驗證它可以全部通過你的域對象來驗證嗎?

其他?有什麼更好的?爲什麼?

編輯 根據下面的鏈接,我在Jimmy Bogard的ViewModels體系結構中找到了一篇不錯的文章。雖然它沒有直接解決上述問題,但它對於任何來這裏獲取ViewModel信息的人來說都是一個很好的參考。 http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/

+0

這裏有一個downvote - 只是好奇爲什麼 - 我可以澄清的任何東西? –

+4

在我的手機上,我試圖星星時無意中點擊了它 - 對不起。現在撤消已經太遲了。 – Jason

+0

ah不用擔心的話:) –

回答

14

我向控制器注入服務,而不是存儲庫,然後使用AutoMapper將其轉換爲視圖模型。在這種情況下,服務層的好處是它可以將一個或多個存儲庫中的多個簡單操作合併爲一個暴露域模型的操作。例如:

private readonly ICustomerService _service; 
public CustomerController(ICustomerService service) 
{ 
    _service = service; 
} 

[AutoMap(typeof(Customer), typeof(CustomerViewModel))] 
public ActionResult Create(int id) 
{ 
    Customer customer = _service.GetCustomer(id); 
    return View(customer); 
} 

在這個例子中是自動映射的自定義動作過濾器,我可以寫其中控制器動作之後執行,檢查返回的對象,並使用所定義AutoMapper映射到其映射到指定的目的地類型。所以視圖將相應的CustomerViewModel作爲模型類型。本來也等同於:

public ActionResult Create(int id) 
{ 
    Customer customer = _service.GetCustomer(id); 
    CustomerViewModel vm = Mapper.Map<Customer, CustomerViewModel>(customer); 
    return View(vm); 
} 

這只是實在是太多了管道和可以集中重複的代碼。

我還建議你看Jimmy Bogard的putting your controllers on a diet video

+0

謝謝Darin。我看到有人演示了類似的AutoMap屬性 - 我看到Jimmy有一個屬性。你爲這些視圖模型的客戶端驗證做了什麼(或者不是嗎?)並在它們之間共享驗證邏輯?你是否將你的倉庫注入你的服務層? –

+0

@AdamTuliper,我使用FluentValidation.NET進行服務器端驗證,並使用簡單的客戶端驗證場景(要求,日期大於,...)。對於更復雜的客戶端驗證場景(依賴屬性,...),我決定是否需要在客戶端處理它,並且如果需要爲這些場景執行客戶端驗證,我編寫自定義jquery驗證appender。就存儲庫到服務層而言,是的,服務層使用ctor注入來讓所有的存儲庫允許在域模型上執行簡單的CRUD操作。 –

+0

感謝達林,另一個很好的答案:) –

0

我們的方法是將存儲庫注入控制器並使用Automapper http://automapper.org/將其映射到ViewModel。我們的ViewModels包含數據註釋屬性,以允許客戶端進行驗證。

我們在存儲庫中調用返回域對象(實體框架)的方法。域對象被映射到ViewModel。我們傾向於使用相同的ViewModel進行編輯並添加,因此需要一次數據註釋。在最簡單的形式,它看起來像下面的代碼:

public ActionResult List(int custId, int projId) 
    { 
     var users = _userRepository.GetByCustomerId(custId); 
     var userList = Mapper.Map<IEnumerable<CMUser>, IEnumerable<UserListViewModel>>(users); 
     return View(userList); 
    } 
+0

但是版本庫沒有映射到視圖模型。必須在存儲庫中調用某個方法,以返回域對象或視圖模型。此外,如果對每個模型或共享位置使用不同的註釋,則這不包括。 –

+0

另外,如果使用相同的ViewModel進行編輯/添加,那麼您將如何處理默認情況下需要使用數據註釋的整數ID字段?如果從表單中遺漏,它將失敗validaton。 Ints默認是必需的,所以你必須初始化爲「創建」場景的0,否? –

1

我完成了一個項目,我們做了#4的變化。我們有一個注入控制器的服務類。服務類擁有存儲庫和模型構建器類(我們稱之爲模型工廠)的依賴關係。

控制器調用服務類,該類處理業務驗證邏輯,然後從相應的工廠中提取視圖模型。模型本身依靠數據註釋進行輸入驗證。

它對我們的團隊非常有用。有足夠的關注點分離,允許開發者在不相互影響的情況下開展工作,但足以應付可理解的事情。

這是我們第一次嘗試它,我們會堅持下去。我很想看看別人如何迴應。

+0

謝謝。所以你的服務類反過來被注入存儲庫?什麼是你的方法設置爲像前例。在服務類?您是如何處理跨多個但相似視圖模型的客戶端驗證的? (例如編輯與創建) –

+0

這與Darin下面的例子非常相似,我們有一個瘋狂的要求,我們不能使用開源軟件,所以我們不能使用Automapper。下次我們將用automapper替換視圖模型工廠。我們使用Display和Editor模板來爲相同模型的不同視圖提供服務,數據註釋爲我們提供了我們需要的所有驗證。 – Jason

+0

模型構建器類從構造函數參數(服務處理存儲庫對象)或模型構建器直接使用存儲庫本身接收存儲庫對象?你能提供一些非常簡單的例子嗎? – Muflix

0

我使用了一個服務層,它隱藏了控制器從服務方法返回ViewModel的域模型。這使我可以在不影響客戶端的情況下更改域模型。