Das Projekt, an dem ich arbeite, hat eine große Anzahl von Währungseigenschaften im Domänenmodell und ich brauche für das Format diese als $#,###.##
für die Übertragung von und von der Ansicht. Ich habe mir Gedanken zu verschiedenen Ansätzen gemacht, die verwendet werden könnten. Ein Ansatz könnte sein, die Werte zu formatieren explizit in der Ansicht, wie in "Pattern 1" from Steve Michelotti:ASP.NET MVC ViewModel Mapping mit benutzerdefinierter Formatierung
... aber das beginnt DRY principle sehr schnell verletzen.
Die bevorzugte Vorgehensweise scheint die Formatierung während der Zuordnung zwischen DomainModel und einem ViewModel zu sein (gemäß ASP.NET MVC in Action Abschnitt 4.4.1 und "Pattern 3"). Mit AutoMapper, wird dies wie folgt aus in einigen Code zur Folge:
[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);
}
}
Mit IValueFormatter
diese Art und Weise funktioniert super. Wie wird es vom DomainModel zu ViewModel zurückverwandelt? Ich habe versucht, 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);
}
}
eine benutzerdefinierte und anschließend kartiert es mit:
// from vm to dm
Mapper.CreateMap<ViewModel, DomainModel>()
.ForMember(dm => dm.CurrencyProperty,
mc => mc
.ResolveUsing<CurrencyResolver>()
.FromMember(vm => vm.CurrencyProperty));
, die diesen Test wird erfüllen:
///<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));
}
... Aber ich fühle, dass Ich sollte nicht explizit definieren müssen, aus welcher Eigenschaft es mit FromMember
nach ResolveUsing
gemappt wird, da die Eigenschaften den gleichen Namen haben - gibt es eine bessere Möglichkeit, diese Zuordnung zu definieren? Wie ich bereits erwähnt habe, gibt es eine gute Anzahl von Eigenschaften mit Währungswerten, die auf diese Weise abgebildet werden müssen.
Das Gesagte - gibt es eine Möglichkeit, diese Mappings automatisch zu lösen, indem Sie eine Regel global definieren? Die Ansichtsmodell Eigenschaften sind bereits dekoriert mit DataAnnotation
Attribute [DataType(DataType.Currency)]
für die Validierung, so dass ich hatte gehofft, dass ich eine Regel definieren könnte, das tut:
if (destinationProperty.PropertyInfo.Attributes.Has(DataType(DataType.Currency))
then Mapper.Use<CurrencyFormatter>()
if (sourceProperty.PropertyInfo.Attributes.Has(DataType(DataType.Currency))
then Mapper.Use<CurrencyResolver>()
... so dass ich die Menge an vorformulierten Setup für jede der minimieren Objekttypen.
Ich bin auch daran interessiert zu hören, alternative Strategien für die benutzerdefinierte Formatierung zu und von der Ansicht zu erreichen.
Zunächst könnten wir dieses einfache Objekt direkt in die Ansicht, aber die Datetime zu passieren versucht sein? Eigenschaften [im Modell] wird Probleme verursachen. Zum Beispiel müssen wir eine Formatierung für sie wie ToShortDateString() oder ToString() wählen. Die Ansicht wäre gezwungen, Null zu machen Prüfung, um den Bildschirm von in die Luft zu sprengen, wenn die Eigenschaften null sind. Ansichten sind schwierig zu Einheit Test, so wollen wir sie so dünn wie möglich halten .Da die Ausgabe einer Ansicht eine Zeichenfolge ist, die an den Antwortstream übergeben wird, verwenden wir nur Objekte, die stringfreundlich sind. dass ist, Objekte, die niemals fehlschlagen werden, wenn ToString() für sie aufgerufen wird. Das ConferenceForm-Ansichtsmodellobjekt ist ein Beispiel dafür. Beachten Sie in Listing 4.14, dass alle Eigenschaften Strings sind. Wir haben die Daten richtig formatiert, bevor diese Ansicht Modell Objekt in Ansicht Daten platziert wird. Diese Weise, die Ansicht muss nicht das Objekt betrachten, und es kann die Information richtig formatieren.
<% = string.Format ("{0: c}", Model.CurrencyProperty)%> sieht gut aus für mich. Vielleicht bin ich einfach daran gewöhnt ... –