Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ASP .NET Web Developer s Guide - Mesbah Ahmed, Chris Garrett

.pdf
Скачиваний:
37
Добавлен:
24.05.2014
Размер:
7.32 Mб
Скачать

620 Chapter 13 • Creating a Message Board with ADO and XML

Figure 13.44 Continued

'we only want to apply these styles if we 'haven't already explicitly set them

If objWebControl.CssClass.Trim() = "" Then objWebControl.CssClass = style

End If

End If

If objControl.HasControls() Then

ApplyStyles(objControl.Controls)

End If

Next objControl

End Sub

Public Function GetStyleName(ByVal controlType As String) As String Dim objNode As XmlNode

objNode = objXml.SelectSingleNode("styles/control[@type='" & _ controlType & "']")

If objNode Is Nothing Then 'do nothing

Return ""

Else

'get the css class specified by this node Return objNode.InnerText

End If

End Function

That’s a lot to digest all at once, so let’s break it down.The first thing you’ll see is that ApplyStyles accepts a ControlCollection as a parameter.This collection can be obtained from Page.Controls or Control.Controls. Next, the subroutine checks to see if the XML document has been loaded yet. If it hasn’t, it retrieves the location of the styles.xml file from the AppSettings and loads it. If there was an error in the loading of the document, it throws an exception. If there are no problems with the XML document, it loops through every Control in the ControlCollection that was passed in. For every control, it sets a variable “style” to the value of what the GetStyleName function returns. GetStyleName takes your

www.syngress.com

Creating a Message Board with ADO and XML • Chapter 13

621

control’s fully qualified type name (represented in the code by objControl.GetType().ToString()), and looks for that in the XML document. It does this by calling the SelectSingleNode function of the XMLDocument object. It builds an XPath query string and looks for the appropriate node with the type attribute that is the same as the type string passed into the GetStyleName function. If it finds that node, it returns the InnerText of the appropriate node; otherwise it returns an empty string.

Control is returned to the ApplyStyles method, and the style that was returned is tested to make sure it is not an empty string; there is no point in setting the value if it is empty. Next, the Control is cast to be a variable of type WebControl. Since the only Control that can have its style attribute programmatically manipulated is the WebControl, and since every control in System.Web.UI.WebControls inherits directly from WebControl, it is safe to perform this cast. Just make sure you do not add anything other than WebControls to your styles.xml file and this will work without error. Next, the CssClass property of your WebControl is tested to make sure it is currently an empty string. It does this because if you specifically set a style on one of your controls, you most likely do not want that style overridden by this method. If it is empty, it sets the CssClass property to the style String that was returned by the GetStyleName function. Finally, if the Control has child controls, it recursively calls ApplyStyles, but instead with the

Control.ChildControls ControlCollection as the parameter.

With these two functions, every type of Control you add to your styles.xml file will automatically get CSS styles applied to them, without any maintenance on your part other than a small XML file.Wondering how this will actually get used? All you need to do is in your classes that inherit from FormBase, call the ApplyStyles method passing the ChildControls of the page you are currently on. Feel free to try this. Modify the stylesheet and styles.xml file all you want. Just rest assured that every control type you add to your XML file will automatically have the CSS classes applied to them that you want.

Building the Log-In Interface

Since we don’t have any users created in the database yet, let’s take a look at how to register with dotBoard. How to create the User Controls and Forms won’t be discussed, but the source code is available on your CD, as well as multiple screen shots for each Web Form and User Control.Take a look at the register.aspx page on Figure 13.45.

www.syngress.com

622 Chapter 13 • Creating a Message Board with ADO and XML

Figure 13.45 The Register.aspx Page

Let’s examine the controls on this page. First, there are a number of labels and text boxes used to capture the user’s information.There is also a button that will submit the form when pressed.The red-colored controls are validation controls. Validation controls allow you to place “rules” on input without needing to actually code it yourself.The display property of these controls is set to None, so they will never show up, but that is where the ValidationSummary comes in.The control in the top right of this page is a ValidationSummary control, which will aggregate all the errors into one area, so you do not need to place your validation controls in a custom place.The other thing on this form is a CustomValidator control. A CustomValidator is typically used to handle client-side JavaScript, but it is also quite useful to handle exceptions thrown and display them to the user. Let’s take a look at the code behind this form in Figure 13.46.

Figure 13.46 The Code-Behind File (Register.aspx.vb)

Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here Me.ApplyStyles(Me.Controls)

End Sub

Continued

www.syngress.com

Creating a Message Board with ADO and XML • Chapter 13

623

Figure 13.46 Continued

Private Sub btnRegister_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnRegister.Click 'attempt to register the user

If Me.Page.IsValid Then

Try

Dim myUser As dotBoardObjects.User

myUser = dotBoardObjects.User.CreateUser( _ txtUsername.Text, txtPassword.Text, _ txtFirstName.Text, txtLastName.Text, _

txtEmailAddress.Text)

'if we've made it this far, the create worked Dim objPage As FormBase

objPage = CType(Me.Page, FormBase) objPage.CurrentUser = myUser 'redirect to the default page Response.Redirect("default.aspx")

Catch Ex As Exception valCustom.ErrorMessage = Ex.Message valCustom.IsValid = False

End Try

End If

End Sub

First, we have the Page_Load subroutine, which handles the Page.Load event. All this event does is call the ApplyStyles method of the FormBase class. Next, we have the btnRegister_Click subroutine that handles the Register button’s click event.The first thing that subroutine does is make sure the page is currently in a valid state.This validity is determined whether or not all of the validation controls you added to your form return a valid result. Only once every validation control becomes valid does Page.IsValid ever return true. Next, a User object is declared and the CreateUser method is called. If the CreateUser method throws an exception, then the custom validator on our form is set to invalid and its ErrorMessage property is set to the Message property of the Exception thrown. If

www.syngress.com

624 Chapter 13 • Creating a Message Board with ADO and XML

the CreateUser succeeded, then a reference to the parent Page, casted to the FormBase type, is created and the CurrentUser property is set to the User that was just created. Once all this is done, the user is redirected to default.aspx.

As we discussed when we went over FormBase, every page will need to know about the currently logged in user. Likely, every page will also need a login form so the user can log in from anywhere.The best way to do this is to create a Web User Control.Take a look at our userArea.ascx control in Figure 13.47.

Figure 13.47 UserArea.ascx

Boy that’s ugly, isn’t it? Don’t worry, that’s why we created the style code in FormBase. Anyway, what we have here are two panels.The top panel contains the controls necessary to log a user in, while the bottom panel contains the welcome message and any specific actions the user can take. Let’s take a look at the codebehind for this page in Figure 13.48.

Figure 13.48 The Code-Behind (UserArea.ascx.vb)

Private Sub Page_Init(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles MyBase.Init

'CODEGEN: This method call is required by the Web Form Designer 'Do not modify it using the code editor.

InitializeComponent()

Continued

www.syngress.com

Creating a Message Board with ADO and XML • Chapter 13

625

Figure 13.48 Continued

pnlNotLoggedIn.Visible = True pnlLoggedIn.Visible = False lnkAdmin.Visible = False

'attempt to log the user in

If Not Session.Contents().Item("userid") Is Nothing Then

Dim userId As Long

userId = CLng(Session.Contents.Item("userid")) Dim myUser As User

Try

myUser = New User(userId) Dim objPage As FormBase

objPage = CType(Me.Page, FormBase) objPage.CurrentUser = myUser pnlNotLoggedIn.Visible = False pnlLoggedIn.Visible = True

lblWelcome.Text = myUser.FirstName & " " & myUser.LastName

If myUser.IsAdmin Then lnkAdmin.Visible = True

End If

Catch Ex As Exception

lblError.Text = Ex.Message

End Try

End If

End Sub

Private Sub btnLogIn_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnLogIn.Click 'attempt to log in the user

If txtUsername.Text.Trim() <> "" And _

Continued

www.syngress.com

626 Chapter 13 • Creating a Message Board with ADO and XML

Figure 13.48 Continued

txtPassword.Text.Trim() <> "" Then Try

Dim myUser As User = User.Validate(txtUsername.Text, _ txtPassword.Text)

Dim objPage As FormBase

objPage = CType(Me.Page, FormBase) objPage.CurrentUser = myUser

'if it got this far it succeeded

'redirect, to allow the whole page to refresh Response.Redirect(Request.RawUrl)

Catch Ex As Exception

lblError.Text = Ex.Message

End Try

End If

End Sub

Private Sub LinkButton1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles LinkButton1.Click 'redirect to the register page Response.Redirect("register.aspx")

End Sub

Private Sub lnkLogOut_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles lnkLogOut.Click Session.Remove("userid") Response.Redirect("default.aspx")

End Sub

Private Sub lnkProfile_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles lnkProfile.Click Response.Redirect("profile.aspx")

End Sub

Continued

www.syngress.com

Creating a Message Board with ADO and XML • Chapter 13

627

Figure 13.48 Continued

Private Sub lnkAdmin_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles lnkAdmin.Click

Response.Redirect("admin.aspx")

End Sub

Okay, there’s a lot here, so let’s break it down.The Page_Init subroutine handles the Page.Init event.When this subroutine gets called, it attempts to log in the user based on the Session userId value. If that value exists, it uses it and initializes the CurrentUser object; otherwise, it exits. Finally, the subroutine hides or shows the correct panel and admin link depending on whether the user was successfully logged in or not and if the use is an admin or not, and then changes the text of the welcome label to the logged in users first and last name.

BtnLogin_Click handles the event when the user clicks the Login button.The first thing it does is check to make sure values have been entered into the username and password fields. If so, it attempts to validate the user with the username and password the user entered. If an exception is thrown, the error label text is set to the message of the exception thrown. If not, it sets the CurrentUser property of the FormBase to the currently logged in user, and then redirects the user back to the page they are currently on. It does this to make sure all controls on the page have gotten a chance to know that the user has logged in.

Finally, we have four link buttons, the first one redirects the user to the register page we’ve already seen, while the other clears the user ID out of Session and redirects them back to default.aspx.The third redirects the user to profile.aspx, the user profile page.The fourth one redirects the user to admin.aspx, the admin page.

Finally, open up your default.aspx page, and drag your userArea.ascx user control onto the page.You now have a fully functioning login/register area to your message board, where anyone can register and log in and receive customized links depending on what type of user they are. See Figure 13.49 to see what the page looks like.

www.syngress.com

628 Chapter 13 • Creating a Message Board with ADO and XML

Figure 13.49 The Default Page, with the Styling Code Applied

Designing the Browsing Interface

The next step in building dotBoard is to determine how to browse through the Boards,Threads, and Posts.When a user first enters the site and views the default page, they should be shown a list of Boards and descriptions they can choose to view.This code is located in default.aspx and default.aspx.vb.

Board Browsing

Browsing through our boards isn’t very difficult. All we need to do is use a Repeater control, and create a custom DataSet out of our list of Board objects. Unfortunately, the only control we can drag and drop onto a Web Form is a Repeater control, and you can’t drag controls into the Repeater, so we are going to have to look at the actual quasi-HTML that ASP.NET uses and write the repeated content by hand, as shown in Figure 13.50.

Figure 13.50 The Repeater Control (Default.aspx)

<asp:Panel runat="server">

<asp:Repeater id="Repeater1" runat="server">

<HeaderTemplate>

Continued

www.syngress.com

Creating a Message Board with ADO and XML • Chapter 13

629

Figure 13.50 Continued

<div class="header">Available boards</div> </HeaderTemplate>

<SeparatorTemplate>

<br><br>

</SeparatorTemplate>

<ItemTemplate>

<a href='board.aspx?boardid=

<%#DataBinder.Eval(Container, "DataItem.BoardName")%>'> <%#DataBinder.Eval(Container, "DataItem.BoardName")%>

</a>

<br>

<%#DataBinder.Eval(Container, "DataItem.BoardDescription")%> </ItemTemplate>

</asp:Repeater>

</asp:Panel>

The repeater code creates a header template, separator template, and the actual item template.The only thing we haven’t discussed thus far is what data source the Repeater should use. Since the Repeater control requires a real data source (i.e., DataSet or something similar), what needs to be done is our list of Boards needs to be “translated” into a DataSet.Take a look at the updated codebehind for the default page in Figure 13.51.

Figure 13.51 The Updated Code-Behind (Default.aspx.vb)

Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here Me.ApplyStyles(Me.Controls)

Me.DisplayBoards()

End Sub

Private Sub DisplayBoards()

Dim myBoards As DataSet = New DataSet()

Dim list As ArrayList

Continued

www.syngress.com