March 16, 2011

Creating a Captcha Control – Part 2

In my last article – Creating a Captcha Control – Part 1, I discussed on the front end of the user control that creates the captcha. In this article, I will discuss on the code-behind of the control – that is, what properties are set and how and what methods are used.

The following code shows the properties that are used.

User Control - Properties
  1. #region field initialisation
  2.  
  3. public Captcha cc;
  4. private int captchaLength;
  5. private double fontSize;
  6. private string fontFamily;
  7. private string backgroundImagePath;
  8. private string textColor;
  9. private string successMessage;
  10. private string errorMessage;
  11. private string characterSet;
  12.  
  13. #endregion

Then, the setters and getters for these properties are created as per below.

User Control - Setter / Getter
  1. #region GetterSetter
  2. public string TestButtonText
  3. {
  4.     get { return B1.Text; }
  5.     set { B1.Text = value; }
  6. }
  7.  
  8. public string SpeakButtonText
  9. {
  10.     get { return BSpeak.Text; }
  11.     set { BSpeak.Text = value; }
  12. }
  13.  
  14. public string ReLoadButtonText
  15. {
  16.     get { return B2.Text; }
  17.     set { B2.Text = value; }
  18. }
  19.  
  20. public string SuccessMessage
  21. {
  22.     get { return successMessage; }
  23.     set { successMessage = value; }
  24. }
  25.  
  26. public string ErrorMessage
  27. {
  28.     get { return errorMessage; }
  29.     set { errorMessage = value; }
  30. }
  31.  
  32. public int CaptchaLength
  33. {
  34.     get { return captchaLength; }
  35.     set
  36.     {
  37.         try
  38.         {
  39.             int k = Convert.ToInt32(value);
  40.             if (k < 5 || k > 10)
  41.                 captchaLength = 6;
  42.             else
  43.                 captchaLength = k;
  44.         }
  45.         catch (Exception ex)
  46.         {
  47.             captchaLength = 6;
  48.         }
  49.     }
  50. }
  51.  
  52. public string FontFamily
  53. {
  54.     get { return fontFamily; }
  55.     set
  56.     {
  57.         if (value != string.Empty && value != null)
  58.             fontFamily = value;
  59.         else
  60.             fontFamily = "Arial";
  61.     }
  62. }
  63.  
  64. public double FontSize
  65. {
  66.     get { return fontSize; }
  67.     set
  68.     {
  69.         try
  70.         {
  71.             fontSize = Convert.ToInt32(value);
  72.             if (fontSize <= 10 && fontSize >= 24)
  73.                 fontSize = 16;
  74.         }
  75.         catch (Exception ex)
  76.         {
  77.             fontSize = 16;
  78.         }
  79.     }
  80. }
  81.  
  82. public string BackgroundImagePath
  83. {
  84.     get { return backgroundImagePath; }
  85.     set
  86.     {
  87.         if (System.IO.File.Exists(Server.MapPath(value)))
  88.             backgroundImagePath = value;
  89.         else
  90.             backgroundImagePath = System.Configuration.ConfigurationManager.AppSettings["defaultImagePath"];
  91.     }
  92. }
  93.  
  94. public string TextColor
  95. {
  96.     get { return textColor; }
  97.     set
  98.     {
  99.         if (value == string.Empty || value == null)
  100.             textColor = "Black";
  101.         else
  102.             textColor = value;
  103.     }
  104. }
  105.  
  106. public string CharacterSet
  107. {
  108.     get { return characterSet; }
  109.     set
  110.     {
  111.         if (value == "" || value == null)
  112.             characterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
  113.         else
  114.             characterSet = value;
  115.     }
  116. }
  117.  
  118. #endregion

The setters and getters are quite straight forward. The captcha length property defaults to 6 in case the value entered is not a number and if the value is less than 6 or greater than 10.

The default font family is set to Arial.

The default font size is set to 16. If fonts are too small – less than 10px – or too large – greater than 24px – the font is automatically set to 16.

The default colour is set to black.

The default character set consists of all letters in uppercase and number from 1 to 9. I have not included lower case letters and 0 as these are sometimes confusing.

The default background image is set within the web.config file. Note that the background image is expected to be within the solution and would require “~” notation to work properly.

Now, in the Page_Load event shown below, I am setting the default values and loading the captcha.

Page_Load event
  1. protected void Page_Load(object sender, EventArgs e)
  2. {
  3.  
  4.     B1.Text = TestButtonText;
  5.     B2.Text = ReLoadButtonText;
  6.     BSpeak.Text = SpeakButtonText;
  7.     
  8.     SetValues();
  9.  
  10.     cc = GetCaptchaClass();
  11.  
  12.     if (!IsPostBack)
  13.     {
  14.         LoadCaptcha();
  15.     }
  16. }

As can be seen, the Button’s text are set a SetValues method is called which sets values for other properties and the method – LoadCaptcha is called if it is not a postback. Another class Captcha is set to method GetCaptchaClass which initiates a Captcha object. I will talk about the Captcha object in a little while.

The SetValues method is below.

SetValues method
  1. private void SetValues()
  2. {
  3.     if (CharacterSet == null)
  4.         CharacterSet = "";
  5.     if(CaptchaLength == 0)
  6.         CaptchaLength = 6;
  7.  
  8.     if(BackgroundImagePath == null)
  9.         BackgroundImagePath = "";
  10.     
  11.     if(FontFamily == null)
  12.         FontFamily = "";            
  13.     
  14.     if(FontSize == 0)
  15.         FontSize = 0.0;
  16.  
  17.     if(TextColor == null)
  18.         TextColor = "";
  19. }

The LoadCaptcha method is interesting – it creates random text and adds it ViewState and Session, adds the Captcha object to Session and sets the path of the Image control to CaptchaHandler.ashx handler. The code for this method is below.

LoadCaptcha method
  1. private void LoadCaptcha()
  2. {
  3.     string text = GetRandomText();
  4.     
  5.     ViewState.Add("captcha", text);
  6.     Session.Add("CaptchaClass", cc);//add captcha object to Session
  7.     Session.Add("captcha", text);//add captcha text to session
  8.     Im1.ImageUrl = "CaptchaHandler.ashx";
  9. }

The random text for the captcha is generated by GetRandomText method which basically creates random text based on the CharacterSet property. The code for this method is below.

GetRandomText method
  1. private string GetRandomText()
  2. {
  3.     char[] letters = CharacterSet.ToCharArray();
  4.     string text = string.Empty;
  5.     Random r = new Random();
  6.     int num = -1;
  7.  
  8.     for (int i = 0; i < this.CaptchaLength; i++)
  9.     {
  10.         num = (int)(r.NextDouble() * (letters.Length - 1));
  11.         text += letters[num].ToString();
  12.     }
  13.     return text;
  14. }

The Captcha class basically properties for the captcha text. The GetCaptchaClass method initiates the Captcha class and set its properties. The code for this method is below.

GetCaptchaClass method
  1. private Captcha GetCaptchaClass()
  2. {
  3.     if (Session["CaptchaClass"] != null)
  4.         cc = (Captcha)Session["CaptchaClass"];
  5.     else
  6.         cc = new Captcha();
  7.  
  8.     cc.FontSize = this.FontSize;
  9.     cc.FontFamily = this.FontFamily;
  10.     cc.BackgroundImagePath = this.BackgroundImagePath;
  11.     cc.TextColor = this.TextColor;
  12.     return cc;
  13. }

That’s pretty much all the methods for the user control. When the Reload Button is clicked the LoadAnother method is run that simply calls the LoadCaptcha method as per below.

LoadAnother method
  1. protected void LoadAnother(object sender, EventArgs e)
  2. {
  3.     LoadCaptcha();
  4. }

When the Test button is clicked, the ValidateCaptcha method is run that compares the text entered with the text in the ViewState. The code is below.

ValidateCaptcha method
  1. protected void ValidateCaptcha(object sender, EventArgs e)
  2. {
  3.     string text = T1.Text;
  4.     if (text == (string)ViewState["captcha"])
  5.         LStatus.Text = SuccessMessage;
  6.     else
  7.         LStatus.Text = ErrorMessage;
  8. }

In my next article, I will explain how the reading out the captcha text works. The captcha control is also available for download from CodePlex at http://captchadotnet.codeplex.com/

0 comments: