< Day Day Up > |
The need for a structured framework is not something new. Over the years , departments in many companies have been developing their own homegrown solutions to problems they encountered . They purchased off-the-shelf software to solve other problems they had. Although these applications solved most of the problems that they were intended to solve, they also introduced other problems into the workplace. The homegrown solutions became harder and harder to maintain and, with all of the independent solutions within the company, almost none of them knew how to "talk" to each other. Many companies started implementing IT departments, and many of the smaller solutions were turned over to the IT department for continued development and maintenance. Purchasing of applications moved from a per-department basis to a company-wide basis. Nevertheless, the advent of the IT department did not solve one of the most important problems ”communication between the applications. The IT departments began to see the power in consolidating many of the singleton applications into larger company-wide systems and so a new trend began. Although consolidation of these small applications was seen as a positive step in the right direction, not all applications can or should be consolidated. For off-the-shelf products and for applications that could not be included in the consolidated systems, the IT departments began to develop application integration solutions. This allowed more applications to be able to communicate with each other. Define Portal Framework GoalsA portal in general and specifically a portal framework can be looked upon as the natural evolution of the consolidation and integration of disparate enterprise systems. One of the main goals of the portal framework is to achieve a high degree of organizational integration. Here is a more complete listing:
Identify Framework BenefitsThere are numerous benefits associated with using a portal framework. This list summarizes the benefits gained by using the portal framework:
These benefits boil down to design savings, code savings, and test savings. Figure 5.3 shows a conceptual view of a portal page, which consists of multiple regions known as panes . Each pane has a specific location within the page. While some panes, like the header, footer, and navigation panes, are only intended to host a single module, all panes can contain zero or more modules. Portal modules provide the actual content of the portal and allow users to customize the portal depending on their preferences. Figure 5.3. Conceptual View of a Portal Page
Define the Portal Module Object ModelPortal modules provide the actual content for the portal. The modules are ASP.NET user controls that inherit from the ModuleControl base class. The ModuleControl class provides functionality common to all modules, enforces behavior common to all modules, creates hooks necessary to control and position each ModuleControl from the portal page, and provides communication between the module and the underlying portal framework. The ModuleControl itself inherits from the UserControl class that is part of the .NET Framework. While this second generation of inheritance gives the module functionality shared by all portal modules, it also gives the module all of the functionality exposed by the UserControl class. Figure 5.4 shows a partial object model for the ModuleControl base class as well as modules that inherit from the ModuleControl . The portal module object model has been designed in such a way that each module type inherits the exact amount of code needed for the implementation of a control of this type. In the diagram you can see that ModuleControl inherits from the System.Web.UI.UserControl, which means that the ModuleControl is a type of UserControl. Figure 5.4. Partial Object Model
Figure 5.5 demonstrates a potential design for a portal module. The portal page controls the modules through two interfaces implemented by each module: IPlacement and ITheme. IPlacement interface contains methods used by the page to position a module in a required location on the selected pane. The ITheme interface contains methods used to control the appearance of each module. The mode of inheritance used in this scenario is called implementation inheritance , which allows each module to use the default implementation of both interfaces implemented in a BaseModule control or to override the default implementation with control-specific implementation. Figure 5.5. BaseModule with Interfaces
The portal framework exposes a set of objects that build on the .NET functionality and offer a set of services consumed by portal modules. The portal framework consists of the following services:
Figure 5.6 illustrates the relationship between portal modules, the portal framework, and .NET Framework. Figure 5.6. Portal Framework Layers
Develop the Data ModelNow, after we have familiarized ourselves with the .NET Framework and with the design goals and practices of portal framework architecture, let's roll up our sleeves and develop a minimal portal framework. Our ultimate goal is to make the framework extensible, easily manageable, and dynamic. To achieve this goal, we first develop the data model for the object that will comprise the portal framework. The data model will provide necessary containers and operations to enable the creation of the dynamic page shown in Figure 5.3. This section describes the tables, their use, and descriptions for each of the fields. The data structure is designed to give the framework a high degree of extensibility. In Figure 5.7, you can see the framework's data model. This diagram shows the tables that make up the data model as well as the relationships between each of the tables. The data model consists of four "nouns" that can be seen as the main entities of the framework: Page, Template, Control, and Area. Figure 5.7. Portal Framework Data Model
As you will see later in the chapter, a template is made up of a number of areas and each page is a specific instance of a template. A common analogy used within object-oriented design can be seen here within the data model. If you think of a template as a blueprint for a house, then a page can be seen as a finished house. In other words, a template defines the structure of the page and each page can be seen as a concrete, implemented instance of that template. Each page can contain one or more controls within each of its areas. For a visual example of the page layout, see Figure 5.3. TemplatetblTemplate contains data that is used to define a template. The template is used to define a page layout. Table 5.1 briefly explains the data that is stored in the tblTemplate table. Table 5.1. Structure of the tblTemplate Table
AreatblArea contains data that is used to describe an area, which is a section of page used to hold one or more controls. Table 5.2 briefly describes the data that is stored in the tblArea table. Table 5.2. Structure of the tblArea Table
Template AreastblTemplateArea contains data that is used to define the relationships between a template and an area. A collection of template-area records, grouped by a single template identifier, defines the areas that make up a single template. Table 5.3 briefly explains the data that is stored in the tblTemplateArea table. Table 5.3. Structure of the tblTemplateArea Table
PagetblPage contains data that is used to define each page within the portal. The page table is the central table of the data model. Table 5.4 briefly explains the data that is stored in the tblPage table. Table 5.4. Structure of the tblPage table
Page TypetblPageType contains data that is used to define each page within the portal. The page table is the central table of the data model. Table 5.5 briefly explains the data that is stored in the tblPage table. Table 5.5. Structure of the tblPageType Table
Page RelationstblPageRelation contains data that is used to define relationships between pages. By maintaining relationship information, the framework can expose functionality that will provide dynamic links between these pages, thus allowing the end users to navigate between them. The extraction of data from this table should take into account that relationships between pages are bidirectional; therefore, there should not be a need to store links in both directions for each of the pages in question. Table 5.6 briefly explains the data that is stored in the tblPageRelation table. Table 5.6. Structure of the tblPageRelation Table
Page HierarchytblPageHeirarchy contains data that is used to define the hierarchy of pages within the portal. The navigation within the portal is generated by recursively "walking" the page hierarchy programmatically and thus building a site map. Table 5.7 briefly explains the data that is stored in the tblPageHierarchy table. Table 5.7. Structure of the tblPageHierarchy Table
ControltblControl contains data that is used to describe controls, which are modular pieces of code that are used to define a specific set of functionality. A control can be placed into any of the areas on one or more pages. Table 5.8 briefly explains the data that is stored in the tblControl table. Table 5.8. Structure of the tblControl Table
Page ControlstblPageControl contains data that is used to describe the relationship between a page and a control. The page-control relationship defines more than just the appearance of a control on a page; it also defines the location of the control and how it should appear in that location. A collection of page-control records, grouped by a single page identifier, defines the controls that will appear on a single page. Table 5.9 briefly explains the data that is stored in the tblPageControl table. Table 5.9. Structure of the tblPageControl Table
Control PropertiestblControlProperty contains data that is used to describe a property that will be exposed by a control. Control properties are used to dynamically configure a control. By describing each of a control's exposed properties, the framework can change the properties based on the specific instance of a control. Table 5.10 briefly explains the data that is stored in the tblControlProperty table. Table 5.10. Structure of the tblControlProperty Table
Page Control PropertiestblPageControlProperty contains data that is used to define a control property's value. A single page-control-property specifies the value of a property for an instance of a control property where it appears on a specific page. Table 5.11 briefly explains the data that is stored in the tblPageControlProperty table. Table 5.11. Structure of the tblPageControlProperty Table
Create SQL Server Stored ProceduresWith the data model in place, we can now proceed to defining the data retrieval operations. We create SQL Server stored procedures to retrieve the information necessary to display the hierarchy within a site and to create a page based on a page template and sets of controls contained within its panes. SQL Server stored procedures represent a compiled SQL code stored within the SQL Server. Stored procedures offer the benefits of additional speed, security and code encapsulation, and reuse, and they are always preferable to the inline SQL statements. The first stored procedure retrieves the information about the page. Because each page is a specialized page template, we return the template and template area information in this stored procedure as well. Listing 5.1. Complete Code Listing for the Stored Procedure Page Data/* Purpose: Stored procedure for retrieving portal page data Inputs: @PageID - numeric ID of the page for which the data is _ retrieved */ Create PROCEDURE spFetchPageInformation @PageID INT AS SET NOCOUNT ON Select P.PageID, P.Title, P.ShortTitle, P.ShowInNav, P.ShowInMainNav, P.TemplateID, P.PageTypeID, PT.Description as PageTypeDescription, T.Name as TemplateName, T.Description as TemplateDescription, T.FileName, T.ImageFileName FROM tblPage P INNER JOIN tblPageType PT ON P.PageTypeID = PT.PageTypeID INNER JOIN tblTemplate T ON P.TemplateID = T.TemplateID WHERE P.PageID = @PageID RETURN @@ERROR SET NOCOUNT OFF With the stored procedure in Listing 5.1, we can now retrieve the page information. The next stored procedure tells us which controls to load into each pane defined for the page. Because we are allowing each control to persist its properties in a table in SQL Server, the same stored procedure retrieves the list of properties for each control and the list of values set for these properties (if any) as well. Listing 5.2. Complete Code Listing for the Stored Procedure Retrieving Control Data for All Controls Within a Page/* Purpose: Stored procedure for retrieving control data for all _ controls within a page Inputs: @PageID - numeric ID of the page for which the data is _ retrieved @ControlID - ID of the control whose information we retrieve */ CREATE PROCEDURE spFetchPageControlInformation @PageID INT, @ControlID INT = NULL AS SET NOCOUNT ON SELECT PC.PageControlID, PC.PageID, PC.ControlID, PC.AreaID, PC.OrderID, PC.[Size], C.[Name] as ControlName, C.[FileName] FROM tblPageControl PC INNER JOIN tblControl C ON PC.ControlID = C.ControlID WHERE PC.PageID = @PageID AND PC.ControlID = CASE WHEN IsNull(@ControlID, 0) = 0 THEN PC.ControlID ELSE @ControlID END ORDER BY PC.AreaID, PC.OrderID RETURN @@ERROR SET NOCOUNT OFF The last stored procedure required for our framework implementation retrieves values for all control properties saved in the database based on the PageControlID parameter. Listing 5.3. Complete Code Listing for the Stored Procedure Retrieving Control Data for All Controls Within a Page/* Purpose: Stored procedure for retrieving the properties, stored in _ the database, for a specific instance of a control within a _ page. Inputs: @ControlID - ID of the control whose information we retrieve */ CREATE PROCEDURE spFetchControlProperties @PageControlID INT AS SET NOCOUNT ON SELECT CP.ControlPropertyID, CP.[Name] as ControlPropertyName, CP.Required, PCP.Value FROM tblPageControl PC INNER JOIN tblControlProperty CP ON PC.ControlID = CP.ControlID INNER JOIN tblPageControlProperty PCP ON PC.PageControlID = PCP.PageControlID and CP.ControlPropertyID = PCP.ControlPropertyID WHERE PC.PageControlID = @PageControlID ORDER BY CP.[Name] RETURN @@ERROR SET NOCOUNT OFF Create Code for Minimal Portal FrameworkArmed with these stored procedures, we can finally start creating the code for the minimal portal framework. In this example, we omit such advanced portal features as authentication, maintenance of user profiles, personalization, and advanced caching techniques. Here are the steps:
Listing 5.4. HTML for the Portal Page Showing Portal Page Panes and Navigation Control Placement<%@ Page Language="vb" AutoEventWireup="false" Codebehind="TemplatePage.aspx.vb" Inherits="PF.TemplatePage"%> <HTML> <HEAD> <TITLE id="PageTitle" runat="server"> Portal Framework Template Page </TITLE> <LINK href="Portal.css" type="text/css" rel="stylesheet"> </HEAD> <BODY style="margin:1px"> <FORM id="Form1" method="post" runat="server"> <TABLE width="800" cellspacing="0" cellpadding="0" border="0"> <TR valign="top"> <TD id="TopPane" visible="False" runat="server" align="center"> </TD> </TR> <TR valign="top" height="20"> <TD id="NavPane" visible="False" runat="server"> </TD> </TR> <TR> <TD> <TABLE width="100%" cellspacing="0" cellpadding="4" _ border="0"> <TR height="*" valign="top"> <TD id="LeftPane" Visible="false" Width="150" _ runat="server"> </TD> <TD id="ContentPane" Visible="false" Width="*" _ runat="server"> </TD> <TD id="RightPane" Visible="false" Width="150" _ runat="server"> </TD> </TR> </TABLE> </TD> </TR> <TR> <TD id="BottomPane" visible="False" runat="server" _ align="center"> </TD> </TR> </TABLE> </FORM> </BODY> </HTML> The page consists of the HTML table containing four user controls: header, top breadcrumb menu control, left menu control, and the footer control. These standard controls will be used to display site navigation, page information, and general site information. If you were to try to run the solution, now it would fail because we have included forward declarations for our standard controls but have not defined the controls themselves . The next step is to create four standard controls:
We will use these four controls on the majority of the portal pages. To make a page dynamic, we will need to complete these steps:
Store and Read the Database Connection InformationWe need to keep the database connection string in a safe but easily reachable place. One good option is to store it in the Web.config file. Let's add the entry shown in Listing 5.5 to the Web.config file: Listing 5.5. Storing the Database Connection String in the Web.config File<appSettings> <add key="ConnectionString" value="Persist Security _ Info=True;User ID=sa;Password=password;Initial _ Catalog=Northwind;Data Source=."/> <appSettings> Note that you will have to modify the connection string to specify a valid user for your database. Create the Base Page ObjectTo create this object:
Create the Base Control Object and Derive All User Controls from the Base ControlComplete these steps:
Implement Breadcrumb and Menu ControlsEasy and convenient navigation is one of the primary objectives of a good portal. Our portal framework will provide two means of navigation: using the site menu displayed on the left side of the page and implemented in the menu control and the breadcrumb trail implemented in the breadcrumb control that shows the user the path traversed to the current page from the top page of the site. The data for the menu control will be generated in XML format by the SQL Server stored procedure and pushed to the Load event of the menu control, where it will be transformed into the HTML format suitable for the display on a page using an XSL style sheet. Due to space limitations, it is impossible to discuss here in detail the usage of XML and XSL with SQL Server and .NET Framework. Refer to the MSDN site for extensive documentation and code samples for these technologies at http://msdn.microsoft.com.
Listing 5.14. XSL File Used to Transform the Breadcrumb Trail from Raw XML into HTML<?xml version="1.0" ?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" _ version="1.0"> <xsl:output method="html" indent="yes" /> <xsl:template match="PAGE"> <xsl:choose> <xsl:when test="@Selected='1'"> <SPAN class="SelectedPage"><xsl:value-of select="@Title" _ /></SPAN> </xsl:when> <xsl:otherwise> <SPAN class="NonSelectedPage"> <A> <xsl:attribute name="href"> <xsl:value-of select="@URL" /> ?PAGEID=<xsl:value-of select="@PageID" /> </xsl:attribute> <xsl:value-of select="@Title" /> <xsl:attribute name="alt"> Go to the "<xsl:value-of select="@Title" />" page </xsl:attribute> </A> > </SPAN> </xsl:otherwise> </xsl:choose> <xsl:apply-templates select="./PAGE" /> </xsl:template> </xsl:stylesheet> Dynamically Load User ControlsNotice that our template page is blank; it does not contain any design-time controls. We will load controls dynamically during the template page's Page Load event by querying the database for the list of all controls belonging to the current page and the area into which the controls should be placed. Our stored procedure will return both the file name of the control and the area name that should contain the control.
Listing 5.15 below shows the complete text of the code-behind module of the portal page implementing these two steps. Listing 5.15. Dynamically Creating User Controls in the Portal PageInherits BasePage ' Inherit template from BasePage ' Define template page's containing area controls Protected PageTitle As HtmlControls.HtmlGenericControl Protected TopPane As System.Web.UI.HtmlControls.HtmlTableCell Protected NavPane As System.Web.UI.HtmlControls.HtmlTableCell Protected LeftPane As System.Web.UI.HtmlControls.HtmlTableCell Protected ContentPane As System.Web.UI.HtmlControls.HtmlTableCell Protected RightPane As System.Web.UI.HtmlControls.HtmlTableCell Protected BottomPane As System.Web.UI.HtmlControls.HtmlTableCell ' define enumerator corresponding to the page areas Enum Pane As Integer TopPane = 1 NavPane = 2 LeftPane = 3 ContentPane = 4 RightPane = 5 BottomPane = 6 End Enum ' define a class member to hold the database-received ID of ' the current page. Default it to Zero. Actual value will ' be retrieved in the Page Load event handler Private _PageID As Integer = 0 ' Page load event handler will: ' - Receive the ID of the current page from the parameter list ' - Retrieve page information using FetchPageInformation() function ' - Load all controls on the page using LoadPageControls() function Private Sub Page_Load(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles MyBase.Load If Not Request.Params("PageID") Is Nothing Then _PageID = CType(Request.Params("PageID"), Integer) Else _PageID = 2 ' Assume the first page with data (ignore _ Root page) End If Dim strTitle As String = "", strShortTitle As String = "" If FetchPageInformation(strTitle, strShortTitle) Then _ PageTitle.InnerText = strTitle LoadPageControls() End Sub ' FetchPageInformation() function will call GetDataTable() function ' defined in the BasePage class to receive page's title and short ' title. ' Data is returned as ADO.NET DataTable. Private Function FetchPageInformation(ByRef Title As String, _ ByRef _ ShortTitle As String) As Boolean Dim retVal As Boolean = False 'ASSUME FAILURE Dim dt As DataTable Try dt = GetDataTable("spFetchPageInformation", "PageID", _ _PageID) Title = CType(dt.Rows(0).Item("Title"), String) ShortTitle = CType(dt.Rows(0).Item("ShortTitle"), String) retVal = True Catch ex As Exception retVal = False Finally dt = Nothing End Try Return retVal End Function ' LoadPageControls() function will: ' - call GetDataTable() function to execute a stored procedure ' which returns the data about controls belonging to the ' current page ' - iterate through the resulting data table; dynamically ' load each control and assign it to the specified area on ' the page Private Function LoadPageControls() As Boolean Dim retVal As Boolean = False 'ASSUME FAILURE Dim dt As DataTable, dr As DataRow Dim ctrl As String = "", intArea As Pane = 0 Dim intOrder As Integer = 0, strFileName As String = "" Dim theControl As BaseControl Try dt = GetDataTable("spFetchPageControlInformation", _ "PageID", _ _PageID) For Each dr In dt.Rows ctrl = dr.Item("ControlName") intArea = dr.Item("AreaID") intOrder = dr.Item("OrderID") strFileName = dr.Item("FileName") ' Find the containing area control Dim ParentTableCell As HtmlControls.HtmlTableCell ParentTableCell = Page.FindControl(intArea.GetName(_ intArea.GetType, intArea)) If ParentTableCell.Controls.Count > 0 Then Dim ctrlLiteral As New WebControls.Literal ctrlLiteral.Text = "<BR>" ParentTableCell.Controls.Add(ctrlLiteral) End If ' Dynamically load new control theControl = Page.LoadControl("~/" & strFileName) theControl.PageControlID = _ CType(dr.Item("PageControlID"), Int32) ParentTableCell.Controls.Add(theControl) ParentTableCell.Visible = True Next retVal = True Catch ex As Exception retVal = False Finally dt = Nothing End Try Return retVal End Function In the code fragment in Listing 5.15, we have defined a set of controls corresponding to the containing panes on the form. We have used a member variable Pane of the Enum data type for easier access to the area controls. Enumerators ( Enum in .NET Framework) let developers supply alternate human-readable names for the underlying primitive types. The Page Load event handler executes a function to load main page “level information and another function to retrieve the list of controls, instantiate and position each control within its target area, and populate control properties. Add Template and Page Information to the DatabaseOur framework is database-driven; but at this point, the database is empty. Let's add the page area definitions and create one generic template and a few pages based on this template. We don't have an administrative module yet, so we will enter the data by hand using SQL Server Enterprise Manager. Note that we need a root page to enable the functioning of the menu and breadcrumb controls. The root page only serves as root of the page hierarchy; it doesn't contain any controls and is never shown to the user. To populate the data, open all portal tables in Enterprise Manager and type in the values for all fields, referring to Figure 5.8. After populating the Area, Template, Template Area, Page, and Page Hierarchy tables, you should see the data as shown in Figure 5.8. Figure 5.8. Adding Page and Template Definitions to the Database
We have defined a single template, Framework Template, which contains all six possible areas. We then created three pages; all based on this template, and we created a simple hierarchy with one page, Home Page, at the root of the hierarchy and two sibling pages, Content Page 1 and Content Page 2, one level below the Home Page. The framework reads the page definition data and loads and displays the page hierarchy. This is great, but the crucial part of any portal ”the content ”is still missing. To display the content, we create a simple content control derived from the base control and we con the framework into displaying it in the content pane of each page. Create the Content ControlTo create this control:
We have defined two label objects and have implemented a Page Load handler event that uses the DataTable object inherited from the parent BaseControl object to loop through the list of property names and property values and populate both label controls with the values defined for them. Finally we can configure our three portal pages to display the content control in its content areas. In a full-blown portal framework implementation, this data is entered by using Administration and Content Management modules. In this stripped-down version, you enter the data by hand using SQL Server Enterprise Manager. If you follow along, you can enter the data shown in Figure 5.9 or create your own content. Figure 5.9. Adding Control Definitions and Content to the Database
Let's review the steps completed so far. We have associated header, breadcrumb trail, menu, footer, and content controls with the header, top, left, footer, and content areas, respectively, on each of our three portal pages using tblPageControl . Next we created two properties, Content and Header, for the content control (ControlID = 2) and a single property, Content, for the inventory control (ControlID = 6) using the tblControlProperty table. Finally we set up some content to be displayed by the content and inventory controls on each of the three portal pages using the tblPageControlProperty table. Run the PortalIf you have followed this exercise closely, you should be able now to successfully compile and run the project. With control content specified as shown in Figure 5.8 and Figure 5.9, the first page of the portal should look like that shown in Figure 5.10. Figure 5.10. First Portal Page
Where to Go from HereAt this point we have a functioning (albeit rather simple) site. We can navigate the site using menu and the breadcrumb trail controls; and we can modify data in SQL Server tables to change the page composition as well as add or delete pages or change control placement within the page. Follow these steps to take your work in this exercise closer to a full-blown portal framework implementation:
|
< Day Day Up > |