stevejgordon
stevejgordon

Reputation: 447

MVC Using Code First with Validation Logic and TDD

I've been getting started with ASP.NET MVC and now have a basic understanding of using a repository pattern with my EF Code First POCO classes and using Ninject for DI.

I'd like to get into proper TDD habits and struggle to fully understand how best to use it along with where to implement some logic.

For example I have the following simplified POCO class:

    public int ProjectID { get; set; }
    [Required]
    [MaxLength(150)]
    public string Title { get; set; }
    public string Description { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? DueDate { get; set; }
    public DateTime? CompletionDate { get; set; }

    public virtual ICollection<ProjectCode> ProjectCodes { get; set; }
    public virtual ICollection<ProjectTask> ProjectTasks { get; set; }

Here is my Interface (generated by the MVCScaffolding)

public interface IProjectRepository
{
    IQueryable<Project> All { get; }
    IQueryable<Project> AllIncluding(params Expression<Func<Project, object>>[] includeProperties);
    Project Find(int id);
    void InsertOrUpdate(Project project);
    void Delete(int id);
    void Save();
}

I'd like to validate that the DueDate and CompletionDate are later than the StartDate. I'm not sure if I can do this using dataannotations as it's a bit complex although it would be useful to allow the unobtrusive javascript validation to work in my view.

If I can use data annotations I'm not sure how to go about writing tests for this logic.

My other idea was to create a service layer between the controller and interface to perform this validation, but then I can't work out an easy way to do the client / server side validation or how best to implement a basic service to validate the dates as I require.

I expect to have more complex variants on this over time and it would be good to get my architecture "right" now.

Upvotes: 2

Views: 334

Answers (1)

AlexC
AlexC

Reputation: 10756

I would use DataAnnotations. I found this article very useful on custom data validations. From it I have a GreaterThanAttribute added to my project custom validations, the server side of which looks like:

public class GreaterThanAttribute : ValidationAttribute{

public GreaterThanAttribute(string otherProperty)
    : base("{0} must be greater than {1}")
{
    OtherProperty = otherProperty;
}

public string OtherProperty { get; set; }

public override string FormatErrorMessage(string name)
{
    return string.Format(ErrorMessageString, name, OtherProperty);
}

protected override ValidationResult
    IsValid(object firstValue, ValidationContext validationContext)
{
    var firstComparable = firstValue as IComparable;
    var secondComparable = GetSecondComparable(validationContext);

    if (firstComparable != null && secondComparable != null)
    {
        if (firstComparable.CompareTo(secondComparable) < 1)
        {
            return new ValidationResult(
                FormatErrorMessage(validationContext.DisplayName));
        }
    }

    return ValidationResult.Success;
}

protected IComparable GetSecondComparable(
    ValidationContext validationContext)
{
    var propertyInfo = validationContext
                          .ObjectType
                          .GetProperty(OtherProperty);
    if (propertyInfo != null)
    {
        var secondValue = propertyInfo.GetValue(
            validationContext.ObjectInstance, null);
        return secondValue as IComparable;
    }
    return null;
}
}

The DataAnnotation itself is reasonably easy to mock and test.

Upvotes: 1

Related Questions