<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>系統架構/機制</title><link>http://blog.blueshop.com.tw/jeff377/category/2564.aspx</link><description>系統架構/機制</description><managingEditor>jeff</managingEditor><dc:language>zh-CHT</dc:language><generator>.Text Version 0.95.2004.101</generator><item><dc:creator>jeff</dc:creator><title>BasePage 撰寫 PageCommand 事件</title><link>http://blog.blueshop.com.tw/jeff377/archive/2008/08/29/56861.aspx</link><pubDate>Fri, 29 Aug 2008 20:46:00 GMT</pubDate><guid>http://blog.blueshop.com.tw/jeff377/archive/2008/08/29/56861.aspx</guid><wfw:comment>http://blog.blueshop.com.tw/jeff377/comments/56861.aspx</wfw:comment><comments>http://blog.blueshop.com.tw/jeff377/archive/2008/08/29/56861.aspx#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://blog.blueshop.com.tw/jeff377/comments/commentRss/56861.aspx</wfw:commentRss><trackback:ping>http://blog.blueshop.com.tw/jeff377/services/trackbacks/56861.aspx</trackback:ping><description>&lt;P&gt;&lt;FONT color=#0000ff size=3&gt;&lt;STRONG&gt;前言&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;在「&lt;A href="http://www.dotblogs.com.tw/jeff377/archive/2008/08/01/4752.aspx"&gt;&lt;FONT color=#669966&gt;撰寫自用 Confirm 方法&lt;/FONT&gt;&lt;/A&gt;」一文中提到的「案例三：先執行伺服端程式再彈出詢問訊息，依用戶端回應再接續執行」，當用戶端回應詢問訊息後，會呼叫 __doPostBack() 函式來產生 PostBack 的動作，頁面再自行判斷 Me.Request.Form("__EVENTTARGET") 及 Me.Request.Form("__EVENTARGUMENT")&amp;nbsp; 來處理後序的作業。可是這樣處理 PostBack 的方式略顯麻煩，換個角度思考，若 Page 也能像 GridView 一樣具有類似 RowCommand 的事件，可以處理這類的 PostBack 那不是更方便了嗎？所以本文將在 BasePage 加入 PageCommand 事件，針對這個案例改用 PageCommand 來處理。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff size=3&gt;&lt;STRONG&gt;程式實作&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;我們將使用「&lt;A href="http://www.dotblogs.com.tw/jeff377/archive/2008/05/25/4116.aspx"&gt;&lt;FONT color=#669966&gt;撰寫自用的 ScriptManager 來管理用戶端指令碼&lt;/FONT&gt;&lt;/A&gt;」文中提及的 TBBasePage 類別及 TBScriptManager 類別為基礎做擴展。首先在 TBBasePage 新增一個 PageCommand 事件，作法如下。&lt;/P&gt;
&lt;P&gt;1.定義 PageCommand 事件。 &lt;BR&gt;2.新增 EventTarget 唯讀屬性，傳回 Me.Request.Form("__EVENTTARGET")。 &lt;BR&gt;3.新增 EventArgument 唯讀屬性，傳回 Me.Request.Form("__EVENTARGUMENT")。 &lt;BR&gt;4.覆寫 OnLoad 方法，判斷 EventTarget 及 EventArgument 屬性值，來決定是否引發 PageCommand 事件。&lt;/P&gt;
&lt;P&gt;&lt;TEXTAREA class=vb name=code rows=6 cols=50&gt;''' &amp;lt;summary&amp;gt;
''' 頁面基礎類別。
''' &amp;lt;/summary&amp;gt;
Public Class TBBasePage
    Inherits System.Web.UI.Page

#Region " PageCommand 事件 "

    ''' &amp;lt;summary&amp;gt;
    ''' DayCommand 事件引數。
    ''' &amp;lt;/summary&amp;gt;
    Public Class PageCommandEventArgs
        Inherits System.EventArgs
        Private FCommandName As String = String.Empty
        Private FCommandArgument As String = String.Empty

        ''' &amp;lt;summary&amp;gt;
        ''' 命令名稱。
        ''' &amp;lt;/summary&amp;gt;
        Public Property CommandName() As String
            Get
                Return FCommandName
            End Get
            Set(ByVal value As String)
                FCommandName = value
            End Set
        End Property

        ''' &amp;lt;summary&amp;gt;
        ''' 命令引數。
        ''' &amp;lt;/summary&amp;gt;
        Public Property CommandArgument() As String
            Get
                Return FCommandArgument
            End Get
            Set(ByVal value As String)
                FCommandArgument = value
            End Set
        End Property

    End Class

    ''' &amp;lt;summary&amp;gt;
    ''' 頁面命令事件。
    ''' &amp;lt;/summary&amp;gt;
    &amp;lt; _
    System.ComponentModel.Description("頁面命令事件。") _
    &amp;gt; _
    Public Event PageCommand(ByVal sender As Object, ByVal e As PageCommandEventArgs)

    ''' &amp;lt;summary&amp;gt;
    ''' 引發 PageCommand 事件。
    ''' &amp;lt;/summary&amp;gt;
    Protected Overridable Sub OnPageCommand(ByVal e As PageCommandEventArgs)
        RaiseEvent PageCommand(Me, e)
    End Sub

#End Region

    ''' &amp;lt;summary&amp;gt;
    ''' 觸發 PostBack 的控制項 UniqueID。
    ''' &amp;lt;/summary&amp;gt;
    Public ReadOnly Property EventTarget() As String
        Get
            Return Me.Request.Form("__EVENTTARGET")
        End Get
    End Property

    ''' &amp;lt;summary&amp;gt;
    ''' 觸發 PostBack 動作事件引數 。
    ''' &amp;lt;/summary&amp;gt;
    Public ReadOnly Property EventArgument() As String
        Get
            Return Me.Request.Form("__EVENTARGUMENT")
        End Get
    End Property

    ''' &amp;lt;summary&amp;gt;
    ''' 判斷二字串是否相同(不區分大小寫)。
    ''' &amp;lt;/summary&amp;gt;
    ''' &amp;lt;param name="S1"&amp;gt;第一個字串。&amp;lt;/param&amp;gt;
    ''' &amp;lt;param name="S2"&amp;gt;第二個字串。&amp;lt;/param&amp;gt;
    Public Shared Function SameText(ByVal S1 As String, ByVal S2 As String) As Boolean
        If S1 Is Nothing Then
            Return S2 Is Nothing
        End If
        Return S1.Equals(S2, StringComparison.CurrentCultureIgnoreCase)
    End Function

    ''' &amp;lt;summary&amp;gt;
    ''' 覆寫。引發 Load 事件。
    ''' &amp;lt;/summary&amp;gt;
    Protected Overrides Sub OnLoad(ByVal e As EventArgs)
        Dim oArgument() As String
        Dim oEventArgs As PageCommandEventArgs

        MyBase.OnLoad(e)

        If SameText(Me.EventTarget, Me.UniqueID) Then
            '引發 PageCommand 事件
            oArgument = Split(Me.EventArgument, "$")
            If oArgument.Length = 3 Then
                If SameText(oArgument(0), "PageCommand") Then
                    oEventArgs = New PageCommandEventArgs()
                    oEventArgs.CommandName = oArgument(1)
                    oEventArgs.CommandArgument = oArgument(2)
                    Me.OnPageCommand(oEventArgs)
                End If
            End If
        End If
    End Sub

End Class&lt;/TEXTAREA&gt;&lt;/P&gt;
&lt;P&gt;然後在 TBScriptManager 類別新增一個 GetPageCommandEventReference 方法，取得引發 PageCommand 事件的用戶端指令碼。&lt;/P&gt;
&lt;P&gt;&lt;TEXTAREA class=vb name=code rows=6 cols=50&gt;''' &amp;lt;summary&amp;gt;
''' 用戶端指令碼管理。
''' &amp;lt;/summary&amp;gt;
Public Class TBScriptManager

    ''' &amp;lt;summary&amp;gt;
    ''' 取得引發 PageCommand 事件的用戶端指令碼。
    ''' &amp;lt;/summary&amp;gt;
    ''' &amp;lt;param name="CommandName"&amp;gt;命令名稱。&amp;lt;/param&amp;gt;
    ''' &amp;lt;param name="CommandArgument"&amp;gt;命令引數。&amp;lt;/param&amp;gt;
    Public Function GetPageCommandEventReference(ByVal CommandName As String, ByVal CommandArgument As String) As String
        Dim sArgument As String

        sArgument = String.Format("{0}${1}${2}", "PageCommand", CommandName, CommandArgument)
        Return Me.GetPostBackEventReference(FPage, sArgument)
    End Function

End Class&lt;/TEXTAREA&gt;&lt;/P&gt;
&lt;P&gt;PageCommand 事件完成了，我們把「案例三：先執行伺服端程式再彈出詢問訊息，依用戶端回應再接續執行」使用 PageCommand 來改寫，它的程式流程如下。&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#800000&gt;請假單儲存(伺服端) -&amp;gt; 彈出詢問訊息(用戶端) -&amp;gt; 取得用戶端回應決定是否送審(伺服端)&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;第一個階段處理「請假單儲存(伺服端) -&amp;gt; 彈出詢問訊息(用戶端) 」，在下面的程式碼中，訊問訊息的回應結果無論是「確定」或「取消」都會引發 PageCommand 事件，CommandName 都是 "SaveConfirm"，差別是 CommandArgument 的值不同。&lt;/P&gt;
&lt;P&gt;&lt;TEXTAREA class=vb name=code rows=6 cols=50&gt;    Protected Sub btnSave_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSave.Click
        Dim sTrueScript As String
        Dim sFalseScript As String

        '執行請假單儲存的程式碼

        '儲存完成彈出詢問訊息
        sTrueScript = Me.BeeScript.GetPageCommandEventReference("SaveConfirm", "True")
        sFalseScript = Me.BeeScript.GetPageCommandEventReference("SaveConfirm", "False")
        Me.BeeScript.Confirm("假單要送審嗎?", sTrueScript, sFalseScript)
    End Sub&lt;/TEXTAREA&gt;&lt;/P&gt;
&lt;P&gt;第二階段在 PageCommand 事件處理用戶端詢問訊息的回應「取得用戶端回應決定是否送審(伺服端)」，在 PageCommand 事件中，我們只需判斷 e.CommandName 及 e.CommandArgument 來決定接續的執行動作即可。&lt;/P&gt;
&lt;P&gt;&lt;TEXTAREA class=vb name=code rows=6 cols=50&gt;    Protected Sub Page_PageCommand(ByVal sender As Object, ByVal e As Bee.Web.TBBasePage.PageCommandEventArgs) Handles Me.PageCommand
        If String.Equals(e.CommandName, "SaveConfirm", StringComparison.CurrentCultureIgnoreCase) Then
            If String.Equals(e.CommandArgument, "True", StringComparison.CurrentCultureIgnoreCase) Then
                '按了確定要執行的程式碼
            Else
                '按了取消要執行的程式碼
            End If
        End If
    End Sub&lt;/TEXTAREA&gt;&lt;/P&gt;&lt;img src ="http://blog.blueshop.com.tw/jeff377/aggbug/56861.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>jeff</dc:creator><title>利用 BasePage 實作表單權限控管</title><link>http://blog.blueshop.com.tw/jeff377/archive/2008/06/19/55346.aspx</link><pubDate>Thu, 19 Jun 2008 20:48:00 GMT</pubDate><guid>http://blog.blueshop.com.tw/jeff377/archive/2008/06/19/55346.aspx</guid><wfw:comment>http://blog.blueshop.com.tw/jeff377/comments/55346.aspx</wfw:comment><comments>http://blog.blueshop.com.tw/jeff377/archive/2008/06/19/55346.aspx#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blog.blueshop.com.tw/jeff377/comments/commentRss/55346.aspx</wfw:commentRss><trackback:ping>http://blog.blueshop.com.tw/jeff377/services/trackbacks/55346.aspx</trackback:ping><description>&lt;P&gt;&lt;FONT color=#0000ff size=3&gt;&lt;STRONG&gt;摘要&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;若表單(頁面)具有「執行、新增、修改、刪除」等操作權限控管，可以使用列舉來描述使用者在該表單的權限，詳細的作法可以參考下面的「&lt;A href="http://www.dotblogs.com.tw/chhuang/archive/2008/04/26/3514.aspx"&gt;&lt;FONT color=#669966&gt;Enum 的設計與應用 - 簡易權限設計&lt;/FONT&gt;&lt;/A&gt;」這篇文章。在此我們將利用這種列舉的方式來描述表單權限，並由 BasePage 來處理表單權限的控管。&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff size=3&gt;&lt;STRONG&gt;程式說明及實作&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;首先定義 EFormActions 列舉，來描述表單操作權限。&lt;/P&gt;
&lt;P&gt;&lt;TEXTAREA class=vb name=code rows=6 cols=50&gt;    ''' &amp;lt;summary&amp;gt;
    ''' 表單操作權限列舉。
    ''' &amp;lt;/summary&amp;gt;
    &amp;lt;Flags()&amp;gt; _
    Public Enum EFormActions
        ''' &amp;lt;summary&amp;gt;
        ''' 無。
        ''' &amp;lt;/summary&amp;gt;
        None = 0
        ''' &amp;lt;summary&amp;gt;
        ''' 執行。
        ''' &amp;lt;/summary&amp;gt;
        Execute = 1
        ''' &amp;lt;summary&amp;gt;
        ''' 新增。
        ''' &amp;lt;/summary&amp;gt;
        Add = 2
        ''' &amp;lt;summary&amp;gt;
        ''' 修改。
        ''' &amp;lt;/summary&amp;gt;
        Update = 4
        ''' &amp;lt;summary&amp;gt;
        ''' 刪除。
        ''' &amp;lt;/summary&amp;gt;
        Delete = 8
        ''' &amp;lt;summary&amp;gt;
        ''' 全部。
        ''' &amp;lt;/summary&amp;gt;
        All = Execute Or Add Or Update Or Delete
    End Enum&lt;/TEXTAREA&gt;&lt;/P&gt;
&lt;P&gt;新增一個 TBActionPage 類別，繼承至 System.Web.UI.Page 或自訂的底層 BaseForm，做為權限控管的 BaseForm。首先新增一個 UserActions 屬性，來描述使用者的表單操作權限，在 OnInitComplete 方法中，第一次載入此表單時取得使用者的表單權限，即設定 UserActions 屬性，此屬性會儲存至 ViewState 中，使下次頁面 PostBack 時無需再重新取得表單權限。另外新增 CheckUserActions 方法，供檢查使用者是否具有指定的表單操作權限。&lt;/P&gt;
&lt;P&gt;&lt;TEXTAREA class=vb name=code rows=6 cols=50&gt;Public Class TBActionPage
    Inherits System.Web.UI.Page
    ''' &amp;lt;summary&amp;gt;
    ''' 使用者權限。
    ''' &amp;lt;/summary&amp;gt;
    Private FUserActions As EFormActions = EFormActions.None

#Region " ViewState 狀態管理　"

    ''' &amp;lt;summary&amp;gt;
    ''' 由 ViewState 還原控制項的狀態。
    ''' &amp;lt;/summary&amp;gt;
    ''' &amp;lt;param name="savedState"&amp;gt;要還原的控制項狀態。&amp;lt;/param&amp;gt;
    Protected Overrides Sub LoadViewState(ByVal savedState As Object)
        If Not (savedState Is Nothing) Then
            ' Load State from the array of objects that was saved at ;
            ' SavedViewState.
            Dim myState As Object() = CType(savedState, Object())

            If Not (myState(0) Is Nothing) Then
                MyBase.LoadViewState(myState(0))
            End If

            If Not (myState(1) Is Nothing) Then
                FUserActions = CType(myState(1), EFormActions)
            End If
        End If
    End Sub

    ''' &amp;lt;summary&amp;gt;
    ''' 控制項的狀態儲存至 ViewState。
    ''' &amp;lt;/summary&amp;gt;
    ''' &amp;lt;returns&amp;gt;含有控制項之目前檢視狀態的物件。&amp;lt;/returns&amp;gt;
    Protected Overrides Function SaveViewState() As Object
        Dim baseState As Object = MyBase.SaveViewState()
        Dim myState(1) As Object
        myState(0) = baseState
        myState(1) = FUserActions
        Return myState
    End Function

#End Region

    ''' &amp;lt;summary&amp;gt;
    ''' 覆寫。引發 InitComplete 事件。
    ''' &amp;lt;/summary&amp;gt;
    Protected Overrides Sub OnInitComplete(ByVal e As System.EventArgs)
        If Not Me.IsPostBack Then
            '取得使用者的表單權限
            '測試用：設定使用者具「執行/新增/修改」權限，實際應呼叫中間層取得使用者的此表單權限
            Me.UserActions = EFormActions.Execute Or EFormActions.Add Or EFormActions.Update

            '第一次載入頁面時檢查執行權限
            If Me.UserActions = EFormActions.None Then
                Throw New Exception("沒有此表單執行權限")
            End If
        End If

        MyBase.OnInitComplete(e)
    End Sub

    ''' &amp;lt;summary&amp;gt;
    ''' 使用者的表單操作權限。
    ''' &amp;lt;/summary&amp;gt;
    Public Property UserActions() As EFormActions
        Get
            Return FUserActions
        End Get
        Set(ByVal value As EFormActions)
            FUserActions = value
        End Set
    End Property

    ''' &amp;lt;summary&amp;gt;
    ''' 檢查使用者是否具有指定的表單操作權限。
    ''' &amp;lt;/summary&amp;gt;
    ''' &amp;lt;param name="Actions"&amp;gt;表單操作權限&amp;lt;/param&amp;gt;
    Public Function CheckUserActions(ByVal Actions As EFormActions) As Boolean
        If (Me.UserActions And Actions) = Actions Then
            Return True
        Else
            Return False
        End If
    End Function

End Class&lt;/TEXTAREA&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff size=3&gt;&lt;STRONG&gt;測試程式&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;為測試使用，在上述的 TBActionPage 的 OnInitComplete 方法，直接設定具有「執行/新增/修改」權限；正確的作法應該是呼叫中間層傳入該表單的識別碼來取得使用者在該表單具有那些權限，並在此設定 UserActions 屬性值。&lt;/P&gt;
&lt;P&gt;&lt;TEXTAREA class=vb name=code rows=6 cols=50&gt;Me.UserActions = EFormActions.Execute Or EFormActions.Add Or EFormActions.Update&lt;/TEXTAREA&gt;&lt;/P&gt;
&lt;P&gt;新增一個測試頁面，繼承至 TBActionPage，當按下按鈕時利用 CheckUserActions 使用者具那些權限並輸出。&lt;/P&gt;
&lt;P&gt;&lt;TEXTAREA class=vb name=code rows=6 cols=50&gt;Imports Bee.Web.WebCommon

Partial Class _Default
    Inherits Bee.Web.TBActionPage

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.Response.Write("執行 -&amp;gt; " &amp;amp; IIf(Me.CheckUserActions(EFormActions.Execute), "Y", "N"))
        Me.Response.Write("&amp;lt; br/ &amp;gt;")
        Me.Response.Write("新增 -&amp;gt; " &amp;amp; IIf(Me.CheckUserActions(EFormActions.Add), "Y", "N"))
        Me.Response.Write("&amp;lt; br/ &amp;gt;")
        Me.Response.Write("修改 -&amp;gt; " &amp;amp; IIf(Me.CheckUserActions(EFormActions.Update), "Y", "N"))
        Me.Response.Write("&amp;lt; br/ &amp;gt;")
        Me.Response.Write("刪除 -&amp;gt; " &amp;amp; IIf(Me.CheckUserActions(EFormActions.Delete), "Y", "N"))
    End Sub
End Class&lt;/TEXTAREA&gt;&lt;/P&gt;
&lt;P&gt;執行結果如下&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://files.dotblogs.com.tw/jeff377/0806/BasePage_13E30/image_thumb.png"&gt;&lt;/P&gt;&lt;img src ="http://blog.blueshop.com.tw/jeff377/aggbug/55346.aspx" width = "1" height = "1" /&gt;</description></item></channel></rss>