3
\$\begingroup\$

I am not sure if I am approaching this task the correct way. I have a view model with multiple string properties. I pass the model through an interface to a service class that contains a void to repopulate the user input with my desired format.

using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web.Helpers;
public class RegisterViewModel
{
    public string UserId { get; set; }
    public string Password { get; set; }
    public string RecoveryAnswer { get; set; }
    public int? EmpId { get; set; }
    public string EId { get; set; }
    public string UId { get; set; }
    public string PeopleSafeId { get; set; }
    public string StarsId { get; set; }
    public string NamePrefix { get; set; }
    public string NameFirst { get; set; }
    public string NameMiddle { get; set; }
    public string NameLast { get; set; }
    public string NameSuffix { get; set; }
    public string Email { get; set; }
    public string PhoneNumber { get; set; }
    public string PhoneExtension { get; set; }
    public int? DepartmentId { get; set; }
    public int? TitleId { get; set; }
    public int DomainId { get; set; }
    public int? LocationId { get; set; }
}

public interface IRegisterService
{
    RegisterViewModel CleanUserInput(RegisterViewModel model);
    //...
}

public class RegisterService : IRegisterService
{
    public RegisterViewModel CleanUserInput(RegisterViewModel model)
    {
        CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
        TextInfo textInfo = cultureInfo.TextInfo;
        model.UserId = model.UserId.ToUpper();
        model.Password = Crypto.HashPassword(model.Password);
        model.RecoveryAnswer = Crypto.HashPassword(model.RecoveryAnswer);
        model.EId = model.EId.ToUpper();
        model.UId = model.UId.ToUpper();
        model.PeopleSafeId = model.PeopleSafeId.ToUpper();
        model.StarsId = model.StarsId.ToUpper();
        model.NamePrefix = textInfo.ToTitleCase(model.NamePrefix);
        model.NameFirst = textInfo.ToTitleCase(model.NameFirst);
        model.NameMiddle = textInfo.ToTitleCase(model.NameMiddle);
        model.NameLast = textInfo.ToTitleCase(model.NameLast);
        model.NameSuffix = textInfo.ToTitleCase(model.NameSuffix);
        model.Email = model.Email.ToLower();
        model.PhoneNumber = Regex.Replace(model.PhoneNumber, "[^0-9]", "");
        model.PhoneExtension = Regex.Replace(model.PhoneNumber, "[^0-9]", "");
        return model;
    }
    //...
}

Is there a better way to approach cleaning up this much input?

\$\endgroup\$
4
\$\begingroup\$

This seems pretty clean to me. It's very testable, which is a definite must-have. It also decouples the reformatting of user input from the view-model. Looser coupling between layers is a positive thing. The downside is that you'd need to create a service for each view model. I'm going back and forth in my head whether this approach is best, or if defining some custom class and property attributes might be more worth while, and then use the service to process any object in a generic manor by looking at the attributes associated with a view-model property.

Some pseudo code:

RegisterViewModel.cs

public class RegisterViewModel
{
    [CleanUserInput.ToUpperCase]
    public string UserId { get; set; }
    [CleanUserInput.HashValue]
    public string Password { get; set; }
    public string RecoveryAnswer { get; set; }
    public int? EmpId { get; set; }
    [CleanUserInput.ToUpperCase]
    public string EId { get; set; }
    [CleanUserInput.ToUpperCase]
    public string UId { get; set; }
    [CleanUserInput.ToUpperCase]
    public string PeopleSafeId { get; set; }
    public string StarsId { get; set; }
    public string NamePrefix { get; set; }
    public string NameFirst { get; set; }
    public string NameMiddle { get; set; }
    public string NameLast { get; set; }
    public string NameSuffix { get; set; }
    [CleanUserInput.ToLowerCase]
    public string Email { get; set; }
    [CleanUserInput.StripNonDigits]
    public string PhoneNumber { get; set; }
    public string PhoneExtension { get; set; }
    public int? DepartmentId { get; set; }
    public int? TitleId { get; set; }
    public int DomainId { get; set; }
    public int? LocationId { get; set; }
}

Then the definitions for the property attributes:

namespace CleanUserInput
{
    public class ToUpperCaseAttribute : System.Attribute
    {
        // ...
    }

    public class HasValueAttribute : System.Attribute
    {
        // ...
    }

    public class StripNonDigitsAttribute : System.Attribute
    {
        // ...
    }
}

Your service could get the System.Type object for the view model, and then inspect the Attributes using class reflection. This could make processing multiple view models easily repeatable with little additional code.

\$\endgroup\$
  • \$\begingroup\$ So like this: public class ToUpperCaseAttribute : Attribute{private string _ToUpperCase{get{return _ToUpperCase.ToUpper();}}}? (excuse the formatting comments don't do well with code). \$\endgroup\$ – aaronmallen Jun 19 '14 at 19:32
  • \$\begingroup\$ This could be further added in to a custom binder so that the viewmodel is already cleaned before it even gets into the controller... \$\endgroup\$ – dreza Jun 19 '14 at 20:40
  • \$\begingroup\$ I am having trouble creating the attribute definitions... I cant seem to find any good tutorials on writing custom attributes without having to pass an argument. \$\endgroup\$ – aaronmallen Jun 19 '14 at 21:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.