2010-03-08 91 views
3

我對MVC並不陌生,隨着我越來越多地涉足整個框架,我發現模型搭配器變得越來越難以維護。如何讓我的MVC Views,模型和模型粘合劑儘可能保持乾淨?

讓我解釋...

我寫一個基本的CRUD,在數據庫應用程序。我的域名模型將會非常豐富。爲了讓我的控制器儘可能瘦,我已經設置好了,這樣在創建/編輯命令時,操作的參數就是我的域模型的一個豐富的實例。爲此,我已經實現了一個自定義模型綁定器。

因此,該自定義模型聯編程序對視圖和模型非常具體。我決定重寫MVC 2附帶的DefaultModelBinder。在綁定到我的模型的字段只是一個文本框(或簡單的東西)的情況下,我只是委託給基本方法。然而,當我使用下拉菜單或更復雜的東西(用戶界面規定日期和時間是單獨的數據輸入字段,但對於該模型,它是一個屬性)時,我必須執行一些檢查和一些手動數據傳輸。

這樣做的最終結果是我在View和Binder之間有一些非常緊密的關係。我在架構上很好,但從代碼維護的角度來看,這是一場噩夢。

例如,我在這裏綁定的模型的類型爲Log(這是我將作爲Action的參數獲取的對象)。 「ServiceStateTime」是Log上的一個屬性。 「log.ServiceStartDate」和「log.ServiceStartTime」的形式值是完全任意的,來自兩個文本框的形式(Html.TextBox(「log.ServiceStartTime」,...))

protected override object GetPropertyValue(ControllerContext controllerContext, 
               ModelBindingContext bindingContext, 
               PropertyDescriptor propertyDescriptor, 
               IModelBinder propertyBinder) 
{ 
     if (propertyDescriptor.Name == "ServiceStartTime") 
     { 
      string date = bindingContext.ValueProvider.GetValue("log.ServiceStartDate").ConvertTo(typeof (string)) as string; 
      string time = 
       bindingContext.ValueProvider.GetValue("log.ServiceStartTime").ConvertTo(typeof (string)) as string; 
      DateTime dateTime = DateTime.Parse(date + " " + time); 
      return dateTime; 
     } 
     if (propertyDescriptor.Name == "ServiceEndTime") 
     { 
      string date = bindingContext.ValueProvider.GetValue("log.ServiceEndDate").ConvertTo(typeof(string)) as string; 
      string time = 
       bindingContext.ValueProvider.GetValue("log.ServiceEndTime").ConvertTo(typeof(string)) as string; 
      DateTime dateTime = DateTime.Parse(date + " " + time); 
      return dateTime; 
     } 

的Log.ServiceEndTime是一個類似的字段。

這對我來說不是很乾燥。首先,如果我將ServiceStartTime或ServiceEndTime重構爲不同的字段名稱,則可能會錯過文本字符串(儘管我選擇的重構工具R#非常適合這類事情,但它不會導致構建時失敗並且只會被手動測試所捕捉)。其次,如果我決定隨意更改描述符「log.ServiceStartDate」和「log.ServiceStartTime」,我會遇到同樣的問題。對我來說,運行時無提示錯誤是最糟糕的一種錯誤。

所以,我看到一對夫婦的選項,以幫助這裏,很想得到誰所遇到的一些問題的人的一些輸入:共同

  • 重構任何文本字符串的視圖和模型之間綁定到連接到我從控制器傳遞到aspx/ascx視圖的ViewModel對象的const字符串中。但是,這污染了ViewModel對象。
  • 提供圍繞所有交互的單元測試。我是單元測試的大支持者,並沒有開始豐富這個選項,但我有一種直覺,它不會讓我從腳部射擊中解脫出來。

如果很重要,系統中的日誌和其他實體使用Fluent NHibernate持久化到數據庫。我真的想保持我的控制器儘可能薄。

因此,這裏的任何建議都非常歡迎!

感謝

回答

1

您可以使用視圖模型:

class ViewModelClass 
{ 
    [DateValidationAttribute] 
    public property DateTime ServiceStartTimeDate { get; set; } 
    [TimeValidationAttribute] 
    public property DateTime ServiceStartTimeTime { get; set; } 
} 

DefaultModelBinder粘合劑不需要任何修改綁定這些字段。然後,你可以寫功能,這些領域結合起來:

class DateUtil 
{ 
    public static DateTime CombineDateAndTime(DateTime Date, DateTime Time); 
} 

然後你從數據庫中獲取實體:

var entity = context.GetUpdatedEntity(id); 
entity.ServiceStartTime = DateUtil.CombineDateAndTime(viewModel.ServiceStartTimeDate,viewModel.ServiceStartTimeTime); 

如果你真的想擁有它的模型綁定,你可以做這樣的:

public class DateAndTimeModelBinder : DefaultModelBinder 
{ 
    protected override object GetPropertyValue(ControllerContext controllerContext, 
              ModelBindingContext bindingContext, 
              PropertyDescriptor propertyDescriptor, 
              IModelBinder propertyBinder) 
    { 
     if (propertyDescriptor.PropertyType == typeof(DateTime)) 
     { 
      string time = bindingContext.ValueProvider.GetValue(CreateSubPropertyName(bindingContext.ModelName, propertyDescriptor.Name + "Time")).ConvertTo(typeof(string)) as string; 
      var date = base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder); 
      if ((date != null) && (time != null)) 
       return CombineDateAndTime(date, time); 
     } 
     return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder); 
    } 
} 

當日期時間字段被綁定,粘結劑看是否還有其他形式的現場與「時代」末(如果我們結合「ServiceStartTime」,它尋找「ServiceStartTimeTime」,讓您綁定日期POR 「ServiceStartTime」字段和時間部分改爲「」ServiceStartTimeTime「)。如果有的話,它會增加它的價值。你只寫一次,並且適用於每個領域。上面的代碼肯定不行,它需要一些調整,但顯示的想法。

+0

我一直在考慮越來越多這個ViewModel類。但我擔心的是,在大多數情況下,ViewModel和Model幾乎都是1比1,所以我會使架構複雜化。 – 2010-03-09 14:05:04

+0

@MBonig:所以你可以添加setter的屬性只給你的模型類。 「ServiceStartTimeTime」設置者將只設置時間部分,「ServiceStartTimeDate」將設置日期部分。你也可以使用這個ModelBinder,這是更好的解決方案。 – LukLed 2010-03-09 17:57:25