
Beginning ASP.NET 2
.0.pdf
Code
Namespaces provide more readable code, because if the namespace is known then only the data type is required to define a variable. For example, consider declaring a SqlConnection object without having the namespace known to the program:
Dim conn As System.Data.SqlClient.SqlConnection()
This is more typing as well as being hard to read. However, with the namespace known this can be reduced to:
Dim conn As SqlConnection()
Namespaces allow both the compiler and IntelliSense to find the variable types.
To use a namespace you use the Imports statement:
Imports System.Data
Imports System.Data.SqlClient
You can test to see if this is working by taking these lines out of the Decisions sample. See what happens in the code editor; IntelliSense squiggles indicate a problem, and you get a compiler error if you try to run the page.
Within your code you can declare namespaces by use of the Namespace statement — you place this around your classes. For example:
Namespace Wrox.Web
‘ class goes here
End Namespace
You can use the same namespace in multiple files, so you can split your code into physical files (a file for each class is a good idea), while the namespace spans those classes — the namespace is logical and not physical.
Now that you know how code works and how it can be organized, you can move on to the subject of classes, a topic that underlies the whole of .NET.
Working with Classes
Object orientation sounds complex and scary, one of those things people tell you that you have to master before you become a “‘proper programmer.” Ignore them; there’s no such thing as a “proper programmer.” It’s a term that doesn’t really mean anything. Object orientation is worth learning though, and it will make you a better programmer; everyone can be a better programmer, and this is just one step along the ladder. It’s important not to worry about this topic, because object orientation is actually quite simple. It can get complex, but at the basic level it’s easy to get into and doesn’t require a degree in rocket science (unless you work at NASA, in which case knowledge of astrophysics might be useful).
Throughout the book you’ve already seen plenty of objects. In fact everything you’ve seen has been an object: the ASP.NET controls are objects, data access is done via objects, ASP.NET pages are objects, even the data types are objects. This is one of the underpinnings of .NET — everything is an object. By defining a few terms you’ll see how these fit in with the existing objects and new objects you create.
329

Chapter 9
First is the difference between objects, classes, and instances. A class is a template for an object; it defines what the object will be able to do — think of it as a cookie cutter, defining the shape of the cookie. An object or instance is a class that’s been created — it’s the actual cookie, once freed from the cutter. Let’s look at these terms with an example, perhaps the SqlConnection:
Dim conn As SqlConnection
This defines the variable conn as being of type SqlConnection. As it stands, however, this isn’t usable, because it just defines the type of object — the object doesn’t yet exist. You’ve only defined the shape of the cookie cutter, and haven’t actually cut the cookie. To create the cookie you create an instance of the object:
conn = New SqlConnection
This can also be done at declaration time:
Dim conn As New SqlConnection
Use of the New keyword creates the instance, and once created the object becomes usable.
The properties of a class define the characteristics of that class. For example, the SqlConnection object has a property called ConnectionString, which defines the details of the database being connected to. Another property is State, which indicates what state the connection is in (open, closed, and so on):
If conn.State = ConnectionState.Open Then ‘ The connection is open
End If
The methods of a class define the actions that can be performed, so for the SqlConnection you can Open or Close it:
conn.Open()
The events of a class provide the user of the class with information about the status. For example, the SqlConnection has two useful events, InfoMessage and StateChange. The first is raised (or fired) when SQL Server returns a warning or some informational message, and the second is raised when the State is changed — when the connection is closed, for example.
Creating Classes
You can create classes in ASP.NET pages, but if you are creating the class for a special purpose it’s best to use a separate file and location. The best place for these is in the App_Code directory, a special directory into which class files can be put. Using this directory allows you to keep your class files together, as well as having them automatically compiled by ASP.NET. You’ll look at creating this later, but for now look at the structure of a class. The syntax is as follows:
[Accessor] Class ClassName
End Class
330

Code
The ClassName can be anything you want, but like variable naming it’s best to use something sensible. For example, the shopping cart item is a class called CartItem, and the cart itself is called ShoppingCart.
The Accessor defines the accessibility of the class; that is where the class can be seen from. This can be one of the values detailed in the following table:
Accessor |
Description |
|
|
Public |
No access restrictions. |
Private |
The class is only accessible from within its declaration context. |
Protected |
The class is only accessible from within its own class or derived classes. |
Friend |
The class is only accessible from within the assembly that contains it. |
Protected Friend |
The class is only accessible from within its own class, a derived class, or |
|
its containing assembly. |
|
|
It’s best not to worry too much about these for the moment. As a general rule, if you create a class that’s going to be used in ASP.NET pages you should use Public. So the shopping cart becomes:
Public Class ShoppingCart
End Class
Constructors
The constructor is a special method that runs when the class is instantiated, and it allows you to set the initial state of the class when it’s created. The constructor is always called New. For example, the shopping cart with the constructor is highlighted in the following code:
Public Class ShoppingCart
Private _dateCreated As DateTime
Private _items As List(Of CartItem)
Public Sub New()
_items = New List(Of CartItem)
_dateCreated = DateTime.Now
End Sub
End Class
What this constructor does is create another object — a new List of CartItem objects. This is what the cart items are stored in — it’s a collection of CartItem objects (this is covered in more detail in the
“Generics” section). Once that’s created, the initial creation date is set. You could use this ShoppingCart class like so:
Dim cart As New ShoppingCart()
This would create a new instance, and you’d know that the items collection had also been created, ready for you to add items.
331

Chapter 9
The CartItem class shows another aspect of constructors — overloading:
Public Class CartItem
Private _productID As Integer
Private _productName As String
Private _productImageUrl As String
Private _quantity As Integer
Private _price As Double
Private _lineTotal As Double
Public Sub New()
End Sub
Public Sub New(ByVal ProductID As Integer, ByVal ProductName As String, _ ByVal ProductImageUrl As String, _
ByVal Quantity As Integer, ByVal Price As Double)
_productID = ProductID
_productName = ProductName
_productImageUrl = ProductImageUrl
_quantity = Quantity
_price = Price
_lineTotal = Quantity * Price
End Sub
End Class
Here there are two constructors. The first, with no parameters, does nothing, and the second accepts parameters containing the details for an item being bought. Don’t worry too much about the specific syntax of the parameters; you’ll look at that in detail when you look at methods. The important point to note is that the constructor is overloaded — that is, there are two of them. You can have overloaded constructors (and methods) as long as the signature differs. A signature is what defines the uniqueness of a constructor or method — this includes its name, its return type, and the type and order of the parameters. Because these two constructors have different signatures, they are both allowed.
Having two constructors means the class can be created in two ways. Either with this:
Dim item As New CartItem()
Or with this:
Dim item As New CartItem(1, “Scarf”, “images\scarf.jpg”, 1, 4.95)
The first constructor creates an empty cart item, ready for you to fill in the details, whereas the second constructor creates a cart item with the details already filled in. These details are passed in as parameters within the parentheses and these get mapped to the parameters declared in the New method.
Properties
Properties are used to control the characteristics of a class, or to expose to users of the class some internal values. For example, consider the CartItem class; if the first constructor is used, how would the details of the item being bought be set? The variables can’t be accessed directly because they are Private, so
332

Code
they can’t be seen outside of the class. Properties are the answer, and these would be created in the following manner:
Public Class CartItem
Private _productID As Integer
Private _productName As String
Private _productImageUrl As String
Private _quantity As Integer
Private _price As Double
Private _lineTotal As Double
Public Property ProductID() As Integer Get
Return _ProductID End Get
Set (ByVal value As Integer) _productID = value
End Set
End Property
End Class
Let’s break this down and look at the parts. First you have the definition of the property itself, by use of Public Property — the Public means it’s going to be accessible outside of the class, which is exactly what you want. In fact it’s the reason for creating the property in the first place, to make the internal variable accessible. You then specify the name of the property and the data type:
Public Property ProductID() As Integer
Next comes the bit allowing read access to the property — the Get ... End Get (often called the getter), which simply returns the value of the internal private variable:
Get
Return _ProductID
End Get
Next is the bit that allows the value to be written to — between the Set ... End Set. The Set (or setter as it’s sometimes called) has a parameter that is of the same type as the property — an Integer in this case. This value is used to set the value of the internal variable:
Set (ByVal value As Integer) _productID = value
End Set
End Property
This form is the same for all properties, with only the name and data type changing. For example, a property for the product name would be:
Public Property ProductName() As String
Get
Return _Productname
333

Chapter 9
End Get
Set (ByVal value As String) _productName = value
End Set
End Property
With these two properties in place, the CartItem could be used like so:
Dim item As New CartItem()
item.ProductID = 1
item.ProductName = “The WroxUnited Scarf”
That would create the class and set the properties. When setting a property value the setter part of the property is called, and the value to be set (1 in this case of the ProductID) is passed into the setter as the variable value.
To read from the properties you could do the following:
IDTextBox.Text = item.ProductID.ToString()
NameTextBox.Text = item.ProductName
The first line reads from the property, converting to a string, because the Text property of the TextBox is a String type. When the property is accessed, the getter is called, which simply returns the value from the internal variable. For the ProductID that is an Integer, but the ProductName property is a String so no conversion is required.
Read-Only Properties
If you only want to provide read-only access to a property, and not allow the user of the class to update the property, you can make it read-only, like so:
Public ReadOnly Property ProductID() As Integer
Get
Return _ProductID
End Get
End Property
Here another keyword has been added — ReadOnly, and only the getter section of the property is included. Now the value cannot be set. This is exactly what the LineTotal property of the CartItem does:
Public ReadOnly Property LineTotal() As Double
Get
Return _quantity * _price
End Get
End Property
Here you can see that you don’t even have a Private variable. The value returned is simply a calculation.
Because the property is read-only, the value cannot be set, and trying to do so will generate a compile error.
334

Code
Write-Only Properties
Making a property write-only follows a similar procedure to the read-only, except for a different keyword and the inclusion of only the setter:
Public WriteOnly Property ProductID() As Integer
Set (ByVal value As Integer)
_productID = value
End Set
End Property
Here the keyword is WriteOnly. With this definition, trying to read from the property would result in a compile error.
Properties Versus Public Variables
While you’ve been reading the text on properties you might have been wondering why you have them, why not just make the internal variables public? Well, you could easily do this:
Public Class CartItem
Public ProductID As Integer
Public ProductName As String
Public ProductImageUrl As String
Public Quantity As Integer
Public Price As Double
Public LineTotal As Double
End Class
This would work, but is not a good idea because it breaks one of the rules of object orientation — abstraction (there are other rules of object orientation, but they aren’t pertinent to this particular topic). This means that you should abstract functionality, thus hiding the inner workings of the class. The reason for working this way is that it allows you to change how the class works internally without changing how it’s used. For example, consider the LineTotal, which is the Quantity multiplied by the Price. You have to have some way of calculating the total, and if you use a Public variable then where do you put the calculation? It could be done in the constructor, but what about the blank constructor that just creates an empty item? Would you have the user of the class calculate the total, or provide some other function to do it? Neither are good solutions.
Abstraction simply means that you are providing a simple, guaranteed way to access the functionality of the class, and that the user doesn’t have to know about how the class works. You’re using properties to hide the internal storage — those private variables are the internal storage and the properties are just a way for users of the class to access the internal variables.
Abstracting the internal storage with properties allows you to handle the problem of a line total, because the property accessor does the calculation for you. In fact, using this type of abstraction means you could store the internal state of the CartItem in any way you pleased, without having to change the code that uses CartItem.
There are no strict rules on naming for the private variables that actually store the property values, but an underscore as a prefix is commonly used, as well as a different case. So your property would be LineTotal, and the internal private variable is _lineTotal.
335

Chapter 9
Methods
Methods are the actions of a class, what you use to get the class to perform a task. The CartItem class is purely for storage, has no actions, and therefore contains no methods (although technically the constructor is a method). The shopping cart, however, contains methods, because you need to do things like insert, update, and delete items.
Methods fall into two types: those that return a value (a Function) and those that don’t (a Sub). The Function is useful for performing an action and then returning some result, perhaps whether or not the action succeeded. The Sub is useful when you don’t need a value from the action.
The syntax for a Function is as follows:
[Accessor] Function FunctionName([parameters]) As DataType
Return value
End Function
For a Sub the syntax is as follows:
[Accessor] Sub FunctionName([parameters])
End Sub
You can see that they are broadly similar. Like classes, the Accessor defines the visibility of the method. Use Public for methods that are visible from everywhere, and use Private for a method that is only used by the class. Both Subs and Functions accept an optional parameter list, much like constructors — you’ll look at the ins and outs of parameters in more detail soon.
The difference between the two method types is the returning of a value. The Function defines a data type, which is the type of the value being returned, and this is done with the Return statement. Let’s use the shopping cart and examine the methods, starting with deleting items, because that’s the simplest:
Public Sub DeleteItem(ByVal rowID As Integer)
_items.RemoveAt(rowID)
_lastUpdate = DateTime.Now
End Sub
Here the Sub takes a single parameter — the index of the row to be deleted. This index is then passed into the RemoveAt method of the _items collection, which is the collection that stores the cart items. When the item has been removed, the last update time is set. The method could be called like so:
Profile.Cart.DeleteItem(2)
This would remove the third row — remember that arrays and collections start at 0.
Inserting items into the cart is done with the Insert method:
Public Sub Insert(ByVal ProductID As Integer, ByVal Price As Double, _
ByVal Quantity As Integer, ByVal ProductName As String, _
336

Code
ByVal ProductImageUrl As String)
Dim NewItem As New CartItem()
NewItem.ProductID = ProductID
NewItem.Quantity = Quantity
NewItem.Price = Price
NewItem.ProductName = ProductName
NewItem.ProductImageUrl = ProductImageUrl
_items.Add(NewItem) _lastUpdate = DateTime.Now()
End Sub
This routine accepts five parameters, one for each part of the item (the ID, the price, and so on). Within the routine, a new CartItem is created, and the properties are set to the values of the parameters. Once all of the parameters are set the item is added to the _items collection and the time is updated.
One problem with the Insert method is that it could be called multiple times for the same product; this would result in multiple items in the cart. It would be more sensible to see if the item is already in the cart, and if so simply add one to the quantity. To do this you need to search through the collection looking for an item with the same ProductID, so a function has been created to do this:
Private Function ItemIndexOfID(ByVal ProductID As Integer) As Integer
Dim index As Integer
For Each item As CartItem In _items
If item.ProductID = ProductID Then
Return index
End If index += 1
Next
Return -1
End Function
Here the function accepts the ProductID as a parameter and returns an Integer. Within the function the _items collection is looped and if the ProductID of an item matches the supplied ProductID, the Return statement is used to return the index. If the loop ends without having found a match, -1 is returned. Notice that this function is marked as Private; that’s because it’s not going to be used from outside the class.
The Insert method can now be changed to the following:
Public Sub Insert(ByVal ProductID As Integer, ByVal Price As Double, _ ByVal Quantity As Integer, ByVal ProductName As String, _ ByVal ProductImageUrl As String)
Dim ItemIndex As Integer = ItemIndexOfID(ProductID)
If ItemIndex = -1 Then
Dim NewItem As New CartItem()
337

Chapter 9
NewItem.ProductID = ProductID
NewItem.Quantity = Quantity
NewItem.Price = Price
NewItem.ProductName = ProductName
NewItem.ProductImageUrl = ProductImageUrl
_items.Add(NewItem) Else
_items(ItemIndex).Quantity += 1 End If
_lastUpdate = DateTime.Now()
End Sub
The method still accepts the same parameters, but the first thing it does is call the private ItemIndexOfID to get the index number of the current product. If the index is -1, then it didn’t already exist in the collection and is added. If it does exist, the Quantity is increased.
Shared Methods and Properties
With classes you’ve seen that you have to create an instance of them before they can be used. For certain classes this can be an overhead that’s not really required. For example, consider a class called Utils that provides a range of utility methods, one of which is Log, to log exceptions:
Public Class Utils
Public Sub Log(ErrorMessage As String)
‘ log the error
End Sub
End Class
You could use this like so:
Dim u As New Utils
u.Log(“An exception occurred”)
The object instance exists only for the purpose of calling the Log method; there are no properties to set, so it seems a bit of a waste to have to create the instance, especially if it’s going to be used only once. To get around this you can create shared class members (sometimes called static members). For example:
Public Class Utils
Public Shared Sub Log(ErrorMessage As String)
‘ log the error
End Sub
End Class
The introduction of the Shared keyword means that a class instance is no longer required, allowing the method to be called like so:
Utils.Log(“An exception occurred”)
When dealing with utility classes, shared methods are extremely useful, and you’ll see how the logging features can be implemented in Chapter 15.
338