ASP.NET MVC ViewModel сопоставления с пользовательским форматированием

Проект, над которым я работаю, имеет большое количество свойств валюты в модели домена, и мне нужно отформатировать их как$#,###.## для передачи в и из вида. У меня были мысли о различных подходах, которые можно использовать. Одним из подходов может быть явное форматирование значений внутри представления, как в«Узор 1» от Стива Микелотти :

... но это начинает нарушатьСУХОЙ принцип очень быстро.

Предполагается, что предпочтительным подходом является форматирование во время отображения между DomainModel и ViewModel (согласноASP.NET MVC в действии раздел 4.4.1 и"Шаблон 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));
 }

... Но я чувствую, что мне не нужно явно определять, из какого свойства оно сопоставляется сFromMember после выполненияResolveUsing поскольку свойства имеют одинаковые имена - есть ли лучший способ определить это отображение? Как я уже упоминал, существует множество свойств с валютными значениями, которые необходимо сопоставить таким образом.

При этом - есть ли способ, которым я мог бы автоматически разрешить эти сопоставления, определив какое-то правило глобально? Свойства ViewModel уже украшены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>()

... так что я могу минимизировать количество шаблонов настройки для каждого из типов объектов.

Мне также интересно услышать о любых альтернативных стратегиях для выполнения пользовательского форматирования в и из View.

ИзASP.NET MVC в действии:

Сначала у нас может возникнуть желание передать этот простой объект прямо в представление, но DateTime? свойства [в модели] вызовут проблемы. Например, нам нужно выбрать для них форматирование, например ToShortDateString () или ToString (). Представление будет вынуждено выполнить нулевую проверку, чтобы экран не всплывал, когда свойства равны нулю. Представления сложны для модульного тестирования, поэтому мы хотим сохранить их как можно более тонкими. Поскольку выходные данные представления представляют собой строку, переданную потоку ответов, мы будем использовать только объекты, которые являются дружественными для строки; то есть объекты, которые никогда не потерпят неудачу при вызове ToString () для них. Объект модели представления ConferenceForm является примером этого. Обратите внимание, что в листинге 4.14 все свойства являются строками. Мы будем правильно отформатировать даты, прежде чем этот объект модели представления будет помещен в данные представления. Таким образом, представление не должно учитывать объект, и оно может правильно форматировать информацию.

Ответы на вопрос(3)

Ваш ответ на вопрос