Píšu webovou aplikaci, která po uživateli chce zadat IP adresu. Samozřejmě si chci pomocí validátoru ověřit, zda jsou zadaná data formálně správná, tedy že uživatel zadal validní IP adresu. Jak na to? Ponaučení první: používejte standardní infrastrukturu. Ponaučení druhé: regulární výrazy nejsou všemocné.

ASP.NET samozřejmě specializovaným validátorem na IP adresu nedisponují. Pravděpodobně nejvhodnější k použití by na první pohled byl RegularExpressionValidator. Bohužel jenom do doby, než si uvědomíme, že regulární výrazy neumějí příliš zacházet s čísly, zpracovávají je textově.

Velmi snadno jsme schopni ověřit, zda text jsou čtyři 1-3 číslicová čísla oddělená tečkami:

\b(?:\d{1,3}\.){3}\d{1,3}\b

Nejsme už ale jednoduše schopni otázat se, zda ona čísla jsou v rozsahu 0-255. Výše popsaný pattern úspěšně zvaliduje třeba i 999.999.999.999. Pattern pro "opravdovou" validaci IP adresy existuje, na webu jsem ho našel takto:

\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b

Shora uvedený výraz je nicméně živým důkazem pravdivosti pradávného citátu Jeremy Zawinskeho (detaily):

Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.

Komplikované regulární výrazy jsou cesta do pekel.

Naštěstí .NET Framework disponuje třídou System.Net.IpAddress, která umí parsovat stringy na IPv4 i IPv6 adresy. To nám umožní vyvázat se z nutnosti validovat IP sami, můžeme to hodit na .NET Framework. Zdarma tím získáme i podporu pro IPv6 pro onen nepravděpodobný případ, že by se tato verze někdy začala masově používat.

Jednoduchou logiku zabalíme do validačního prvku, který nazveme IpAddressValidator. Ten podědíme od třídy BaseValidator, která je v .NET Frameowrku právě pro tyto případy. Stačí nám přepsat metodu EvaluateIsValid a dopsat vlastní validační logiku. Kompletní zdrojový kód je zde:

using System.ComponentModel;

using System.Net;

using System.Web.UI;

using System.Web.UI.WebControls;

 

namespace Altairis.Web.UI.WebControls {

 

    public enum IpAddressType {

        IPv4,   // Internet Protocol version 4 address required

        IPv6,   // Internet Protocol version 6 address required

        Any     // Any IP version accepted

    }

 

    [ToolboxData("<{0}:IpAddressValidator runat=server></{0}:IpAddressValidator>")]

    public class IpAddressValidator : BaseValidator {

 

        [Description("The required version of IP address. Most likely the family you want is IPv4.")]

        public IpAddressType AddressType {

            get { return (IpAddressType)(this.ViewState["AddressType"] ?? IpAddressType.IPv4); }

            set { this.ViewState["AddressType"] = value; }

        }

 

        protected override bool EvaluateIsValid() {

            // Get string to validate

            string s = this.GetControlValidationValue(this.ControlToValidate);

 

            // Always respond to empty string as valid

            if (string.IsNullOrEmpty(s)) return true;

 

            // Try to parse string as IP address

            IPAddress ip;

            bool result = IPAddress.TryParse(s, out ip);

            if (!result) return false;

 

            // Check version of IP address

            switch (this.AddressType) {

                case IpAddressType.IPv4:

                    return ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork;

                case IpAddressType.IPv6:

                    return ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6;

                default:    // Any

                    return true;

            }

        }

 

    }

}

Po klasické registraci pak můžeme prvek použít stejně jako jakýkoliv jiný validátor:

<altairis:IpAddressValidator ID="IpAddressValidator1" runat="server" ControlToValidate="TextBoxIpAddress" Display="Dynamic" ErrorMessage="IP address is invalid" Text="*" />

Tento prvek je součástí mého balíčku Altairis Web UI Controls, který najdete na CodePlexu. Zatím ještě není v release, ale jenom ve zdrojovém kódu.