我正在处理的项目在域模型中有大量的货币属性,我需要将这些格式设置为$#,###.##
来传输视图。我已经对可以使用的不同方法有了一些看法。一种方法可以是明确的值设置格式的视图中,在"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