kendallsoft posted on August 17, 2008 01:19

Portal Starter Kit: Design and Implementation

Vertigo Software, Inc.

November 2002

Updated to ASP.net 2.0 by Mark Kendall

Source Code

 

Requirements:

1.    ASP 3.5 Framework

2.    SQL Server

3.    Visual Studio 2008

4.    IIS

 

·         No Assemblies in this project- all BLL code has been moved to the APP_Code directory

·         Desktop Modules converted to have Partial Classes

·         AJAX Enabled

·         Script Manager On Default.aspx

·         Milestone User control Reworked

·         VB Only

·         New Module Advanced Data Grid for illustrative purposes

·         Good start to Intranet

·         Tested

·         Windows Authentication Tested

  

Summary: This article describes the design and architecture decisions for the ASP.NET Portal Starter Kit. In addition, a detailed look and explanation of the code required to extend it is also covered.
This article brings the Portal Starter Kit up to date as far as VB.net is concerned. The aim of this upgrade is provide a framework for .net developers who might be charged with building an intranet and need a good stating point. As we all know, this starter kit was the basis for Dotnetnuke, and we think it still has potential in the intranet area of many companies.

Overview

What is the Portal Starter Kit?

The Portal Starter Kit demonstrates how you can use ASP.NET along with the Microsoft .NET Framework to build intranet and Internet portal applications. The sample shows off many key features available with ASP.NET and also provides a “best practices” application that developers can use as a base to build their own ASP.NET applications.

The portal demonstrates many features offered by the ASP.NET technology including:

·         Cross-browser support for Netscape and Internet Explorer

·         Mobile device support for WAP/WML and Pocket Browser devices

·         Clean code/html content separation using server controls

·         Pages that are constructed from dynamically-loaded user controls

·         Configurable output caching of portal page regions

·         Multi-tier application architecture

·         ADO.NET data access using SQL stored procedures

·         Windows authentication - username/password in Active DS or NT SAM

·         Forms authentication using a database for usernames/passwords

·         Role-based security to control user access to portal content

This white paper discusses the portal in depth and provides insight from the perspective of the creators. In addition, the article covers how the portal can be used as a template for building online portals by examining many of the key application features and the technology used to implement them.

The Portal Starter Kit was developed by Microsoft and updated to the latest version of ASP.net by Mark Kendall. The database was moved to SQL Server because I like the performance and reliability of a solid database such as SQL Server.

Application Architecture

The portal uses a multi-tier application architecture.  The Portal contains two data sources. The configuration settings are stored in PortalCFG.xml and the content for the application is stored in a SQL Server database.  The data access is provided through classes that reside in the app_code directory that provides access to the data source via the stored procedures.  In addition, the portal framework is built through the use of a number of assemblies that handle the security and configuration of the portal.  Web Forms and user controls make up the presentation layer and handle the display and management of the portal data for the user.

Database

All of the content for the portal is stored in a SQL Server database. This allows server administrators to farm the front-end of the portal across a number of servers each pulling from a single unique data store. This section provides an overview of the database used in the portal.

Database Schema

The portal database schema is a very simple schema that contains a simple repository for Module content and 3 tables to store Users and User Roles. The physical schema is shown in Figure 1.

Figure 1. Physical Database Schema

Portal Configuration XML Schema

The schema based on the PortalCFG.xml file contains all the configuration settings for the Portal. The schema is simple and easy to understand. The XML Configuration file stores all the high level Portal, Tab and Module Definitions. The configuration settings are stored in a cache and GetSiteSettings() only reads from the xml file if the settings have changed. The physical schema is shown in Figure 2.

               


Figure 2. PortalCFG.xsd Schema

Stored Procedures

The portal uses stored procedures to encapsulate all of the database queries. Stored procedures provide a clean separation between the database and the middle-tier data access layer. This in turn provides easier maintenance, since changes to the database schema will be invisible to the data access components. Using stored procedures also provide performance benefits since they are optimized the first time they are run and then retained in memory for subsequent calls.

The Portal Framework

The portal contains an extensible framework that allows users to build and use individual portal modules to handle the display and management of data.  The following sections will cover the basics of what the portal framework consists of as well as how it was built.

Portal Settings

The portal settings are represented by the PortalSettings Class, which is defined in the Configuration business component.  These settings include the following:

·         The Portal ID

·         The Portal Name

·         The Desktop Tabs Collection

·         The Mobile Tabs Collection

·         The Currently Active Tab

·         The “AlwaysShowEditButton” Setting

The PortalSettings class is updated and placed into the “Context” object upon each web request of the portal application. This is achieved by using the Application_BeginRequest event in the Global.asax file.

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

 

Once stored in the Context object, these settings can be obtained from anywhere in the application including all pages, components, and controls by accessing the Context item with the name “PortalSettings”.

Dim portalSettings As portalSettings = _

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

 
Portal Tabs

The Tabs are stored in two public fields of the PortalSettings object we described in the previous section.  The fields, DesktopTabs and MobileTabs, are of the type ArrayList and contain instances of the TabStripDetails class, which represents an individual tab.  Access to the tabs collection is achieved through the PortalSettings Context item.

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

 

The display of the tabs (as shown in Figure 2 below) is handled in the DesktopPortalBanner.ascx user control. The control iterates through the tabs collection, in the same way shown above, checking whether the current user has rights to view the tab.  If the necessary role is met, the tab is added to another collection that will be bound to a DataList.

Figure 2. Portal Tabs

When a user clicks on a given tab, the PortalSettings object is updated to include the new ActiveTab. When the DesktopPortalBanner.ascx is reloaded, the item in the DataList that corresponds to the active tab’s index is set to the DataList’s SelectedIndex property.

Portal Modules

Portal Modules provide the actual content of the Portal Starter Kit. The modules are user controls that inherit the PortalModuleControl base class, which provides the necessary communication between the modules and the underlying Portal Framework. The portal comes with eleven built-in portal modules that are available “out of the box,” seven of which are shown in Figure 3. Portal Modules.

 

Figure 3. Portal Modules

Portal Security

The security design in the portal makes use of both authentication and authorization. Authentication is the process in which the application verifies a user’s identity and credentials. Authorization will actually verify the authenticated user’s permissions for a requested resource.

The portal supports both forms based and windows based authentication. The authentication mode is defined in the web.config and the User.Identity.Name property maintains the user name. Forms based authentication stores the usernames and passwords in the database and the Windows authentication uses a domain/active directory with the NTLM  challenge/response protocol. The authorization for the portal is handled using role based security to determine whether or not a user has access to a particular resource. Users are grouped into various roles (admins, power users, devs, etc.) and the role mappings are stored in the database. The tabs and modules in the portal maintain access control lists (ACL) to determine who has permission to access the control. This prevents a normal user to access the administration functionality.

For example in the Page_Load event in the admin Tabs.ascx user control, a call is made to 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

The current users’s role mappings are set for the request in Global.asax in the Application_AuthenticateRequest() event. The Context.User is then set using the GenericPrincipal method and the User.IsInRole can be used to verify whether the current user is in a specific role.

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

The database calls for all of the role-based checks are contained in Security.vb.

Administering the ASP.NET Portal Starter Kit

The portal has an online administration tool that allows users in the “Admins” role to manage the security, layout, and content of the portal.  Users that are logged in that belong to the “Admins” role will see an “Admin” tab that takes them to the administration tool. This tool is shown in Figure 4 below.

 

Figure 4. Portal Administration

The portal administration allows the user to perform a variety of site management and configuration tasks. This is place where new modules can be added, tabs that appear horizontal across the top of the site can be configured, and security roles are defined.

Extending the ASP.NET Portal Starter Kit

The portal was built with the idea of extensibility in mind, providing a way for developers to easily add portal modules that can “plug” into the framework. In this section we will look at the steps that you can follow to build your own portal modules. To do this, we will build a Milestones portal module that will display project milestones.

Extending the Data Layer
 

Most of the portal modules use the portal database as their primary data store. We will do the same for our example. Therefore the first step is to extend the data layer.  We begin by creating a new Table called Milestones, as shown in Figure 5.

 

Figure 5.  Milestones Table Above

 

                       

The Stored Procedures:

 USE [Portal]GO/****** Object:  Table [dbo].[Milestones]    Script Date: 07/31/2008 15:37:46 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [dbo].[Milestones](     [ItemID] [int] IDENTITY(1,1) NOT NULL,     [ModuleID] [int] NULL,     [CreatedByUser] [nchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,     [CreatedDate] [datetime] NULL CONSTRAINT [DF_Milestones_CreatedDate]  DEFAULT (getdate()),     [Title] [nchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,     [EstCompleteDate] [datetime] NULL,     [Status] [nchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, CONSTRAINT [PK_Milestones] PRIMARY KEY CLUSTERED (     [ItemID] ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY]  USE [Portal]GO/****** Object:  StoredProcedure [dbo].[Portal_AddMilestone]    Script Date: 07/31/2008 15:50:25 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO    CREATE PROCEDURE [dbo].[Portal_AddMilestone](    @ModuleID    int,    @Title       nvarchar(100),    @UserName        nvarchar(250),    @Status   nvarchar(250),    @CompleteddateTime   datetime,    @ItemID      int OUTPUT)AS INSERT INTO Milestones(    ModuleID,    CreatedByUser,    CreatedDate,    Title,    EstCompleteDate,    Status )VALUES(    @ModuleID,    @UserName,    GetDate(),    @Title,    @CompleteddateTime ,    @Status  ) SELECT    @ItemID = @@Identity USE [Portal]GO/****** Object:  StoredProcedure [dbo].[Portal_DeleteMilestone]    Script Date: 07/31/2008 15:50:48 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO    CREATE PROCEDURE [dbo].[Portal_DeleteMilestone](    @ItemID int)AS DELETE FROM Milestones WHERE    ItemID = @ItemID   USE [Portal]GO/****** Object:  StoredProcedure [dbo].[Portal_GetMilestones]    Script Date: 07/31/2008 15:51:17 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO    CREATE PROCEDURE [dbo].[Portal_GetMilestones](    @ModuleID int)AS SELECT * from Milestones    WHERE    ModuleID = @ModuleID     USE [Portal]GO/****** Object:  StoredProcedure [dbo].[Portal_GetSingleMilestone]    Script Date: 07/31/2008 15:51:50 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO     CREATE  PROCEDURE [dbo].[Portal_GetSingleMilestone](    @ItemID int)AS SELECT   * FROM Milestones WHERE    ItemID = @ItemID    USE [Portal]GO/****** Object:  StoredProcedure [dbo].[Portal_UpdateMilestone]    Script Date: 07/31/2008 15:52:19 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO    CREATE PROCEDURE [dbo].[Portal_UpdateMilestone](    @ModuleID    int,     @item        int,    @Title       nvarchar(100),    @UserName        nvarchar(250),    @Status   nvarchar(250),    @CompleteddateTime   datetime,    @ItemID      int OUTPUT)AS update Milestones    set ModuleID=@ModuleID ,CreatedByUser= @UserName,EstCompleteDate=@CompleteddateTime, Title=@Title , Status=@Status where itemid=@item SELECT    @ItemID = 1  

Next, we will create the stored procedures required to handle access to the Milestones table. The stored procedures we need are:

·         AddMilestone

·         DeleteMilestone

·         GetMilestone

·         GetSingleMilestone

·         UpdateMilestone

After the stored procedures are created we need to create a data access layer (DAL) component to provide access to the Milestone procedures. We will define the following methods, the first of which is shown in Listing 1 below. 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 Microsoft.VisualBasic

Imports System

Imports System.Configuration

Imports System.Data

Imports System.Data.SqlClient

Imports MK.Portal

Namespace MK.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("Portal_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

        Public Function AddMilestones(ByVal moduleId As Integer, ByVal user As String, ByVal item As String, ByVal Title As String, ByVal CompleteddateTime As String, ByVal status As String) As Integer

            If user.Length < 1 Then

                user = "unknown"

            End If

 

            ' Create Instance of Connection and Command Object

            Dim myConnection As New SqlConnection(ConfigurationSettings.AppSettings("connectionString"))

            Dim myCommand As New SqlCommand("Portal_AddMilestone", myConnection)

 

            ' Mark the Command as a SPROC

            myCommand.CommandType = CommandType.StoredProcedure

 

            ' Add Parameters to SPROC

            Dim parameterItemID As New SqlParameter("@ItemID", SqlDbType.Int, 4)

            parameterItemID.Direction = ParameterDirection.Output

            myCommand.Parameters.Add(parameterItemID)

 

            Dim parameterModuleID As New SqlParameter("@ModuleID", SqlDbType.Int, 4)

            parameterModuleID.Value = moduleId

            myCommand.Parameters.Add(parameterModuleID)

 

            Dim parameterUserName As New SqlParameter("@UserName", SqlDbType.NVarChar, 100)

            parameterUserName.Value = user

            myCommand.Parameters.Add(parameterUserName)

 

            Dim parameterTitle As New SqlParameter("@Title", SqlDbType.NVarChar, 100)

            parameterTitle.Value = Title

            myCommand.Parameters.Add(parameterTitle)

 

            Dim parameterDescription As New SqlParameter("@CompleteddateTime", SqlDbType.DateTime)

            parameterDescription.Value = CompleteddateTime

            myCommand.Parameters.Add(parameterDescription)

 

            Dim parameterUrl As New SqlParameter("@Status", SqlDbType.NVarChar, 100)

            parameterUrl.Value = status

            myCommand.Parameters.Add(parameterUrl)

 

            myConnection.Open()

            myCommand.ExecuteNonQuery()

            myConnection.Close()

 

            Return CInt(parameterItemID.Value)

        End Function

 

        Public Function UpdateMilestones(ByVal moduleId As Integer, ByVal item As String, ByVal user As String, ByVal Title As String, ByVal completeddateTime As String, ByVal status As String) As Integer

            If user.Length < 1 Then

                user = "unknown"

            End If

 

            ' Create Instance of Connection and Command Object

            Dim myConnection As New SqlConnection(ConfigurationSettings.AppSettings("connectionString"))

            Dim myCommand As New SqlCommand("Portal_UpdateMilestone", myConnection)

 

            ' Mark the Command as a SPROC

            myCommand.CommandType = CommandType.StoredProcedure

 

            ' Add Parameters to SPROC

            Dim parameterItemID As New SqlParameter("@ItemID", SqlDbType.Int, 4)

            parameterItemID.Direction = ParameterDirection.Output

            myCommand.Parameters.Add(parameterItemID)

 

            Dim parameterModuleID As New SqlParameter("@ModuleID", SqlDbType.Int, 4)

            parameterModuleID.Value = moduleId

            myCommand.Parameters.Add(parameterModuleID)

 

            Dim parameteritem As New SqlParameter("@item", SqlDbType.Int, 4)

            parameteritem.Value = item

            myCommand.Parameters.Add(parameteritem)

 

            Dim parameterUserName As New SqlParameter("@UserName", SqlDbType.NVarChar, 100)

            parameterUserName.Value = user

            myCommand.Parameters.Add(parameterUserName)

 

            Dim parameterTitle As New SqlParameter("@Title", SqlDbType.NVarChar, 100)

            parameterTitle.Value = Title

            myCommand.Parameters.Add(parameterTitle)

 

            Dim parameterDescription As New SqlParameter("@CompleteddateTime", SqlDbType.DateTime)

            parameterDescription.Value = CompleteddateTime

            myCommand.Parameters.Add(parameterDescription)

 

            Dim parameterUrl As New SqlParameter("@Status", SqlDbType.NVarChar, 100)

            parameterUrl.Value = status

            myCommand.Parameters.Add(parameterUrl)

 

            myConnection.Open()

            myCommand.ExecuteNonQuery()

            myConnection.Close()

 

            Return CInt(parameterItemID.Value)

        End Function

        Public Function GetSingleMilestone(ByVal itemId As Integer) As System.Data.SqlClient.SqlDataReader

 

            ' Create Instance of Connection and Command Object

            Dim myConnection As New SqlConnection(ConfigurationSettings.AppSettings("connectionString"))

            Dim myCommand As New SqlCommand("Portal_GetSingleMilestone", myConnection)

 

            ' Mark the Command as a SPROC

            myCommand.CommandType = CommandType.StoredProcedure

 

            ' Add Parameters to SPROC

            Dim parameterItemId As New SqlParameter("@ItemID", SqlDbType.Int, 4)

            parameterItemId.Value = itemId

            myCommand.Parameters.Add(parameterItemId)

 

            ' Execute the command

            myConnection.Open()

            Dim result As System.Data.SqlClient.SqlDataReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection)

 

            ' Return the datareader

            Return result

 

        End Function

        Public Sub DeleteMileStone(ByVal itemID As Integer)

 

            ' Create Instance of Connection and Command Object

            Dim myConnection As New SqlConnection(ConfigurationSettings.AppSettings("connectionString"))

            Dim myCommand As New SqlCommand("Portal_DeleteMilestone", myConnection)

 

            ' Mark the Command as a SPROC

            myCommand.CommandType = CommandType.StoredProcedure

 

            ' Add Parameters to SPROC

            Dim parameterItemID As New SqlParameter("@ItemID", SqlDbType.Int, 4)

            parameterItemID.Value = itemID

            myCommand.Parameters.Add(parameterItemID)

 

            myConnection.Open()

            myCommand.ExecuteNonQuery()

            myConnection.Close()

 

        End Sub

    End Class

End Namespace

 

    ' Other methods elided for clarity.

  End Class

End Namespace

Listing 1

Creating the User Control

After the database is taken care of, the next step is to create the user control that will handle the milestone user interface. The user control will contain a DataGrid that will define three columns: Title, Completion Date, and Status. The implementation of the user control is shown in Listing 2 below.

<%@ Control Language="VB" AutoEventWireup="false" CodeFile="MileStones.ascx.vb" Inherits="MK.Portal.DesktopModules_MileStones" %>

<%@ Register TagPrefix="ASPNETPortal" TagName="Title" Src="~/DesktopModuleTitle.ascx"%>

<aspnetportal:title editurl="~/DesktopModules/EditMilestones.aspx" edittext="Add Milestone" runat="server" id="Title1" />

<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>

 

And the code behind:

 

Namespace MK.Portal

    Partial Class DesktopModules_MileStones

        Inherits MK.Portal.PortalModuleControl

 

        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

            Dim milestones As New MK.Portal.MilestonesDB()

            myDataGrid.DataSource = milestones.GetMilestones(ModuleId)

            myDataGrid.DataBind()

        End Sub

 

    End Class

End Namespace

 

Listing 2

Inherit the ASPNET.StarterKit.Portal Module Control Base Class

All portal modules are actually no more than simple ASP.NET user controls that inherit the PortalModuleControl base class. This base class provides all the hooks that are required for the portal module to interact with the framework. To inherit the base class, place the following line at the top of the user control.

<%@ Control language="VB" Inherits=" ASPNET.StarterKit.Portal.PortalModuleControl" %>
Add the Module Title

One of the user controls that are available to portal modules is the Title user control. This control will generate the appropriate HTML.

<portal:title runat="server" />

 
Add Support for an Edit Page

In order to allow users to edit and add additional Milestones, support for an edit page must be added.   Support is added by passing two additional properties to the Module Title User Control.  

@ Page Language="VB" AutoEventWireup="false" CodeFile="EditMilestones.aspx.vb" Inherits="MK.Portal.DesktopModules_EditMilestones" %>

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

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html>

   <head>

      <link rel="stylesheet" href='<%= MK.Portal.Global.GetApplicationPath(Request) & "/ASPNETPortal.css" %>' type="text/css">

   </head>

   <body leftmargin="0" bottommargin="0" rightmargin="0" topmargin="0" marginheight="0" marginwidth="0">

      <form id="Form1" runat="server">

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

            <tr valign="top">

               <td colspan="2">

                  <aspnetportal:banner id="SiteHeader" runat="server" />

               </td>

            </tr>

            <tr>

               <td>

                  <br>

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

                     <tr valign="top">

                        <td width="150">

                           &nbsp;

                        </td>

                        <td width="*">

                           <table width="500" cellspacing="0" cellpadding="0">

                              <tr>

                                 <td align="left" class="Head">

                                    Milestone Details

                                 </td>

                              </tr>

                              <tr>

                                 <td colspan="2">

                                    <hr noshade size="1">

                                 </td>

                              </tr>

                           </table>

                           <table width="750" cellspacing="0" cellpadding="0" border="0">

                              <tr>

                                 <td width="100" class="SubHead">

                                    Title:

                                 </td>

                                 <td rowspan="3">

                                    &nbsp;

                                 </td>

                                 <td>

                                    <asp:textbox id="TitleField" cssclass="NormalTextBox" width="390" columns="30" maxlength="150" runat="server" />

                                 </td>

                                 <td width="25" rowspan="3">

                                    &nbsp;

                                 </td>

                                 <td class="Normal" width="250">

                                    <asp:requiredfieldvalidator id="Req1" display="Static" errormessage="You Must Enter a Valid Title" controltovalidate="TitleField" runat="server" />

                                 </td>

                              </tr>

                              <tr>

                                 <td class="SubHead">

                                    Completed:

                                 </td>

                                 <td>

                                    <asp:textbox id="CompleteDateField" cssclass="NormalTextBox" width="390"

                                                    columns="30" maxlength="150" runat="server" />

                                 </td>

                                 <td class="Normal">

                                    <asp:requiredfieldvalidator id="Req2" display="Static" runat="server"

                                                    errormessage="You Must Enter a Valid Date"

                                                    controltovalidate="CompleteDateField" />

                                 </td>

                              </tr>

                              <tr>

                                 <td class="SubHead">

                                    Status:

                                 </td>

                                 <td>

                                    <asp:textbox id="StatusField" cssclass="NormalTextBox" width="390" columns="30"

                                                    maxlength="150" runat="server" />

                                 </td>

                                 <td class="Normal">

                                     <asp:requiredfieldvalidator id="Requiredfieldvalidator1" display="Static" runat="server"

                                                    errormessage="You Must Enter a Valid Status"

                                                    controltovalidate="StatusField" />

                                 </td>

                              </tr>

                              </table>

                          

                              <asp:linkbutton id="updateButton" text="Update" runat="server" cssclass="CommandButton" borderstyle="none" />

                              &nbsp;

                              <asp:linkbutton id="cancelButton" text="Cancel" causesvalidation="False" runat="server" cssclass="CommandButton" borderstyle="none" />

                              &nbsp;

                              <asp:linkbutton id="deleteButton" text="Delete this item" causesvalidation="False" runat="server" cssclass="CommandButton" borderstyle="none" />

                              <hr noshade size="1" width="500">

                              <span class="Normal">Created by

                                            <asp:label id="CreatedBy" runat="server" />

                                            on

                                            <asp:label id="CreatedDate" runat="server" />

                                            <br>

                                        </span>

                           <p>

                           </p>

                        </td>

                     </tr>

                  </table>

               </td>

            </tr>

         </table>

      </form>

   </body>

</html>

 

And the code behind:

 
Create the Edit Page

 Once we have added support for an edit page using the Title User Control, we need to create the actual edit page. In addition to the HTML, we will define four methods:

·         Page_Load

·         UpdateBtn_Click

·         DeleteBtn_Click

·         CancelBtn_Click

The source for the DeleteBtn_Click method and the HTML associated with it in the edit page is shown in Listing 3 below. The rest of the implementation may be found in EditMilestones.aspx as part of the Milestone Extension download.

 

Imports System.Data.SqlClient

Namespace MK.Portal

    Partial Class DesktopModules_EditMilestones

        Inherits System.Web.UI.Page

 

        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

 

            ' Determine ModuleId of Links Portal Module

            moduleId = Int32.Parse(Request.Params("Mid"))

 

            ' Verify that the current user has access to edit this module

            If PortalSecurity.HasEditPermissions(moduleId) = False Then

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

            End If

 

            ' Determine ItemId of Link to Update

            If Not (Request.Params("ItemId") Is Nothing) Then

                itemId = Int32.Parse(Request.Params("ItemId"))

            End If

 

            If Page.IsPostBack = False Then

                ' Store URL Referrer to return to portal

                ViewState("UrlReferrer") = Request.UrlReferrer.ToString()

                If itemId <> 0 Then

                    ' Obtain a single row of link information

                    Dim milestones As New MilestonesDB()

                    Dim dr As System.Data.SqlClient.SqlDataReader = milestones.GetSingleMilestone(itemId)

 

                    ' Read in first row from database

                    dr.Read()

 

                    ' Security check.  verify that itemid is within the module.

                    Dim dbModuleID As Integer = Convert.ToInt32(dr("ModuleID"))

                    If dbModuleID <> moduleId Then

                        dr.Close()

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

                    End If

 

                    TitleField.Text = CStr(dr("Title"))

                    CompleteDateField.Text = CStr(dr("EstCompleteDate"))

                    Me.StatusField.Text = CStr(dr("Status"))

                    CreatedBy.Text = CStr(dr("CreatedByUser"))

                    CreatedDate.Text = CType(dr("CreatedDate"), DateTime).ToShortDateString()

 

                    ' Close datareader

                    dr.Close()

                End If

            End If

 

          

 

        End Sub

        Private itemId As Integer = 0

        Private moduleId As Integer = 0

        Private Sub CancelBtn_Click(ByVal sender As Object, ByVal e As EventArgs) Handles cancelButton.Click

 

            ' Redirect back to the portal home page

            Response.Redirect(CStr(ViewState("UrlReferrer")))

 

        End Sub

        Protected Sub updateButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles updateButton.Click

            If Page.IsValid = True Then

 

                ' Create an instance of the Link DB component

                Dim milestones As New MK.Portal.MilestonesDB()

 

                If itemId = 0 Then

 

                    ' Add the link within the Links table

                    milestones.AddMilestones(moduleId, itemId, Context.User.Identity.Name, TitleField.Text, Me.CompleteDateField.Text, Me.StatusField.Text)

 

                Else

 

                    ' Update the link within the Links table

                    milestones.UpdateMilestones(moduleId, itemId, Context.User.Identity.Name, TitleField.Text, Me.CompleteDateField.Text, Me.StatusField.Text)

 

                End If

 

                ' Redirect back to the portal home page

                Response.Redirect(CStr(ViewState("UrlReferrer")))

 

            End If

 

        End Sub

 

        Protected Sub deleteButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles deleteButton.Click

            If itemId <> 0 Then

 

                Dim milestone As New MK.Portal.MilestonesDB()

                milestone.DeleteMilestone(itemId)

 

            End If

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

        End Sub

    End Class

End Namespace

Listing 3

Adding the New Portal Module to the Framework

The Milestones Portal Module is now complete.  The only step left to perform is to add the module to the portal framework by using the online administrator’s Module Definitions section.  In this section, click on the Add New Module Type to bring up the page shown in Figure 6.  Enter the information for the new module and click Update.   The module can then be added to the different tabs by using the online administrator’s “Tab Name and Layout” section.

Figure 6. Module Type Definition

Conclusion

 

The portal demonstrates the key techniques used to build a portal web application using ASP.NET. In addition to web-based administration and content management, the portal is also extremely easy to extend as shown in this white paper with the Milestone module. This sample provides a great reference in terms of learning the .NET technologies as well as powerful framework that can be used for Internet or intranet portals.

For More Information

·         The complete documentation and source code can be obtained at Kendallsoft

    

Posted in:   Tags:

Currently rated 2.0 by 1 people

  • Currently 2/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Related posts

Comments

Add comment


(Will show your Gravatar icon)  

  Country flag

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview


 
July 30. 2010 05:31

no site

Calendar

«  July 2010  »
MoTuWeThFrSaSu
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678
View posts in large calendar

Tag Cloud

Recent Posts

Recent Comments

Banners

Theme Grabber
Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010 Mark Kendall's Blog