Generating Captcha images – ASP.NET MVC
Wikipedia describes Captcha images as:
a type of challenge-response test used in computing as an attempt to ensure that the response is generated by a person
There are a few simple plug-ins that you can use in your ASP.NET MVC app, like reCaptcha, but to have a fully flexible and integrated solution, you have to create your own. In this article, we will define our implementation to handle Captcha images.
Start by creating an empty MVC 3 Internet application.
Go to the HomeController.vb class and add the following Action method.
HomeController.vb
GetCaptcha Action
Function GetCaptcha() As ActionResult
'Captcha Image Size Width - Height
Dim width As Integer = 75
Dim height As Integer = 20
'Captcha String
Dim fontFamily = "Tahoma"
' - Generate Random
Dim randomsize As Integer = 5
Dim randomstringbuilder As New StringBuilder()
Dim random As New Random(DateTime.Now.Millisecond)
Dim ch As Char
For i As Integer = 0 To randomsize - 1
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)))
randomstringbuilder.Append(ch)
Next
Dim captchaString = randomstringbuilder.ToString
' Create a new 32-bit bitmap image.
Dim bitmap As New Drawing.Bitmap(width, height, _
Drawing.Imaging.PixelFormat.Format32bppArgb)
' Create a graphics object for drawing.
Dim g As Drawing.Graphics = Drawing.Graphics.FromImage(bitmap)
g.SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias
Dim rect As New Drawing.Rectangle(0, 0, width, height)
' Fill in the background.
Dim hatchBrush As New Drawing.Drawing2D.HatchBrush(_
Drawing.Drawing2D.HatchStyle.Wave, _
Drawing.Color.LightGray, Drawing.Color.White)
g.FillRectangle(hatchBrush, rect)
' Set up the text font.
Dim size As Drawing.SizeF
Dim fontSize As Single = rect.Height + 1
Dim font As Drawing.Font
Dim format As New Drawing.StringFormat()
format.Alignment = Drawing.StringAlignment.Center
format.LineAlignment = Drawing.StringAlignment.Center
' Adjust the font size until the text fits within the image.
Do
fontSize -= 1
font = New Drawing.Font(fontFamily, fontSize, Drawing.FontStyle.Bold)
size = g.MeasureString(captchaString, font, _
New Drawing.SizeF(width, height), format)
Loop While size.Width > rect.Width
' Create a path using the text and warp it randomly.
Dim path As New Drawing.Drawing2D.GraphicsPath()
path.AddString(captchaString, font.FontFamily, _
CInt(font.Style), font.Size, rect, format)
Dim v As Single = 4.0F
Dim points As Drawing.PointF() = {New Drawing.PointF(random.[Next](rect.Width) / v, _
random.[Next](rect.Height) / v), New Drawing.PointF(rect.Width - _
random.[Next](rect.Width) / v, random.[Next](rect.Height) / v), _
New Drawing.PointF(random.[Next](rect.Width) / v, _
rect.Height - random.[Next](rect.Height) / v), _
New Drawing.PointF(rect.Width - random.[Next](rect.Width) / v, _
rect.Height - random.[Next](rect.Height) / v)}
Dim matrix As New Drawing.Drawing2D.Matrix()
matrix.Translate(0.0F, 0.0F)
path.Warp(points, rect, matrix, Drawing.Drawing2D.WarpMode.Perspective, 0.0F)
' Draw the text.
hatchBrush = New Drawing.Drawing2D.HatchBrush(_
Drawing.Drawing2D.HatchStyle.DashedUpwardDiagonal, _
Drawing.Color.DarkGray, Drawing.Color.Black)
g.FillPath(hatchBrush, path)
' Add some random noise.
Dim m As Integer = Math.Max(rect.Width, rect.Height)
For i As Integer = 0 To CInt(Math.Truncate(rect.Width * rect.Height / 30.0F)) - 1
Dim x As Integer = random.[Next](rect.Width)
Dim y As Integer = random.[Next](rect.Height)
Dim w As Integer = random.[Next](m \ 50)
Dim h As Integer = random.[Next](m \ 50)
g.FillEllipse(hatchBrush, x, y, w, h)
Next
' Clean up.
font.Dispose()
hatchBrush.Dispose()
g.Dispose()
Dim captchaImageResult As FileContentResult = Nothing
Using mystream As New System.IO.MemoryStream()
bitmap.Save(mystream, System.Drawing.Imaging.ImageFormat.Jpeg)
captchaImageResult = MyBase.File(mystream.GetBuffer, "image/jpeg")
End Using
bitmap.Dispose()
'Save the Captcha Hash in the Session
Session("botdeflector") = _
Convert.ToBase64String(System.Security.Cryptography.MD5.Create().
ComputeHash(Encoding.UTF8.GetBytes(captchaString)))
'Return the Captcha Image
Return captchaImageResult
End Function
What is mostly happening here is the generation of the image, pasting in the text that you want for the Captcha image, adding some noise, and in the end, we save the hash for the generated text. This is what we will use later to verify that the user submitted the correct string of text. The most important part is saving the hash to the session state.
Change the index page a little, adding a new form, an image tag with its source set as the captcha image, and a submit button.
Index.vbhtml
@Code
ViewData("Title") = "Home Page"
End Code
<h2>@ViewData("Message")</h2>
@Using Html.BeginForm
@<div>
<img src='@Url.Action("GetCaptcha")' alt='Captcha' />
<input type="text" size="10"
name="CaptchaAnswer" autocomplete="off" />
<br />
<input type="submit" value="Submit"/>
</div>
End Using
Add a new POST only index Action method.
HomeController.vb
Index Action (POST)
<HttpPost()>
Function index(CaptchaAnswer As String) As ActionResult
Dim captchaHash = Session("botdeflector")
If captchaHash = Convert.ToBase64String(_
System.Security.Cryptography.MD5.Create().ComputeHash(_
Encoding.UTF8.GetBytes(UCase(CaptchaAnswer)))) Then
'Valid
ViewData("Message") = "YOU ARE A PERSON :>"
Else
'Invalid
ViewData("Message") = "YOU ARE A ROBOT!"
End If
Return View()
End Function
The validation begins with converting the Captcha answer the user supplied to its hash equivalent, then we get our saved hash from the current user session, compare them, and return the result.
Here is the complete project if you want it. And you can also use the following helper functions for random generation of strings or numbers:
Generate Random Number Function
Private Function generateRandomNumber(ByVal size As Integer) As String
Dim builder As New StringBuilder()
Dim random As New Random(DateTime.Now.Millisecond)
Dim ch As Char
For i As Integer = 0 To size - 1
ch = random.Next(9).ToString
builder.Append(ch)
Next
Return builder.ToString()
End Function
Generate Random String Function
Private Function generateRandomString(ByVal size As Integer) As String
Dim builder As New StringBuilder()
Dim random As New Random(DateTime.Now.Millisecond)
Dim ch As Char
For i As Integer = 0 To size - 1
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)))
builder.Append(ch)
Next
Return builder.ToString()
End Function
Screenshot of Demo Site

Post Comment
yPbrTh Thanks for sharing, this is a fantastic blog post.Really looking forward to read more. Cool.
iIJSOV I wanted to thank you for this great article, I definitely loved each and every little bit of it. I ave bookmarked your internet site to look at the newest stuff you post.
cKB8H6 This is really interesting, You are a very skilled blogger. I ave joined your feed and look forward to seeking more of your fantastic post. Also, I ave shared your website in my social networks!
Tvi3Vx Very fantastic information can be found on site.
Very true! Makes a change to see soeomne spell it out like that. :)
sychEH Muchos Gracias for your article. Will read on
FqBm8q Really appreciate you sharing this post.Really looking forward to read more. Fantastic.
wFVt9q Some truly prize content on this internet site, saved to bookmarks.
ASdZbf
OSuFm2 I cannot thank you enough for the post.Thanks Again. Cool.
9H3uxX While checking out DIGG yesterday I found this
Проводится набор сотрудников на высокооплачиваемую работу через интернет.
Требования: Наличие компьютера, интернет, желание работать.
Оплата ежедневная.
affiliates@greedeals.comПроводится набор сотрудников на высокооплачиваемую работу через интернет.
Требования: Наличие компьютера, интернет, желание работать.
Оплата ежедневная.
affiliates@greedeals.comПроводится набор сотрудников на высокооплачиваемую работу через интернет.
Требования: Наличие компьютера, интернет, желание работать.
Оплата ежедневная.
pabloblanes@photaki.comПроводится набор сотрудников на высокооплачиваемую работу через интернет.
Требования: Наличие компьютера, интернет, желание работать.
Оплата ежедневная.
info@forma.coXP7eqb I really enjoy the blog article.Much thanks again. Awesome.
TXGKRY Thanks again for the post.Thanks Again.
P7vhK7 This is one awesome post. Cool.
OumC2s Looking forward to reading more. Great article.Really looking forward to read more. Fantastic.
sAYPvP Thanks a lot for the post. Much obliged.
name
Gijsbert Sonneveltname
Petdr Allenname
Mikal Sky-Shrewsberryname
Flemming Krristensenname
Rhonda alexandername
Greg Brewername
Manuel Grenachername
Serge UDRISARDname
Dennis Ruggerename
Roberto Gnerrename
Katherine L. Gabehartname
Linda Barirngtonname
George Whysallname
Greg Johllname
Cheryyl Vaukname
Sterwart Collisname
Sean OConnorname
William ETurcottename
Federico Simonettiname
Jacek Kundzikname
Daniel Szymanskiname
Jargen Pemselname
Don Milidesname
lakshmi narayanAname
Jos=C3=A9 Costaname
David Wangname
Michael T Moriartyname
Chris Wenhamname
Richard Borlazaname
James King