• Home
  • About the Author
  • Disclosure Policy
KEEP IN TOUCH

Creating a South African ID Number custom validation attribute for ASP.Net MVC

Jan08
2013
1 Comment Written by Pieter van der Westhuizen

ASP.Net MVC gives you the option to create your own custom validation attributes in order to validate your models. I’ve recently needed such a validation attribute in order to check whether a valid South African ID Number was entered in a web form.

I’ve stumbled upon a nice C# implementation of this article by Donovan Olivier, in order to validate a South African ID Number and return information such as gender and whether the person is a South African citizen. I’ve changed his code a little bit by adding extra functionality to get the person’s age.

The Basics

First, let’s create the classes we require, the first is the IdentityInfo class, that is used to validate the ID Number.

IdentityInfo.cs

    public class IdentityInfo
    {
        public IdentityInfo(string identityNumber)
        {
            this.Initialize(identityNumber);
        }

        public string IdentityNumber { get; private set; }

        public DateTime BirthDate { get; private set; }

        public String Gender { get; private set; }

        public int Age { get; private set; }

        public string AgeToLongString { get; private set; }

        public bool IsSouthAfrican { get; private set; }

        public bool IsValid { get; private set; }

        private void Initialize(string identityNumber)
        {
            this.IdentityNumber = (identityNumber ?? string.Empty).Replace(" ", "");
            if (this.IdentityNumber.Length == 13)
            {
                var digits = new int[13];
                for (int i = 0; i < 13; i++)
                {
                    digits[i] = int.Parse(this.IdentityNumber.Substring(i, 1));
                }
                int control1 = digits.Where((v, i) => i % 2 == 0 && i < 12).Sum();
                string second = string.Empty;
                digits.Where((v, i) => i % 2 != 0 && i < 12).ToList().ForEach(v =>
                                                                 second += v.ToString());
                var string2 = (int.Parse(second) * 2).ToString();
                int control2 = 0;
                for (int i = 0; i < string2.Length; i++)
                {
                    control2 += int.Parse(string2.Substring(i, 1));
                }
                var control = (10 - ((control1 + control2) % 10)) % 10;
                if (digits[12] == control)
                {
                    this.BirthDate = DateTime.ParseExact(this.IdentityNumber
                                                       .Substring(0, 6), "yyMMdd", null);
                    this.Gender = digits[6] < 5 ? "Female" : "Male";
                    this.IsSouthAfrican = digits[10] == 0;
                    this.Age = CalculateAge(BirthDate);
                    this.AgeToLongString = CalculateAgeToLongString(BirthDate);
                    this.IsValid = true;
                }
            }
        }

        private int CalculateAge(DateTime birthDay)
        {
            DateTime today = DateTime.Today;
            int age = today.Year - birthDay.Year;
            if (birthDay > today.AddYears(-age)) age--;

            return age;
        }

        private string CalculateAgeToLongString(DateTime birthDay)
        {
            TimeSpan difference = DateTime.Now.Subtract(birthDay);
            DateTime currentAge = DateTime.MinValue + difference;
            int years = currentAge.Year - 1;
            int months = currentAge.Month - 1;
            int days = currentAge.Day - 1;

            return String.Format("{0} years, {1} months and {2} days.", years, months, days);
        }

Add a new class to your project, and make sure it derives from ValidationAttribute class. We only need to override two methods for this to work.

RSAIDNumberAttribute.cs

    public class RSAIDNumber : ValidationAttribute
    {
        public RSAIDNumber()
            : base("{0} is not a valid South African ID Number")
        {

        }

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

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            IdentityInfo idInfo = new IdentityInfo(value.ToString());

            if (!idInfo.IsValid)                
                return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));

            return null;
        }
    }

You’ll notice that we create a new instance of the IdentityInfo class and pass it the ID Number value. We then use the IsValid property to check if the user did indeed enter a valid South African ID Number.

Next, we need to create a model to validate. Decorate the RSAIDNumber field with the RSAIDNumber custom validation attribute we’ve created earlier:

ApplyModel.cs

public class ApplyModel
{
    [RSAIDNumber(ErrorMessage = "A valid RSA ID Number is required.")]
    public string RSAIDNumber { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Client-side validation

At this point we have enough for the model to be able to validate the ID Number when the user submits the form i.e server side validation. But it would be much better if we could use client validation, so when the user enters a wrong ID in the field they immediately get a message informing them that the ID number is not valid – eliminating the need to submit the form first.

In order to use client-side validation make sure you set the ClientValidationEnabled and UnobtrusiveJavaScriptEnabled keys in the web.config file to true. These values should be true by default when creating a new MVC project.

  <appSettings>
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  </appSettings>
     
Step 1 – Enabling client validation on the validation attribute class

Before we can enable client-side validation for our custom validation attribute, we need to change it to implement the IClientValidatable interface.

    public class RSAIDNumber : ValidationAttribute, IClientValidatable

We then need to implement the GetClientValidationRules method. In this method we’ll create a new instance of a ModelClientValidationRule object and set its ErrorMessage as well as the ValidationType properties. The ValidationType property is important for later, when we build our own jQuery validation method.

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, 
            ControllerContext context)
        {
            ModelClientValidationRule rule = new ModelClientValidationRule();
            rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
            rule.ValidationType = "rsaid";
            yield return rule;
        }
Step 2 – Create the jQuery validation method and adapter

Next, add a new JavaScript file to your project, and call it validations.js.

image

We’re using MVC 4 so, we need to add our validations.js file to our jqueryval bundle in the BundleConfig.cs class – It’s in the App_Start folder.

            bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                        "~/Scripts/jquery.unobtrusive*",
                        "~/Scripts/jquery.validate*",
                        "~/Scripts/validations.js"));

Add the following to your validations.js file:

validations.js

// Validation Method
$.validator.addMethod("rsaid", function (value, element, param) {
    var idnumber = value;

    //1. numeric and 13 digits
    if (isNaN(idnumber) || (idnumber.length != 13)) {
        return false;
    }
    //2. first 6 numbers is a valid date
    var tempDate = new Date(idnumber.substring(0, 2), idnumber.substring(2, 4) - 1, idnumber.substring(4, 6));
    if (!((tempDate.getYear() == idnumber.substring(0, 2)) &&
        (tempDate.getMonth() == idnumber.substring(2, 4) - 1) &&
        (tempDate.getDate() == idnumber.substring(4, 6)))) {
        return false;
    }

    //3. luhn formula
    var tempTotal = 0; var checkSum = 0; var multiplier = 1;
    for (var i = 0; i < 13; ++i) {
        tempTotal = parseInt(idnumber.charAt(i)) * multiplier;
        if (tempTotal > 9) {
            tempTotal = parseInt(tempTotal.toString().charAt(0)) + parseInt(tempTotal.toString().charAt(1));
        }
        checkSum = checkSum + tempTotal;
        multiplier = (multiplier % 2 == 0) ? 1 : 2;
    }
    if ((checkSum % 10) == 0) {
        return true
    };
    return false;
});

// Validation Adapter
jQuery.validator.unobtrusive.adapters.addBool('rsaid');

In case you’re wondering; Yes, you’ll need to add the same type of logic you’ve used in C# to determine whether the ID is valid but in this case using JavaScript. I found the above JavaScript to validate a RSA ID on David Russell’s Blog

The validation adaptor is very easy in this example because we only need to know whether the validation result is True or False, so we register the validation method using the addBool method.

Adding the View

All that is left to do is add a view.

Image5

Check the Create a strongly-typed view checkbox and select the model in the combo box( Make sure you’ve compiled your project first!), also check the Reference script libraries checkbox – this will automatically include the jqueryval bundle in the view. Select Edit as the Scaffold template.

Image6

The code for your view should look like:

@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Index</h2>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>ApplyModel</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.RSAIDNumber)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.RSAIDNumber)
            @Html.ValidationMessageFor(model => model.RSAIDNumber)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.FirstName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.FirstName)
            @Html.ValidationMessageFor(model => model.FirstName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.LastName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Notice the Scripts section in which the jqueryval bundle is rendered – Remember this bundle contains our validation.js file!

And if everything builds and runs, your page should look like this when the user types an incorrect South African ID Number:

image

Thank you for reading! I hope you can find this example useful for your own projects!

Download the sample C# project here.

PS: I’ve used ASP.Net MVC 4 for this example, but it should work equally well in MVC 3, only difference is you’ll need to add the scripts manually as bundling is not available out of the box in MVC 3!

 

 

Share this:

  • Twitter
  • Google +1
  • Facebook
  • LinkedIn
  • Reddit
  • Digg
  • Send to Kindle
Posted in ASP.Net MVC - Tagged ASP.Net MVC, C#
SHARE THIS Twitter Facebook Delicious StumbleUpon E-mail
« How to create custom Outlook rules and execute them programmatically
» Deliver personalized, proactive, website content using TrackToAct

1 Comment

  1. BuckminsterWade's Gravatar BuckminsterWade
    February 7, 2013 at 15:52 | Permalink

    I consent with you as a developer i also used client side validation, if something’s wrong, the alarm is triggered upon submission of the form. You can safely display only one error at a time and focus on the wrong field, to help ensure that the user correctly fills in all the details you need.

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Recent Posts

  • Outlook 2013 and Visual Studio 2012: Getting started for VSTO developers
  • Office 2013 and Visual Studio 2012: Getting started for VSTO developers
  • Excel 2013 single document interface (SDI): How to rebuild your task panes to support it
  • Converting a .vdproj to WiX in Visual Studio 2012, 2010, 2008
  • How to dynamically bind Outlook add-in UI elements to the context

Tag Cloud

.net ACCPAC Add-in Express Advanced Regions ASP.Net ASP.Net MVC C# CRM CSLA CSS Datafier Toolkit deployment Entity Framework Excel HTML In-app Analytics Internet Explorer Java jQuery LINQ MS Access MS Excel Ms Outlook MS Project MVC NHibernate ODBC Office 365 Office 2013 sdk SharePoint 2010 silverlight Source control SQL SQL Connector TrackToAct Twitter VB.net Visio Visual Studio Visual Studio 2012 vsto WCF WiX WSDL

Blogroll

  • David Turvey's Blog

EvoLve theme by Theme4Press  •  Powered by WordPress Mythical Man Moth
IT Mythbusting