Wiley ASP.NET 2.0 Instant Results Datasheet


Add to my manuals
36 Pages

advertisement

Wiley ASP.NET 2.0 Instant Results Datasheet | Manualzz

04_749516 ch01.qxp 2/10/06 9:11 PM Page 1

1

The Online Diar y and Organizer

By the end of this chapter you’ll have created an online diary, organizer, and contacts manager. So what exactly does the online diary and organizer do? Using a calendar-based interface it allows you to add, delete, and edit a diary entry for any day. It also allows you to create events: for example, to keep a note of your rich Uncle Bob’s birthday — wouldn’t want to forget that, would you?

It’s not just limited to birthdays, but any event: meetings, appointments, and so on.

The system has a basic username and password logon system, so that only you and no one else can view your own diary. This is what differentiates it from a blog. This system is a private diary and contacts manager — a place to put all those thoughts and comments you’d rather not have the world see. Unlike a blog, where you want the world to see it!

This whole project demonstrates the power of ASP.NET 2.0 and how easy it makes creating projects like this. Gone are the days of hundreds of lines of code to do security logons, create new users, and so on. This chapter employs the new security components of ASP.NET 2.0 to show just how easy it is to create fun, exciting, and useful projects.

The first section takes you through using the diary and its main screens. Then, the “Design of the

Online Diary” section walks you through an overview of the system’s design. After that you get into the nuts and bolts of the system and how it all hangs together. In the final section, you set up the diary.

COPYRIGHTED MATERIAL

Using the Online Diar y

Each user has his or her own online diary; to access it requires logging on. Enter username user5 with the password 123!abc

to log in as a test user. The log on screen is shown in Figure 1-1.

Although the screenshot may suggest lots of controls and lots of code to make the security function, in fact with the new security controls in ASP.NET 2.0 it’s very easy and not much work at all.

If you have not registered, a link will take you to the Sign Up page, depicted in Figure 1-2.

04_749516 ch01.qxp 2/10/06 9:11 PM Page 2

Chapter 1

Figure 1-1

Figure 1-2

This shows another of the new security controls in ASP.NET 2.0; creating a registration process is now just a matter of adding a control to a form!

If you’ve forgotten your password, you can click the Forgotten Your Password? link, which directs you to the Password Reminder wizard pages (see Figure 1-3).

Figure 1-3

2

Having logged on, you arrive at the main diary page, as displayed in Figure 1-4.

04_749516 ch01.qxp 2/10/06 9:11 PM Page 3

The Online Diary and Organizer

Figure 1-4

On this page you see a monthly calendar. Days with diary entries are marked with a blue background.

Days with events are marked in red text. Notice also on the right that upcoming events are highlighted, as are recent diary entries.

Clicking on a day moves you through to the area where you can enter your diary entry for that day; and add, edit, and delete events (see Figure 1-5).

Figure 1-5

3

04_749516 ch01.qxp 2/10/06 9:11 PM Page 4

Chapter 1

You can also navigate your diary from here via the small calendar to the right.

Adding a diary entry simply involves typing in the Entry Title and Diary Text boxes and clicking the

Save Entry button.

Events happening on a particular day are listed in the Events table at the bottom-left of Figure 1-5. You can edit and delete events, or click the Add New Event link to add a new event. The Edit and Add event pages are almost identical in look. An example of the Edit Event page is shown in Figure 1-6.

Figure 1-6

In the Edit Event page, you can set the event’s name, include a brief description, what time the event starts, and how long it lasts.

Returning to the main diary page (refer to Figure 1-4) you’ll see a Manage Your Contacts link, as shown in Figure 1-7.

4

Figure 1-7

Clicking that link takes you to the Contact Management page (see Figure 1-8).

04_749516 ch01.qxp 2/10/06 9:11 PM Page 5

The Online Diary and Organizer

Figure 1-8

Here you see a list of your contacts, which you can edit and delete by clicking the appropriate link in the

Contacts table. You can also add a new contact by clicking the Add New Contact link, which takes you to the New Contact page (no surprise there!), shown in Figure 1-9.

Figure 1-9

Currently the contacts functionality is fairly simple, with such things as linking events and contacts and automatically e-mailing contacts to remind them of an event.

5

04_749516 ch01.qxp 2/10/06 9:11 PM Page 6

Chapter 1

So you’ve seen what the Online Diary does, now you can look at how it does it! The next section describes the overall design and how the system hangs together. You get a high-level tour of the database setup and each of the classes the system uses.

Design of the Online Diar y

The diary system is split into the common three-layer architecture. All data and direct data modifying code are in the data layer, a combination of database tables and stored procedures. The data access layer is examined next.

Above the data access layer is the business layer providing all the rules and intelligence of the system.

The business layer has been coded as seven classes, which you tour through shortly.

Finally, the bit the user sees is the presentation layer, consisting of a number of .aspx files that utilize the business and data access layers to create the diary’s interface. This layer is discussed in the last part of this section.

The Data Access Layer

The Online Diary uses a SQL Server 2005 Express database. However, there’s no reason why this couldn’t be changed to work with other databases. If the database supports stored procedures, then in theory all that’s needed is a change of connection string and creation of stored procedures matching those in the current SQL Server database. If the database doesn’t support stored procedures — for example, MS

Access — changes to class code would be necessary but not difficult.

Figure 1-10 shows the tables in the Online Diary database (DiaryDB).

6

Figure 1-10

04_749516 ch01.qxp 2/10/06 9:11 PM Page 7

The Online Diary and Organizer

The default database created using the new membership features of ASP.NET 2.0 is also used. The database is a SQL Server Express database and not modified from the one created by Visual Studio

Express. However, to link the log on and the diary details, the UserName field in the DiaryDB database takes its value originally from the membership database. You go through this in more detail shortly.

Membership details are contained in the ASPNETDB database that Visual Web Developer Express creates for you. Although it contains quite a few tables, you never access them via the code in this project.

It’s accessed exclusively by the new Login controls — it does all the hard work behind the scenes!

This project only makes use of the aspnet_Users table, shown in Figure 1-11, to provide log on security checking and provide a username for the main DiaryDB. You may well want to extend the membership database to include extra functionality such as personalizing the user experience or providing different levels of membership (admin, user, operator), among other things.

Figure 1-11

The tables of the main Online Diary database and their roles are listed in the following table:

Table Name

Diary

DiaryEntry

DiaryEvent

Contact

Description

Contains details of all Online Diary users, their DiaryId, and names.

Contains all the diary entries for all diary users.

Contains all the diary events for all diary users.

Holds the details of all contacts for the diaries.

The key that links all of the tables together is the DiaryId field. It’s the primary key field in the Diary table and a foreign key field in all the other tables. Why not use the UserName field? Basically speed — it’s easier and therefore faster for the database to do joins and searches on an integer field than it is on character-based fields.

All access to the database is via a stored procedure. The naming convention is simply as follows:

ActionThingThisActionRelatesTo

7

04_749516 ch01.qxp 2/10/06 9:11 PM Page 8

Chapter 1

Consider this very simple stored procedure:

DeleteContact

Rather unsurprisingly, DeleteContact deletes a contact from the database. The naming convention means the purpose of each stored procedure doesn’t need a lot of explanation. As the code is discussed, you look at the stored procedures in more detail where necessary.

The Business Layer

The business layer is organized into seven classes. The four main classes are as follows:

OnlineDiary

DiaryEntry

DiaryEvent

Contact

These classes do most of the work of temporarily holding diary-related data and retrieving and storing it in the database. There are also three collection classes. The first order of business is the OnlineDiary class.

The OnlineDiary Class

This class contains only two shared public methods, detailed in the following table:

Method

InsertDiary(ByVal UserName As String,

ByVal FirstName As String, ByVal

LastName As String)

GetDiaryIdFromUserName(ByVal

UserName As String)

Return Type

None

Integer

Description

Inserts a new diary user into the OnlineDiary database.

Looks up the UserName in the database and returns the associated DiaryId.

The purpose of the OnlineDiary class is simply to provide a couple of handy shared methods relating to an online diary as a whole. It could also be used to expand the diary system and add new functionality that relates to the overall diary system, rather than a specific part such as contacts.

The Contact Class

The Contact class objectifies a single contact — a person or thing for which you want to store contact information. It encapsulates everything to do with contacts, including the storing and retrieving of contact information in the database.

8

04_749516 ch01.qxp 2/10/06 9:11 PM Page 9

The Online Diary and Organizer

It has two constructors, outlined in the following table:

Constructor

New(ByVal Diaryid as Integer)

New(ByVal ContactId As Long)

Description

Creates a new Contact object with all properties set to their default values.

Creates a new Contact object with its properties retrieved from the database using the argument ContactId .

Having created a Contact object, saving it involves simply calling the Save() method. The class will work out whether it’s a new contact that needs to be inserted into the database, or an existing one that needs to be updated. In addition to the Save() method, the Contacts class contains two Delete() methods, as well as two GetContacts() methods, all of which are outlined in the following table:

Method

Save()

DeleteContact()

DeleteContact(ByVal

ContactId As Long)

Return Type

None

None

None

GetContactsByFirstLetter(ByVal SqlDataReader

DiaryId As

Integer,Optional ByVal

FirstLetterOfSurname

As Char)

Description

Saves a fully populated Contact object. If it’s a new contact, Save() calls InsertNewContact sub, and the details are inserted into the database. The new ContactId is returned from the database and entered into mContactId . If the contact already exists in the database,

Save() calls UpdateContact , which updates the database values with those in the Contact object.

Deletes from the database the Contact object with ContactId equal to mContactId of the object. Contact object’s values are re-initialized to their defaults.

Shared method that deletes the

Contact object from the database with a ContactId value equal to the

ContactId argument of the method.

Shared method that returns a

SqlDataReader object populated with a list of contacts whose surname’s first letter matches the

FirstLetterOfSurname argument.This argument is optional; if left off, all Contact objects regardless of surname’s first letter are included in the DataSet’s rows.

Table continued on following page

9

04_749516 ch01.qxp 2/10/06 9:11 PM Page 10

Chapter 1

Method Return Type

GetContactsByFirstLetterAsCollection(ByVal SqlDataReader

DiaryId As Integer, Optional ByVal

FirstLetterOfSurname As Char)

Description

Shared method that returns a

ContactCollection object populated with Contact objects whose surname’s first letter matches the

FirstLetterOfSurname argument. This argument is optional; if left off, all

Contact objects regardless of surname’s first letter are included in the DataSet’s rows.

Finally, the Contact class contains the following properties:

Property

ContactId

FirstName

LastName

Email

Telephone

MobilePhone

AddressLine1

City

State

PostalCode

Type

Long

String

String

String

String

String

String

String

String

String

Description

Each contact is represented by a unique ID. The ID is autogenerated by the Contact table in the database whenever a new contact is inserted.

Contact’s first name.

Contact’s surname.

Contact’s e-mail address.

Contact’s telephone number.

Contact’s mobile phone number.

Contact’s house name and street address.

Contact’s city of residence.

Contact’s state.

Contact’s zip or postal code.

The ContactCollection Class

The ContactCollection class inherits from the System.Collections.CollectionBase

class. The

ContactCollection class’s purpose is simply to store a collection of Contact objects. This class gets extensive use in the next chapter, when you create a contacts organizer.

10

04_749516 ch01.qxp 2/10/06 9:11 PM Page 11

The Online Diary and Organizer

The ContactCollection class has only one property:

Property

Item(ByVal Index As Integer)

Type

Integer

Description

Returns the Contact object stored at the position in index in the collection.

The ContactCollection class’s public methods are as follows:

Method

Add(ByVal NewContact As Contact)

Return Type

None

Add(ByVal ContactId As Long)

Remove(ByVal Index as Integer)

None

None

Description

Adds a Contact object to the collection held by the

ContactCollection object.

Creates a new Contact object.

ContactId

Contact is passed to the object’s constructor to ensure it’s populated with the contact’s details from the database. The new Contact object is then added to the collection maintained by the

ContactCollection object.

Removes the Contact object from the collection at the specified index.

That deals with the Contact classes; now take a look at the two classes dealing with diary entries.

The DiaryEntry Class

The DiaryEntry class objectifies a single entry in a diary. It encapsulates everything to do with diary entries, including creating, updating, and retrieving diary entry data. It handles all the database access for diary entries.

It has three constructors, outlined in the following table:

Constructor

New(ByVal DiaryId as Integer)

New(ByVal DiaryEntryId As Long)

New(ByVal DiaryId AS Integer,

ByVal EntryDate As Date)

Description

Creates a new DiaryEntry object with all properties set to their default values.

Creates a new DiaryEntry object with its properties retrieved from the database using the argument

DiaryEntryId .

Creates a new DiaryEntry object with its properties retrieved from the database using the arguments

DiaryId and EntryDate .

11

04_749516 ch01.qxp 2/10/06 9:11 PM Page 12

Chapter 1

Having created a DiaryEntry object, saving it involves simply calling the Save() method. As with the

Save() method of the Contacts class, the DiaryEntry class will work out whether it’s a new diary entry that needs to be inserted into the database, or an existing entry that needs to be updated. As well as enabling retrieval of one diary entry’s details, the DiaryEntry class provides additional methods for getting details of a number of diary entries as either a collection or as a DataSet by returning a sqlDataReader object. The methods of this class are explained in the following table:

Method

Save()

GetDaysInMonthWithEntries(ByVal

DiaryId As Integer, ByVal Month

As Integer, ByVal Year As

Integer)

Return Type

None

Boolean Array

GetDiaryEntriesByDate(ByVal SqlDataReader

DiaryId As Integer, ByVal

FromDate As Date, ByVal ToDate

As Date)

Description

Saves a fully populated

DiaryEntry object. If it’s a new entry, Save() calls

InsertNewDiaryEntry sub and the details are inserted in to the database.

The new DiaryEntryId is returned from the database and entered in to mDiaryEntryId .

If the entry already exists in the database, Save() calls UpdateContact , which updates the database values with those in the DiaryEntry object.

Shared method that returns a Boolean array detailing which days have a diary entry associated with them. The array index matches with the day of the month (1 is the first of the month, 2 the second, and so on).

Shared method that returns a

SQLDataReader object populated with rows from the database detailing diary entries between the

FromDate arguments.

and ToDate

12

04_749516 ch01.qxp 2/10/06 9:11 PM Page 13

The Online Diary and Organizer

Method Return Type

GetDiaryEntriesByDateAsCollection(ByVal DiaryEntryCollection

DiaryId As Integer, ByVal FromDate

As Date, ByVal ToDate As Date)

GetDiaryEntriesRecentlyChanged(ByVal SqlDataReader

DiaryId As Integer)

Description

Creates a new

DiaryEntry

Collection object and populates it with DiaryEntry objects whose

EntryDate is between the

FromDate and

ToDate arguments.

Returns a

SqlDataReader containing a DataSet of diary entries recently created.

In addition to the constructors and methods, the DiaryEntry class contains the following properties:

Property

EntryTitle

EntryText

EntryDate

Type

String

String

Date

Description

Title for the day’s diary entry.

Text of the day’s diary entry.

Date the entry was posted.

The other class dealing with diary entries is the DiaryEntryCollection class, which is explained next.

The DiaryEntryCollection Class

The DiaryEntryCollection class inherits from the System.Collections.CollectionBase

class. Its purpose is simply to store a collection of DiaryEntry objects.

This class contains only one property, described in the following table:

Property

Item(ByVal Index As

Integer)

Type

Integer

Description

Returns the DiaryEntry object stored at the specified position in index in the collection.

13

04_749516 ch01.qxp 2/10/06 9:11 PM Page 14

Chapter 1

Along with the Item() property, the DiaryEntryCollection class has three public methods:

Method

Add(ByVal New DiaryEntry

As DiaryEntry)

Return Type

None

Add(ByVal DiaryEntryId

As Long)

Remove(ByVal Index as

Integer)

None

None

Description

Adds a DiaryEntry object to the collection held by the DiaryEntryCollection object.

Creates a new DiaryEntry object.

DiaryEntryId is passed to the

DiaryEntry object’s constructor to ensure it’s populated with the diary entry’s details from the database. The new DiaryEntry object is then added to the collection maintained by the DiaryEntryCollection object.

Removes the DiaryEntry object from the collection at the specified index.

So far the classes dealing with contacts and diary entries have been discussed. The next section discusses the diary events.

The DiaryEvent Class

The DiaryEvent class objectifies a single entry in a diary. It encapsulates everything to do with diary entries, including creating, updating, and retrieving diary events data. It handles all the database access for diary events.

The DiaryEvent class has three constructors, outlined as follows:

Constructor Description

New(ByVal Diaryid as Integer)

New(ByVal EntryId As Long)

Creates a new DiaryEvent object with all properties set to their default values.

Creates a new DiaryEvent object with its properties retrieved from the database using the argument EventId .

New(ByVal DiaryId AS Integer,

ByVal EventDate As Date)

Creates a new DiaryEvent object with its properties retrieved from the database using a combination of the arguments DiaryId and EventDate .

14

Having created a DiaryEvent object, saving it involves simply calling the Save() method. The class will work out whether it’s a new diary event to insert into the database, or an existing one in need of updating. The DiaryEvent class also has two Delete() methods. One is a shared method and therefore doesn’t require a DiaryEvent to be created, and requires an EventId parameter. It’s used by some of the built-in data access components provided with ASP.NET 2.0. The second is an object method that deletes the event referenced by the current DiaryEvent object. As well as enabling the details of one diary entry to be retrieved, the DiaryEvent class provides additional methods for getting details of a number of diary events as either a collection or as a DataSet by returning a SqlDataReader object.

04_749516 ch01.qxp 2/10/06 9:11 PM Page 15

The Online Diary and Organizer

The following table explains these methods in detail:

Method Return Type Description

Save()

GetDaysInMonthWithEvents(ByVal

DiaryId As Integer, ByVal

Month As Integer, ByVal Year

As Integer)

None

Boolean Array

Saves a fully populated

DiaryEvent object. If it’s a new entry, Save() calls

InsertNew DiaryEvent sub and the details are inserted into the database. The new EventId is returned from the database and entered in to mEventId .

If the entry already exists in the database,

Save() calls

UpdateDiaryEvent , which updates the database values with those in the DiaryEvent object.

Shared method that returns a Boolean array detailing which days have events associated with them. The array index matches with the day of the month (1 is the first of the month, 2 the second, and so on).

GetDiaryEventsByDate(ByVal DiaryId

As Integer, ByVal FromDate As Date,

ByVal ToDate As Date)

SqlDataReader Shared method that returns a

SqlDataReader object populated with rows from the database detailing diary events between the FromDate and

ToDate arguments.

GetDiaryEventsByDateAsCollection(ByVal DiaryEventCollection

DiaryId As Integer, ByVal FromDate As

Date, ByVal ToDate As Date)

Creates a new Diary

EventCollection object and populates it with DiaryEvent objects whose EntryDate is between the FromDate and ToDate arguments.

Table continued on following page

15

04_749516 ch01.qxp 2/10/06 9:11 PM Page 16

Chapter 1

Method

DeleteEvent()

DeleteEvent(ByVal EventId As Long)

Return Type

None

None

Description

Deletes from the database the event with EventId equal to mEventId of the object. The

DiaryEvent object’s values are re-initialized to their defaults.

Shared method that deletes the event from the database with an EventId value equal to the

EventId argument of the method.

In addition to the constructors and public methods, the DiaryEvent class has these four properties:

Property

EventDescription

EventName

EventDate

EventDuration

Type

String

String

Date

Integer

Description

Description of the event.

Short name for the event.

Date the event starts.

Length of time in minutes that the event lasts.

One more class to go. The next section looks at the diary collection handling class:

DiaryEventCollection .

The DiaryEventCollection Class

The DiaryEventCollection class inherits from the System.Collections.CollectionBase

class. Its purpose is simply to store a collection of DiaryEvent objects. The class employs the following methods:

Method

Add(ByVal NewDiaryEvent As

DiaryEvent)

Add(ByVal DiaryEventId

As Long)

Remove(ByVal Index As

Integer)

Return Type Description

None

None

None

Adds a DiaryEvent object to the collection held by the DiaryEventCollection object.

Creates a new DiaryEvent object.

DiaryEventId is passed to the

DiaryEvent object’s constructor to ensure it’s populated with the event’s details from the database. The new DiaryEvent object is then added to the collection maintained by the DiaryEventCollection object.

Removes the DiaryEvent object from the collection at the specified index.

16

04_749516 ch01.qxp 2/10/06 9:11 PM Page 17

The Online Diary and Organizer

This class contains only one property:

Property

Item(ByVal Index As Integer)

Type

Integer

Description

Returns the DiaryEvent object stored at the position in index in the collection.

That completes an overview of all the classes and their design, methods, and properties. The next section takes a more in-depth look at the code and the .aspx pages dealing with presentation.

Code and Code Explanation

This section digs into each of the important pages and shows you how they interact with each other, as well as how they use the classes in the business layer. This section doesn’t cover every single line of every page, but rather it takes a general overview of how the application works and dives a bit deeper where necessary.

Discussion of the project is approached in a functionality-based way. Instead of discussing a specific page and what it does, the following sections discuss a process — such as registration — and how it’s achieved.

It begins with an overview of the files and file structure.

File Structure

An overview of the file structure is shown in Figure 1-12.

Figure 1-12

17

04_749516 ch01.qxp 2/10/06 9:11 PM Page 18

Chapter 1

Each of the seven class files is stored in the App_Code directory (at the top of the figure). The App_Data directory contains the two databases: the login database (ASPNETDB.MDF) and the Online Diary database (DiaryDB.mdf). Pages that require you to log in before viewing are stored separately in the

SecureDiary directory. Finally, the root directory contains login pages, registration pages, and password reminder pages; basically anything that requires you to be logged in to view.

Registration, Logging On, and Security

The Online Diary application uses the new Login controls to provide the diary’s user handing features, including new user registration, log in, and password reminder.

The Login controls are a real time saver, allowing a lot of sophisticated functionality to be added with just a little work and hardly any code! ASP.NET 2.0 has seven new security or login controls:

Login : Enables users to log in and verifies username and password.

LoginView : Enables the display of different templates depending on whether a user is logged in and also his or her role membership.

PasswordRecovery : Provides password reminder functionality for users who forget their password.

LoginStatus : Displays whether a user is logged in or out.

LoginName : Displays currently logged-in username.

CreateUserWizard : Creates a new user wizard — registration of a new user in simple steps.

ChangePassword : Enables users to change their password.

The Online Diary project, however, use only the Login , LoginName , CreateUserWizard , and

ChangePassword controls.

Logging On

The SignOn.aspx page contains a Login control. The user database is created using the web site administration tools. This goes through the steps needed one by one, and once it’s finished a new database called ASPNETDB.MDF appears in the App_Data directory of the diary project.

The markup for the Login control is shown here:

<asp:Login ID=”Login1” runat=”server” BackColor=”#F7F6F3” BorderColor=”#E6E2D8”

BorderPadding=”4”

BorderStyle=”Solid” BorderWidth=”1px” CreateUserText=”Not registered? Click here to register now.”

CreateUserUrl=”~/RegisterStart.aspx”

DestinationPageUrl=”~/SecureDiary/DiaryMain.aspx” Font-Names=”Verdana”

Font-Size=”0.8em” ForeColor=”#333333” Height=”197px”

PasswordRecoveryText=”Forgotten your password?”

PasswordRecoveryUrl=”~/PasswordReminder.aspx” Style=”zindex: 100; left: 78px; position: absolute; top: 55px” Width=”315px”>

<LoginButtonStyle BackColor=”#FFFBFF” BorderColor=”#CCCCCC”

BorderStyle=”Solid” BorderWidth=”1px”

18

04_749516 ch01.qxp 2/10/06 9:11 PM Page 19

The Online Diary and Organizer

Font-Names=”Verdana” Font-Size=”0.8em”

ForeColor=”#284775” />

Size=”0.9em” ForeColor=”White” />

<InstructionTextStyle Font-Italic=”True” ForeColor=”Black”

/>

<TextBoxStyle Font-Size=”0.8em” />

<TitleTextStyle BackColor=”#5D7B9D” Font-Bold=”True” Font-

</asp:Login>

Important attributes to note are DestinationPageUrl , which determines where the user is navigated to if he or she enters a valid username and password. In the Online Diary project it’s the Diarymain.aspx

page, the center of the Online Diary’s interface.

To enable new users to register, the CreateUserText has been set to a friendly “register here” message; the URL for registering is specified in CreateUserUrl .

Finally, just in case the user has already registered but forgotten his or her password, the

PasswordRecoveryText attribute displays a “Forgotten your password?” message and

PasswordRecoveryUrl sets the URL the users are navigated to if they need to find out their password.

The only code you need to write is in the Login control’s LoggedIn event, which fires if the user successfully enters a username and password:

Protected Sub Login1_LoggedIn(ByVal sender As Object, ByVal e As

System.EventArgs) Handles Login1.LoggedIn

Dim DiaryId As Integer = GetDiaryIdFromUserName(Login1.UserName)

Session(“DiaryId”) = DiaryId

End Sub

This uses the supplied username to look up the user’s DiaryId in the Online Diary database. This is then stored in the session variable.

The SignOn.aspx page also allows new users to register.

New User Registration

The RegisterStart.aspx. page deals with the registration of a new user. As with SignOn.aspx, this page also uses one of the new Login controls, this time the CreateUserWizard control. The markup for the

CreateUserWizard control is shown in the following code:

<asp:CreateUserWizard ID=”CreateUserWizard1” runat=”server”

BackColor=”#F7F6F3” BorderColor=”#E6E2D8”

BorderStyle=”Solid” BorderWidth=”1px” Font-Names=”Verdana” Font-

Size=”0.8em”

Style=”z-index: 100; left: 66px; position: absolute; top: 43px”

Height=”164px” Width=”300px” FinishDestinationPageUrl=”~/SignOn.aspx”>

<SideBarStyle BackColor=”#5D7B9D” BorderWidth=”0px” Font-Size=”0.9em”

VerticalAlign=”Top” />

<SideBarButtonStyle BorderWidth=”0px” Font-Names=”Verdana”

ForeColor=”White” />

19

04_749516 ch01.qxp 2/10/06 9:11 PM Page 20

Chapter 1

<NavigationButtonStyle BackColor=”#FFFBFF” BorderColor=”#CCCCCC”

BorderStyle=”Solid”

BorderWidth=”1px” Font-Names=”Verdana” ForeColor=”#284775” />

<HeaderStyle BackColor=”#5D7B9D” BorderStyle=”Solid” Font-Bold=”True”

Font-Size=”0.9em”

ForeColor=”White” HorizontalAlign=”Left” />

<CreateUserButtonStyle BackColor=”#FFFBFF” BorderColor=”#CCCCCC”

BorderStyle=”Solid”

BorderWidth=”1px” Font-Names=”Verdana” ForeColor=”#284775” />

<ContinueButtonStyle BackColor=”#FFFBFF” BorderColor=”#CCCCCC”

BorderStyle=”Solid”

BorderWidth=”1px” Font-Names=”Verdana” ForeColor=”#284775” />

<StepStyle BorderWidth=”0px” />

<TitleTextStyle BackColor=”#5D7B9D” Font-Bold=”True” ForeColor=”White”

/>

<WizardSteps>

<asp:CreateUserWizardStep runat=”server”>

</asp:CreateUserWizardStep>

<asp:WizardStep ID=”personalDetailsStep” runat=”server” Title=”User

Details”>

<table border=”0” style=”font-size: 100%; font-family:

Verdana; z-index: 100; left: 0px; position: absolute; top: 0px;”>

<tr>

<td align=”center” colspan=”2” style=”font-weight: bold; color: white; background-color: #5d7b9d”>

Your Personal Details</td>

</tr>

<tr>

<td align=”right” style=”height: 26px”>

<label for=”UserName”>

Your First Name:</label></td>

<td style=”width: 179px; height: 26px”>

<asp:TextBox ID=”firstNameTextBox” runat=”server” CausesValidation=”True”></asp:TextBox>&nbsp;

</td>

</tr>

<tr>

<td align=”right”>

<label for=”Password”>

Your Last Name:</label></td>

<td style=”width: 179px”>

<asp:TextBox ID=”lastNameTextBox” runat=”server” CausesValidation=”True”></asp:TextBox>&nbsp;

</td>

</tr>

<tr>

<td align=”center” colspan=”2” style=”height:

18px”>

&nbsp;</td>

</tr>

<tr>

<td align=”center” colspan=”2” style=”color: red”>

&nbsp;</td>

</tr>

20

04_749516 ch01.qxp 2/10/06 9:11 PM Page 21

The Online Diary and Organizer

</table>

</asp:WizardStep>

<asp:CompleteWizardStep runat=”server”>

<ContentTemplate>

<table border=”0” style=”font-size: 100%; width: 383px; font-family: Verdana; height: 164px”>

<tr>

<td align=”center” colspan=”2” style=”font-weight: bold; color: white; background-color: #5d7b9d”>

Complete</td>

</tr>

<tr>

<td>

Your account has been successfully created.</td>

</tr>

<tr>

<td align=”right” colspan=”2”>

<asp:Button ID=”ContinueButton” runat=”server”

BackColor=”#FFFBFF” BorderColor=”#CCCCCC”

BorderStyle=”Solid” BorderWidth=”1px”

CausesValidation=”False” CommandName=”Continue”

Font-Names=”Verdana” ForeColor=”#284775”

Text=”Continue” ValidationGroup=”CreateUserWizard1” />

</td>

</tr>

</table>

</ContentTemplate>

</asp:CompleteWizardStep>

</WizardSteps>

</asp:CreateUserWizard>

Most of the markup and attributes relate to style settings. However, one essential attribute is the

FinishDestinationPageUrl . This is where the user is taken once the registration process is completed; in the Online Diary it’s the SignOn.aspx page.

You’ve probably noticed a number of WizardStep tags in the markup, such as this one:

<asp:WizardStep ID=”personalDetailsStep” runat=”server” Title=”User Details”>

The CreateUserWizard works on a step-by-step basis. There must be least one step that allows the user to choose a username and password and various security questions (see Figure 1-13).

This step and its style can be modified, but Figure 1-13 shows its default value. The control takes care of inserting the new user data into the user database.

A second step, shown in Figure 1-14, is displayed after the user is created.

21

04_749516 ch01.qxp 2/10/06 9:11 PM Page 22

Chapter 1

Figure 1-13

22

Figure 1-14

This screen asks users for their first name and last name. This time it’s up to you to store the data somewhere, and you do that in the CreateUserWizard control’s FinishButtonClick event:

Protected Sub CreateUserWizard1_FinishButtonClick(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.WizardNavigationEventArgs) Handles

CreateUserWizard1.FinishButtonClick

Dim myTextBox As TextBox

Dim UserName, FirstName, LastName myTextBox = CreateUserWizard1.FindControl(“firstNameTextBox”)

FirstName = myTextBox.Text

myTextBox = CreateUserWizard1.FindControl(“lastNameTextBox”)

LastName = myTextBox.Text

UserName = CreateUserWizard1.UserName

OnlineDiary.InsertDiary(UserName, FirstName, LastName)

End Sub

04_749516 ch01.qxp 2/10/06 9:11 PM Page 23

The Online Diary and Organizer

This step creates a new diary for users and stores their first and last names. The UserName comes from the CreateUserWizard control’s UserName property, and then uses the shared method InsertDiary() to insert the new user in the Online Diary’s database.

Being human, sometimes people forget their passwords. Fortunately, ASP.NET 2.0 comes with the capability to refresh overloaded memories.

Password Reminder

Again with virtually no code, you can create a fully functional password reminder feature for the Online

Diary, this time courtesy of the PasswordRecovery control. Virtually all of its settings are at the default values or simply related to style. Even better, there’s just one line of code and that’s in the SendingMail event:

Protected Sub PasswordRecovery1_SendingMail(ByVal sender As Object, ByVal e As

System.Web.UI.WebControls.MailMessageEventArgs) Handles

PasswordRecovery1.SendingMail

returnToLogOnHyperLink.Visible = True

End Sub

The SendingMail event fires when the user presses the Send Email button and simply displays the

Return to Main Page link, rather than leaving the user guessing as to where to go next.

The main work involved is configuring the SMTP server settings that’ll be used to actually send the password reminder e-mail. Visual Web Developer doesn’t come with an SMTP server. However, if you are using Windows XP or 2000, all you need to do to install one is go to the Start➪Settings➪Control

Panel➪Add or Remove Programs. From there, select Add/Remove Windows Components. Select the

Internet Information Server (IIS) option and click Details at the bottom-right of the dialog. In the resulting dialog box, you’ll see a list. Check the box next to SMTP Service and click OK. Then click Next to install an SMTP service.

Once the SMTP service is installed, add the following shaded code between the <configuration> tags in the Web.config file:

<configuration xmlns=”http://schemas.microsoft.com/.NetConfiguration/v2.0”>

<connectionStrings>

<add name=”DiaryDBConnectionString” connectionString=”Data

Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\DiaryDB.mdf;Integrated

Security=True;User Instance=True” providerName=”System.Data.SqlClient” />

</connectionStrings>

<system.web>

<roleManager enabled=”true” />

<authentication mode=”Forms”/>

<compilation debug=”true”/></system.web>

<system.net>

<mailSettings>

<smtp from=”[email protected]”>

<network host=”localhost” password=”” userName=”” />

</smtp>

</mailSettings>

</system.net>

</configuration>

23

04_749516 ch01.qxp 2/10/06 9:11 PM Page 24

Chapter 1

Viewing the Online Calendar

The DiaryMain.aspx page is the central hub of the application. It displays a calendar of the current month, showing which days have events or diary entries associated with them. It also displays a list of upcoming events and diary entries for the current month.

To display when a day has events or a diary entry, the OnDayRender event of the Calendar control is used:

Protected Sub Calendar1_OnDayRender(ByVal sender As Object, ByVal e As

System.Web.UI.WebControls.DayRenderEventArgs) Handles Calendar1.DayRender

If Not e.Day.IsOtherMonth Then

If entryArrayOfDays Is Nothing Then entryArrayOfDays = GetDaysInMonthWithEntries(Session(“DiaryId”), e.Day.Date.Month, e.Day.Date.Year)

End If

If eventArrayOfDays Is Nothing Then eventArrayOfDays = GetDaysInMonthWithEvents(Session(“DiaryId”), e.Day.Date.Month, e.Day.Date.Year)

End If

If entryArrayOfDays(CInt(e.Day.DayNumberText)) Then e.Cell.BackColor = Drawing.Color.Blue

End If

If eventArrayOfDays(CInt(e.Day.DayNumberText)) Then e.Cell.ForeColor = Drawing.Color.Red

End If

End If

End Sub

The first If block in the preceding event code deals with ensuring entryArrayOfDays and eventArrayOfDays are populated with details of which days have an associated event or diary entry.

They are both Boolean arrays; if a day has an event or entry, the array element for that day contains

True . Arrays are populated by the DiaryEnty and DiaryEvent classes’ shared functions

GetDaysInMonthWithEntries() and GetDaysInMonthWithEvents() .

In the second If block of the event the code checks to see whether the day of the month being rendered has a diary event or diary entry. If there’s an event, the day’s text is set to red. If there’s a diary entry the day’s background is rendered in blue.

As well as a Calendar control, the main page also has two GridView controls (discussed a bit later).

The upper one displays upcoming events; the lower one displays recent diary entries. Both GridView controls get their data from an ObjectDataSource control, new to ASP.NET 2.0. In the past, data source controls have interacted directly with the database. They are nice and easy to use — put on one a page, set a few properties, drop in a few data-aware controls, and away you go. However, that’s not actually good coding practice. Splitting up the data access, business, and presentation layers is generally considered good practice, but means leaving behind nice and easy-to-use data source controls.

24

04_749516 ch01.qxp 2/10/06 9:11 PM Page 25

The Online Diary and Organizer

However, the new ObjectDataSource lets you have the best of both: easy-to-use data controls and use of classes to separate business, data, and presentation layers. Instead of connecting directly to a database, the ObjectDataSource takes its data from one of the classes. diaryEntriesObjectDataSource on

DiaryMain.aspx, for example, takes its data from the GetDiaryEntriesRecentlyChanged() method of the DiaryEntry class, whose markup is shown here:

<asp:ObjectDataSource ID=”diaryEntriesObjectDataSource” runat=”server”

SelectMethod=”GetDiaryEntriesRecentlyChanged”

TypeName=”DiaryEntry”>

<SelectParameters>

<asp:SessionParameter DefaultValue=”-1” Name=”DiaryId”

SessionField=”DiaryId” Type=”Int32” />

</SelectParameters>

</asp:ObjectDataSource>

The TypeName attribute specifies the class name to use, and the SelectMethod attribute specifies which method of that class will provide the data. GetDiaryEntriesRecentlyChanged() is a shared method, shown here:

Public Shared Function GetDiaryEntriesRecentlyChanged(ByVal DiaryId As Integer)

As SqlDataReader

Dim diaryDBConn As New SqlConnection(conString)

Dim sqlString As String = “GetRecentDiaryEntries”

Dim sqlCmd As New SqlCommand(sqlString, diaryDBConn) sqlCmd.CommandType = CommandType.StoredProcedure

sqlCmd.Parameters.AddWithValue(“@DiaryId”, DiaryId) diaryDBConn.Open()

Dim entrySQLDR As SqlDataReader = sqlCmd.ExecuteReader(CommandBehavior.CloseConnection) sqlCmd = Nothing

Return entrySQLDR

End Function

The method returns a SqlDataReader object populated with the data the ObjectDataSource control will use.

Actually displaying the data is then just a matter of pointing a data-aware control at the

ObjectDataSource :

<asp:GridView ID=”recentEntriesGridView” runat=”server”

AutoGenerateColumns=”False”

Caption=”Recent Entries” CaptionAlign=”Left” CellPadding=”4”

DataSourceID=”diaryEntriesObjectDataSource”

ForeColor=”#333333” GridLines=”None” Style=”z-index: 105; left:

535px; position: absolute; top: 321px” Width=”476px” Height=”208px”>

<FooterStyle BackColor=”#5D7B9D” Font-Bold=”True” ForeColor=”White”

/>

<RowStyle BackColor=”#F7F6F3” ForeColor=”#333333” />

<Columns>

<asp:BoundField DataField=”EntryDate” />

<asp:BoundField DataField=”EntryTitle” />

25

04_749516 ch01.qxp 2/10/06 9:11 PM Page 26

Chapter 1

<asp:BoundField DataField=”EntryText” />

</Columns>

<PagerStyle BackColor=”#284775” ForeColor=”White”

HorizontalAlign=”Center” />

<SelectedRowStyle BackColor=”#E2DED6” Font-Bold=”True”

ForeColor=”#333333” />

<HeaderStyle BackColor=”#5D7B9D” Font-Bold=”True” ForeColor=”White”

/>

<EditRowStyle BackColor=”#999999” />

<AlternatingRowStyle BackColor=”White” ForeColor=”#284775” />

</asp:GridView>

In the GridView control’s markup, the DataSourceID attribute specifies the source of the data, which is the ObjectDataSource control. In addition, the markup specifies which columns to display by setting

AutoGenerateColumns to False . A final step is to create a list of columns:

<Columns>

<asp:BoundField DataField=”EntryDate” />

<asp:BoundField DataField=”EntryTitle” />

<asp:BoundField DataField=”EntryText” />

</Columns>

As well as enabling the display of data, the ObjectDataSource control can also update, insert, and delete records from a database, as demonstrated shortly.

Creating, Editing, and Viewing a Diary Entry

The DayView.aspx page allows for diary editing. This page contains a simple form allowing you to enter title and diary entry details. It also displays any existing diary entry.

All of the hard work is done by use of the DiaryEntry class. Its Page_Load event creates a new

DiaryEntry class, passing its constructor the current user’s DiaryId and also the date the page refers to:

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

Handles Me.Load

mDiaryEntry = New DiaryEntry(CInt(Session(“DiaryId”)),

CDate(dayShownLabel.Text)) changeDayCalendar.SelectedDate = CDate(dayShownLabel.Text) changeDayCalendar.VisibleDate = changeDayCalendar.SelectedDate

If Not IsPostBack Then entryTextTextBox.Text = mDiaryEntry.EntryText

entryTitleTextBox.Text = mDiaryEntry.EntryTitle

End If

End Sub

26

04_749516 ch01.qxp 2/10/06 9:11 PM Page 27

The Online Diary and Organizer mDiaryEntry is a global variable used to hold the DiaryEntry object relating to the day being edited.

The constructor, shown in the following code, does all the hard work of actually getting the data:

Public Sub New(ByVal DiaryId As Integer, ByVal EntryDate As Date) mDiaryId = DiaryId

If mDiaryId > 0 Then

Try

Dim diaryDBConn As New SqlConnection(conString)

Dim sqlString As String = “GetDiaryEntryByDate”

Dim sqlCmd As New SqlCommand(sqlString, diaryDBConn) sqlCmd.CommandType = CommandType.StoredProcedure

sqlCmd.Parameters.AddWithValue(“@DiaryId”, mDiaryId) sqlCmd.Parameters.AddWithValue(“@EntryFromDate”, EntryDate) sqlCmd.Parameters.AddWithValue(“@EntryToDate”, EntryDate) diaryDBConn.Open()

Dim diaryEntrySQLDR As SqlDataReader = sqlCmd.ExecuteReader(CommandBehavior.CloseConnection) sqlCmd = Nothing

If diaryEntrySQLDR.Read() Then mDiaryEntryId = CLng(diaryEntrySQLDR(“DiaryEntryId”)) mEntryDate = CDate(diaryEntrySQLDR(“EntryDate”)) mEntryTitle = diaryEntrySQLDR(“EntryTitle”).ToString

mEntryText = diaryEntrySQLDR(“EntryText”).ToString

Else mDiaryEntryId = -1 mEntryDate = EntryDate

End If

Catch ex As Exception mDiaryEntryId = -1

End Try

End If

End Sub diaryEntrySQLDR.Close() diaryEntrySQLDR = Nothing diaryDBConn.Close() diaryDBConn = Nothing

The GetDiaryEntryByDate stored procedure is called to get the data. If there isn’t an existing entry for that day, mDiaryEntryId is set to -1 and all the other properties are left at their default values.

Otherwise they are populated with the data from the database.

27

04_749516 ch01.qxp 2/10/06 9:11 PM Page 28

Chapter 1

When the diary title or entry boxes are changed, mDiaryEntry is updated:

Protected Sub entryTitleTextBox_TextChanged(ByVal sender As Object, ByVal e As

System.EventArgs) Handles entryTitleTextBox.TextChanged

mDiaryEntry.EntryTitle = entryTitleTextBox.Text

End Sub

Protected Sub entryTextTextBox_TextChanged(ByVal sender As Object, ByVal e As

System.EventArgs) Handles entryTextTextBox.TextChanged

mDiaryEntry.EntryText = entryTextTextBox.Text

End Sub

Saving changes occurs when you click the Save button:

Protected Sub saveDiaryEntryButton_Click(ByVal sender As Object, ByVal e As

System.EventArgs) Handles saveDiaryEntryButton.Click

mDiaryEntry.Save()

End Sub

All that’s involved is calling the Save() method of the DiaryEntry object:

Public Sub Save()

If mDiaryEntryId = -1 Then

Else

InsertNewDiaryEntry()

UpdateDiaryEntry()

End If

End Sub

Based on whether or not mDiaryEntryId is -1 , the method either inserts a new entry into the database or updates an existing one. The private method InsertNewDiaryEntry() inserts a new diary entry:

Private Sub InsertNewDiaryEntry()

If mDiaryId <> -1 Then

Dim diaryDBConn As New SqlConnection(conString)

Dim sqlString As String = “InsertDiaryEntry”

Dim sqlCmd As New SqlCommand(sqlString, diaryDBConn) sqlCmd.CommandType = CommandType.StoredProcedure

sqlCmd.Parameters.AddWithValue(“@DiaryId”, mDiaryId) sqlCmd.Parameters.AddWithValue(“@EntryDate”, mEntryDate) sqlCmd.Parameters.AddWithValue(“@EntryTitle”, mEntryTitle) sqlCmd.Parameters.AddWithValue(“@EntryText”, mEntryText) sqlCmd.Parameters.Add(“@NewDiaryEntryId”, SqlDbType.BigInt) sqlCmd.Parameters(“@NewDiaryEntryId”).Direction =

ParameterDirection.ReturnValue

diaryDBConn.Open() sqlCmd.ExecuteNonQuery() mDiaryEntryId = CLng(sqlCmd.Parameters(“@NewDiaryEntryId”).Value()) diaryDBConn.Close() sqlCmd = Nothing

28

04_749516 ch01.qxp 2/10/06 9:11 PM Page 29

The Online Diary and Organizer diaryDBConn = Nothing

End If

End Sub

The private method UpdateDiaryEntry() updates it:

Private Sub UpdateDiaryEntry()

If mDiaryEntryId <> -1 Then

Dim diaryDBConn As New SqlConnection(conString)

Dim sqlString As String = “UpdateDiaryEntry”

Dim sqlCmd As New SqlCommand(sqlString, diaryDBConn) sqlCmd.CommandType = CommandType.StoredProcedure

sqlCmd.Parameters.AddWithValue(“@DiaryEntryId”, mDiaryEntryId) sqlCmd.Parameters.AddWithValue(“@EntryDate”, mEntryDate) sqlCmd.Parameters.AddWithValue(“@EntryTitle”, mEntryTitle) sqlCmd.Parameters.AddWithValue(“@EntryText”, mEntryText) diaryDBConn.Open() sqlCmd.ExecuteNonQuery() diaryDBConn.Close() sqlCmd = Nothing diaryDBConn = Nothing

End If

End Sub

Moving on, the next section discusses aspects of the code dealing with editing, viewing, and deleting events.

Creating, Editing, and Viewing Diary Events

Events are created by clicking the Add New Event link on the DayView.aspx page. This takes you to a simple form on the AddEvent.aspx page. When the Save button is clicked, the button’s click event creates a new DiaryEvent object, populates its properties from the form, and then calls its Save() method.

The code flow is much the same as for the DiaryEvent object’s Save() method. Where the functionality is similar or the same, the names of methods on different objects have been kept the same. It reduces confusion and makes your life easier.

All events relating to a particular day are shown on the DayView.aspx page. An ObjectDataSource control on the DayView.aspx page draws its data from the DiaryEvent object’s GetDiaryEventsByDate() shared method. The markup for the ObjectDataSource control is shown here:

<asp:ObjectDataSource ID=”eventsObjectDataSource” runat=”server”

SelectMethod=”GetDiaryEventsByDate”

TypeName=”DiaryEvent” DeleteMethod=”DeleteEvent”>

<SelectParameters>

<asp:SessionParameter DefaultValue=”-1” Name=”DiaryId”

SessionField=”DiaryId” Type=”Int32” />

<asp:ControlParameter ControlID=”dayShownLabel” DefaultValue=””

Name=”FromDate” PropertyName=”Text”

Type=”DateTime” />

<asp:ControlParameter ControlID=”dayShownLabel” DefaultValue=””

Name=”ToDate” PropertyName=”Text”

29

04_749516 ch01.qxp 2/10/06 9:11 PM Page 30

Chapter 1

30

Type=”DateTime” />

<asp:Parameter DefaultValue=”0” Name=”MaxRows” Type=”Int32” />

</SelectParameters>

<DeleteParameters>

<asp:Parameter Name=”EventId” Type=”Int64” />

</DeleteParameters>

</asp:ObjectDataSource>

Notice that the SelectParameters and the DeleteParameters are set to specify the data passed to the

GetDiaryEventsByDate() method used to pull back the data, and the DeleteEvent() method is used to delete diary events.

A GridView control is hooked to the ObjectDataSource in the code above:

<asp:GridView ID=”eventsGridView” runat=”server”

AutoGenerateColumns=”False” CellPadding=”4”

DataSourceID=”eventsObjectDataSource” ForeColor=”#333333”

GridLines=”None” Height=”1px”

PageSize=”5” Style=”z-index: 108; left: 78px; position: absolute; top:

357px”

Width=”542px” DataKeyNames=”EventId”>

<FooterStyle BackColor=”#5D7B9D” Font-Bold=”True” ForeColor=”White” />

<RowStyle BackColor=”#F7F6F3” ForeColor=”#333333” />

<Columns>

<asp:HyperLinkField DataNavigateUrlFields=”EventId” Text=”Edit”

DataNavigateUrlFormatString=”~/SecureDiary/EditEvent.aspx?EventId={0}” />

<asp:CommandField ShowDeleteButton=”True” />

<asp:BoundField DataField=”EventName” HeaderText=”Event” />

<asp:BoundField DataField=”EventDescription”

HeaderText=”Description” />

</Columns>

<PagerStyle BackColor=”#284775” ForeColor=”White”

HorizontalAlign=”Center” />

<SelectedRowStyle BackColor=”#E2DED6” Font-Bold=”True”

ForeColor=”#333333” />

<HeaderStyle BackColor=”#5D7B9D” Font-Bold=”True” ForeColor=”White” />

<EditRowStyle BackColor=”#999999” />

<AlternatingRowStyle BackColor=”White” ForeColor=”#284775” />

</asp:GridView>

Again, the AutoGenerateColumns parameter is set to False , and the columns are specified as follows:

<Columns>

<asp:HyperLinkField DataNavigateUrlFields=”EventId” Text=”Edit”

DataNavigateUrlFormatString=”~/SecureDiary/EditEvent.aspx?EventId={0}” />

<asp:CommandField ShowDeleteButton=”True” />

<asp:BoundField DataField=”EventName” HeaderText=”Event” />

<asp:BoundField DataField=”EventDescription”

HeaderText=”Description” />

</Columns>

Notice the hyperlink and field that when clicked will take the user to the EditEvent.aspx page, and the

URL contains data passed to the EventId in the URL by way of the EventId querystring parameter. It’s set to be {0} , which at run time will be substituted by the value of the first column for each row in the DataSet.

04_749516 ch01.qxp 2/10/06 9:11 PM Page 31

The Online Diary and Organizer

In addition, the code specifies a Delete button on each row in the grid:

<asp:CommandField ShowDeleteButton=”True” />

When you click the Delete button, the GridView control asks the ObjectDataSource control to call the specified delete method of the data providing class. In this case it’s the DeleteEvent() method of the

DiaryEvent class. The DataKeyNames attribute in the GridView control’s markup specifies the primary key field that needs to be used to delete the row.

Returning to editing the event: When you click the Edit link you are taken to the EditEvent.aspx page.

The clicked Edit link’s EventId is passed as a URL parameter. The EditEvent.aspx page is virtually identical to the AddEvent.aspx page discussed previously. The main difference is when the page initializes.

The Page_Init event handler is shown in the following code, and it’s here that the event details are entered into the form:

Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)

Handles Me.Init

Dim EventBeingEdited As New

DiaryEvent(CLng(Request.QueryString(“EventId”))) eventNameTextBox.Text = EventBeingEdited.EventName

eventDescriptionTextBox.Text = EventBeingEdited.EventDescription

dayShownLabel.Text = EventBeingEdited.EventDate.Day & “ “ &

MonthName(EventBeingEdited.EventDate.Month) & “ “ & EventBeingEdited.EventDate.Year

Dim NewListItem As ListItem, HourCount, MinuteCount

For HourCount = 0 To 23

If HourCount < 10 Then

Else

NewListItem = New ListItem(“0” & HourCount, HourCount.ToString)

NewListItem = New ListItem(HourCount.ToString, HourCount.ToString)

End If

If EventBeingEdited.EventDate.Hour = HourCount Then

NewListItem.Selected = True

End If

StartHourDropDownList.Items.Add(NewListItem)

Next

For MinuteCount = 0 To 59

If MinuteCount < 10 Then

NewListItem = New ListItem(“0” & MinuteCount.ToString,

MinuteCount.ToString)

Else

NewListItem = New ListItem(MinuteCount.ToString,

MinuteCount.ToString)

End If

If EventBeingEdited.EventDate.Minute = MinuteCount Then

NewListItem.Selected = True

End If

StartMinuteDropDownList.Items.Add(NewListItem)

Next

Dim itemToSelect As ListItem

31

04_749516 ch01.qxp 2/10/06 9:11 PM Page 32

Chapter 1 itemToSelect = eventDurationDropDownList.Items.FindByValue(EventBeingEdited.EventDuration.ToString

()) itemToSelect.Selected = True

EventBeingEdited = Nothing

End Sub

The EventId is extracted from the URL parameters and used to create a new DiaryEvent object.

Populating the event text boxes is easy enough, but the details of time and duration of the event involve populating the Hour and Minute drop-down boxes and ensuring the correct value is selected. This is achieved by looping through hours from 0 to 23 and then minutes from 0 to 59. If the hour to be added to the list is the same as the hour about to be added to the list box, make sure it’s the default selected one. The same goes for the minute list box population.

Managing Contacts

Managing contacts is the last aspect of the Online Diary you’ll examine, and uses many of the same principles as the other sections. YourContacts.aspx is the central contact management page. Here a list of current contacts is displayed, and the option to add, edit, and delete contacts is possible.

All contacts are displayed using a DataObjectSource and a GridView control; the principles being identical to the displaying, deleting, and editing of the diary events. This time the Contact class is used for editing and display contact details, but otherwise the code is very similar to the events code.

The main page for displaying contacts is YourContacts.aspx, which contains a GridView control in which all current contacts are listed:

<asp:GridView ID=”GridView1” runat=”server” AutoGenerateColumns=”False”

CellPadding=”4”

DataSourceID=”ObjectDataSource1” ForeColor=”#333333” GridLines=”None”

Style=”z-index: 101; left: 36px; position: absolute; top: 137px” DataKeyNames=”ContactId”>

<FooterStyle BackColor=”#5D7B9D” Font-Bold=”True” ForeColor=”White” />

<Columns>

<asp:CommandField ShowDeleteButton=”True” />

<asp:HyperLinkField DataNavigateUrlFields=”ContactId”

DataNavigateUrlFormatString=”~/SecureDiary/EditContact.aspx?ContactId={0}”

Text=”Edit” />

<asp:BoundField DataField=”LastName” HeaderText=”Last Name” />

<asp:BoundField DataField=”FirstName” HeaderText=”First Name” />

<asp:BoundField DataField=”Telephone” HeaderText=”Telephone” />

<asp:BoundField DataField=”Email” HeaderText=”Email Address” />

</Columns>

<RowStyle BackColor=”#F7F6F3” ForeColor=”#333333” />

<EditRowStyle BackColor=”#999999” />

<SelectedRowStyle BackColor=”#E2DED6” Font-Bold=”True”

ForeColor=”#333333” />

<PagerStyle BackColor=”#284775” ForeColor=”White”

HorizontalAlign=”Center” />

<HeaderStyle BackColor=”#5D7B9D” Font-Bold=”True” ForeColor=”White” />

<AlternatingRowStyle BackColor=”White” ForeColor=”#284775” />

</asp:GridView>

32

04_749516 ch01.qxp 2/10/06 9:11 PM Page 33

The Online Diary and Organizer

It gets its data from the ObjectDataSource control ObjectDataSource1 , which in turn connects to the

Contact class’s GetContactByFirstLetter() shared method:

<asp:ObjectDataSource ID=”ObjectDataSource1” runat=”server”

SelectMethod=”GetContactsByFirstLetter”

TypeName=”Contact” DeleteMethod=”DeleteContact”>

<SelectParameters>

<asp:SessionParameter DefaultValue=”6” Name=”DiaryId”

SessionField=”DiaryId” Type=”Int32” />

<asp:Parameter Name=”FirstLetterOfSurname” Type=”Char” />

</SelectParameters>

<DeleteParameters>

<asp:ControlParameter ControlID=”GridView1” Name=”ContactId”

PropertyName=”SelectedValue”

Type=”Int64” />

</DeleteParameters>

</asp:ObjectDataSource>

The ObjectDataSource control’s DeleteMethod parameter is also hooked to the Contact class’s

DeleteContact . The GridView control has been set to show a link to delete each contact, and it’s this method that does the actual deleting:

Public Shared Sub DeleteContact(ByVal ContactId As Long)

Dim diaryDBConn As New SqlConnection(conString)

Dim sqlString As String = “DeleteContact”

Dim sqlCmd As New SqlCommand(sqlString, diaryDBConn) sqlCmd.CommandType = CommandType.StoredProcedure

sqlCmd.Parameters.AddWithValue(“@ContactId”, ContactId) diaryDBConn.Open() sqlCmd.ExecuteNonQuery() diaryDBConn.Close() sqlCmd = Nothing diaryDBConn = Nothing

End Sub

The GridView also includes an Edit link, which when clicked navigates the user to the EditContact.aspx

page:

<asp:HyperLinkField DataNavigateUrlFields=”ContactId”

DataNavigateUrlFormatString=”~/SecureDiary/EditContact.aspx?ContactId={0}”

Text=”Edit” />

The corresponding ContactId is passed in the URL as URL data.

Adding a new user involves clicking the Add Contact link on the YourContacts.aspx page. This takes you to a basic form for adding contact information such as name, e-mail, phone number, and so on. This page and the EditContact.aspx page are identical in operation except for one important detail: The

EditContact.aspx page retrieves the details of the contact to be edited using the Contact class. This happens in the Page_Load event:

33

04_749516 ch01.qxp 2/10/06 9:11 PM Page 34

Chapter 1

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

Handles Me.Load

If IsPostBack Then

Dim currentContact As New

Contact(CLng(Request.QueryString(“ContactId”))) currentContact.FirstName = firstNameTextBox.Text

currentContact.LastName = lastNameTextBox.Text

currentContact.AddressLine1 = addressLine1TextBox.Text

currentContact.City = cityTextBox.Text

currentContact.PostalCode = postalCodeTextBox.Text

currentContact.State = stateTextBox.Text

currentContact.Telephone = telephoneTextBox.Text

currentContact.MobilePhone = mobilePhoneTextBox.Text

currentContact.Email = emailTextBox.Text

currentContact.SaveContact() currentContact = Nothing

Else

Response.Redirect(“YourContacts.aspx”)

Dim currentContact As New

Contact(CLng(Request.QueryString(“ContactId”))) firstNameTextBox.Text = currentContact.FirstName

lastNameTextBox.Text = currentContact.LastName

addressLine1TextBox.Text = currentContact.AddressLine1

cityTextBox.Text = currentContact.City

postalCodeTextBox.Text = currentContact.PostalCode

stateTextBox.Text = currentContact.State

telephoneTextBox.Text = currentContact.Telephone

mobilePhoneTextBox.Text = currentContact.MobilePhone

emailTextBox.Text = currentContact.Email

currentContact = Nothing

End If

End Sub

The If statement determines whether this is a postback (the form has been submitted to itself) or whether the page has just been loaded. If it’s a postback, you need to save the data and then move back to the main contacts section. If it’s a new page load, it’s necessary to create a new Contact object, and use the data from that to populate the form fields with the contact information.

The AddContact.aspx page is identical except there’s no need to populate with existing contact data, because a new contact has no prior data!

Setting up the Online Diar y

One of the great things about ASP.NET 2.0 is how easy it is to set up web applications created on one machine onto another. To install the application on your PC, simply copy the entire directory and files from the accompanying CD-ROM (or download it from www.wrox.com

) onto a directory on your PC

(for example, C:\Websites ). In VWD, all you have to do is choose File➪Open Web Site and browse to the folder where you copied the files. Then press F5 to run it.

34

04_749516 ch01.qxp 2/10/06 9:11 PM Page 35

The Online Diary and Organizer

Alternatively, if you have IIS installed make the OnlineDiary directory you copied over a virtual directory and then simply browse to SignOn.aspx.

To find out how to modify the Online Diary application, visit www.wrox.com

and download this chapter’s code, or you can grab it from the companion CD-ROM in the back of the book.

Summar y

In this chapter you’ve seen how to create a fully functioning diary and contacts management system, all with only a little code thanks to ASP.NET 2.0’s new controls and functionality. The new security controls in particular help save a lot of time and coding. In this chapter they’ve been used to create users and login control. However, they can also help provide a lot more functionality like creating different types of user roles, which then allows you to specify what users can and cannot do based on their role. Or you can let users determine the look and feel of their pages using their account details and ASP.NET 2.0’s new login and role controls.

Another great control you discovered in this chapter is the ObjectDataSource control. In the past data source controls have made life nice and easy. But they were quick and dirty, which meant poor code design, and you had to wave goodbye to a three-tier architecture. Now with the ObjectDataSource control you can have quick and dirty and three-tier architecture — great news for creating easily maintainable, well-designed projects.

In the next chapter you will be creating a file sharing project and learning some more about ASP.NET 2.0’s great new features.

35

04_749516 ch01.qxp 2/10/06 9:11 PM Page 36

advertisement

Was this manual useful for you? Yes No
Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Related manuals

advertisement