同样,先看下我们的web.config文件:
<httpHandlers>
<add verb="*" path="*.yy" type="Identify.LandpyHttpHander,Identify"/>
</httpHandlers>
首先提个问题大家见过后缀名为“yy”的文件吗,呵呵,这里实际上是使用了一个小技巧。利用IHttphandler来实现服务器端控件的事件,当点击控件时,发送一个“*.yy”路径的请求,从而实现Identify.LandpyHttpHander处理并返回客户端。
下面上代码:
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Text;
using
System.Web;
using
System.Web.UI;
using
System.Web.UI.WebControls;
using
System.Web.SessionState;
namespace
Identify
{
[DefaultProperty(
"
Text
"
)]
[ToolboxData(
"
<{0}:LandpyIdentityControl runat=server></{0}:LandpyIdentityControl>
"
)]
public
class
LandpyIdentityControl : WebControl
{
[Bindable(
true
)]
[Category(
"
Appearance
"
)]
[DefaultValue(
""
)]
[Localizable(
true
)]
public
string
Text
{
get
{
String s
=
(String)ViewState[
"
Text
"
];
return
((s
==
null
)
?
String.Empty : s);
}
set
{
ViewState[
"
Text
"
]
=
value;
}
}
internal
static
int
_wordLength;
[Description(
"
验证码长度
"
)]
public
int
WordLength
{
get
{
return
LandpyIdentityControl._wordLength; }
set
{
LandpyIdentityControl._wordLength
=
value;
}
}
internal
static
string
_value;
[Description(
"
验证码内容
"
)]
public
string
Value
{
get
{
return
LandpyIdentityControl._value; }
}
protected
override
void
RenderContents(HtmlTextWriter output)
{
//
output.Write(Text);
}
public
LandpyIdentityControl()
:
base
(HtmlTextWriterTag.Img)
//
重写父类的构造(输出流的HTML标记设置为图像类型)
{ }
protected
override
void
AddAttributesToRender(HtmlTextWriter writer)
{
base
.AddAttributesToRender(writer);
writer.AddStyleAttribute(HtmlTextWriterStyle.Cursor,
"
pointer
"
);
writer.AddAttribute(
"
onclick
"
,
"
this.src='img.yy?id='+Math.random()
"
);
writer.AddAttribute(HtmlTextWriterAttribute.Src,
"
img.yy
"
);
writer.AddAttribute(
"
alt
"
,
"
点击刷新
"
);
}
}
}
下面是处理类:
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Web;
using
System.Web.UI.WebControls;
using
System.Web.UI;
using
System.Web.SessionState;
using
System.Drawing;
using
System.IO;
namespace
Identify
{
public
class
LandpyHttpHander : IHttpHandler, IRequiresSessionState
{
///
<summary>
///
返回验证码字符
///
</summary>
///
<param name="codeCount">
验证码长度
</param>
///
<returns></returns>
private
string
GetRandomNumberString(
int
codeCount)
{
string
strChoice
=
"
2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,T,U,V,W,X,Y,Z
"
;
string
[] strResult
=
strChoice.Split(
new
Char[] {
'
,
'
});
string
strReturn
=
""
;
Random rnd
=
new
Random();
for
(
int
i
=
0
; i
<
codeCount; i
++
)
{
int
j
=
rnd.Next(strResult.Length);
strReturn
=
strReturn
+
strResult[j].ToString();
}
return
strReturn;
}
private
Color GetColor()
{
return
Color.Black;
}
private
Bitmap CreateImage(
string
str_AuthCode)
{
int
width
=
str_AuthCode.Length
*
21
;
int
height
=
30
;
Random rad
=
new
Random();
Bitmap bmp
=
new
Bitmap(width, height);
Graphics grp
=
Graphics.FromImage(bmp);
//
在图片上绘制图形
grp.Clear(Color.LightGreen);
grp.DrawRectangle(
new
Pen(Color.DarkGreen,
1
),
0
,
0
, width
-
1
, height
-
1
);
//
画图片的背景噪音线
for
(
int
i
=
0
; i
<
15
; i
++
)
{
int
x1
=
rad.Next(width);
int
x2
=
rad.Next(width);
int
y1
=
rad.Next(height);
int
y2
=
rad.Next(height);
grp.DrawLine(
new
Pen(Color.Black), x1, y1, x2, y2);
}
//
画图片的前景噪音点
for
(
int
i
=
0
; i
<
100
; i
++
)
{
int
x
=
rad.Next(width);
int
y
=
rad.Next(height);
bmp.SetPixel(x, y, Color.Black);
}
Font f
=
new
Font(
"
宋体
"
,
20
, FontStyle.Bold);
Brush br
=
new
SolidBrush(Color.Black);
for
(
int
i
=
0
; i
<
str_AuthCode.Length; i
++
)
{
string
s
=
str_AuthCode.Substring(i,
1
);
Point p
=
new
Point(i
*
20
+
rad.Next(
3
), rad.Next(
3
)
+
1
);
grp.DrawString(s, f, br, p);
}
grp.Dispose();
return
bmp;
}
///
<summary>
///
是否可以处理远程的HTTP请求
///
</summary>
public
bool
IsReusable
{
get
{
return
true
; }
}
///
<summary>
///
将验证码图片发送给WEB浏览器
///
</summary>
///
<param name="context"></param>
public
void
ProcessRequest(HttpContext context)
{
int
size
=
LandpyIdentityControl._wordLength;
//
Int32.Parse((String)context.Session["Size"]);
MemoryStream ms
=
new
MemoryStream();
string
NumStr
=
GetRandomNumberString(size);
LandpyIdentityControl._value
=
NumStr;
//
context.Session.Add("value", NumStr);
//
将验证码字符保存到session里面
Bitmap theBitmap
=
CreateImage(NumStr);
theBitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
context.Response.ClearContent();
context.Response.ContentType
=
"
image/jpeg
"
;
//
需要输出图象信息 要修改HTTP头为jpeg类型
context.Response.BinaryWrite(ms.ToArray());
theBitmap.Dispose();
ms.Close();
ms.Dispose();
context.Response.End();
}
}
}
其中验证码图片的生成随便copy了下,实际就是GDI+实现DrawString方法。如果对GDI+有了解相信会很容易理解的。
这样“验证码”服务器控件就OK了,如果要使用,引入相应的Dll,设置下web.config,设置下控件的字符个数就可以使用了,很简单。
在设计视图中,自定义服务器控件的属性可以赋初始值。比如我们的控件属性:
[Description("验证码长度")]
public int WordLength
{
get { return LandpyIdentityControl._wordLength; }
set
{
LandpyIdentityControl._wordLength = value;
}
}
可以设置验证码的长度。
另外,自定义控件是从WebControl继承,可以重写很多方法,比如RenderControl,RenderContents,AddAttributesToRender等,各个方法的作用可以查阅相关资料,本文不再说明。其中,对于UI来说RenderXXXX一系列方法是很重要的,如同Winfrom程序中的OnPrint方法一样。
快去做自己喜欢的控件吧:)