站內搜尋


 進階搜尋



2003 年 10 月版
 
Visual Studio > ASP.NET 入門套件 

入口網站入門套件:設計與實作

Vertigo Software, Inc.
2002 年 15 日

摘要: 本文說明「ASP.NET 入口網站入門套件」的設計與架構決策。此外,文中也涵蓋了詳細外觀和擴充套件所需程式碼的說明。 (列印頁數:14 頁)

概觀

什麼是入口網站入門套件?
「入口網站入門套件」會示範如何使用 ASP.NET 與 Microsoft .NET Framework 來建置網際網路和內部網路的入口網站應用程式。範例中示範了許多 ASP.NET 的主要功能,還提供一個「最佳範例」應用程式,讓開發人員可以用該應用程式為基礎,自行建置 ASP.NET 應用程式。

如果您的瀏覽器不支援內嵌框架,請按一下此處,另外在其他頁面上檢視。

入口網站示範了許多 ASP.NET 技術提供的功能,包括:

  • 同時支援 Netscape 和 Internet Explorer 的跨瀏覽器支援功能
  • 支援 WAP/WML 和 Pocket Browser 裝置的行動裝置支援功能
  • 使用伺服器控制項清楚劃分程式碼與 HTML 內容
  • 使用動態載入之使用者控制項建構的頁面
  • 入口網站頁面區域可設定輸出快取組態
  • 多層應用程式架構
  • 使用 SQL 預存程序進行 ADO.NET 資料存取
  • Windows 驗證 - 自 Active DS 或 NT SAM 擷取使用者名稱/密碼
  • 使用「使用者名稱/密碼資料庫」的表單驗證
  • 以角色式安全性控制使用者對入口網站內容的存取

這份白皮書將深入討論入口網站套件,並以撰寫軟體之工程師的觀點,提供您最獨到的見解。此外,內容中還會說明如何檢查許多主要的應用程式功能和實作技巧,將套件中的入口網站當作範本來建置其他線上入口網站。
「入口網站入門套件」同時開發了內嵌和程式碼後置兩種版本。SDK 版本則為內嵌編碼模式,最適合 ASP.NET Web Matrix Project 和 .NET Framework SDK。第二個版本是使用 Microsoft ® Visual Studio.NET™,以程式碼後置編碼模式撰寫。兩種版本皆有以 C# 和 VB.NET 撰寫的實作。

應用程式架構

「入口網站套件」使用多層應用程式架構,其資料來源則有兩種。組態設定儲存於 PortalCFG.xml 中,而應用程式的內容則儲存於 SQL Server 資料庫中。資料存取是透過 Microsoft .NET 組件,該組件會透過預存程序存取資料來源。此外,入口網站架構的建置是使用了許多組件,而這些組件會處理入口網站的安全性和組態。展示層則由 Web Form 和使用者控制項組成,協助使用者處理入口網站資料的顯示和管理。

資料庫

入口網站的所有內容都儲存在 SQL Server 資料庫中,如此一來,伺服器管理員便可跨伺服器管理入口網站的前端 (每部伺服器都從單一的資料儲存中提取)。這一節是有關入口網站中所使用之資料庫的概觀。

資料庫結構描述

入口網站資料庫結構描述非常簡單,只有一個用於儲存「模組」內容的簡單儲存機制,以及三個用於儲存「使用者」和「使用者角色」的資料表。這個實體結構描述如圖 1 所示。


如果您的瀏覽器不支援內嵌框架,請按一下此處,另外在其他頁面上檢視。
圖 1. 實體資料庫結構描述

入口網站組態 XML 結構描述

以 PortalCFG.xml 檔案為基礎的結構描述中,包含了所有的「入口網站」組態設定。這個結構描述簡單易懂。「XML 組態檔」中儲存了所有的高層「入口網站定義」、「索引標籤定義」和「模組定義」。組態設定儲存於快取裝置中,如果設定變更,GetSiteSettings() 只會讀取 xml 檔案。實體結構描述如圖 2 所示。


如果您的瀏覽器不支援內嵌框架,請按一下此處,另外在其他頁面上檢視。
圖 2. PortalCFG.xsd 結構描述

預存程序

入口網站使用預存程序來封裝所有的資料庫查詢。預存程序可以清楚劃分資料庫和中層資料存取層。如此一來,由於資料存取元件中看不到資料庫結構描述變更,維護作業也較為簡單。使用預存程序可以增進效能,因為預存程序會於首次執行時進行最佳化,並留存於記憶體中等待呼叫。

入口網站架構

入口網站具備可擴充的架構,使用者可以建置和使用個別入口網站模組來處理資料的顯示和管理作業。以下各節將說明入口網站架構組成與建置方法的基本概念。 

入口網站設定

入口網站設定是依 PortalSettings 類別表示,該類別則定義於組態商務元件中。設定內容如下:

  • 入口網站 ID
  • 入口網站名稱
  • 桌面索引標籤集合
  • 行動索引標籤集合
  • 使用中索引標籤
  • AlwaysShowEditButton 設定

入口網站應用程式每次發出 Web 要求時,PortalSettings 類別便會更新並置入 Context 物件。上述作業是採用 Global.asax 檔案中的 Application_BeginRequest 事件完成。

Context.Items.Add("PortalSettings", New PortalSettings(tabIndex, tabId))

設定一旦存入 Context 物件中,便可以使用 PortalSettings 這個名稱存取 Context 項目,從應用程式各處取得這些設定,包括所有的頁面、元件和控制項。

Dim portalSettings As portalSettings = _

CType(HttpContext.Current.Items("PortalSettings"), portalSettings)

入口網站索引標籤

索引標籤儲存於前述 PortalSettings 物件的兩個公用欄位中,這兩個欄位分別是 DesktopTabs 和 MobileTabs,其型別都是 ArrayList,而且都含有代表個別索引標籤的 TabStripDetails 類別。對索引標籤集合的存取,必須透過 PortalSettings Context 項目來完成。

Dim portalSettings As portalSettings = _

CType(HttpContext.Current.Items("PortalSettings"), portalSettings)

Dim i As Integer

For i = 0 To portalSettings.DesktopTabs.Count - 1

Dim tab As TabStripDetails = CType(portalSettings.DesktopTabs(i), TabStripDetails)

Next I

索引標籤顯示 (如下圖 2 所示) 是在 DesktopPortalBanner.ascx 使用者控制項中處理。控制項會與上列相同方式重複索引標籤集合,檢查目前的使用者是否具備檢視索引標籤的權限。如果角色符合條件,系統便會將索引標籤加入另一個可以繫結至 DataList 的集合。


圖 2. 入口網站索引標籤

當使用者按一下指定的索引標籤時,PortalSettings 物件便會更新,納入新的 ActiveTab。重新載入 DesktopPortalBanner.ascx 時,DataList 內與做用中索引標籤索引相對應的項目屬性,便會設定為該 DataList 的 SelectedIndex 屬性。

入口網站模組

入口網站模組提供您「入口網站入門套件」的實際內容。模組就是繼承 PortalModuleControl 基礎類別的使用者控制項,可以協助模組和基礎入口網站架構進行必要的溝通。「入口網站套件」中內建十一個可以立即使用的入口網站模組,其中七個模組如圖 3. 入口網站模組所示。


如果您的瀏覽器不支援內嵌框架,請按一下此處,另外在其他頁面上檢視。
圖 3. 入口網站模組

入口網站安全性

入口網站中的安全性設定須同時使用驗證和授權。驗證是應用程式確認使用者識別項和憑證的過程,授權則會實際確認通過驗證之使用者對要求資源的存取權限。
入口網站同時支援表單式和 Windows 驗證模式。驗證模式定義於 web.config 中,User.Identity.Name 屬性則是用來維護使用者名稱。表單式驗證會將使用者名稱和密碼儲存在資料庫中;而 Windows 驗證則使用 domain/active directory 與 NTLM challenge/response 通訊協定。入口網站的授權是使用角色式安全性來處理,以決定使用者是否有存取特定資源的權限。使用者分為多個角色群組 (admins、power users、devs 等),角色對應則儲存於資料庫中。入口網站以索引標籤和模組維護存取控制清單 (ACL),以決定哪種使用者具備存取控制項的權限。這樣可以防止一般使用者存取管理功能。

例如,在 admin Tabs.ascx 使用者控制項的 Page_Load 事件中,呼叫 IsInRoles() 的方式為:

' Verify that the current user has access to access this page

If PortalSecurity.IsInRoles("Admins") = False Then

    Response.Redirect("~/Admin/EditAccessDenied.aspx")

End If

目前使用者的角色對應要求設定,是位於 Application_AuthenticateRequest() 事件中的 Global.asax,然後再使用 GenericPrincipal 方法設定 Context.User,如此一來,User.IsInRole 便可用來確認目前的使用者是否屬於特定角色。

Sub Application_AuthenticateRequest(ByVal sender As Object, _

                                    ByVal e As EventArgs)

    If Request.IsAuthenticated = True Then

        Dim roles() As String      

        ' Create the roles cookie if it doesn't exist yet for

        ' this session.

        If Request.Cookies("portalroles") Is Nothing Then

            ' Get roles from UserRoles table, and add to cookie

            Dim _user As New UsersDB()

            roles = _user.GetRoles(User.Identity.Name)

            ' Create a string to persist the roles

            Dim roleStr As String = ""

            Dim role As String

           

            For Each role In roles

                roleStr += role

                roleStr += ";"

            Next role

 

            ' Create a cookie authentication ticket.

            '   version

            '   user name

            '   issue time

            '   expires every hour

            '   don't persist cookie

            '   roles

            Dim ticket As New FormsAuthenticationTicket(1, _

                Context.User.Identity.Name, _

                DateTime.Now, _

                DateTime.Now.AddHours(1), _

                False, _

                roleStr)

 

            ' Encrypt the ticket

            Dim cookieStr As String = FormsAuthentication.Encrypt(ticket)

 

            ' Send the cookie to the client

            Response.Cookies("portalroles").Value = cookieStr

            Response.Cookies("portalroles").Path = "/"

            Response.Cookies("portalroles").Expires = _

                DateTime.Now.AddMinutes(1)

        Else

            ' Get roles from roles cookie

            Dim ticket As FormsAuthenticationTicket = _

 FormsAuthentication.Decrypt(Context.Request.Cookies("portalroles").Value)

 

            'convert the string representation of the role data

            'into a string array

            Dim userRoles As New ArrayList()

            Dim role As String

            For Each role In ticket.UserData.Split(New Char() {";"c})

                userRoles.Add(role)

            Next role

            roles = CType(userRoles.ToArray(GetType(String)), String())

        End If

 

        ' Add our own custom principal to the request containing

        ' the roles in the auth ticket

        Context.User = New GenericPrincipal(Context.User.Identity, roles)

    End If

End Sub

所有角色檢查的資料庫呼叫設定都在 Security.vb 中。

管理 ASP.NET 入口網站入門套件

入口網站套件具備線上管理工具,可以讓使用者以 Admins 角色管理安全性、配置和入口網站內容。使用者以 Admins 角色登入後,會看到可連結管理工具的 [Admin] 索引標籤。工具如下圖 4 所示。


如果您的瀏覽器不支援內嵌框架,請按一下此處,另外在其他頁面上檢視。
圖 4. 入口網站管理

使用者可以利用入口網站管理執行各種網站管理與組態設定工作,此外,還可以在此新增模組、設定水平顯示於網頁頂端的索引標籤組態,以及定義安全性角色。

擴充 ASP.NET 入口網站套件

入口網站具備擴充性建置概念,開發人員可以輕易在架構中加入嵌入式入口網站模組。本節將說明自行建置入口網站模組時,您可以遵循的步驟。為方便說明,我們將建置一個名為 Milestones 的入口網站模組,以顯示專案里程碑。

擴充資料層

多數入口網站模組都將入口網站資料庫當作主要的資料儲存位置,本範例將如法炮製。因此,第一個步驟是擴充資料層。一開始,我們將建立一個新的資料表,名稱為 Milestones (如圖 5 所示)。


圖 5. Milestones 資料表

接下來,我們還會建立處理 Milestones 資料表存取工作時所需的預存程序。我們需要的預存程序如下:

  • AddMilestone
  • DeleteMilestone
  • GetMilestone
  • GetSingleMilestone
  • UpdateMilestone

建立預存程序後,我們就要建立存取 Milestone 程序所需資料存取層 (DAL) 元件。我們會定義下列方法,而第一個方法的定義方式如下清單 1 所示。其他方法先行省略,以簡化說明;如需這些方法的詳細資料,請參閱「ASP.NET 入口網站入門套件」下載頁面中,Milestone 擴充套件內的 MilestonesDB.vb 檔案。

  • ASPNET.StarterKit.Portal.MilestonesDB.GetMilestones()
  • ASPNET.StarterKit.Portal.MilestonesDB.GetSingleMilestone()
  • ASPNET.StarterKit.Portal.MilestonesDB.DeleteMilestone()
  • ASPNET.StarterKit.Portal.MilestonesDB.AddMilestone()
  • ASPNET.StarterKit.Portal.MilestonesDB.UpdateMilestone()

Imports System

Imports System.Configuration

Imports System.Data

Imports System.Data.SqlClient

Imports ASPNET.StarterKit.Portal

 

Namespace ASPNET.StarterKit.Portal

  Public Class MilestonesDB

    Public Function GetMilestones(ByVal moduleId As Integer) As DataSet

      ' Create Instance of Connection and Command Object

      Dim myConnection As _

        New SqlConnection(ConfigurationSettings.AppSettings("connectionString"))

      Dim myCommand As New SqlDataAdapter("GetMilestones", myConnection)

 

      ' Mark the Command as a SPROC

      myCommand.SelectCommand.CommandType = CommandType.StoredProcedure

 

      ' Add Parameters to SPROC

      Dim parameterModuleId As New SqlParameter("@ModuleId", SqlDbType.Int, 4)

      parameterModuleId.Value = moduleId

      myCommand.SelectCommand.Parameters.Add(parameterModuleId)

 

      ' Create and Fill the DataSet

      Dim myDataSet As New DataSet()

      myCommand.Fill(myDataSet)

 

      ' Return the DataSet

      Return myDataSet

    End Function

 

    ' Other methods elided for clarity.

  End Class

End Namespace

清單 1

建立使用者控制項

完成資料庫相關作業後,下一個步驟是建立要處理 Milestone 使用者介面的使用者控制項。使用者控制項含有 DataGrid,DataGrid 中則定義了三種資料行:Title、Completion Date 和 Status。使用者控制項實作如下清單 2 所示。

<script runat="server">

  Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)

    Dim milestones As New ASPNET.StarterKit.Portal.MilestonesDB()

    myDataGrid.DataSource = milestones.GetMilestones(ModuleId)

    myDataGrid.DataBind()

  End Sub

</script>

 

<asp:DataGrid

id="myDataGrid"

HeaderStyle-CssClass="Normal"

HeaderStyle-Font-Bold="true"

ItemStyle-CssClass="Normal"

AutoGenerateColumns="false"

CellPadding="5"

Border="0"

Width="100%"

EnableViewState="false"

runat="server">

  <Columns>

    <asp:TemplateColumn>

      <ItemTemplate>

       <asp:HyperLink

         id="editLink"

         ImageUrl="~/images/edit.gif"

         NavigateUrl='<%# "~/DesktopModules/EditMilestones.aspx?ItemID=" & DataBinder.Eval(Container.DataItem,"ItemID") & "&mid=" & ModuleId %>' Visible="<%# IsEditable %>" runat="server" />

      </ItemTemplate>

    </asp:TemplateColumn>

    <asp:BoundColumn DataField="Title" HeaderText="Title"

                     runat="server" />

    <asp:BoundColumn DataField="EstCompleteDate"

                     HeaderText="Comp. Date" runat="server"

                     DataFormatString="{0:d}" />

    <asp:BoundColumn DataField="Status" HeaderText="Status" runat="server" />

  </Columns>

</asp:DataGrid>
清單 2

繼承 ASPNET.StarterKit.Portal 模組控制項基礎類別

實際上,所有入口網站模組中的控制項,都是繼承 PortalModuleControl 基礎類別的簡單 ASP.NET 使用者控制項。這個基礎類別內有入口網站模組與架構互動所需的所有項目。若要繼承基礎類別,請將下列程式碼置於使用者控制項前。 <%@ Control language="VB" Inherits=" ASPNET.StarterKit.Portal.PortalModuleControl" %>

加入模組標題

入口網站模組可以使用的其中一個使用者控制項為 Title 使用者控制項,這個控制項可以用來產生適當的 HTML。

<portal:title runat="server" />

加入編輯頁支援

如果使用者要編輯和加入其他的 Milestones,則必須加入編輯頁支援。加入支援的方式,就是再傳送兩個額外的屬性至模組的 Title 使用者控制項。

<portal:title

EditText="Add New Milestone"

EditUrl="~/DesktopModules/EditMilestones.aspx"

runat="server" />

建立編輯頁

使用 Title 使用者控制項加入編輯頁支援後,還需要實際建立編輯頁。除了 HTML 外,我們還定義了四種方法:

  • Page_Load
  • UpdateBtn_Click
  • DeleteBtn_Click
  • CancelBtn_Click

DeleteBtn_Click 方法的來源以及編輯頁中與其有關的 HTML,如下清單 3 所示。實作其餘部份請參閱 Milestone 擴充下載頁面中的 EditMilestones.aspx。

<%@ Page Language="VB" %>

<%@ Register TagPrefix="ASPNETPortal" TagName="Banner" Src="~/DesktopPortalBanner.ascx" %>

<%@ Import Namespace="System.Data.SqlClient" %>

<%@ Import Namespace=" ASPNET.StarterKit.Portal " %>

<script runat="server">

 

    Private itemId As Integer = 0

    Private moduleId As Integer = 0

 

    Sub UpdateBtn_Click(ByVal sender As Object, ByVal e As EventArgs)

 

        ' Only Update if the Entered Data is Valid

        If Page.IsValid = True Then

 

            ' Create an instance of the Milestone DB component

            Dim milestones As New ASPNET.StarterKit.Portal.MilestonesDB()

 

            If itemId = 0 Then

 

                ' Add the milestone within the Milestones table

                milestones.AddMilestone(moduleId, itemId, _

                    Context.User.Identity.Name, TitleField.Text, _

                    DateTime.Parse(CompleteDateField.Text), StatusField.Text)

 

            Else

 

                ' Update the milestone within the Milestones table

                milestones.UpdateMilestone(moduleId, itemId, _

                    Context.User.Identity.Name, TitleField.Text, _

                    DateTime.Parse(CompleteDateField.Text), StatusField.Text)

 

            End If

 

            ' Redirect back to the portal home page

            Response.Redirect(CType(ViewState("UrlReferrer"), String))

 

        End If

 

    End Sub

</script>

<html>

   <head>

      <link rel="stylesheet"

         href='<%= Request.ApplicationPath & "/ASPNETPortal.css" %>' type="text/css" />

   </head>

   <body leftmargin="0" bottommargin="0" rightmargin="0" topmargin="0"

      marginheight="0" marginwidth="0">

      <form runat="server">

         <table width="100%" cellspacing="0" cellpadding="0" border="0">

            <tr>

               <td>

                  <br>

                  <table width="98%" cellspacing="0" cellpadding="4" >

                     <tr valign="top">

                        <td width="100">

                           &nbsp;

                        </td>

                        <td width="*">

                           <p>

                              <asp:LinkButton

                                 id="deleteButton"

                                 Text="Delete this item"

                                 CausesValidation="False"

                                 runat="server"

                                 class="CommandButton"

                                 BorderStyle="none"

                                 OnClick="DeleteBtn_Click" />

                           </p>

                        </td>

                     </tr>

                  </table>

               </td>

            </tr>

         </table>

      </form>

   </body>

</html>

清單 3

將新的入口網站模組加入架構

Milestones 入口網站模組現已完成。最後一個步驟,是使用線上管理員的 [模組定義] 區段,將該模組加入入口網站架構。按一下這個區段中的 [新增模組型別],便可連結到圖 6 所示的頁面。輸入新模組的資訊,然後按一下 [更新]。接下來,您便可以使用線上管理員的 [索引標籤名稱及配置] 區段,將模組加入到不同的索引標籤。


如果您的瀏覽器不支援內嵌框架,請按一下此處,另外在其他頁面上檢視。
圖 6. 模組型別定義

結論

入口網站示範了使用 ASP.NET 建置入口網站 Web 應用程式的主要技術,除 Web 管理和內容管理外,入口網站擴充也十分簡單,擴充方式請參閱這份白皮書中的 Milestone 模組範例。若要學習 .NET 技術及功能強大之 Internet 或 Intranet 入口網站架構,此範例是絕佳的參考資料。

相關資訊