Phone validation with C#

When a new or small business starts a new website or web application with an online form. In the beginning, the business is focused on one country, and so the phone validation might be simple, but soon or later the business will grow and validation of international phone numbers becomes complex.

I have seen often code bases with different variations of phone number validation, and it feels like each time, someone like to re-invent the wheel.

I have had exactly such a situation to find a solution for an existing enterprise for this problem and ended up using libphonenumber developed by Google.

The same library source code is ported to C# and a NuGet package is published with name libphonenumber-csharp.

In this article, I am going to demonstrate libphonenumber-csharp example.

First of all, create a new net 6 project (btw this package is compatible with this framework or higher. .NET Standard 2.0 or .NET Framework 4.6.2) and install NuGet package libphonenumber-csharp version 8.12.50,

<ItemGroup>
  <PackageReference Include="libphonenumber-csharp" Version="8.12.50" />
</ItemGroup>

Now we can create a phone number util instance and test a phone number from the United States:

var util = PhoneNumberUtil.GetInstance();

var number = util.Parse("+1-800-800-6000", "US");

Console.WriteLine(util.IsValidNumber(number));
Console.WriteLine(number.CountryCode.ToString());
Console.WriteLine(util.GetRegionCodeForCountryCode(number.CountryCode));
Console.WriteLine(number.NationalNumber.ToString());
Console.WriteLine(util.Format(number, PhoneNumberFormat.E164));

The result of the code will be:

True
1
US
8008006000
+18008006000

Now let’s go deeper and test more phone numbers, for a fun test a list of phone numbers.

Here is a list of dummy and random phone numbers:

var list = new List<string>()
{
    "+4570111112",
    "50123456",
    "+4550123456",
    "4550123456",
    "+45 70 11 11 12",
    "+4570111112",
    "+48577100001",
    "+1-800-900-6000",
    "+44 123 442 1001",
    "+48577100000",
    "+358500000000",
    "+45701280811",
    "+457012808",
    "+45701280815",
    "+4512345678"
};

Let’s run a for loop and make some analysis on the code and the results:

foreach (var s in list)
{
    var number = util.ParseAndKeepRawInput(s, "DK");
    var line = $"|{util.IsValidNumber(number),5}" +
               $"|{number.CountryCode,4}" +
               $"|{util.GetRegionCodeForCountryCode(number.CountryCode),3}" +
               $"|{number.NationalNumber,12}" +
               $"|{util.Format(number, PhoneNumberFormat.E164),16}|";
    Console.WriteLine(line);
}

Here is the result

| True|  45| DK|    70111112|     +4570111112|
| True|  45| DK|    50123456|     +4550123456|
| True|  45| DK|    50123456|     +4550123456|
| True|  45| DK|    50123456|     +4550123456|
| True|  45| DK|    70111112|     +4570111112|
| True|  45| DK|    70111112|     +4570111112|
| True|  48| PL|   577100001|    +48577100001|
| True|   1| US|  8009006000|    +18009006000|
| True|  44| GB|  1234421001|   +441234421001|
| True|  48| PL|   577100000|    +48577100000|
| True| 358| FI|   500000000|   +358500000000|
|False|  45| DK|   701280811|    +45701280811|
|False|  45| DK|     7012808|      +457012808|
|False|  45| DK|   701280815|    +45701280815|
|False|  45| DK|    12345678|     +4512345678|

As you can see, we chose DK as the default region, this means my base country for phone validation is Denmark, but if another number comes in, it will check those by country code. This also means if I give a phone number without +45, 45 or 0045 which is Denmark’s international phone code, the phone number will be labeled and validated as a Danish number. One thing to mention, in Denmark we have fixed 8 numbers as phone numbers, so if you pass 12345678 as the phone number in this library, it will fail, as the case in the last item in our list.

As you also can see, if the number of Denmark has less or more than 8 digits it will fail as well.

The same is valid for all other counties without worrying about how phone numbers are formatted.

Conclusion

We do not always need to re-create new or re-invent solutions for problems that are common, and already solved. Of course, we can do that if we bring new value with it or has a justifiable explanation.

As you can see a little library cover phone validation for all counties in the world.

I have on the other hand discovered a possible bug or issue with this library. The library has an extra feature to predict mobile numbers like util.GetNumberType(number) == PhoneNumberType.MOBILE, I have tried my mobile phone number and it was not a valid mobile number.

Leave a Comment