一颗不安分的创业心

IHttphandler之“验证码”服务器控件

同样,先看下我们的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), 00, 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方法一样。

快去做自己喜欢的控件吧:)

 

posted @ 2009-06-28 16:45  pangxiaoliang[北京]流浪者  阅读(288)  评论(0编辑  收藏  举报
小豆芽之父