ASP.NET MVC ViewModel, отображающийся с пользовательским форматированием

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

... но это начинает нарушать принцип DRY очень быстро.

Предпочтительный подход, кажется, чтобы сделать форматирование во время отображения между DomainModel и ViewModel (согласно ASP.NET MVC в разделе Action 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
{
 ///Currency Property - formatted as $#,###.##
 public string CurrencyProperty { get; set; }

 ///Setup mapping between domain and view model
 static ViewModel()
 {
  // map dm to vm
  Mapper.CreateMap()
   .ForMember(vm => vm.CurrencyProperty, mc => mc.AddFormatter());
 }

 ///  Creates the view model from the domain model.
 public ViewModel(DomainModel domainModel)
 {
  Mapper.Map(domainModel, this);
 }

 public ViewModel() { }
}

public class CurrencyFormatter : IValueFormatter
{
 ///Formats source value as currency
 public string FormatValue(ResolutionContext context)
 {
  return string.Format(CultureInfo.CurrentCulture, "{0:c}", context.SourceValue);
 }
}

Используя IValueFormatter этот путь работает отлично. Теперь, как отобразить его назад от DomainModel до ViewModel? Я попытался использовать пользовательское class CurrencyResolver : ValueResolver

public class CurrencyResolver : ValueResolver
{
 ///Parses source value as currency
 protected override decimal ResolveCore(string source)
 {
  return decimal.Parse(source, NumberStyles.Currency, CultureInfo.CurrentCulture);
 }
}

И затем отображенный это с:

  // from vm to dm
  Mapper.CreateMap()
   .ForMember(dm => dm.CurrencyProperty, 
    mc => mc
     .ResolveUsing()
     .FromMember(vm => vm.CurrencyProperty));

Который удовлетворит этот тест:

 ///DomainModel maps to ViewModel
 [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()
if (sourceProperty.PropertyInfo.Attributes.Has(DataType(DataType.Currency)) 
  then Mapper.Use()

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

Я также интересуюсь слушанием любых альтернативных стратегий выполнения пользовательского форматирования to-from Представление.


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

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

6
задан James Kolpack 4 January 2010 в 15:31
поделиться

2 ответа

Пользовательский TypeConverter это то, что вы ищете:

Mapper.CreateMap<string, decimal>().ConvertUsing<MoneyToDecimalConverter>();

Тогда создайте конвертер:

public class MoneyToDecimalConverter : TypeConverter<string, decimal>
{
   protected override decimal ConvertCore(string source)
   {
      // magic here to convert from string to decimal
   }
}
2
ответ дан 9 December 2019 в 22:35
поделиться

Рассматривали ли вы возможность использования метода расширения для форматирования денег?

public static string ToMoney( this decimal source )
{
    return string.Format( "{0:c}", source );
}


<%= Model.CurrencyProperty.ToMoney() %>

Поскольку это явно вопрос, связанный с представлением (а не с моделью), я бы постарался держать его в поле зрения, если это вообще возможно. В основном это переносит его в метод расширения в десятичном виде, но использование находится в представлении. Можно также сделать расширение HtmlHelper:

public static string FormatMoney( this HtmlHelper helper, decimal amount )
{
    return string.Format( "{0:c}", amount );
}


<%= Html.FormatMoney( Model.CurrencyProperty ) %>

Если вам больше нравится этот стиль. Он немного более связан с видом, так как это расширение HtmlHelper.

6
ответ дан 9 December 2019 в 22:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: