ASP .NET Web Developer s Guide - Mesbah Ahmed, Chris Garrett
.pdf
580 Chapter 13 • Creating a Message Board with ADO and XML
Figure 13.8 Continued
appSettings = settings.AppSettings()
connectionString = appSettings.Item("ConnectionString")
Dim connection As New OleDbConnection(connectionString) connection.Open()
Dim adapter As New OleDbDataAdapter(SQL, connection)
Dim myData As New DataSet()
adapter.Fill(myData)
adapter.Dispose()
connection.Close()
Return myData
End Function
Friend Shared Sub ExecuteNonQuery(ByVal SQL As String)
Dim connectionString As String
Dim settings As ConfigurationSettings
Dim appSettings As NameValueCollection
appSettings = settings.AppSettings()
connectionString = appSettings.Item("ConnectionString")
Dim connection As New OleDbConnection(connectionString) connection.Open()
Dim myCommand As New OleDbCommand() myCommand.Connection = connection myCommand.CommandText = SQL myCommand.CommandType = CommandType.Text myCommand.ExecuteNonQuery()
'clean up
Continued
www.syngress.com
Creating a Message Board with ADO and XML • Chapter 13 |
581 |
Figure 13.8 Continued
connection.Close()
myCommand.Dispose()
connection.Dispose()
End Sub
End Class
You see that the two methods in DataControl are in fact, rather simple. As was discussed earlier in this book, these functions connect to the database and do a specific function (execute SQL scripts and one returns a DataSet).The one thing to note is that the connection string is being retrieved from the ConfigurationSettings.AppSettings.These are dynamic settings that the .NET runtime gives you access to.When you’re running an ASP.NET application, they are located in the web.config file. In another type of application, they are located in ProjectName.exe.config.That’s it for our Data object.The next step is to take a look at our User object.
Designing the User Class
When we looked at the user information when thinking about the database, we discovered a number of fields that needed to reside in the User table. Luckily all our classes will be structured in a way to nearly match the database; the User class is no exception.The only difference is that this User is a VB.NET class and not a database table.
There are four basic types of users: Guests, Registered users, Administrators, and Moderators. All of these should be represented when we build our User class. Again, you might say something like “but this is an object-oriented application, and if we have multiple types of one object, shouldn’t they be separate?” Again, you would be right.There are three types of users. All have similar properties; the only difference is that some do certain things that others can’t. For instance, a registered user in a bulletin board would have the ability to post threads and messages, whereas a guest user would not. A registered user would also have the ability to edit his or her profile and edit his or her messages, whereas a guest user would not be able to. An administrator would have the ability to do everything a registered user could, except globally. A moderator can modify posts and threads in boards he or she has moderator privileges to.
Now that we’ve identified the multiple types of users, we need to determine if we should have multiple types of users in our application. A Guest can only
www.syngress.com
582 Chapter 13 • Creating a Message Board with ADO and XML
browse a bulletin board, as no security is necessary for browsing. A Registered User can create and edit posts, and modify his or her profile. An Administrator can do anything he or she wants to the bulletin board. A Moderator can do what a Registered User can, and can act like an Administrator on the board he or she is given moderation rights to.
You may want to build some neat OO objects here, but all these things can be accomplished through a single User class.Take a look at Figure 13.9.
Figure 13.9 The User Object Diagram
User
+ID : Long
+Username : String
+Password : String
+FirstName : String
+LastName : String
+Email : String
+IsAdmin : Boolean
+IsBanned : Boolean
+Validate() : User +Update() +Create() : User
You see that our User object will have the exact same fields as our database table, which is named exactly the same.This makes it a bit easier to remember which field in the object matches up to which field in the database.The other thing you should notice is the three items down at the bottom of the diagram: Create, Validate, and Update. All are methods the User object will have. Update() will update the user’s details and save them to the database. Validate is a shared method of the User class, and can be used to perform all user validation. Create is also a shared method, and can be used to create a brand new user in the database.
That’s it.That’s the whole User object. Not much to it is there? It has a Boolean field to signify whether or not it is an administrator, and each Board object will store the ID of the administrator of that Board, so the User object doesn’t have to.The only other thing to mention is guest users—a guest user will just be a User that is Nothing.That is, if you are currently a guest in the application, you won’t have a User object created for you. Let’s take a look at the code involved to create this User object in Figure 13.10 (which can also be found on your CD called User.vb).
www.syngress.com
Creating a Message Board with ADO and XML • Chapter 13 |
583 |
Figure 13.10 The Basics (User.vb)
Public Class |
User |
|
|
Private |
mUsername As |
String |
|
Private |
mPassword As |
String |
|
Private |
mFirstName As String |
||
Private |
mLastName As |
String |
|
Private |
mUserID |
As Long |
|
Private |
mIsAdmin As |
Boolean |
|
Private |
mEmail |
As String |
|
Private |
mUserID |
As Long |
|
End Class |
|
|
|
|
|
|
|
That part is clear enough.We declare the User class, and the private variables necessary to represent each user. Next, declare the public properties for each of these private variables as shown in Figure 13.11.
Figure 13.11 Public Properties (User.vb)
Public WriteOnly Property Password() As String
Set(ByVal Value As String)
MPassword = Value
End Set
End Property
Public ReadOnly Property ID() As Long
Get
Return mUserID
End Get
End Property
Public Property LastName() As String
Get
Return mLastName
End Get
Set(ByVal Value As String)
Continued
www.syngress.com
584 Chapter 13 • Creating a Message Board with ADO and XML
Figure 13.11 Continued
mLastName = Value
End Set
End Property
Public Property FirstName() As String
Get
Return mFirstName
End Get
Set(ByVal Value As String)
mFirstName = Value
End Set
End Property
Public Property Username() As String
Get
Return mUsername
End Get
Set(ByVal Value As String)
mUsername = Value
End Set
End Property
Public Property IsAdmin() As Boolean
Get
Return mIsAdmin
End Get
Set(ByVal Value As Boolean)
mIsAdmin = Value
End Set
End Property
Public Property IsBanned() As Boolean
Get
Continued
www.syngress.com
Creating a Message Board with ADO and XML • Chapter 13 |
585 |
Figure 13.11 Continued
Return mIsBanned
End Get
Set(ByVal Value As Boolean)
mIsBanned = Value
End Set
End Property
Public Property Email() As String
Get
Return mEmail
End Get
Set(ByVal Value As String)
mEmail = Value
End Set
End Property
With that out of the way, let’s look at the methods the User object will have.As we saw earlier, there will be three methods: Validate, CreateUser, and Update. Validate is a shared method which will give a developer the ability to validate and return a valid User object, or throw an exception. CreateUser is also a shared method that gives the developer the ability to create a new User object. Finally, Update will allow a developer to update the private fields in the User object and commit them to the database.This will be for tasks like saving passwords and updating e-mail addresses. Let’s take a look at the first method, Validate, in Figure 13.12.
Figure 13.12 The Validate Method (User.vb)
Public Shared Function Validate(ByVal username As String, _ ByVal password As String) As User
If password.Equals("") Then
Throw New ArgumentException("You must enter a password.") Else
Dim myData As DataSet = DataControl.GetDataSet("SELECT * " & _ "FROM [Users] WHERE [UserName] = '" & username & "'")
If myData.Tables(0).Rows.Count <= 0 Then
Continued
www.syngress.com
586 Chapter 13 • Creating a Message Board with ADO and XML
Figure 13.12 Continued
Throw New ArgumentException("Username does not exist.")
Else
If CBool(myData.Tables(0).Rows(0)("IsBanned")) = True Then
Throw New Exception("User is banned")
Else
If password <> _
CStr(myData.Tables(0).Rows(0)("Password")) Then
Throw New ArgumentException("Invalid password")
Else
Return New User(myData.Tables(0).Rows(0))
End If
End If
End If
End If
End Function
The Validate method accepts a username and a password as parameters, and attempts to verify that those parameters are a valid combination for a registered user. If the password is empty, it throws an ArgumentException. If, while looking up the username, it finds that the username is not present in the database, it again throws an ArgumentException. If the username exists, but the user is banned, then it throws an Exception. If the username exists, the user is not banned, and the password passed in was incorrect, once again it throws an ArgumentException. Finally, if the username is valid and the password is correct, it returns a new User object, passing in the first DataRow to the User constructor.
At this point, you’re probably wondering why we haven’t discussed the constructor of the User object.Well, wait no longer! Here’s the code for the User object constructor in Figure 13.13.
Figure 13.13 Constructors (User.vb)
Public Sub New(ByVal userId As Long)
Dim myData As DataSet
myData = DataControl.GetDataSet("SELECT * FROM Users " & _
"WHERE UserID = " & Me.mUserID)
Continued
www.syngress.com
Creating a Message Board with ADO and XML • Chapter 13 |
587 |
Figure 13.13 Continued
If myData.Tables(0).Rows.Count <= 0 Then
Throw New ArgumentException("The requested user " & _ does not exist.")
Else
inflate(myData.Tables(0).Rows(0)) End If
myData.Dispose() End Sub
Public Sub New(ByVal row As DataRow) inflate(row)
End Sub
There are two constructors here.The second constructor is what the Validate method called.That constructor forwards the DataRow on to another method called inflate, which will be discussed in a moment.The first constructor accepts a user ID as a parameter.This user ID is synonymous with the UserID field in the User table.The constructor looks up the user based on the user ID. If that user ID is not found, it throws an ArgumentException. If the user ID is found, it forwards the first DataRow in the DataSet to the fillData method in Figure 13.14.
Figure 13.14 The fillData Method (User.vb)
Private Sub inflate(ByVal row As DataRow)
Me.mUsername = CStr(row("Username"))
Me.mFirstName = CStr(row("FirstName"))
Me.mLastName = CStr(row("LastName"))
Me.mIsAdmin = CBool(row("IsAdmin"))
Me.mEmail = CStr(row("Email"))
Me.mUserID = CLng(row("UserID"))
Me.mPassword = CStr(row("Password"))
End Sub
www.syngress.com
588 |
Chapter 13 • Creating a Message Board with ADO and XML |
|||
|
|
As you can see, the inflate method accepts a DataRow as a parameter, and pop- |
||
|
|
ulates all the private fields with values from the database.This is frequently called |
||
|
|
“inflating” your objects, hence the appropriately named subroutine.The other |
||
|
|
thing to notice is that inflate is a private subroutine.This is because you don’t |
||
|
|
want any objects outside of the current User object to have access to this method. |
||
|
|
It does “utility” work on the object, and is unnecessary for any other object to |
||
|
|
call this method. |
|
|
|
|
Now that we’ve discussed how to Validate and return a valid User object, let’s |
||
|
|
move on to creating users. Any user can have any username.The only restriction |
||
|
|
is that no two users can have the same username.This is because if you had two |
||
|
|
users with the same username, the only way to identify which one you wanted is |
||
|
|
to have some other sort of unique identifier. Unfortunately, people can typically |
||
|
|
remember names and usernames much better than they could some (relatively) |
||
|
|
random number. So, in order to keep this username unique, you have to manually |
||
|
|
check. If you were a database administrator, you would probably insist on creating |
||
|
|
a unique index on the username field in the database, which is completely rea- |
||
|
|
sonable. If you feel you need the extra “security” in place to make sure the same |
||
|
|
username isn’t taken twice, go ahead and put it in there, but it’s in the CreateUser |
||
|
|
method as well, which we will now take a look at in Figure 13.15. |
||
|
|
Figure 13.15 The CreateUser Method (User.vb) |
||
|
|
|
||
|
|
Public Shared Function CreateUser(ByVal userName As String, _ |
||
|
|
ByVal password As String, _ |
||
|
|
ByVal firstName As String, _ |
||
|
|
ByVal lastName As String, ByVal email As String) As User |
||
|
|
Dim |
sql As String |
|
|
|
Dim |
myData As |
DataSet |
|
|
sql = "SELECT |
userName FROM Users WHERE userName = '" & _ |
|
|
|
|
userName & "'" |
|
|
|
myData = DataControl.GetDataSet(sql) |
||
|
|
If myData.Tables(0).Rows.Count <= 0 Then |
||
|
|
|
'this username has not been taken |
|
|
|
|
sql = "INSERT INTO [Users] ([Username], [Password], " & _ |
|
"[FirstName], [LastName], " & _
Continued
www.syngress.com
Creating a Message Board with ADO and XML • Chapter 13 |
589 |
Figure 13.15 Continued
"[Email], [IsAdmin], [IsBanned]) VALUES ('" & userName & _ "','" & password & "','" & firstName & "','" & lastName & _ "','" & email & "',0,0)"
DataControl.ExecuteNonQuery(sql)
Return User.Validate(userName, password)
Else
'this username has already been taken
Throw New ArgumentException("The username is already taken") End If
End Function
First, the CreateUser function scans the database to see if the request username already exists. If it does, it throws an ArgumentException. If the username doesn’t exist, it builds a SQL statement to insert a new row into the user table and executes it. Finally it calls the Validate method and returns the result.
The last method to discuss is the Update method.This method updates the database with the current state of the object. See Figure 13.16 for the Update method.
Figure 13.16 The Update Method (User.vb)
Public Sub Update()
Dim sql As String
sql = "UPDATE [Users] SET [Password] = '" & mPassword & _ "', [FirstName] = '" & mFirstName & _
"', [LastName] = '" & mLastName & _ "', [Email] = '" & mEmail & "'"
If Me.IsAdmin = True Then
sql = sql & ", [IsAdmin] = 1"
Else
sql = sql & ", [IsAdmin] = 0" End If
If Me.IsBanned = True Then
sql = sql & ", [IsBanned] = 1"
Else
Continued
www.syngress.com
