Simple Multi-Threading

We’ve all installed programs on our computers and seen different things happening on the screen right?
Progress bars counting to 100%… Labels changing to show us what file is being worked on… Did you ever wonder how to do that? If you like essentially useless, but attractive stuff like that as much as I do, you’re answer is definitely going to be “YES!”

Using an installer as an example, the simple theory behind it is that the installer runs on (at least) two different threads. When working with threads, imagine the execution of the application flows like a river; a single passage of the water from point A to point B.
If the river should split down another tributary, though, some of the water goes in a different direction, doesn’t it? That’s what threads do, it basically allows you to split an application up, so that it can do more things at any given time.

Let’s get into a simple example…

The following code opens a connection to a database and writes the selected data into a ListBox control (not a practical application, as most people won’t go looking through a full table’s worth of data in a ListBox, but it shows you what threading actually does quite nicely on the form).
The data access will be done on a separate thread, while another thread counts from 0 while the data access thread is still busy.
So, we’ll have 3 threads:

  1. The main thread that builds and controls the form
  2. The 2nd thread that queries the database and modifies the ListBox
  3. The 3rd thread that makes the Label count while thread 2 is busy

The form will consist of a Button, a Label, and a ListBox. I’m keeping the names of these controls as the Visual Studio defaults for clarity.

‘ Imports and Global Variables
1 Imports System.Threading
2 Imports System.Data
3 Imports System.Data.SqlClient
4  
5 Private DS As New DataSet
6 Private DA As New SqlDataAdapter
7  
8 Private t1 As Thread
9 Private t2 As Thread
10  
11 Private SetTextDelegate As SetTextCallBack = _
New SetTextCallBack(AddressOf SetTextMethod)
12 Private AddItemDelegate As AddItemCallBack = _
New AddItemCallBack(AddressOf AddItemMethod)
13 Delegate Sub SetTextCallBack(ByVal Text As String)
14 Delegate Sub AddItemCallBack(ByVal Item As String)

We’re creating 2 threads here. Thread t1 will perform the data access and add items to the ListBox, and thread t2 will just update the Label’s text while t1 is working. This is just for a visual indication that things are actually working.

I’ve already covered connections to SQL Data Sources in my blog, and, since it’s a lot of code, I won’t be including it in this post. Just know that even though we’re working with threads here, there’s nothing different that needs to be done to the code that connects to the database and populates the dataset.

Next we’re going to write the button click event handler, this is just going to set the threads up and start them.

1 Private Sub Button1_Click(ByVal Sender As Object, ByVal e As System.EventArgs) Handles Me.Button1.Click
2     t1 = New Thread(New ThreadStart(AddressOf GetData))
3     t2 = New Thread(New ThreadStart(AddressOf ProgressCounter))
4     t1.Start
5     t2.Start
6 End Sub

When we set the threads in lines 2 and 3, we use AddressOf to tell the threads what code they’re supposed to handle. Lines 11 – 14 in the global declarations are used for interacting with form elements, because controls can’t be accessed from a thread that they weren’t created on.

Now, let’s write the code that t1 will use:

1 Private Sub GetData()
2     ‘ SQL Data Access code goes here
3 Dim CurrentRow As String = Nothing
4 For i As Integer = 0 To DS.Tables(0).Rows.Count – 1
5     CurrentRow = DS.Tables(0).Rows(i)(1).ToString
6     Thread.Sleep(400)
7      Me.Invoke(Me.AddItemDelegate, New Object() {CurrentRow})
8 Next i
9 End Sub

Here, we’re simply looping through the DataSet, and, on each, we’re storing the value in the specified cell. We’re then passing that value to the delegate sub which will use it to execute the next procedure to add it to the ListBox.

1 Private Sub AddItemMethod(ByVal Item As String)
2     ListBox1.BeginUpdate()
3     ListBox1.Items.Add(Item)
4     ListBox1.EndUpdate()
5 End Sub

That’s it for the first thread. The main part of the application is now done, now, let’s get to the 2nd thread:

1 Private Sub ProgressCounter()
2     Dim i As Integer = 0
3     While Not t1.IsAlive = False
4         Me.Invoke(Me.SetTextDelegate, New Object() {i.ToString})
5         i = i + 1
6     End While
7 End Sub
8  
9 Public Sub SetTextMethod(ByVal Text As String)
10     Label1.Text = Text
11 End Sub

Very simple, we’re just storing an integer value and passing it to our delegate so that the delegate can write it to the label.

Lastly, know that a typical application on a 32-bit platform has capacity for 250 threads. You generally shouldn’t need to use more than 10 though (if that). Managing a lot of threads does become quite a nightmare, so be very sure about what your application needs to do before you go crazy creating threads. Also, don’t worry about writing code to close your threads. They will close themselves when they complete execution (i.e. when they’re done working).

In my next post, I’ll show you how to make a delegate procedure modify the text value of any control on your form, so watch this space!

-L

Advertisements

[ASP.NET] Horizontal Submenu from XML

In my last post I showed you a workaround that allowed you to create a horizontal submenu when you clicked on a MenuItem from another menu on the same page. That example hard-coded the MenuItem definitions into the code file, and I said that I’d be demonstrating how to create a horizontal submenu from a sitemap file. While attempting this, I got hit in the face by an error that has to do with hierarchy which I researched only to find that most people suggest it would be easier to find another alternative rather than try to solve the problem.

My alternative was to create a custom xml file that contains property definitions for the MenuItem class (namely Text and NavigateURL). Here it is:

<name>Visual Basic.NET</name>

1 <?xml version=1.0encoding=utf-8?>
2 <CategoriesMenu>
3 <item>
4 <id>0</id>
5 <name>VBScript</name>
6 <url>~/Articles/List.aspx?t=cat&amp;r=vbs</url>
7 </item>
8 <item>
9 <id>1</id>
10
11 <url>~/Articles/List.aspx?t=cat&amp;r=vbs</url>
12 </item>
13 <item>
14 <id>2</id>
15 <name>ASP.NET</name>
16 <url>~/Articles/List.aspx?t=cat&amp;r=vbs</url>
17 </item>
18 </CategoriesMenu>

Unfortunately, here’s where the frustration kicked in (mostly because I have very little experience working with XML). I had a lot of problems figuring out how to get the right values out of the XML and into my menu where I needed them. Good thing for you, I’ve spared you the aggravation by fighting through it for you.

Basically, we need to select each <name> and <url> element outlined in the XML and use the text inside of those as our menu definition properties. It took a few hours, but I managed it; here’s how:

<col style="width: 760 Continue reading

[ASP.NET] Horizontal Drop down Menu

I really like multi-level menus; they save space, but still allow you to put the same amount of content on your page.
ASP.NET is the only technology I know of that comes with its own menu that supports multiple menus, and it also allows you to change the menu’s orientation (Horizontal or Vertical). It’s great!

Sadly though, it does have one drawback, all “pop out” menus are fixed vertically, and there’s no way (that I’ve found) to change that. You just can’t get a menu/submenu pair that looks like this:

Home Categories Contact Us
VBScript Visual Basic.NET ASP.NET

 This type of menu cannot be designed with a standard ASP.NET menu control. So, here’s my workaround to get the same effect.
I’m keeping this simple, we’re not going to go into making it look pretty or anything, just the cold hard functionality of it; you can play with colors and design later.

For now, we won’t be using a sitemap, I’ll go into that soon as it requires modification of the web.config file and it’s quite a bit to go into.

Hard-coded Menu

First, create 2 menu controls on your page (Default names Menu1, and Menu2); set the orientation for both of them to Horizontal.
Next, populate the first menu (be sure to leave menu2 blank):

MenuItem Text MenuItem Value
Home Home
Categories Categories
Contact Us Contact Us

 Add the following to your code file:

1 Protected Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.MenuEventArgs) Handles Menu1.MenuItemClick
2     Select Case e.Item.Value ‘ You could also use e.Item.Name
3         Case “Categories”
4             Dim m1 As New MenuItem
5             m1.Text = “VBScript”
6             m1.Value = “VBScript”
7             m1.NavigateUrl = “Articles/List.aspx?Type=Cat&Ref=VBS”
8  
9             Dim m2 As New MenuItem
10             m2.Text = “Visual Basic.NET”
11             m2.Value = “Visual Basic.NET”
12             m2.NavigateUrl = “Articles/List.aspx?Type=Cat&Ref=VBnet”
13  
14             Dim m3 As New MenuItem
15             m3.Text = “ASP.NET”
16             m3.Value = “ASP.NET”
17             m3.NavigateUrl = “Articles/List.aspx?Type=Cat&Ref=ASPnet”
18  
19             Menu2.Items.Add(m1)
20             Menu2.Items.Add(m2)
21             Menu2.Items.Add(m3)
22     End Select
23 End Sub

 Basically, we’re populating a static menu on the fly. Because the page loads while the menu is empty, it doesn’t start off visible. This changes when we add items, so we don’t even need to tell VB to hide the menu on page load.

It’s not an elegant solution by any stretch of the imagination, but it works. My next post will show you how to do the same thing by using sitemaps.

Until then…

-L

Using Sockets to connect to HTTP

This may seem pretty basic, but it took me a long time to understand how to establish a connection to a server somewhere online.

Since I started programming, I’ve wanted to write my own IRC client. Because I’ve just recently started chatting on IRC again in my spare time, I decided that I’d actively start doing the necessary research that would help me do this.
I started by doing a Google search on basic IRC Client in vb.net. In subsequent searches, I found the same code that I found initially, but it’s brilliant because it explains how an HTTP connection is made:

The following code defines a few Global Variables and a sub that will be used in a different class file to establish the connection. Other operations are beyond the scope of this article, and so will be excluded.

1 Imports System.Net.Sockets
2  
3 Private Shared port As
Integer = 44
4 Private Shared IpHostInfo As IPHostEntry = Dns.GetHostEntry(“localhost”)
5 Private Shared IpAddress As IpAddress = IpHostInfo.AddressList(0)
6 Private Shared client As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
7  
8 Public Sub Connect(ByVal RemoteHostName As String, ByVal RemotePort As Integer)
9

Try

10

client = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)

11

port = RemotePort

12

ipHostInfo = Dns.GetHostEntry(RemoteHostName)

13

ipAddress = ipHostInfo.AddressList(0)

14

Dim remoteEP As New IPEndPoint(ipAddress, port)

15

Client.BeginConnect(remoteEP, AddressOf SocketConnected, client)

16

Catch ex As Exception

17

MsgBox(ex.Message)

18

Exit Sub

19

End Try

20 End Sub
   

It’s worth mentioning that unless you have the code for SocketConnected (which is used as a Delegate on line 15), you won’t be able to run your application as the compiler will indicate that SocketConnected has not been declared.
For that reason, I give you now, the code for SocketConnected:

1

Private Sub SocketConnected(ByVal ar As IAsyncResult)

2

Try

3

If client.Connected = False Then RaiseEvent onError(“Connection refused.”) : Exit Sub

4

Dim state As New StateObject()

5

state.WorkSocket = client

6

client.BeginReceive(state.buffer, 0, state.BufferSize, 0, AddressOf SocketDataArrival, state)

7

RaiseEvent onConnect()
‘ onConnect handles the Connect Sub above from another class file

8

Catch ex As Exception

9

MsgBox(ex.Message)

10

Exit Sub

11

End Try

12

End Sub

   

The delegate sub SocketDataArrival (as defined in line 6 above) handles data that is received by the socket during operation of the code. The code for this Sub is specific to the application, so I won’t include it here.

I’ll be posting my IRC Client on CodePlex when it’s complete, but at the moment, there’s still a lot to do.

Thanks for reading!!!

-L

EDIT: (Fixed Carriage Return Line Feeds in code snippets)
Turns out MS Word 2007 isn’t perfect when it comes to blogging

Google-like site search in Visual Basic

For a long time, I wondered how to organise a search feature on my site. I could never figure it out… I knew that the search needed something to search (like a database, a web page, or something), but I had no idea about how to conduct the search.

Now I’ve started working again, I’ve learnt a lot of things in the last short month. One of these things that I’ve learnt is how to make an app (web/windows forms/wpf) search for records in a database.
This’ll work very well if your website uses a SQL database as a DataSource for content.

I’ll walk you through creating a Stored Procedure in your database, and having your vb code execute that sp and return the results ^_^

So, we need a Stored Procedure to run, lets write it real quick:
You’ll need either Visual Studio (express editions will do), or SQL Server Management Studio.
I’m using Management Studio here, but there should be little difference to VS’s interface.

Connect to your server, and expand your database from the list on the left. You should find something that says “Programmability” or “Stored Procedures” in the list under your database’s name. If it’s “Programmability”, expand it, and right-click on “Stored Procedures” and select “New Stored Procedure…”

This will create a new query. In the query window, add the following code:

1 SET ANSI_NULLS ON
2 SET QUOTED_IDENTIFIER ON
3 GO
4  
5 USE MyBlog
6  
7 CREATE PROCEDURE [dbo].[sp_Search]
8 (
9     @SearchText varchar(50)
10 )
11 AS
12 SELECT *
13 FROM Articles
14 WHERE ArticleTitle LIKE @SearchText


This selects all the rows in the table where the ArticleTitle column’s value is similar to the search text.
Now, we need to hook this into our site/app – this is the fun bit.

We need to write code that executes our Stored Procedure. It’s tidier in your code to place the Function that we’re writing below in a class file separate to your form.
I’m naming my class file Search.vb.

1 Imports System.Data
2 Imports System.Data.SqlClient
3  
4 Public Class Search
5 ‘ This Region houses all the variables we’re declaring globally.
6 #Region
“Global Variables”
7     ‘ Connection String to be used throughout the application.
8     Public ConnectionString As String = “Data Source=.\SQLEXPRESS; “ & _
9                     “Initial Catalog=MyBlog; “ & _
10                     “Integrated Security=True;”
11  
12     ‘ Connection object.
13     Public conn As New SqlConnection(ConnectionString)
14 #End Region
15  
16     ‘ Execute the Stored Procedure based on input from the user in
17     ‘ the form of a Function Parameter.
18     Public Function SearchData(ByVal SearchText As String)
19  
20

‘ Command and connection to use when processing the search.

21         Dim cmd As New SqlCommand(“[dbo].[sp_Search]”, conn)
22         cmd.CommandType = CommandType.StoredProcedure
23  
24         ‘ Parameters to use. This will be your search criteria.
25         cmd.Parameters.AddWithValue(“@SearchText”, SearchText)
26         Try
27             ‘ Attempt to open the connection and execute the Stored Procedure.
28             conn.Open()
29             cmd.ExecuteNonQuery()
30         Catch ex As Exception
31             ‘ If there’s an error with processing the above, alert the user.
32             ‘ If your application of this is web-based, then replace the following line
33             ‘ of code with this:
34             ‘ <Label>.Text = “An error was encountered: ” & vbCrLf & ex.ToString()
35             MsgBox(“An error was encountered: ” & vbCrLf & ex.ToString)
36         Finally
37             ‘ Close the connection and clear the memory blocks that the connection
38             ‘ Close the connection and clear the memory blocks that the connection
39             ‘ and command objects were using
40             conn.Close()
41             conn.Dispose()
42             cmd.Dispose()
43         End Try
44     End Function
45  
46 End Class

We’re not done yet. Save your class file and then go back to your form/page’s code behind.
We need to make sure we have the controls on our form to use for the search. Typically, this is just a textbox and a button. I’ve named mine txtSearch and btnSearch respectively.
Add the following to your code behind (obviously replacing names with your own):

1 Imports System.Data
2 Imports System.Data.SqlClient
3  
4 ‘ Import the class file that has our stored procedure in it (Search.vb)
5 ‘ Dim <variable name> As New <external class name>
6 Dim Search As New Search
7  
8 Private Sub btnSearch_Click(ByVal Sender As Object, ByVal e As System.EventArgs) Handles Me.btnSearch.Click
9     ‘ We want to force conversion on our textbox to make sure that the right data type is being passed to the Stored Procedure
10     Dim SearchText As String = txtSearch.Text.ToString
11  
12     ‘ Create the ADO Data Objects for the DataGrid to use.
13     Dim SearchDataSet As New DataSet(“ArticlesDataSet”)
14     Dim SearchDataAdapter As New SqlDataAdapter(“SELECT * FROM Articles”)
15  
16     ‘ Set the schema (structure definition) of the table and fill the DataAdapter
17     SearchDataAdapter.FillSchema(SearchDataSet, SchemaType.Source, “Articles”)
18     SearchDataAdapter.Fill(SearchDataSet, “Articles”)
19     ‘ Set the DataSource for the grid to use our newly created dataset
20     SearchGrid.DataSource = SearchDataSet.Tables(“Articles”)
21  
22     ‘ Execute the function that runs our Stored Procedure.
23     Search.SearchData(SearchText)
24 End Sub

A good idea might be to put the code that creates and populates the DataSet in a separate procedure and just have your Event Handler execute that procedure. This will cause the DataGridView to update every time the button is clicked, meaning that the user can change search criteria and get new results all the time.
There’s nothing different that goes on with the operation of the app when doing this, it just makes the event handler a little neater:

1 Private Sub CreateADO()
2         ‘ We want to force conversion on our textbox to make sure that the right data type is being passed to the Stored Procedure
3     Dim SearchText As String = txtSearch.Text.ToString
4     ‘ Create the ADO Data Objects for the DataGrid to use.
5     Dim SearchDataSet As New DataSet(“ArticlesDataSet”)
6     Dim SearchDataAdapter As New SqlDataAdapter(“SELECT * FROM Articles”)
7  
8     ‘ Set the schema (structure definition) of the table and fill the DataAdapter
9     SearchDataAdapter.FillSchema(SearchDataSet, SchemaType.Source, “Articles”)
10     SearchDataAdapter.Fill(SearchDataSet, “Articles”)
11  
12     ‘ Set the DataSource for the grid to use our newly created dataset
13     SearchGrid.DataSource = SearchDataSet.Tables(“Articles”)
14  
15     ‘ Execute the function that runs our Stored Procedure.
16     Search.SearchData(SearchText)
17 End Sub
18  
19 Private Sub btnSearch_Click(ByVal Sender As Object, ByVal e As System.EventArgs) Handles Me.btnSearch.Click
20     CreateADO()
21  
22     ‘ Do something else here (if needed)
23 End Sub

OK, so, there’s a database search. I did it simply for the purposes of this post (placing search results in a DataGridView, but you can customize the output of your search as you like.

An app like this will be easier to create using LINQ Queries, but that’s for another post. I strongly recommend getting your hands on (at least) the Express Edition of VB2008 and playing around with it. It simplifies so much from VS2005, and, based on the speed at which MS is releasing new stuff, it may be a better idea to forget VS2005 altogether in favor of VS2008.

That’s it for me. For now. Hope you enjoyed reading.

-L

New User Registration

This is a follow-up to my post on a Data Driven Login System.

If you haven’t read it yet, go do that now, I’ll wait…

Done? Good.

Just to add to my data driven login system post, your form (Default.aspx) isn’t just magically going to be able to read the code from the code file (Default.aspx.vb), you have to set it to do that in the @Page directive right at the top of your form as follows:

<%@ Page Language=”VB” CodeFile=”Default2.aspx.vb” Inherits=”Default2″ %>

And then right at the top of your code file, you need to have this:

Partial Class Default2

This Partial Class Default2 is the class where all your code is going to go. Your form is going to inherit this class from the code file which means that the form (Default.aspx) is going to read all the data from the class when the page loads.

“Default2″ is the name of the class I used on the page I copied this code from, but, as long as the value of your Inherits”” field on the form is the same as the name of the class in your code file, you should be OK. You can use any name you like. 

This example isn’t going to include account activation, all we’re going to do is create an entry in the database that users can sign in with.

Just as before, I’m going to start out by designing the web form that users are going to register on:

So, the form’s going to go in Default.aspx. The code file we’re inheriting from (see above) is going to be Default.aspx.vb.

<asp:Label runat=”server” id=”lblUsername” value=”Username:”></asp:Label><br />

<asp:Textbox runat=”server” id=”txtUsername”></asp:Textbox><br />

<asp:Label runat=”server” id=“lblUsername” value=”Password:”></asp:Label><br />

<asp:Textbox runat=”server” id=”txtPassword” Textmode=”Password”></asp:Textbox><br />

<asp:Button runat=”server” id=”btnRegister” text=”Register” />

We’re just going to add the record to the same table that we logged in with in the login system, but you can change the table name in the SQL Statement if you like.

These two lines of code have to go right at the top of your code file (lines 1, and 2)

Imports System.Data

Imports System.Data.SqlClient

The next bit of code goes inside your Class Statement:

Private Sub btnRegister_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnRegister.Click

Dim connection As New SqlConnection(“Data Source=.\SQLEXPRESS;” & _

“Initial Catalog=Users;” & _

“Integrated Security=True;”)

 Dim sql As String “INSERT INTOAdmins(AdminName, AdminPass) “ + _

“VALUES(@Name, @Pass)”

Dim command As New SqlCommand(sql, connection)

 command.Parameters.Add(“@Name”, SqlDBType.varChar, 10)

 command.Parameters.Add(“@Pass”, SqlDBType.varChar, 10) 

command.Parameters(“@Name”).value = txtUsername.Text

command.Parameters(“@Pass”).value = txtPassword.Text

 connection.Open() 

 command.ExecuteNonQuery()

 connection.Close()

End Sub

That’ll do it! So lets go through what’s happening here.

The first thing we’re doing is establishing our database connection. Data Source is the SQL Server the database is on, Initial Catalog is the database we’re connecting to, and Integrated Security is the method we use to log into the server with. When set to true, Integrated Security tells SQL Server to use Windows Authentication. We’re not going to go into that now, but all you need to know is that it’s simpler to use, and more secure than other authentication types.

The 2nd thing we’re doing is declaring our SQL Statement. This is where the magic happens. The format is:

INSERT INTO Admins(AdminName, AdminPass) VALUES (@Name, @Pass)

[insert command] [table]([field1], [field2]) VALUES (‘value1’, ‘value2’)

All this is saying is that we want to insert the values @Name, and @Pass into the AdminName and AdminPass fields of the Admins table respectively.

Next we’re creating a SQLCommand object that uses our SQL Statement and connection string (sql, connection) and adding creating SQL Parameters and giving them values based on the user’s input on our form. We do it this way to stop SQL injection which is a bad thing; I’ll go into it at a later stage.

The last 3 lines before the End Sub statement open the connection to the database, execute the SQL Statement (inserting the user’s input), and closes the connection to the database.

So that’s it. I’d like to thank you for your time; I hope you enjoyed this tutorial. If anything’s still unclear, post a comment and I’ll do my best to elaborate.

-L

Data Driven Login System

Lets explore a login system that uses data stored in a database table.

All we’re going to do is create a database with 1 table. In this table, we’re going to store user information that we’ll use for authentication. The only downside to this is that if anyone knows the URL to the protected page, they can easily browse to it and bypass the login protection. This is not an issue in a Windows Forms environment.

So, first thing’s first; lets create our database and populate it.
In Visual Studio, open the Server Explorer and select the “Connect to Database” button from the top row of buttons. Enter your SQL Server’s name and type Users as the database name. We’re going to use Windows Authentication.
Once the database has been created, add a table called Admins with the following columns:

Column Name – Data Type – Allow Nulls
AdminID – int – No
AdminName – varchar(10) – No
AdminPass – varchar(10) – No

Select the AdminID column and set it as “Identity Specification” on the bottom half of the screen. Save the table and close it. Right-click on the table in Server Explorer and select “Show Table Data”. Enter a username and password for yourself so you can test the login system.

On your site’s Default.aspx page, add 3 labels, 2 textboxes, and a button. Your code should look like this:

<asp:Label runat=”server” id=”lblName” text=”Username:”></asp:Label><br />
<asp:TextBox runat=”server” id=”txtName”></asp:TextBox><br />
<asp:Label runat=”server” id=”lblPass” text=”Password:”></asp:Label><br />
<asp:TextBox runat=”server” id=”txtPass” textmode=”password”></asp:TextBox><br />
<asp:Label runat=”server” id=”lblError” text=””></asp:Label>&nbsp;
<asp:Button runat=”server” id=”btnSignIn” text=”Sign In” />

Once you’ve done this, open the code file (Default.aspx.vb by default) and add the following code into the click event handler for btnSignIn:

Dim connection As New SqlConnection(“Data Source=.\SQLEXPRESS;” & _
                                                             “Initial Catalog=Users;” & _
                                                             “Integrated Security=True;”)

Dim sql As String = “SELECT [AdminName], [AdminPass] FROM Admins “ + _
                                                “WHERE [AdminName] = @AName AND [AdminPass] = @APass”

Dim command As New SqlCommand(sql, connection)

command.Parameters.AddWithValue(“@AName”, Convert.ToString(txtName.Text))
command.Parameters.AddWithValue(“@APass”, Convert.ToString(txtPass.Text))

connection.Open()

Dim reader As SqlClient.SqlDataReader
reader = command.ExecuteReader()
If reader.HasRows() Then
    While reader.Read
        If reader.Item(“AdminName”).ToString.ToLower() = txtName.Text And reader.Item(“AdminPass”).ToString.ToLower() = txtPass.Text Then
            Response.Redirect(“Admin/Default.aspx”)
        Else
            lblError.Text = “Incorrect username and/or password.”
            lblError.ForeColor = Drawing.Color.Red
            txtName.Text = “”
            txtPass.Text = “”
        End If
        If Not reader Is Nothing Then reader.Close()
        connection.Close()
    End Sub

Now, what we have here is a DataReader that reads data in the table we specify in our SQL Command (as you can see by the command.ExecuteReader() statement) and we’re comparing what the DataReader reads to what the user has input. If the user’s input matches what’s in the database, we redirect to the protected page. If the user input doesn’t match, we’re setting the 3rd label’s text property to tell the user that they need to try to log in again.

One thing we’re also doing is making sure the user input is matched 100% (including case-sensitivity) with the data in the table.

So that’s it for this entry. I hope you enjoyed it and that it helped you.

If you happen to know how to include a way of stopping users browsing directly to the protected page (by means of a cookie or something), post a comment and let us all know.

-L