top
Loading...
ASP.NET設計控件凈化網站語言


一、概述

考慮一下這種情形:你為一個Web網站寫了一個應用程序,它的功能是接受用戶的輸入并將輸入內容永久保存,例如保存到數據庫,另外還要在網站上顯示出用戶輸入的內容,例如論壇就是一個很典型的例子。

如果用戶來源很雜,必須考慮如何防止用戶提交和張貼攻擊性(或者色情的、庸俗的)的內容。可能的解決方案包括:

⑴ 將用戶群限制到一個封閉的用戶團體,即要求用戶使用程序功能之前必須先注冊/登錄。這樣,由于每次提交的內容都可以追查到提交者,用戶破壞網站規則的可能性就小了很多。如果有用戶做出了不應該做的事,你就可以核實用戶身份,予以相應的處理。

⑵ 在網站上發布用戶提交的內容之前,先由管理員審閱。很多時候,由于人力資源有限,這個辦法不一定行得通。

⑶ 禁止用戶提交攻擊性內容。這是最理想的解決辦法,把問題解決在起源。但具體應該怎么實現呢?

本文介紹的方案以一個復合控件為基礎,利用一個XML文件來定義攻擊性詞語。我們將用VB.NET編寫這個復合控件,用普通的文本編輯器和命令行編譯器(vbc)完成整個工程的構建。

在正式編寫控件之前,首先我們來簡單地回顧一下ASP.NET中控件的概念。本文出現的所有控件都是服務器控件,它們在服務器上運行,將HTML代碼發送到客戶端。要理解控件的分類,可以從控件是否嵌入到Web表單頁面(因而采用按需編譯方式)或預先編譯的角度來觀察。微軟定義了下列ASP.NET服務器控件:HTML服務器控件,Web服務器控件,驗證控件,用戶控件。

前三種控件讀者應該已經比較熟悉了,對于開發者來說,它們是最簡單的控件類型,在ASP.NET中已經由微軟為我們編寫好。用戶控件則有所不同。用戶控件是“包裝”成.ascx頁面形式的.aspx頁面,其他.aspx頁面可以通過注冊和實例化來調用用戶控件的功能。這是一種被寄予厚望的服務器端控件,對于ASP/ASP.NET開發者來說,它代表著一大進步,特別地,現在編寫控件的語言已經全面支持面向對象技術。

ASP.NET用戶控件由一個或多個服務器控件、靜態HTML元素構成,可以包含額外的代碼,每個用戶控件封裝一組特定的功能。用戶控件可以通過簡單地擴展現有服務器控件(控件組)得到,例如,帶有旋轉功能的圖形控件,在文本框中保存日期的日歷控件。

二、開發復合控件

控件要檢查用戶提交的內容是否包含“攻擊性”詞語,攻擊性詞語由一個XML文件定義,XML文件的結構如下:

<?xml version="1.0"? encoding="GB2312">
<words>
<word>詞語一</word>
<word>詞語二</word>
</words>

本文的復合控件(Composite)包含三個ASP.NET服務器控件:一個Textbox控件,一個Label控件,還有一個Button控件。當用戶點擊Button控件,Composite檢查用戶提交的文本是否包含了XML文件中指定的詞語(XML文件的默認名字是bad_words.xml,通過一個自定義屬性定義),并拋出一個自定義事件。另外,Composite控件還將它的Label子控件的一個Text屬性顯露成頂級屬性。

復合控件可以有選擇地將子控件顯露成屬性,或者有選擇地將子控件的屬性和事件作為頂級屬性和事件顯露出來。當復合控件整合來自子控件的屬性時,它通常只是簡單地委托子控件執行操作,如下面的例子所示:

// 將操作委托給標簽對象,標簽對象是一個
// System.Web.UI.WebControls.Label的實例
Public Property Text() As String
Get
EnsureChildControls()
Return label.Text
End Get
Set
EnsureChildControls()
label.Text = value
End Set
End Property

我們需要一個文本輸入框讓用戶輸入內容,一個按鈕來提交表單,還要一個向用戶反饋信息的文本標簽。下面我們來看看Web表單的代碼,復合控件就是在這里實例化的:

【composite.aspx】

<%@ page language="vb" debug="false" trace="false" %>
<%@ Register TagPrefix="Custom" Namespace="CustomControls" Assembly = "CustomControls" %>
<html>
<script language="VB" runat=server>
Private Sub CheckText(sender As Object, e As CheckEventArgs)
If e.Match = false Then
Composite.Text = "<h2>發布內容請遵守本站規則!不得發布攻擊性言辭!</h2>"
Else
Composite.Text = "你提交的內容已通過檢查!"
End If
End Sub
</script>

<body>

<h1>語言凈化控件實例</h1><br>
<form runat=server>
<Custom:Composite id = "Composite" OnCheck = "CheckText"
filename = "bad_words.xml" runat = server/></form></body>
</html>

上面的代碼首先注冊指定的復合控件。我們將把控件的代碼編譯成一個.dll文件,放入應用的bin目錄,這是ASP.NET首先搜索的位置。在Web表單構成的用戶界面中,我們實例化了自定義控件,同時指定了:

⑴ 當控件拋出OnCheck事件,執行一個本地的子過程CheckText。我們把復合控件的標簽的文本通過一個公用屬性顯露出來,標簽的內容由OnCheck事件句柄設置的另一個公用屬性決定。

⑵ 定義攻擊性詞語的XML文件的名字。

⑶ 另外,我們還定義了一個由復合控件調用的CheckText子過程。

現在來看復合控件本身。復合控件有兩個類,用兩個獨立的VB源文件實現,分別是composite.vb和checkevent.vb。

【composite.vb】

Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Xml
Imports System.Collections

Namespace CustomControls
Public Class Composite
Inherits Control
Implements INamingContainer
Private _filename As String = "bad_words.xml"
Private label As Label
Private box1 As TextBox

Public Property filename() As String
Get
Return _filename
End Get
Set
_filename = value
End Set
End Property

' 以用戶提交的文本內容為輸入參數。如果用戶提交的內容包含攻擊性言辭,
' 則返回修改后的版本,
' 否則,直接返回原始的文本。
Public Function CheckString(InputString as String) as string
Dim alWordList As new ArrayList
dim xmlDocPath as string = mappathsecure("bad_words.xml")
dim xmlReader as XmlTextreader = new xmlTextReader(xmlDocPath)
dim element as string
dim output as string
dim asterisks as string = "*************************"

' 將定義攻擊性言辭的xml文件內容讀入到一個ArrayList
while (xmlReader.Read())
if xmlReader.NodeType=xmlNodeType.Text then
alWordList.Add(xmlReader.Value)
end if
end while
xmlReader.Close()

' 檢查用戶提交的文本內容,將攻擊性言辭替換為適當數量的星號
For Each element in alWordList
InputString=InputString.Replace(element,
asterisks.substring(1, (element.length)))
Next

Return InputString

End Function

Public Property Text() As String
Get
' 該方法首先檢查ChildControlsCreated屬性的當前值。如果該值是false,
' 則調用CreateChildControls方法
EnsureChildControls()
Return label.Text
End Get
Set
EnsureChildControls()
label.Text = value
End Set
End Property

Public Event Check As CheckEventHandler

Protected Overridable Sub OnCheck(ce As CheckEventArgs)
RaiseEvent Check(Me, ce)
End Sub

'創建Composite控件的子控件
Protected Overrides Sub CreateChildControls()

Controls.Add(New LiteralControl("<h3>請在下面輸入文字內容: "))

'文本輸入框
Dim box1 As New Textbox()
box1.Text = ""
Controls.Add(box1)

Controls.Add(New LiteralControl("</h3>"))

'按鈕
Dim button1 As New Button()
button1.Text = "提交"
Controls.Add(New LiteralControl("<br>"))
Controls.Add(button1)

' 將一個事件句柄加入新創建的按鈕對象
AddHandler button1.Click, AddressOf Me.ButtonClicked

Controls.Add(New LiteralControl("<br><br>"))
label = New Label()
label.Height = Unit.Pixel(50)
label.Width = Unit.Pixel(500)
label.Text = ""
Controls.Add(label)
End Sub

Protected Overrides Sub OnPreRender(e As EventArgs)
CType(Controls(1), TextBox).Text = ""
End Sub

Private Sub ButtonClicked(sender As [Object], e As EventArgs)
OnCheck(New CheckEventArgs(CType(Controls(1), TextBox).Text,
CheckString(CType(Controls(1), TextBox).Text)))
End Sub
End Class
End Namespace

上面代碼的主要任務是:

⑴ 首先導入必要的名稱空間,聲明當前類所屬的名稱空間。

⑵ 接下來定義Composite的主體。Composite從最基本的Control類繼承,另外還要實現INamingContainer接口。INamingContainer接口允許Composite控件將事件轉發到它的Button子控件。

⑶ 用CreateChildControls方法(而不是OnInit或構造函數)創建子控件。

⑷ Composite控件沒有顯露出Button子控件的Click事件。相反,它處理了Click事件,并拋出自定義事件Check。

⑸ Composite控件顯露了下列公用屬性:Text,即Label子控件的Text屬性值;FileName,允許獲取和設置定義攻擊性詞語的XML文件的名字

⑹ 主要的檢查功能由CheckString方法實現,它的輸入參數是一個文本字符串。CheckString方法從XML文件讀取禁用的詞語,放入一個數組列表(ArrayList),然后檢查指定的字符串是否包含禁用的詞語。所有“攻擊性”的詞語將被適當數量的“*”替代。

⑺ OnPreRender清除文本框子控件的文本。

⑻ 當用戶點擊按鈕,ButtonClicked開始執行。ButtonClicked調用onCheck子過程,傳入適當的參數(一個新建的CheckEventArgs對象,創建CheckEventArgs對象的參數是檢查前和檢查后的文本)。OnCheck隨后觸發一個事件,該事件將由.aspx頁面中的代碼處理。

【CheckEvent.vb】

' 包含定制事件數據類CheckEventArgs的代碼.
' 另外還定義了Check事件的事件句柄
Imports System
Namespace CustomControls
Public Class CheckEventArgs
Inherits EventArgs
Private _match As Boolean = False

Public Sub New(string1 As String, string2 as String)
If string1=string2 Then
_match = True
End If
End Sub

Public ReadOnly Property Match() As Boolean
Get
Return _match
End Get
End Property
End Class

Public Delegate Sub CheckEventHandler(sender As Object, ce As CheckEventArgs)
End Namespace

CheckEventArgs的構造函數是兩個字符串,根據字符串的值設置相應的匹配標記_match。另外,上面的代碼還定義了CheckEventHandler事件句柄。

編寫好上面的代碼后,如果你沒有安裝IDE,用下面的命令執行編譯即可:

vbc /t:library /out:./bin/CustomControls.dll /r:System.dll /r:System.web.dll
/r:System.drawing.dll /r:System.Data.dll /r:System.xml.dll *.vb





作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗