0

I'm converting a WinForms app to ASP.NET MVC4 and trying to implement a ViewModel approach using AutoMapper to map between the domain entities and the ViewModels, mostly to flatten the more complex object graphs into ViewModels for easy binding in the views.

The problem I'm running into is that when leaving some fields blank that the domain model wants to apply a Trim() a NullReferenceException is thrown.

Originally this was all handled in the domain objects for example in the Customer object I have a string property that trims to ensure whatever value was passed in is trimmed, and that way not have to clutter the original WinForms with Trim everywhere the value could be set, just rely on passing it to the domain model and let it set do the Trim or ToUpper as the value was persisted.

public virtual String Name
{
    get { return _name; }
    set { _name = StringFormatting.ToTitleCase(value.Trim()); }
}

public virtual String Email
{
    get { return _email; }
    set { _email = value.Trim(); }
}

and in terms of my ViewModel I've just got auto implemented properties:

public class CustomerCreateViewModel
{
    [Required(ErrorMessage="Please enter a name for this customer")]
    public string Name { get; set; }

    [DataType(DataType.EmailAddress)]
    public string Email { get; set; }
}

However if the email textbox is empty when the form is submitted then a NullReferenceException would be thrown on

set { _email = value.Trim() ; }

To get around that I added a setter guard clause

public virtual String Email
{
    get { return _email; }
    set
    {
        if (_email == value) return;
        _email = value.Trim();
    }
}

and that worked in that the error with that field went away, but it moved to the next property, Mobile - which I repeated the fix for and then on to the next and the next and the next. None of these are required so it is correct for them to be passed in empty.

Is there a way in AutoMapper to specify that all strings being mapped are to be trimmed? Am I approaching this wrongly; is it not necessary to Trim strings? Or whereabouts should that trimming be performed, my preference would be to only need to trim strings as they're submitted, but not in the code for any individual controller, it feels like it should be done somewhere in the ViewModel / Domain model, but where?

Simon Martin
  • 4,203
  • 7
  • 56
  • 93
  • Why do you need to trim the strings? You can say that the Binder will do that job, it's not correct design if automapper do that, it's not SRP – hackp0int Mar 23 '13 at 00:34
  • Because I don't trust the user not to have padded the textbox; possibly by mistake, spacebar got stuck or something. The same is true for text I want to `ToUpper`, for example the UK postcode. I know I *could* use css to style it and leave it as the user entered it, but then I have to remember to apply the css rule wherever I use the value. Easier to 'correct' the user input and know that once it's been saved it is in the right format. – Simon Martin Mar 23 '13 at 00:40

2 Answers2

7

As alternative and easier solution

Mapper.CreateMap<string, string>().ConvertUsing(
   str => !string.IsNullOrEmpty(str) ? str.Trim() : null
);
Andrei Schneider
  • 3,618
  • 1
  • 33
  • 41
1

You can use ITypeConverter<M,V> like so...

public class ModelToViewModelConverter : ITypeConverter<Model, ViewModel>
{
        public UIItemViewModel Convert(ResolutionContext context)
        {
            Model model = (Model)context.SourceValue;
            // Perform your logic 
        }
}
hackp0int
  • 4,052
  • 8
  • 59
  • 95
  • If I understand this correctly I would need to have an explicit `Convert` for each Model->ViewModel mapping I need in order for all strings to be trimmed? – Simon Martin Mar 23 '13 at 11:41