Assignment 3

Course Number and Name: COMP 466 - Advanced Technologies for Web-Based Systems

Student Name: Sammy Dods

Student ID: REDACTED

Date Started: Aug 22, 2025

Date Completed: Jan 26, 2026

Estimated Hours Spent: 80

Part 1 - Visitor Tracking Application

Technology Stack: ASP.NET Web Forms, Bootstrap 5, jQuery
Framework: .NET Framework 4.7.2
Data Storage: Browser Cookies

Project Description and Requirements

Part 1 is a simple visitor tracking web application that monitors and displays visitor information. The application tracks the number of times a visitor has accessed the site, displays their IP address, and detects their timezone using client-side JavaScript.

Requirements

Analysis and Design

Architecture

The application uses ASP.NET Web Forms with a Master Page pattern for consistent layout. The main page (Default.aspx) handles visitor tracking logic in teh code-behind file.

Data Flow

flowchart TD A[User Visits Page] --> B[Page_Load Event Fires] B --> C{Cookie Exists?} C -->|Yes| D[Increment Count] C -->|No| E[Initialize to 1] D --> F[Get IP Address from server variables] E --> F F --> G[Display Visit Count & IP Address] G --> H[JavaScript Detects Timezone] H --> I[Display All Info to User]
  1. User visits Default.aspx
  2. Page_Load event checks for "NumVisits" cookie
  3. If cookie exists, increment visit count; otherwise, initialize to 1
  4. Retrieve IP address from server variables
  5. Display visit count and IP address on page
  6. Client-side JavaScript detects timezone using Intl.DateTimeFormat API

Note: The Page_Load event fires every time the page loads, which is perfect for tracking visits. I had to be careful with the cookie logic - if the cookie doesn't exist, I create a new one, otherwise I increment the existing value. The IP address thing was way trickier than I thought it'd be because of proxies and stuff. Took me a while to figure that out.

Key Components

Implementation Documentation

Cookie Management

protected void Page_Load(object sender, EventArgs e) { int numVisits = 1; HttpCookie cookie = Request.Cookies["NumVisits"]; if (cookie != null) { numVisits = int.Parse(cookie.Value) + 1; } else { cookie = new HttpCookie("NumVisits"); } cookie.Value = numVisits.ToString(); cookie.Expires = DateTime.Now.AddDays(30); Response.Cookies.Add(cookie); string ipAddress = Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (string.IsNullOrEmpty(ipAddress)) { ipAddress = Request.ServerVariables["REMOTE_ADDR"]; } litNumVisits.Text = numVisits.ToString(); litIPAddress.Text = ipAddress; }

Timezone Detection

Timezone is detected client-side using JavaScript's Intl.DateTimeFormat API:

<script> document.getElementById("timezone").innerText = Intl.DateTimeFormat().resolvedOptions().timeZone; </script>

Note: I tried to get the timezone server-side at first, but that was a pain. Way easier to just use the browser's built-in API. The Intl.DateTimeFormat thing works great in modern browsers and I don't need any extra libraries, so that's nice.

Project Structure

Note: I kept the project structure simple for Part 1. The Master Page pattern is really useful - I used it in all parts to maintain consistent styling. Bootstrap made the UI look professional without too much custom CSS work. I use bootstrap every day at my job, so it was easy to plug in here.

User Guide

Setup Instructions

  1. Open the solution file (TM3A.sln) in Visual Studio
  2. Set part1 as the startup project (right-click part1 → Set as StartUp Project)
  3. Build the solution (Build → Build Solution)
  4. Run the application (F5 or Debug → Start Debugging)
  5. The application will open in your browser at Default.aspx

Using the Application

  1. Upon first visit, the visit count will be 1
  2. Refresh the page or visit again - the visit count will increment
  3. The IP address is displayed automatically
  4. The timezone is detected and displayed automatically
  5. Visit count persists for 30 days via browser cookie

Note: When I was testing, I noticed that clearing browser cookies resets the visit count, which makes sense. The IP address might show as "::1" when testing locally (that's IPv6 localhost), which is totally normal. The timezone detection works great - it just automatically figures out what timezone the user is in.

Accessing the Application

Note to Instructor: This application demonstrates basic cookie management, server variable access, and client-side JavaScript integration in ASP.NET Web Forms. The visit counter persists accross browser sessions using cookies with a 30-day expiration.

Personal note: This was a good starting point to get familiar with ASP.NET Web Forms. I chose a 30-day expiration for the cookie because it seemed like a reasonable balance - long enough that users would see their visit count persist, but not so long that it would clutter their browser. I also learned that IP address detection can be tricky with proxies and load balancers, which is why I check both HTTP_X_FORWARDED_FOR and REMOTE_ADDR.

Part 2 - Picture Slideshow Application

Technology Stack: ASP.NET Web Forms, Bootstrap 5, jQuery, JavaScript
Framework: .NET Framework 4.7.2
Data Storage: Text file (App_Data/pictures.txt)

Project Description and Requirements

Part 2 is a picture slideshow application that displays images in a slideshow format. The application reads picture information from a server-side text file and provides controls for starting/stopping the slideshow, toggling between random and sequential modes, and manually navigating throught pictures.

Requirements

Analysis and Design

Architecture

The application uses ASP.NET Web Forms with a Master Page. Picture data is loaded from a text file on the server and serialized to JSON for client-side JavaScript processing.

Data Storage Format

Picture information is stored in App_Data/pictures.txt with the following format:

Picture Name|Image URL|Description Example Picture|https://example.com/image.jpg|This is an example picture

Each line contains three fields separated by pipe (|) characters: Name, URL, and Description.

Note: I went with a simple text file because it's super easy to edit. I thought about using JSON or XML, but honestly a plain text file with '|' as a separator was way simpler. The pipe character works good as a separator since you probably won't see it in picture names or URLs.

Slideshow Modes

Slideshow Flow

flowchart TD A[Page Loads] --> B[Load Pictures from Text File] B --> C[Serialize to JSON Send to Client] C --> D{User Clicks Start?} D -->|No| E[Wait for Input] D -->|Yes| F[Start Slideshow] F --> G{Random Mode?} G -->|Yes| H[Shuffle Array
Disable Nav Buttons] G -->|No| I[Sequential Order
Enable Nav Buttons] H --> J[Display Picture at Interval] I --> J J --> K{User Clicks Stop?} K -->|No| J K -->|Yes| L[Stop Timer] L --> M[Show Current Picture] E --> D

Implementation Documentation

Picture Loading (Server-Side)

private List<Picture> LoadPictures() { var list = new List<Picture>(); var path = Server.MapPath("~/App_Data/pictures.txt"); var lines = System.IO.File.ReadAllLines(path); foreach (var raw in lines) { var line = raw.Trim(); if (string.IsNullOrEmpty(line)) continue; var parts = line.Split(new[] { '|' }, 3); if (parts.Length != 3) continue; var name = parts[0].Trim(); var url = parts[1].Trim(); var desc = parts.Length >= 3 ? parts[2].Trim() : ""; list.Add(new Picture() { Name = name, Url = url, Description = desc }); } return list; }

Slideshow Control (Client-Side JavaScript)

Key JavaScript functions:

Note: The JavaScript for this was way more complicated than I thought it'd be. I had to be careful with the interval timer - make sure to clear it when stopping, and don't let it create a bunch of timers if someone clicks start a bunch of times. The random mode just uses Math.random() to shuffle stuff around, which works fine for small picture sets.

Project Structure

User Guide

Setup Instructions

  1. Open the solution file (TM3A.sln) in Visual Studio
  2. Set part2 as the startup project
  3. Ensure App_Data/pictures.txt exists with picture data in the format: Name|URL|Description
  4. Build and run the application
  5. The application will redirect to Slide.aspx automatically

Using the Slideshow

  1. Click "Start" to begin the slideshow
  2. Adjust the interval (in seconds) using the number input
  3. Check "Random Mode" to display pictures randomly
  4. In sequential mode, use "Back" and "Next" buttons to navigate manually
  5. Click "Stop" to pause the slideshow
  6. The caption appears below each picture
  7. The total picture count is displayed at the bottom

Note: I messed around with different interval values - too fast (under 2 seconds) and you can't really see the pictures, too slow (over 10 seconds) and it gets boring. 3 seconds seems like a sweet spot. The random mode is pretty cool - it never shows the same picture twice in a cycle, which I did by shuffling the array.

Picture Data File Format

Create or edit App_Data/pictures.txt with one picture per line:

Sunset Beach|https://example.com/sunset.jpg|Beautiful sunset over the ocean Mountain View|https://example.com/mountain.jpg|Snow-capped mountain peak City Skyline|https://example.com/city.jpg|Urban cityscape at night

Accessing the Application

Note to Instructor: This application demonstrates file I/O operations, JSON serialization, client-side JavaScript state management, and dynamic UI updates. The slideshow supports both automatic and manual navigation modes with proper button state managment.

Personal note: This part was more challenging than Part 1, especially getting the random vs sequential modes to work correctly. I had some issues initially with the buttons not enabling/disabling properly, but eventually figured out the state management. The interval control was a nice touch - I tested it with different values and found that 3-5 seconds works well for most pictures. Also learned that JSON serialization in C# is really straightforward with Newtonsoft.Json.

Part 3 - Computer Store (Basic Version)

Technology Stack: ASP.NET Web Forms, Bootstrap 5, jQuery, JSON
Framework: .NET Framework 4.7.2
Data Storage: Hardcoded data (StaticData.cs), Browser Cookies for cart

Project Description and Requirements

Part 3 is the initial version of the computer store application, created as the foundation before Part 4. It provides a core shopping experience without user authentication or database integration. Computer and component data are hardcoded, and the shopping cart is stored in browser cookies. This version establishes the basic functionality that is later extended in Part 4.

Requirements

Analysis and Design

Architecture

The application uses ASP.NET Web Forms with hardcoded data in StaticData.cs. The shopping cart is managed entirely through browser cookies, and no persistent storage is used.

Data Model

Key Features

The prices I used are based on market research from when I started this project - for example, the RAM prices were set before the recent DDR5 RAM shortages that drove prices up significantly. If I were to update this now, I'd probably increase the RAM prices by an unreasonable ammount to reflect current market conditions. The prices are based on a more consumer friendly fantasty world (haha)

Shopping Flow

flowchart TD A[User Visits Products Page] --> B[Display Available Computers] B --> C{User Clicks Configure & Buy?} C -->|No| B C -->|Yes| D[Load Configuration Page
Show Component Dropdowns] D --> E{User Changes Component?} E -->|Yes| F[AJAX Call Update Price] E -->|No| G{User Clicks Add to Cart?} F --> G G -->|No| D G -->|Yes| H[Save to Cookie] H --> I[View Cart] I --> J{Proceed to Checkout?} J -->|No| B J -->|Yes| K[Clear Cart] K --> L[Order Complete No DB Save]

Implementation Documentation

Hardcoded Data Structure

All computer and component data is defined in DAL/StaticData.cs:

public static class StaticData { public static List<Component> GetAllComponents() { ... } public static Component GetComponentById(string id) { ... } public static List<Computer> GetAllComputers() { ... } public static Computer GetComputerById(string id) { ... } }

Note: I just threw all the data into static lists in the class. Made it super easy to add or change stuff while I was working on it. I used IDs like "cpu-i7" and "ram-16" so the code makes sense when you read it. The component categories are basically what you'd see at a real computer store.

Cart Management

Cart items are stored in browser cookies as JSON:

var cart = JsonConvert.DeserializeObject<List<CartItem>>(cookie.Value) ?? new List<CartItem>(); cart.Add(newCartItem); var cookie = new HttpCookie("cart", JsonConvert.SerializeObject(cart)); cookie.Expires = DateTime.Now.AddDays(30); Response.Cookies.Add(cookie);

Note: I know cookies have size limitations (usually 4KB), but for a typical shopping cart with a few items, this works fine. The JSON serialization makes it easy to store complex objects.

Dynamic Price Calculation

AJAX WebMethod provides real-time price updates:

[WebMethod] [ScriptMethod(ResponseFormat = ResponseFormat.Json)] public static string GetComponentPrice(string componentId) { var component = StaticData.GetComponentById(componentId); return component != null ? component.Price.ToString("F2") : "0.00"; }

Note: The AJAX calls make the price updates feel pretty snappy. I had to make sure the WebMethod was static and had the right attributes or it wouldn't work. The "F2" formatting thing makes sure we always show two decimal places, which looks better. If a component ID doesn't exist, it just returns 0.00 as a safe bet.

Project Structure

User Guide

Setup Instructions

  1. Open the solution file (TM3A.sln) in Visual Studio
  2. Set part3 as the startup project
  3. Build and run the application

Using the Application

  1. Browse available computers on the Products page
  2. Click "Configure & Buy" on any computer
  3. Customize components using the dropdown menus
  4. Watch the total price update in real-time
  5. Click "Add to Cart" to add the configured computer
  6. View cart to see all items and total
  7. Remove items from cart if needed
  8. Proceed to checkout (cart will be cleared, no order is saved)

Note: The real-time price updates were probably my favorite thing to build. Makes the whole shopping thing feel way more modern and interactive. I tested it with a bunch of different component combos to make sure the math was right. The cart stays in cookies so users can close the browser and come back later, which is pretty handy.

Accessing the Application

Note to Instructor: This application represents the initial e-commerce implementation created before Part 4. It demonstrates the foundational e-commerce flow without database dependencies. It showcases AJAX-based dynamic updates, JSON cookie management, and component-based pricing calculations. This version was later extended in Part 4 with user authentication and order persistence.

Personal note: This part was pretty fun to build! I spent way too much time getting the dynamic price calculation to work right - working with AJAX was cool though. I had to think about the component categories a bit. I went with 9 categories total, which seemed like a good middle ground between realistic and not too complicated. The "No Monitor" and "No Sound Card" options are there because not everyone needs those, especially if you're building a server or already got external stuff. Building this without a database first was actually a good learning thing - helped me figure out what data I'd need when I moved to Part 4.

Part 4 - Computer Store with Database Integration

Technology Stack: ASP.NET Web Forms, ADO.NET, SQL Server LocalDB, Bootstrap 5, jQuery
Framework: .NET Framework 4.7.2
Database Access: ADO.NET with parameterized queries for security

Project Overview

Part 4 is an extended and advanced version of the computer store application, built upon the foundation established in Part 3. This version adds comprehensive customer management, order management, and database integration using ADO.NET. The system extends Part 3's functionality by adding user authentication, order tracking, and persistent data storage. The application maintains the same ASP.NET Web Forms architecture and folder structure from Part 3, with additional features and database intergration.

Database Design

Database Schema Overview

The database consists of 5 main tables designed to support a complete e-commerce system:

Note: I chose to use 5 tables instead of a more normalized approach with separate junction tables. This keeps the schema simpler and works well for this application's needs. I stored component configurations as JSON strings in the Computers and OrderItems tables, which allows flexibility without needing additional tables. the JSON approach made sense and kept the database structure manageable.

Application Flow

flowchart TD A[User Visits Site] --> B{Logged In?} B -->|No| C[Register/Login] B -->|Yes| D[Browse Products] C --> D D --> E{Configure Computer?} E -->|No| D E -->|Yes| F[Select Components
Calculate Price] F --> G[Add to Cart Cookie Storage] G --> H{Checkout?} H -->|No| D H -->|Yes| I[Enter Shipping Info] I --> J[Create Order in Database] J --> K[Create Order Items
Save Component Config] K --> L[Clear Cart] L --> M[View Order Details]

Registration/Login Flow

flowchart TD A[User Wants to Register] --> B[Fill Registration Form] B --> C{Email Already Exists?} C -->|Yes| D[Show Error] C -->|No| E[Hash Password] D --> B E --> F[Save to Database
Create Session] F --> G[User Logged In]

Table Structure

Table Name Purpose Primary Key Key Relationships
Customers Stores customer information and authentication credentials Id (INT, IDENTITY) Referenced by Orders table
Computers Available computer configurations and base information ID (NVARCHAR(50)) Referenced by OrderItems table
Components Individual computer components (CPU, RAM, Storage, GPU, etc.) ID (NVARCHAR(50)) Stored as JSON in Computers and OrderItems
Orders Customer orders with shipping and payment information Id (INT, IDENTITY) Foreign Key: CustomerId → Customers(Id)
OrderItems Individual items within each order Id (INT, IDENTITY) Foreign Key: OrderId → Orders(Id) ON DELETE CASCADE

Detailed Table Definitions

Customers Table

Column Name Data Type Constraints Description
Id INT PRIMARY KEY, IDENTITY(1,1) Unique customer identifier
FirstName NVARCHAR(50) NOT NULL Customer's first name
LastName NVARCHAR(50) NOT NULL Customer's last name
Email NVARCHAR(100) NOT NULL, UNIQUE Customer's email address (used for login)
Password NVARCHAR(100) NOT NULL SHA256 hashed password

Note: I made Email UNIQUE because it's used for login, and we don't want people making duplicate accounts. The password field is 100 characters to fit SHA256 hashes (which are 64 hex characters). I thought about adding a salt column, but for this assignment, SHA256 without salt was fine. In a real app, I'd definitely do something more secure.

Computers Table

Column Name Data Type Constraints Description
PhoneNumber NVARCHAR(20) NULL Contact phone number
Address NVARCHAR(200) NULL Street address
City NVARCHAR(50) NULL City
PostalCode NVARCHAR(20) NULL Postal/ZIP code
Country NVARCHAR(50) NULL Country
CreatedDate DATETIME2 NOT NULL Account creation timestamp
LastLoginDate DATETIME2 NULL Last successful login timestamp
IsActive BIT DEFAULT 1 Account active status flag

Computers Table

Column Name Data Type Constraints Description
ID NVARCHAR(50) PRIMARY KEY Unique computer identifier (e.g., "pc-gamer")
Name NVARCHAR(100) NOT NULL Computer name (e.g., "Gaming PC")
Description NVARCHAR(500) NULL Computer description
BasePrice DECIMAL(18,2) NOT NULL Base price of the computer
ImageUrl NVARCHAR(500) NULL URL to computer image
DefaultComponentIDsJson NVARCHAR(1000) NULL JSON string containing default component configuration

Components Table

Column Name Data Type Constraints Description
ID NVARCHAR(50) PRIMARY KEY Unique component identifier (e.g., "cpu-i7")
Category NVARCHAR(50) NOT NULL Component category (CPU, RAM, Storage, GPU, etc.)
Name NVARCHAR(100) NOT NULL Component name
Price DECIMAL(18,2) NOT NULL Component price
Description NVARCHAR(500) NULL Component description
IsActive BIT DEFAULT 1 Component availability flag

Orders Table

Column Name Data Type Constraints Description
Id INT PRIMARY KEY, IDENTITY(1,1) Unique order identifier
CustomerId INT NOT NULL, FOREIGN KEY Reference to Customers.Id
OrderDate DATETIME2 NOT NULL Order placement timestamp
Status NVARCHAR(50) NOT NULL Order status (Pending, Processing, Shipped, Delivered, Cancelled)
TotalAmount DECIMAL(18,2) NOT NULL Total order amount
ShippingAddress NVARCHAR(200) NULL Shipping address
BillingAddress NVARCHAR(200) NULL Billing address
PaymentMethod NVARCHAR(100) NULL Payment method (Credit Card, PayPal, etc.)
Notes NVARCHAR(500) NULL Additional order notes

OrderItems Table

Column Name Data Type Constraints Description
Id INT PRIMARY KEY, IDENTITY(1,1) Unique order item identifier
OrderId INT NOT NULL, FOREIGN KEY Reference to Orders.Id (CASCADE DELETE)
ComputerId NVARCHAR(50) NOT NULL Computer identifier
ComputerName NVARCHAR(100) NOT NULL Computer name at time of order
UnitPrice DECIMAL(18,2) NOT NULL Price per unit
Quantity INT NOT NULL Quantity ordered
TotalPrice DECIMAL(18,2) NOT NULL Total price for this item
SelectedComponentsJson NVARCHAR(2000) NULL JSON string containing selected component configuration

Entity Relationships

Note: I used CASCADE DELETE on the OrderItems table so that if an order is deleted, all its items are automatically removed. This prevents orphaned records and keeps the database clean. I debated whether to allow order deletion at all, but decided it was a useful feature for testing and administrative purposes.

SQL Scripts

Database Creation Script

IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'ComputerStore') BEGIN CREATE DATABASE ComputerStore END

Table Creation Scripts

The following SQL scripts are executed automatically by the DatabaseHelper.CreateTables() method:

Note: I used IF NOT EXISTS checks everywhere so you can run the scripts a bunch of times without breaking anything. This was super helpful when I was messing around with the schema. The sysobjects check is SQL Server specific, but since we're using LocalDB, that's fine. I learned that NVARCHAR is better than VARCHAR for internationalization stuff, even though it takes up more space.

Components Table
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='Components' AND xtype='U') CREATE TABLE Components ( ID NVARCHAR(50) PRIMARY KEY, Category NVARCHAR(50) NOT NULL, Name NVARCHAR(100) NOT NULL, Price DECIMAL(18,2) NOT NULL, Description NVARCHAR(500), IsActive BIT DEFAULT 1 );
Computers Table
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='Computers' AND xtype='U') CREATE TABLE Computers ( ID NVARCHAR(50) PRIMARY KEY, Name NVARCHAR(100) NOT NULL, Description NVARCHAR(500), BasePrice DECIMAL(18,2) NOT NULL, ImageUrl NVARCHAR(500), DefaultComponentIDsJson NVARCHAR(1000) );
Customers Table
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='Customers' AND xtype='U') CREATE TABLE Customers ( Id INT IDENTITY(1,1) PRIMARY KEY, FirstName NVARCHAR(50) NOT NULL, LastName NVARCHAR(50) NOT NULL, Email NVARCHAR(100) NOT NULL UNIQUE, Password NVARCHAR(100) NOT NULL, PhoneNumber NVARCHAR(20), Address NVARCHAR(200), City NVARCHAR(50), PostalCode NVARCHAR(20), Country NVARCHAR(50), CreatedDate DATETIME2 NOT NULL, LastLoginDate DATETIME2, IsActive BIT DEFAULT 1 );
Orders Table
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='Orders' AND xtype='U') CREATE TABLE Orders ( Id INT IDENTITY(1,1) PRIMARY KEY, CustomerId INT NOT NULL, OrderDate DATETIME2 NOT NULL, Status NVARCHAR(50) NOT NULL, TotalAmount DECIMAL(18,2) NOT NULL, ShippingAddress NVARCHAR(200), BillingAddress NVARCHAR(200), PaymentMethod NVARCHAR(100), Notes NVARCHAR(500), FOREIGN KEY (CustomerId) REFERENCES Customers(Id) );
OrderItems Table
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='OrderItems' AND xtype='U') CREATE TABLE OrderItems ( Id INT IDENTITY(1,1) PRIMARY KEY, OrderId INT NOT NULL, ComputerId NVARCHAR(50) NOT NULL, ComputerName NVARCHAR(100) NOT NULL, UnitPrice DECIMAL(18,2) NOT NULL, Quantity INT NOT NULL, TotalPrice DECIMAL(18,2) NOT NULL, SelectedComponentsJson NVARCHAR(2000), FOREIGN KEY (OrderId) REFERENCES Orders(Id) ON DELETE CASCADE );

Data Seeding Script

Initial data is populated automatically on first run. The seeding includes:

Note: It was fun to use my PC knowledge (shout out to linus tech tips)to come up with realistic component prices and configurations. The 5 computer types cover different use cases - gaming, office work, professional workstations, budget builds, and content creation. Each has a default configuration that makes sense for that use case. The component selection gives users good options without being overwhelming.

Application Architecture

Technology Stack

Project Structure

Data Access Layer (DAL)

Note: I chose ADO.NET over Entity Framework because I wanted more direct control over the SQL queries. It was more work, but I feel like I understand what's happening under the hood better. The DatabaseHelper class centralizes all database operations, which makes it easier to maintain and debug. I also made the database initialization automatic - it creates everything on first run, which is convenient for deployment.

Web Pages and Functionality

Account Pages

Account/Login.aspx - User Login

Functionality: User authentication with email and password. Validates credentials against database using SHA256 password hashing. Updates LastLoginDate upon successful login. Creates session variables for authenticated users.

Account/Register.aspx - User Registration

Functionality: New customer account creation. Validates email uniqueness. Hashes password using SHA256 before storage. Creates customer record in database with CreatedDate timestamp.

Note: The registration form has validation on both the client side and server side. I check if the email is already taken by querying the database before making the account. The password confirmation field helps catch typos. I set CreatedDate automatically using DateTime.Now, which is way more reliable than trusting the user's computer clock.

Account/Profile.aspx - Customer Profile Management

Functionality: View and update customer profile information. Optional password change. Updates customer data in database and session variables.

Account/ForgotPassword.aspx - Password Recovery

Functionality: Password recovery functionality for customers who have forgotten their password.

Store Pages

Store/Products.aspx - Product Catalog

Functionality: Displays all available computers from database. Shows default component configurations. Provides "Configure & Buy" button for each computer.

Store/Configure.aspx - Computer Configuration

Functionality: Allows customization of computer components. Dynamic price calculation using AJAX. Real-time total price updates. Add configured computer to cart.

Note: This page is basically the same as Part 3, but now it reads from the database instead of StaticData. The AJAX calls are the same, which made moving from Part 3 to Part 4 way easier. I kept the same user experience - users shouldn't really notice a difference except the data can be updated in the database now.

Store/Cart.aspx - Shopping Cart

Functionality: Displays cart items from browser cookie. Calculate total price. Remove items from cart. Proceed to checkout (requires login).

Store/Checkout.aspx - Order Checkout

Functionality: Collects shipping and payment information. Creates order record in database. Creates order items for each cart item. Clears cart after successful order creation. Redirects to order details page.

Note: The checkout process creates both the order and all order items together (well, as close as I could get with ADO.NET). I store the component configuration as JSON in each order item, which saves exactly what the customer picked. This matters because component prices might change later, but we want to keep the original order prices.

Orders Pages

Orders/MyOrders.aspx - Order History

Functionality: Displays all orders for logged-in customer. Shows order date, status (with color-coded badges), and total amount. Provides link to view order details.

Note: I used Bootstrap badges for the order status - green for "Completed", yellow for "Processing", red for "Cancelled", stuff like that. Makes it super easy to see what's going on. The orders are sorted by date with newest first, which seems like the most useful way. I only show orders for the logged-in customer - gotta keep things secure.

Orders/OrderDetails.aspx - Order Details View

Functionality: Displays comprehensive order information. Shows order items with component configurations. Validates order ownership (security check). Provides links to edit or delete order.

Orders/EditOrder.aspx - Order Editing

Functionality: Allows editing of order items (component selection and prices). Order status is read-only. Updates order and order items in database. Recalculates total order amount.

Order Editing Flow

flowchart TD A[User Views Order] --> B[Load Order Items from Database] B --> C[Display Components in Dropdowns] C --> D{User Changes Component?} D -->|Yes| E[AJAX Call Get New Price] D -->|No| F{User Clicks Save Changes?} E --> G[Recalculate Item Total Update Display] G --> H[Recalculate Order Total Show New Total] H --> F F -->|No| I[Cancel] F -->|Yes| J[Update Database] J --> K[Update Order Items Update Order Total] K --> L[Reload Page Show Updated Order]

Note: The EditOrder page was one of the more complex pages to implement. I had to make sure the dynamic price calculation worked correctly when components were changed, and that the total order amount was recalculated properly. I made the order status read-only because I wanted to keep that as an administrative function (though I didn't implement an admin interface). The component dropdowns are populated dynamically, which required careful handling of the Repeater control and JavaScript integration.

Security Features

Authentication Security

Note: I used SHA256 for password hashing, which is better than plain text but I know that for production systems, you'd want to use bcrypt or Argon2 with salt. For this assignment, SHA256 was sufficient. I made sure to check order ownership on every page that displays order details - it's important to prevent users from accessing other people's orders. You can't just trust the URL parameters!

Data Security

Database Initialization

Automatic Database Setup

The database is automatically initialized when the application starts:

Note: The automatic database initialization was a lifesaver during development. I could delete the database files and restart the app, and everything would be recreated. The IF NOT EXISTS checks in the SQL scripts make it safe to run multiple times. I used LocalDB because it's easy to set up and doesn't require a full SQL Server installation. The database files are stored in App_Data, which makes it easy to back up or reset.

Configuration

Connection String

<connectionStrings> <add name="DefaultConnection" connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\ComputerStore.mdf;Integrated Security=True" providerName="System.Data.SqlClient" /> </connectionStrings>

Note: LocalDB is pretty sweet for development - it's a lightweight version of SQL Server that you don't need to fully install. The |DataDirectory| thing automatically points to the App_Data folder, which is handy. Integrated Security=True means it uses Windows authentication, which is way simpler for local development. For production, you'd want to use SQL Server authentication with a dedicated user account.

User Guide

Setup Instructions

  1. Open the solution file (TM3A.sln) in Visual Studio
  2. Restore NuGet packages (right-click solution → Restore NuGet Packages)
  3. Build the solution (Build → Build Solution or Ctrl+Shift+B)
  4. Set part4 as the startup project (right-click part4 project → Set as StartUp Project)
  5. Run the application (F5 or Debug → Start Debugging)
  6. Database will be created automatically on first run in App_Data folder
  7. Initial data (components and computers) will be seeded automatically

Using the Application

  1. Registration: Create a new account at /Account/Register.aspx
  2. Login: Log in with your credentials at /Account/Login.aspx
  3. Browse Products: View available computers at /Store/Products.aspx
  4. Configure Computer: Customize components at /Store/Configure.aspx
  5. Add to Cart: Add configured computers to shopping cart
  6. View Cart: Review cart items at /Store/Cart.aspx
  7. Checkout: Complete order at /Store/Checkout.aspx (requires login)
  8. View Orders: See order history at /Orders/MyOrders.aspx
  9. Order Details: View detailed order information at /Orders/OrderDetails.aspx
  10. Edit Order: Modify order items at /Orders/EditOrder.aspx
  11. Profile Management: Update account information at /Account/Profile.aspx

Accessing the Application

Technical Implementation Details

Password Hashing Implementation

private string HashPassword(string password) { using (SHA256 sha256Hash = SHA256.Create()) { byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(password)); StringBuilder builder = new StringBuilder(); for (int i = 0; i < bytes.Length; i++) { builder.Append(bytes[i].ToString("x2")); } return builder.ToString(); } }

JSON Serialization for Component Configurations

The application uses JSON to store component configurations in the database:

{"CPU":"cpu-i7","RAM":"ram-16","Storage":"ssd-512","GPU":"gpu-gtx1660", "Monitor":"monitor-none","Power Supply":"psu-750w","Case":"case-atx", "Operating System":"os-windows","Sound Card":"sound-logitech"}

Note: Storing component configurations as JSON is pretty flexible - we can add new component categories without messing with the database schema. I use Newtonsoft.Json for serialization, which is the go-to library for this. The JSON is stored as NVARCHAR in the database, which works fine for this. If I needed to query by specific components, I'd have to rethink this, but for now it works great.

Parameterized Query Example

All database queries use parameterized statements to prevent SQL injection:

var sql = "SELECT Id, FirstName, LastName, Email FROM Customers WHERE Email = @Email AND IsActive = 1"; var dataTable = DatabaseHelper.ExecuteDataTable(sql, new SqlParameter("@Email", email));

Note: I made sure to use parameterized queries everywhere - keeps SQL injection attacks from happening. I used SqlParameter objects for all user input, which automatically handles escaping and type conversion stuff.

Key Design Decisions

Note to Instructor: This is a complete e-commerce application demonstrating proper use of ADO.NET data access, session management, and database design principles. The application includes comprehensive customer management, order tracking, and security features. All database operations use parameterized queries for security, and the application automatically initializes the database structure on first run.

Personal note: Part 4 was definitely the hardest part of the whole assignment. Moving from hardcoded data to a real database was a big jump, and I had to learn a ton about ADO.NET, SQL Server, and database design. The most time-consuming part was getting all the order management stuff working right - especially the EditOrder page with dynamic price recalculation. That was a pain. I also spent way too much time debugging connection string issues and making sure the database initialization actually worked. Overall, I'm pretty happy with how it turned out, though there's definitely stuff I'd improve if I had more time (like adding an admin interface, better error handling, and more customization options). The progression from Part 1 to Part 4 really shows how web apps can get complicated fast!

Summary

This assignment showcases multiple sites using ASP.NET Web Forms:

All parts use consistent Bootstrap styling and follow ASP.NET Web Forms best practices. The progression demonstrates the evolution of web application complexity: starting with basic visitor tracking, moving to interactive slideshows, then building an initial e-commerce application (Part 3), and finally extending it into a full-featured database-driven system (Part 4)..

All Applications Accessible From: