Note: This is not the complete source code--just the main source file.
You can download the full source (with include files) from our sample code archive by clicking on the diskette icons.
// HexillionEmailValidator sample control // version 1.0.0.0 // // Demonstrates how to create a custom email validator control. // It does client-side validation with a JavaScript regular // expression and server-side validation with the HexValidEmail // component. // // HexGadgets (components) required: // - HexValidEmail COM // Info: http://www.HexGadgets.com/ // Download: http://www.hexillion.com/download/HexGadgets.exe // // History: // 2003-01-23 1.0.0.0 Created // // Copyright 2003 Hexillion Technologies. All rights reserved. // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT // LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND/OR // FITNESS FOR A PARTICULAR PURPOSE. using System; using System.Web.UI; using System.Web.UI.WebControls; using System.ComponentModel; using System.Text; using Hexillion.HexValidEmail.Interop; namespace Hexillion.Samples.Interop { /// <summary> /// An ASP.NET validator server control that validates email addresses using both /// client-side and advanced server-side tests. /// </summary> /// <remarks> /// <note>This control requires the <see href="http://www.hexillion.com/hg/HexValidEmail/">HexValidEmail</see> /// component (COM version), which you can download as part of the /// <see href="http://www.HexGadgets.com/">HexGadgets installation package</see>. /// It also needs the HexValidEmail interop assembly, which is included with the /// HexillionEmailValidator assembly.</note> /// <note>To put the HexillionEmailValidator control in your Visual Studio .NET toolbox, /// choose Customize Toolbox from the Tools menu. In the dialog, click on the .NET /// Framework Components tab, then click Browse. Use the file dialog to find and select /// HexillionEmailValidator.dll. After you close the Customize Toolbox dialog, the /// validator control should be in your toolbox.</note> /// <para>Use this control to validate email addresses entered into a text field. It does /// both client-side validation (if enabled) and server-side validation. The server-side /// validation uses <see href="http://www.hexillion.com/hg/HexValidEmail/">HexValidEmail</see> /// to check the syntax, domain, and username.</para> /// <para>The only property that you <i>must</i> set is <see cref="BaseValidator.ControlToValidate"/>. /// However, we strongly urge you to also set the <see cref="FromDomain"/> and /// <see cref="FromEmail"/> properties to <see href="http://www.hexillion.com/docs/guides/HexValidEmail/concepts/polite_usage.htm">be polite</see> /// to mail server administrators.</para> /// </remarks> /// <include file='Examples.xml' path='documentation/class[@name="HexillionEmailValidator"]/*' /> [ DefaultProperty("ControlToValidate"), ToolboxData("<{0}:HexillionEmailValidator runat=\"server\"></{0}:HexillionEmailValidator>") ] public class HexillionEmailValidator : BaseValidator { public HexillionEmailValidator() { // Create a HexValidEmail.Connection object _conn = new Connection(); _initialError = _conn.Error; // Error message is client-side message initially ErrorMessage = _clientSideMessage; } /// <summary> /// Adds an attribute to the validator tag to hook it in to the client-side form validation. /// </summary> protected override void AddAttributesToRender( HtmlTextWriter writer ) { base.AddAttributesToRender( writer ); if( RenderUplevel ) writer.AddAttribute("evaluationfunction", "HexillionEmailValidatorValidate"); } /// <summary> /// Places JavaScript code on the page for client-side validation. /// </summary> protected override void OnPreRender( EventArgs e ) { base.OnPreRender( e ); // Register our client-side script block if( RenderUplevel ) Page.RegisterClientScriptBlock( "HexillionEmailValidator", string.Format( _clientScript, _regex, ControlToValidate, ID, _clientSideMessage ) ); } /// <summary> /// Gets or sets the highest level of validation to attempt. /// </summary> /// <value><b>1</b> for syntax, <b>2</b> for domain (DNS), <b>3</b> for username (SMTP)</value> [ Description("The highest level of validation to attempt: 1 for syntax, 2 for domain (DNS), 3 for username (SMTP)" ), DefaultValue(3), Category("Behavior") ] public int TryLevel { get { return (int)_levelTry; } set { if( value < 1 || value > 3 ) throw new ArgumentException( "TryLevel must have a value from 1 to 3." ); _levelTry = (HexValidEmailLevel)value; } } /// <summary>Gets or sets the lowest confidence rating required for the validator to pass the input.</summary> /// <value>An integer from <b>1</b> to <b>3</b>. This should usually be set to <b>1</b>, the default value.</value> /// <remarks>Only a rating of <b>0</b> indicates a bad address. Thus, this property should usually be /// set to <b>1</b> to pass all addresses that are not confirmed bad.</remarks> [ Description("The lowest confidence rating required for the validator to pass the input. This should usually be set to 1." ), DefaultValue(1), Category("Behavior") ] public int RequiredRating { get { return (int)_levelRequired; } set { if( value < 1 || value > 3 ) throw new ArgumentException( "RequiredRating must have a value from 1 to 3." ); _levelRequired = (HexValidEmailLevel)value; } } /// <summary> /// Gets or sets text to place after the server-side error message. /// </summary> /// <remarks>After a postback, the server-side validation determines the error message /// to be displayed. This property gives you a chance to place text or HTML at the /// end of that message.</remarks> [ Description("Text to place after the server-side error message."), DefaultValue(""), Category("Appearance") ] public string AppendedMessage { get { return _appendedMessage; } set { _appendedMessage = value; } } /// <summary> /// Gets or sets text to place before the server-side error message. /// </summary> /// <remarks>After a postback, the server-side validation determines the error message /// to be displayed. This property gives you a chance to place text or HTML in front of /// that message.</remarks> [ Description("Text to place before the server-side error message."), DefaultValue(""), Category("Appearance") ] public string PrependedMessage { get { return _prependedMessage; } set { _prependedMessage = value; } } /// <summary> /// Gets or sets the error message to displayed if the client-side validation /// rejects the input. /// </summary> [ Description("Error message for client-side validation."), DefaultValue("The email address is invalid"), Category("Appearance") ] public string ClientSideErrorMessage { get { return _clientSideMessage; } set { _clientSideMessage = value; } } /// <summary> /// Gets or sets the regular expression for validating the email address on the client side. /// </summary> /// <remarks> /// Notes about the default regular expression: /// <list type="bullet"> /// <item><description> /// It is liberal within legal syntax. If you look at <see href="http://www.rfc-editor.org/rfc/rfc2822.txt">RFC 2822</see>, /// there are a lot more legal characters than you might expect. /// This regex allows them in the local part, regardless of whether /// they are common. Likewise, the regex passes just about any /// legal domain name, regardless of whether it's likely. /// The general philosophy is to let most legal stuff /// slide through the client-side validation and let the server-side /// validations check for realism. /// </description></item> /// <item><description> /// It is strict when syntax is illegal. Dash characters ("-"), for /// example, are not allowed on the ends of the domain labels. /// Also, domains cannot contain underscores ("_")... at least not /// domains that conform to the old host name rules, which are what /// domains in email addresses must follow these days. /// </description></item> /// <item><description> /// It does require at least a second-level domain and conformance /// conformance to host name standards (<see href="http://www.rfc-editor.org/rfc/rfc2822.txt">RFC 952</see> /// and <see href="http://www.rfc-editor.org/rfc/rfc1123.txt">RFC 1123</see>). /// </description></item> /// <item><description> /// It allows only IPv4 domain literals. /// </description></item> /// <item><description> /// It does not allow display names, quoted literals, comments, or /// whitespace. It basically allows a limited version of the /// addr-spec form described in RFC 2822. /// </description></item> /// </list> /// </remarks> [ Description("Regular expression for validating the email address on the client side."), DefaultValue(_defaultRegex), Category("Behavior") ] public string ClientSideRegex { get { return _regex; } set { _regex = value; } } /// <summary> /// Gets or sets the maximum time to wait for DNS validation (milliseconds). /// </summary> /// <value>An integer from 50 to 60000 representing milliseconds. The default is 4000.</value> [ Description("Maximum time to wait for DNS validation (milliseconds)."), DefaultValue(4000), Category("Behavior") ] public int DnsTimeout { get { return _dnsTimeout; } set { if( value < 50 || value > 60000 ) throw new ArgumentException( "DnsTimeout must have a value from 50 to 60000 (milliseconds). We suggest 4000." ); _dnsTimeout = value; } } /// <summary> /// Gets or sets the maximum time to wait for SMTP validation (milliseconds). /// </summary> /// <value>An integer from 50 to 120000 representing milliseconds. The default is 10000.</value> [ Description("Maximum time to wait for SMTP validation (milliseconds)."), DefaultValue(10000), Category("Behavior") ] public int SmtpTimeout { get { return _smtpTimeout; } set { if( value < 50 || value > 120000 ) throw new ArgumentException( "DnsTimeout must have a value from 50 to 120000 (milliseconds). We suggest 10000." ); _smtpTimeout = value; } } /// <summary> /// Gets or sets the domain name to use as identification during SMTP validation. /// </summary> /// <value>A domain name string that will be sent with the SMTP HELO command. /// Set this to the domain name of your machine.</value> /// <remarks>See <see href="http://www.hexillion.com/docs/guides/HexValidEmail/concepts/polite_usage.htm"> /// http://www.hexillion.com/docs/guides/HexValidEmail/concepts/polite_usage.htm</see> for more details.</remarks> [ Description("The domain name to use as identification during SMTP validation. Set this to the domain name of your machine." ), DefaultValue("hexillion.com"), Category("Behavior") ] public string FromDomain { get { return _conn.FromDomain; } set { if( null == value ) throw new ArgumentNullException(); _conn.FromDomain = value; } } /// <summary> /// Gets or sets the email address to use as contact information during SMTP validation. /// </summary> /// <value>An email address string that will be sent with the SMTP MAIL FROM command. /// Set this to the email address of a technical contact person at your domain.</value> /// <remarks>See <see href="http://www.hexillion.com/docs/guides/HexValidEmail/concepts/polite_usage.htm"> /// http://www.hexillion.com/docs/guides/HexValidEmail/concepts/polite_usage.htm</see> for more details.</remarks> [ Description("The email address to use as contact information during SMTP validation. Set this to the email address of a technical contact person at your domain." ), DefaultValue("HexValidEmail@hexillion.com"), Category("Behavior") ] public string FromEmail { get { return _conn.FromEmail; } set { if( null == value ) throw new ArgumentNullException(); _conn.FromEmail = value; } } /// <summary> /// Validates the referenced email address field. /// </summary> /// <returns><b>true</b> if the email address passes, <b>false</b> if it fails.</returns> protected override bool EvaluateIsValid() { HexValidEmailLevel rating; // Set the timeouts _conn.Timeouts.Item(HexValidEmailTimeout.hexVeTimeoutDnsTotal).Value = _dnsTimeout; _conn.Timeouts.Item(HexValidEmailTimeout.hexVeTimeoutSmtpTotal).Value = _smtpTimeout; // Do the validation rating = (HexValidEmailLevel)_conn.Validate( GetControlValidationValue( ControlToValidate ), _levelTry ); StringBuilder sb = new StringBuilder(); sb.Append( _prependedMessage ); sb.Append( GetErrorString( _conn.Error ) ); sb.Append( _appendedMessage ); ErrorMessage = sb.ToString(); // Establish whether the address passed bool passed = (rating >= _levelRequired); // Set visibility of the error message Style["visibility"] = passed ? "hidden" : "visible"; return passed; } private string GetErrorString(int error) { switch( (HexValidEmailErrors)error ) { case HexValidEmailErrors.hexVeErrTimedOut: return "Timed out"; case HexValidEmailErrors.hexVeErrConnectionRefused: return "Connection refused"; case HexValidEmailErrors.hexVeErrConnectionReset: return "Connection reset"; case HexValidEmailErrors.hexVeErrHostUnreachable: return "Host unreachable"; case HexValidEmailErrors.hexVeErrAddressNotAvailable: return "Address not available"; case HexValidEmailErrors.hexVeErrNetworkDown: return "Network down"; case HexValidEmailErrors.hexVeErrNetworkUnreachable: return "Network unreachable"; case HexValidEmailErrors.hexVeErrConnectionAborted: return "Connection aborted"; case HexValidEmailErrors.hexVeErrHostNotFound: return "Host not found"; case HexValidEmailErrors.hexVeErrTryAgain: return "Try again"; case HexValidEmailErrors.hexVeErrNoRecovery: return "No recovery"; case HexValidEmailErrors.hexVeErrNoData: return "No data"; case HexValidEmailErrors.hexVeErrUnexpected: return "Unexpected error"; case HexValidEmailErrors.hexVeErrAddrTooLong: return "The email address is too long"; case HexValidEmailErrors.hexVeErrExtraTextPresent: return "The email address has extra text that is not allowed"; case HexValidEmailErrors.hexVeErrIllegalChar: return "The email address contains an illegal character"; case HexValidEmailErrors.hexVeErrUnbalancedParenthesis: return "The email address contains an unbalanced parenthesis"; case HexValidEmailErrors.hexVeErrUnbalancedSquareBracket: return "The email address contains an unbalanced square bracket"; case HexValidEmailErrors.hexVeErrUnbalancedAngleBracket: return "The email address contains an unbalanced angle bracket"; case HexValidEmailErrors.hexVeErrQuotationMarksNotClosed: return "Quotation marks in the email address are not closed"; case HexValidEmailErrors.hexVeErrDomainLiteralPresent: return "The email address contains a domain literal, which is not allowed"; case HexValidEmailErrors.hexVeErrMisplacedDomainLiteral: return "The email address contains a misplaced domain literal"; case HexValidEmailErrors.hexVeErrMisplacedQuotedString: return "The email address contains a misplaced quoted string"; case HexValidEmailErrors.hexVeErrNoLocalPart: return "The email address does not include a local part (username)"; case HexValidEmailErrors.hexVeErrNoDomain: return "The email address does not include a domain"; case HexValidEmailErrors.hexVeErrInvalidDomain: return "The domain in the email address is invalid"; case HexValidEmailErrors.hexVeErrInvalidDomainLiteral: return "The email address contains an invalid domain literal"; case HexValidEmailErrors.hexVeErrNoDnsServerConfigured: return "No DNS servers configured"; case HexValidEmailErrors.hexVeErrDomainDoesNotExist: return "The email address domain does not exist"; case HexValidEmailErrors.hexVeErrNoMxForDomain: return "The email address domain does not have a mail exchanger"; case HexValidEmailErrors.hexVeErrCouldNotVerifyRecipient: return "Could not verify the local part (username) due to a problem communicating with the mail server"; case HexValidEmailErrors.hexVeErrRecipientRejected: return "The domain's mail server rejected the email address"; case HexValidEmailErrors.hexVeErrNoAddrSpecified: return "No email address was specified"; case HexValidEmailErrors.hexVeErrSuccess: return "None"; case HexValidEmailErrors.hexVeErrLicenseFileNotFound: return "License file not found"; case HexValidEmailErrors.hexVeErrCouldNotOpenLicenseFile: return "Could not open license file"; case HexValidEmailErrors.hexVeErrCorruptLicenseFile: return "License file is corrupt"; case HexValidEmailErrors.hexVeErrWrongProductLicense: return "License is for wrong product"; case HexValidEmailErrors.hexVeErrWrongVersionLicense: return "License is for wrong version"; case HexValidEmailErrors.hexVeErrUnlicensedProcessors: return "Running on machine with unlicensed processors"; default: return "Unknown error"; } } private HexValidEmailLevel _levelTry = HexValidEmailLevel.hexVeLevelSmtp; private HexValidEmailLevel _levelRequired = HexValidEmailLevel.hexVeLevelSyntax; private int _dnsTimeout = 4000; private int _smtpTimeout = 10000; private int _initialError; private Connection _conn; private string _appendedMessage = String.Empty; private string _prependedMessage = String.Empty; private string _clientSideMessage = "The email address is invalid"; private string _regex = _defaultRegex; // See the ClientSideRegex property for comments about this expression. private const string _defaultRegex = @"^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$"; private const string _clientScript = @" <script language=""JavaScript""><!-- // Client-side script for the HexillionEmailValidator sample control. // http://www.Hexillion.com/samples/#HexillionEmailValidator function HEVGetElement( id ) {{ if( document.all ) return document.all[id]; else return document.getElementById( id ); }} function HexillionEmailValidatorValidate() {{ var re = /{0}/i; if( !re.test( HEVGetElement( '{1}' ).value ) ) {{ // Reset to the client-side message in case there's // an old server-side message still in place HEVGetElement( '{2}' ).firstChild.nodeValue = '{3}'; return false; }} return true; }} //--></script> "; } }