我正在處理的項目在域模型中有大量的貨幣屬性,我需要將這些格式設置爲$#,###.##
來傳輸視圖。我已經對可以使用的不同方法有了一些看法。一種方法可以是明確的值設置格式的視圖中,在"Pattern 1" from Steve Michelotti:使用自定義格式的ASP.NET MVC ViewModel映射
...但是這違反開始DRY principle非常快。
首選的方法似乎是在DomainModel和ViewModel之間的映射期間進行格式設置(根據ASP.NET MVC in Action第4.4.1節和第"Pattern 3"節)。使用AutoMapper,這會導致類似下面的一些代碼:
[TestFixture]
public class ViewModelTests
{
[Test]
public void DomainModelMapsToViewModel()
{
var domainModel = new DomainModel {CurrencyProperty = 19.95m};
var viewModel = new ViewModel(domainModel);
Assert.That(viewModel.CurrencyProperty, Is.EqualTo("$19.95"));
}
}
public class DomainModel
{
public decimal CurrencyProperty { get; set; }
}
public class ViewModel
{
///<summary>Currency Property - formatted as $#,###.##</summary>
public string CurrencyProperty { get; set; }
///<summary>Setup mapping between domain and view model</summary>
static ViewModel()
{
// map dm to vm
Mapper.CreateMap<DomainModel, ViewModel>()
.ForMember(vm => vm.CurrencyProperty, mc => mc.AddFormatter<CurrencyFormatter>());
}
/// <summary> Creates the view model from the domain model.</summary>
public ViewModel(DomainModel domainModel)
{
Mapper.Map(domainModel, this);
}
public ViewModel() { }
}
public class CurrencyFormatter : IValueFormatter
{
///<summary>Formats source value as currency</summary>
public string FormatValue(ResolutionContext context)
{
return string.Format(CultureInfo.CurrentCulture, "{0:c}", context.SourceValue);
}
}
使用IValueFormatter
這樣的偉大工程。現在,如何將其從DomainModel映射回ViewModel?我已經使用自定義class CurrencyResolver : ValueResolver<string,decimal>
public class CurrencyResolver : ValueResolver<string, decimal>
{
///<summary>Parses source value as currency</summary>
protected override decimal ResolveCore(string source)
{
return decimal.Parse(source, NumberStyles.Currency, CultureInfo.CurrentCulture);
}
}
審判,然後用它映射:
// from vm to dm
Mapper.CreateMap<ViewModel, DomainModel>()
.ForMember(dm => dm.CurrencyProperty,
mc => mc
.ResolveUsing<CurrencyResolver>()
.FromMember(vm => vm.CurrencyProperty));
將滿足這個測試:
///<summary>DomainModel maps to ViewModel</summary>
[Test]
public void ViewModelMapsToDomainModel()
{
var viewModel = new ViewModel {CurrencyProperty = "$19.95"};
var domainModel = new DomainModel();
Mapper.Map(viewModel, domainModel);
Assert.That(domainModel.CurrencyProperty, Is.EqualTo(19.95m));
}
...但我覺得我不應該在做ResolveUsing
之後明確定義它正在映射的屬性FromMember
,因爲屬性具有相同的名稱 - 是否有更好的如何定義這個映射?正如我所提到的,有很多貨幣值需要以這種方式映射。
這就是說 - 我有辦法通過定義全局的規則來自動解決這些映射嗎?該視圖模型屬性已經裝飾了DataAnnotation
屬性[DataType(DataType.Currency)]
進行驗證,所以我希望我可以定義一些規則,做:
if (destinationProperty.PropertyInfo.Attributes.Has(DataType(DataType.Currency))
then Mapper.Use<CurrencyFormatter>()
if (sourceProperty.PropertyInfo.Attributes.Has(DataType(DataType.Currency))
then Mapper.Use<CurrencyResolver>()
...所以,我可以最大限度地減少爲每個樣板安裝量對象類型。
我也有興趣聽到任何實現自定義格式的視圖的替代策略。
起初我們可能會嘗試通過 這個簡單的對象直接到 視圖,但日期時間?屬性 [在模型中]會導致問題。例如,我們需要爲它們選擇 格式,例如 ToShortDateString()或ToString()。當 爲空時, 視圖將被強制爲空 檢查以保持屏幕不會從 炸燬。觀點很難單位 測試,所以我們希望儘可能讓他們儘可能薄 。由於 視圖的輸出是傳遞給 響應流的字符串,因此我們將只使用字符型友好的 對象; 是,對象 ToString()被調用時永不會失敗的對象。 ConferenceForm視圖模型對象 是一個 示例。注意列表 4.14所有屬性都是字符串。我們將在此視圖模型 對象被放置在視圖數據中之前格式化日期正確的 。這樣 的方式,該視圖不需要考慮 對象,它可以正確格式化 信息。
<(%)=的String.Format( 「{0:C}」,Model.CurrencyProperty)%>看起來相當我。也許我只是習慣了它...... – 2010-01-01 15:23:12