首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET 驗證碼 HttpHandler 實作(C# 與 VB.NET 完整代碼)

     編輯:ASP.NET 基礎

架構優勢

  • 分離關注點:.ashx 專責圖片產生,.aspx 專責頁面邏輯
  • 無 ViewState/頁面生命週期:輕量、回應快
  • 易於快取控制:可精確設定 Response.Cache

C# 版 ValidationCode.ashx

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Reflection;
using System.Web;

public class ValidationCode : IHttpHandler
{
    static Random r = new Random(Guid.NewGuid().GetHashCode());
    // 取得 Brushes/Pens 所有公開靜態屬性(排除黑色/透明)
    static PropertyInfo[] colors = typeof(Brushes)
        .GetProperties(BindingFlags.Public | BindingFlags.Static)
        .Where(p => p.Name != "Black" && p.Name != "Transparent").ToArray();
    static PropertyInfo[] lineColors = typeof(Pens)
        .GetProperties(BindingFlags.Public | BindingFlags.Static)
        .Where(p => p.Name != "Black").ToArray();
    static object brushObj = typeof(Brushes).GetConstructor(BindingFlags.NonPublic, null, Type.EmptyTypes, null);
    static object penObj = typeof(Pens).GetConstructor(BindingFlags.NonPublic, null, Type.EmptyTypes, null);

    const float CharWidth = 40f;
    const float CharHeight = 50f;

    public void ProcessRequest(HttpContext context)
    {
        int count = 5;
        int.TryParse(context.Request.QueryString["reqNum"], out count);

        Bitmap bmp = new Bitmap((int)(CharWidth * count), (int)CharHeight);
        Graphics g = Graphics.FromImage(bmp);

        string code = "";
        for (int i = 1; i <= count; i++)
        {
            code += r.Next(0, 9);
            var prop = colors[r.Next(colors.Length)];
            Brush brush = (Brush)prop.GetValue(brushObj, null);
            g.DrawString(code[i-1].ToString(), new Font("黑體", CharWidth), brush, new PointF((i-1)*CharWidth, 0));
        }

        // 干擾線
        int lineCount = r.Next(10, 21);
        for (int i = 0; i < lineCount; i++)
        {
            var prop = lineColors[r.Next(lineColors.Length)];
            Pen pen = (Pen)prop.GetValue(penObj, null);
            g.DrawLine(pen,
                new PointF((float)(r.NextDouble() * CharWidth * count), (float)(r.NextDouble() * CharHeight)),
                new PointF((float)(r.NextDouble() * CharWidth * count), (float)(r.NextDouble() * CharHeight)));
        }

        g.Dispose();
        context.Response.Clear();
        context.Response.ContentType = "image/jpeg";
        bmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);
        bmp.Dispose();
        context.Response.End();
    }

    public bool IsReusable => false;
}

VB.NET 版


Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Reflection
Imports System.Web

Public Class ValidationCode
    Implements IHttpHandler

    Shared r As New Random(Guid.NewGuid().GetHashCode())
    Shared colors As PropertyInfo() = GetType(Brushes).GetProperties(
        BindingFlags.Public Or BindingFlags.Static).Where(Function(p) p.Name <> "Black" AndAlso p.Name <> "Transparent").ToArray()
    Shared lineColors As PropertyInfo() = GetType(Pens).GetProperties(
        BindingFlags.Public Or BindingFlags.Static).Where(Function(p) p.Name <> "Black").ToArray()
    Shared brushObj As Object = GetType(Brushes).GetConstructor(BindingFlags.NonPublic, Nothing, Type.EmptyTypes, Nothing)
    Shared penObj As Object = GetType(Pens).GetConstructor(BindingFlags.NonPublic, Nothing, Type.EmptyTypes, Nothing)
    Const CharWidth As Single = 40F
    Const CharHeight As Single = 50F

    Public Sub ProcessRequest(context As HttpContext) Implements IHttpHandler.ProcessRequest
        Dim count As Integer = 5
        Integer.TryParse(context.Request.QueryString("reqNum"), count)
        Dim bmp As New Bitmap(CInt(CharWidth * count), CInt(CharHeight))
        Dim g As Graphics = Graphics.FromImage(bmp)
        Dim code As String = ""
        For i = 1 To count
            code += r.Next(0, 9).ToString()
            Dim prop = colors(r.Next(colors.Length))
            Dim brush As Brush = DirectCast(prop.GetValue(brushObj, Nothing), Brush)
            g.DrawString(code(i-1).ToString(), New Font("黑體", CharWidth), brush, New PointF((i-1)*CharWidth, 0))
        Next
        Dim lineCount = r.Next(10, 21)
        For i = 1 To lineCount
            Dim prop = lineColors(r.Next(lineColors.Length))
            Dim pen As Pen = DirectCast(prop.GetValue(penObj, Nothing), Pen)
            g.DrawLine(pen,
                New PointF(CSng(r.NextDouble() * CharWidth * count), CSng(r.NextDouble() * CharHeight)),
                New PointF(CSng(r.NextDouble() * CharWidth * count), CSng(r.NextDouble() * CharHeight)))
        Next
        g.Dispose()
        context.Response.Clear()
        context.Response.ContentType = "image/jpeg"
        bmp.Save(context.Response.OutputStream, ImageFormat.Jpeg)
        bmp.Dispose()
        context.Response.End()
    End Sub

    Public ReadOnly Property IsReusable As Boolean Implements IHttpHandler.IsReusable
        Get : Return False : End Get
    End Property
End Class

前台引用與換圖

<img src="/ValidationCode.ashx?reqNum=10" id="imgSD" />
<input type="button" value="換一張" onclick="ChangeSD()" />
<script>
function ChangeSD() {
    var img = document.getElementById("imgSD");
    img.src = "";              // 清空觸發重新請求
    img.src = "/ValidationCode.ashx?reqNum=10";
}
</script>

驗證碼示意圖

設計細節說明

  1. 靜態反射快取:colors/lineColors/brushObj/penObj 為 static,避免每次請求反射效能損耗
  2. 排除顏色:背景為黑色,故排除 Brushes.Black/Transparent;線條排除黑色
  3. 隨機種子:Guid.NewGuid().GetHashCode() 確保高熵值
  4. 雙次設 src:瀏覽器對相同 URL 不重新請求,先清空再設回原 URL 強制重載
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved