Wednesday, March 16, 2016

foolproof

Challenge: How can I compare two form fields at ASP.NET MVC DataAnnotations and have that make its way into jquery.validate.unobtrusive.min.js client-side validations as a sanity check? Like so?

using System;
using System.ComponentModel.DataAnnotations;
namespace Airport.Core.Objects
{
   public class Flight
   {
      public int FlightId { get; set; }
      public float Duration { get; set; }
      public DateTime DepartureTime { get; set; }
      
      [Required]
      public int DepartureCity { get; set; }
      
      [Required]
      [Compare("DepartureCity", ErrorMessage = "No one flies to the same city.
            Com'on.")]
      public int DestinationCity { get; set; }
   }
}

 
 

Well, that would work dandy if I wanted DepartureCity and DestinationCity to be the same as I might for the two fields for double-entry of a password, but it this case I want just the opposite. I want to be sure that DepartureCity and DestinationCity are different. Could I do this instead?

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Airport.Core.Objects
{
   public class Flight : IValidatableObject
   {
      public int FlightId { get; set; }
      public float Duration { get; set; }
      public DateTime DepartureTime { get; set; }
      
      [Required]
      public int DepartureCity { get; set; }
      
      [Required]
      public int DestinationCity { get; set; }
      
      public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
      {
         if (DepartureCity == DestinationCity)
         {
            yield return new ValidationResult("No one flies to the same city. Com'on.", new[]
                  { "DestinationCity" });
         }
      }
   }
}

 
 

The yield keyword before return above suggests that the enumeration in scope will be incremented in addition to the return doing its thing. I don't use the yield keyword enough to feel comfortable (well, confident) with it. Meh. Anyhow, this is also not what I want because it only happens server-side and not client-side and that sucks. The fix is the get the foolproof NuGet package like so:

install-package foolproof "Airport.Core"

 
 

This installed version 0.9.5851.39131 of FoolproofValidation. I'm realizing that the package manager console is really just a PowerShell console and install-package is a PowerShell command. If something distinguishes the NuGet console from a PowerShell window in another light, I don't know what it is. Clearly there are going to be some directory settings (defaults) that are not out-of-the-box, but beyond just settings is anything different? I dunno. Anyways, in trying to get back on topic, I noticed that the NuGet package made a "Client Scripts" folder full of .js files, but as I did not install the package at my UI project I manually moved the .js files to my "Scripts" folder in the MVC project. I put this...

<script src="~/Scripts/mvcfoolproof.unobtrusive.min.js" type="text/javascript">
</script>

 
 

...just below this...

<script src="~/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript">
</script>

 
 

...at my view and I changed my model again like so:

using System;
using System.ComponentModel.DataAnnotations;
using Foolproof;
namespace Airport.Core.Objects
{
   public class Flight
   {
      public int FlightId { get; set; }
      public float Duration { get; set; }
      public DateTime DepartureTime { get; set; }
      
      [Required]
      public int DepartureCity { get; set; }
      
      [Required]
      [NotEqualTo("DepartureCity", ErrorMessage="No one flies to the same city.
            Com'on.")]
      public int DestinationCity { get; set; }
   }
}

 
 

This is what I wanted. http://foolproof.codeplex.com/ has some examples (well, notes) on other comparisions you may do with foolproof. You may do greater-than/less-than comparisons to compare dates and the like. Yay! In all three validations above the error message will appear by the DestinationCity field and not the DepartureCity field and if you look close you can probably figure out why.

No comments:

Post a Comment