IHttphandler之“验证码”服务器控件
同样,先看下我们的web.config文件:
<httpHandlers>
<add verb="*" path="*.yy" type="Identify.LandpyHttpHander,Identify"/>
</httpHandlers>
首先提个问题大家见过后缀名为“yy”的文件吗,呵呵,这里实际上是使用了一个小技巧。利用IHttphandler来实现服务器端控件的事件,当点击控件时,发送一个“*.yy”路径的请求,从而实现Identify.LandpyHttpHander处理并返回客户端。
下面上代码:
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.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方法一样。
快去做自己喜欢的控件吧:)