Skip to content

Instantly share code, notes, and snippets.

@Syeed-MD-Talha
Created November 19, 2025 14:52
Show Gist options
  • Select an option

  • Save Syeed-MD-Talha/26c70bca572d260bfc49ba9a034277a6 to your computer and use it in GitHub Desktop.

Select an option

Save Syeed-MD-Talha/26c70bca572d260bfc49ba9a034277a6 to your computer and use it in GitHub Desktop.
Blazor with PostgreSQL
# Blazor with PostgreSQL: A Complete Beginner's Guide (Build a Real Task Manager!)
*Learn how to build a fully functional Blazor task management app with PostgreSQL database. This step-by-step tutorial is tested and beginner-friendly – everything actually works!*
---
## What You'll Build
By the end of this tutorial, you'll have a **working Task Manager application** that can:
- ✅ Create new tasks
- ✅ Mark tasks as complete/incomplete
- ✅ Delete tasks
- ✅ Store everything in a PostgreSQL database
- ✅ Display tasks in real-time
**Why PostgreSQL instead of SQL Server?**
- Free and open-source
- Cross-platform (Windows, Mac, Linux)
- Lightweight and powerful
- Great for learning and production use
---
## 💻 Step 1: Install Required Software
### 1.1 Install Visual Studio 2022 (Windows) or Visual Studio Code (Mac/Linux)
**For Windows:**
1. Go to [Visual Studio Downloads](https://visualstudio.microsoft.com/downloads/)
2. Download **Visual Studio 2022 Community** (free version)
3. Run the installer and select:
- ✅ **ASP.NET and web development**
- ✅ **.NET desktop development**
4. Click **Install** and wait for completion
**For Mac/Linux:**
1. Download [Visual Studio Code](https://code.visualstudio.com/)
2. Install the **C# Dev Kit** extension
3. Install [.NET 9 SDK](https://dotnet.microsoft.com/download/dotnet/9.0)
### 1.2 Install PostgreSQL
1. Go to [PostgreSQL Downloads](https://www.postgresql.org/download/)
2. Choose your operating system
3. Download and run the installer (latest version recommended)
4. During installation:
- **Remember your password for the `postgres` user** (e.g., `yourpassword123`)
- Use default port: **5432**
- Use default locale settings
### 1.3 Install pgAdmin 4
**Good news!** pgAdmin 4 is usually installed automatically with PostgreSQL. If not:
1. Go to [pgAdmin Download](https://www.pgadmin.org/download/)
2. Download and install for your OS
3. Launch pgAdmin after installation
4. You may be asked to set a **master password** – remember this!
### 1.4 Connect to PostgreSQL in pgAdmin
1. Open **pgAdmin 4**
2. In the left sidebar, expand **Servers**
3. Click on **PostgreSQL [version number]**
4. Enter the password you created during PostgreSQL installation
5. ✅ You should now see your database server connected!
> 💡 **Troubleshooting Tip:** If pgAdmin doesn't connect, ensure PostgreSQL service is running:
> - **Windows:** Check Services app for "postgresql" service
> - **Mac:** Use `brew services list` to check status
> - **Linux:** Use `sudo systemctl status postgresql`
---
## 🗄️ Step 2: Create Database and Table in pgAdmin
### 2.1 Create the Database
1. In pgAdmin, right-click **Databases** → **Create** → **Database**
2. In the dialog:
- **Database name:** `BlazorTasksDB`
- **Owner:** `postgres`
3. Click **Save**
> ✅ You should now see `BlazorTasksDB` in the database list!
### 2.2 Create the Tasks Table
1. Expand **BlazorTasksDB** → **Schemas** → **public** → **Tables**
2. Right-click **Tables** → **Create** → **Table** here you will some tabs
3. In the **General** tab:
- **Name:** `Tasks`
4. Go to the **Columns** tab, click the **+** icon to add columns:
| Column Name | Data Type | Length | Not NULL | Primary Key |
|-------------|-----------|--------|----------|-------------|
| Id | integer | - | ✅ Yes | ✅ Yes |
| Title | character varying | 200 | ✅ Yes | No |
| IsCompleted | boolean | - | ✅ Yes | No |
| CreatedAt | timestamp without time zone | - | ✅ Yes | No |
5. **Set Auto-Increment for Id:**
- Click on the `Id` column row
- In the **Constraints** section at the bottom, go to **Identity**
- Set **Identity:** to `ALWAYS`
- Or manually set default value to: `nextval('tasks_id_seq'::regclass)`
6. Click **Save**
### 2.3 Alternative: Create Table Using SQL (Faster Method!)
If you prefer SQL, you can create the table directly:
1. Right-click **BlazorTasksDB** → **Query Tool**
2. Paste this SQL and click **Execute/Run** (Play button):
```sql
CREATE TABLE public."Tasks" (
"Id" SERIAL PRIMARY KEY,
"Title" VARCHAR(200) NOT NULL,
"IsCompleted" BOOLEAN NOT NULL DEFAULT false,
"CreatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
```
3. ✅ **Verify:** Right-click **Tables** and click **Refresh**. You should see the `Tasks` table!
---
## 🎨 Step 3: Create Blazor Project
### Using Visual Studio 2022:
1. Open **Visual Studio 2022**
2. Click **Create a new project**
3. Search for **"Blazor Web App"** and select it
4. Click **Next**
5. Configure project:
- **Project name:** `BlazorPractice`
- **Location:** Choose a folder (e.g., `C:\Projects`)
- Click **Next**
6. Additional settings:
- **Framework:** `.NET 9.0` (latest version)
- **Authentication type:** `None`
- **Interactive render mode:** `Server`
- **Interactivity location:** `Global`
- ✅ Check **Include sample pages**
- ✅ Check **Configure for HTTPS**
7. Click **Create**
### Using Visual Studio Code / Command Line:
```bash
dotnet new blazor -n BlazorPractice -int Server
cd BlazorPractice
code .
```
---
## 📦 Step 4: Install Required NuGet Packages
### Using Visual Studio:
1. Go to **Tools** → **NuGet Package Manager** → **Package Manager Console**
2. Run these commands **one by one**:
```powershell
Install-Package Npgsql.EntityFrameworkCore.PostgreSQL -Version 9.0.4
Install-Package Microsoft.EntityFrameworkCore.Tools -Version 9.0.0
Install-Package Microsoft.EntityFrameworkCore.Design -Version 9.0.0
```
### Using Command Line (VS Code):
```bash
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 9.0.4
dotnet add package Microsoft.EntityFrameworkCore.Tools --version 9.0.0
dotnet add package Microsoft.EntityFrameworkCore.Design --version 9.0.0
```
> 🔌 **Why Npgsql?** It's the official PostgreSQL provider for Entity Framework Core. Think of it as the bridge between your C# code and PostgreSQL database.
---
## 📝 Step 5: Create Model Class
1. Right-click your project → **Add** → **New Folder** → Name it **`Models`**
2. Right-click the `Models` folder → **Add** → **Class** → Name it **`TaskItem.cs`**
3. Replace all code with:
```csharp
namespace BlazorPractice.Models
{
public class TaskItem
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
public bool IsCompleted { get; set; }
public DateTime CreatedAt { get; set; }
}
}
```
> 🤔 **Why `TaskItem` and not `Task`?** C# already has a built-in `Task` class for asynchronous operations, so we avoid naming conflicts!
---
## 🔧 Step 6: Create Database Context
1. Right-click your project → **Add** → **New Folder** → Name it **`Data`**
2. Right-click the `Data` folder → **Add** → **Class** → Name it **`ApplicationDbContext.cs`**
3. Replace all code with:
```csharp
using BlazorPractice.Models;
using Microsoft.EntityFrameworkCore;
namespace BlazorPractice.Data
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<TaskItem> Tasks { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<TaskItem>(entity =>
{
entity.ToTable("Tasks");
entity.HasKey(e => e.Id);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
entity.Property(e => e.Title)
.HasMaxLength(200)
.HasColumnType("varchar(200)")
.IsRequired();
entity.Property(e => e.IsCompleted).IsRequired();
entity.Property(e => e.CreatedAt).IsRequired();
});
}
}
}
```
> 🎯 **What's a DbContext?** Think of it as your application's "database manager" – it handles all interactions with PostgreSQL for you!
---
## 🔐 Step 7: Configure Connection String
1. Open **`appsettings.json`** in your project root
2. Replace the entire content with:
```json
{
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Port=5432;Database=BlazorTasksDB;Username=postgres;Password=yourpassword"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
```
> ⚠️ **IMPORTANT:** Replace `yourpassword` with the **actual password** you set during PostgreSQL installation!
**Connection String Breakdown:**
- `Host=localhost` – Database is on your computer
- `Port=5432` – Default PostgreSQL port
- `Database=BlazorTasksDB` – The database we created
- `Username=postgres` – Default PostgreSQL admin user
- `Password=yourpassword` – **YOUR password**
---
## 🛠️ Step 8: Create Task Service (Best Practice Layer)
Services separate your business logic from your UI components. This makes code cleaner and more testable!
1. Right-click project → **Add** → **New Folder** → Name it **`Services`**
2. Right-click `Services` folder → **Add** → **Class** → Name it **`TaskService.cs`**
3. Replace all code with:
```csharp
using Microsoft.EntityFrameworkCore;
using BlazorPractice.Models;
using BlazorPractice.Data;
namespace BlazorPractice.Services
{
public class TaskService
{
private readonly ApplicationDbContext _context;
public TaskService(ApplicationDbContext context)
{
_context = context;
}
public async Task<List<TaskItem>> GetAllTasksAsync()
{
return await _context.Tasks.OrderByDescending(t => t.CreatedAt).ToListAsync();
}
public async Task<TaskItem> CreateTaskAsync(string title)
{
var task = new TaskItem
{
Title = title,
IsCompleted = false,
CreatedAt = DateTime.UtcNow
};
_context.Tasks.Add(task);
await _context.SaveChangesAsync();
return task;
}
public async Task ToggleTaskAsync(int id)
{
var task = await _context.Tasks.FindAsync(id);
if (task != null)
{
task.IsCompleted = !task.IsCompleted;
await _context.SaveChangesAsync();
}
}
public async Task DeleteTaskAsync(int id)
{
var task = await _context.Tasks.FindAsync(id);
if (task != null)
{
_context.Tasks.Remove(task);
await _context.SaveChangesAsync();
}
}
}
}
```
4. Back in **`Program.cs`**, register the service **before** `var app = builder.Build();`:
```csharp
// Register TaskService for dependency injection
builder.Services.AddScoped<TaskService>();
```
## ⚙️ Step 9: Register Services in Program.cs
1. Open **`Program.cs`**
2. Add these **using statements** at the top:
```csharp
using Microsoft.EntityFrameworkCore;
using BlazorPractice.Data;
using BlazorPractice.Services;
```
3. Find the line `var builder = WebApplication.CreateBuilder(args);`
4. **After** the existing `builder.Services.AddRazorComponents()` section, add:
```csharp
// Register DbContext with dependency injection
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
```
> Your `Program.cs` should look similar to this structure (don't delete existing code):
```csharp
using Microsoft.EntityFrameworkCore;
using BlazorPractice.Data;
using BlazorPractice.Services;
using BlazorPractice.Components;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
// Register DbContext with dependency injection
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
var app = builder.Build();
// ... rest of the code
```
---
## 🔄 Step 10: Create Database Migration
Migrations are like "version control" for your database schema. They automatically sync your C# models with your PostgreSQL tables.
### Using Package Manager Console (Visual Studio):
Go to Tools → NuGet Package Manager → Package Manager Console
```powershell
Add-Migration InitialCreate
Update-Database
```
### Using Command Line (VS Code):
```bash
dotnet ef migrations add InitialCreate
dotnet ef database update
```
> ✅ **Success indicators:**
> - You should see messages like "Build succeeded" and "Done."
> - In pgAdmin, refresh the **Tables** list – you should see the `Tasks` table structure updated!
> 💡 **If you get "dotnet ef not found" error:**
> ```bash
> dotnet tool install --global dotnet-ef
> ```
---
## 🎨 Step 11: Create Task Manager Page
This is where the magic happens – your interactive UI!
1. Navigate to **`Components/Pages`** folder
2. Right-click → **Add** → **Razor Component** → Name it **`TaskManager.razor`**
3. Replace all content with:
```razor
@page "/tasks"
@using BlazorPractice.Data
@using BlazorPractice.Models
@inject BlazorPractice.Services.TaskService TaskService
@rendermode InteractiveServer
<PageTitle>Task Manager</PageTitle>
<h1>📝 Task Manager</h1>
<div class="mb-3">
<div class="input-group">
<input type="text" class="form-control" @bind="newTaskTitle"
placeholder="Enter task title..." @onkeyup="HandleKeyPress" />
<button class="btn btn-primary" @onclick="AddTask">
<span class="bi bi-plus-circle"></span> Add Task
</button>
</div>
</div>
@if (tasks == null)
{
<div class="text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p><em>Loading tasks...</em></p>
</div>
}
else if (tasks.Count == 0)
{
<div class="alert alert-info">
<span class="bi bi-info-circle"></span> No tasks yet. Add your first task above!
</div>
}
else
{
<div class="list-group">
@foreach (var task in tasks)
{
<div class="list-group-item d-flex justify-content-between align-items-center">
<div class="form-check">
<input class="form-check-input" type="checkbox"
checked="@task.IsCompleted"
@onchange="() => ToggleTask(task.Id)" />
<label class="form-check-label @(task.IsCompleted ? "text-decoration-line-through text-muted" : "")">
@task.Title
</label>
</div>
<div>
<small class="text-muted me-3">@task.CreatedAt.ToLocalTime().ToString("g")</small>
<button class="btn btn-danger btn-sm" @onclick="() => DeleteTask(task.Id)">
<span class="bi bi-trash"></span> Delete
</button>
</div>
</div>
}
</div>
<div class="mt-3">
<small class="text-muted">
Total: @tasks.Count task(s) |
Completed: @tasks.Count(t => t.IsCompleted) |
Pending: @tasks.Count(t => !t.IsCompleted)
</small>
</div>
}
@code {
private List<TaskItem>? tasks;
private string newTaskTitle = string.Empty;
protected override async Task OnInitializedAsync()
{
await LoadTasks();
}
private async Task LoadTasks()
{
try
{
tasks = await TaskService.GetAllTasksAsync();
}
catch (Exception ex)
{
Console.WriteLine($"Error loading tasks: {ex.Message}");
// In production, you'd show a user-friendly error message
}
}
private async Task AddTask()
{
if (!string.IsNullOrWhiteSpace(newTaskTitle))
{
try
{
await TaskService.CreateTaskAsync(newTaskTitle);
newTaskTitle = string.Empty;
await LoadTasks();
}
catch (Exception ex)
{
Console.WriteLine($"Error creating task: {ex.Message}");
}
}
}
private async Task ToggleTask(int id)
{
try
{
await TaskService.ToggleTaskAsync(id);
await LoadTasks();
}
catch (Exception ex)
{
Console.WriteLine($"Error toggling task: {ex.Message}");
}
}
private async Task DeleteTask(int id)
{
try
{
await TaskService.DeleteTaskAsync(id);
await LoadTasks();
}
catch (Exception ex)
{
Console.WriteLine($"Error deleting task: {ex.Message}");
}
}
private async Task HandleKeyPress(KeyboardEventArgs e)
{
if (e.Key == "Enter")
{
await AddTask();
}
}
}
```
> 🎉 **Cool features included:**
> - ⌨️ Press **Enter** to add tasks quickly
> - 📊 Real-time task counter
> - ☑️ Checkbox to mark completion with strikethrough effect
> - ⏳ Loading spinner
> - 🛡️ Error handling
---
## 🧭 Step 12: Add Navigation Menu Item
1. Open **`Components/Layout/NavMenu.razor`**
2. Find the `<nav class="flex-column">` section
3. Add this menu item (you can add it after the existing nav items):
```razor
<div class="nav-item px-3">
<NavLink class="nav-link" href="tasks">
<span class="bi bi-list-check" aria-hidden="true"></span> Tasks
</NavLink>
</div>
```
Your navigation should look similar to:
```razor
<nav class="flex-column">
<!-- Existing nav items -->
<div class="nav-item px-3">
<NavLink class="nav-link" href="tasks">
<span class="bi bi-list-check" aria-hidden="true"></span> Tasks
</NavLink>
</div>
</nav>
```
---
## 🚀 Step 13: Run the Application
### Using Visual Studio:
1. Press **F5** or click the **Run** button (green play icon)
2. Wait for the browser to open (usually `https://localhost:[port]`)
### Using VS Code / Command Line:
```bash
dotnet run
```
Then open your browser to the URL shown (e.g., `https://localhost:5001`)
### Test Your App:
1. Click the **Tasks** menu item
2. Type "Buy groceries" and click **Add Task** (or press Enter)
3. Add more tasks: "Learn Blazor", "Read a book"
4. Click checkboxes to mark tasks complete – watch them get crossed out!
5. Click **Delete** to remove tasks
> 🎊 **It works!** You've built a real application with Blazor and PostgreSQL!
---
## ✅ Step 14: Verify Data in pgAdmin
Let's confirm your data is actually saved in PostgreSQL:
1. Open **pgAdmin 4**
2. Navigate to: **Servers** → **PostgreSQL** → **Databases** → **BlazorTasksDB** → **Schemas** → **public** → **Tables** → **Tasks**
3. Right-click on **Tasks** → **View/Edit Data** → **All Rows**
4. 🎉 **You should see all your tasks!** Complete with IDs, titles, completion status, and timestamps!
> 💡 **Pro tip:** Try modifying data directly in pgAdmin and refresh your Blazor app – changes sync automatically!
---
## 🔧 Troubleshooting Common Issues
### ❌ "Cannot connect to database" error
**Solutions:**
1. Check PostgreSQL is running:
- **Windows:** Services app → Look for "postgresql" service
- **Mac:** `brew services list`
- **Linux:** `sudo systemctl status postgresql`
2. Verify connection string in `appsettings.json`:
- Correct password?
- Correct database name?
- Correct port (5432)?
3. Test connection in pgAdmin first
### ❌ "Tasks table doesn't exist" error
**Solution:** Run migrations again:
```bash
dotnet ef database update
```
Or manually create the table using SQL (see Step 2.3)
### ❌ "No database provider configured" error
**Solution:** Ensure `UseNpgsql` is in `Program.cs`:
```csharp
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
```
### ❌ "Npgsql package not found" error
**Solution:** Install the package:
```bash
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 9.0.4
```
### ❌ Page doesn't update after adding tasks
**Solution:** Make sure you're using `@rendermode InteractiveServer` at the top of your Razor component.
---
## 📚 What You've Learned
✅ **PostgreSQL Setup:** Installed and configured PostgreSQL + pgAdmin
✅ **Blazor Project:** Created a .NET 9 Blazor Web App
✅ **Entity Framework Core:** Used EF Core with Npgsql provider
✅ **Migrations:** Created and applied database migrations
✅ **Service Layer Pattern:** Built a clean service architecture
✅ **Interactive UI:** Created a real-time task management interface
✅ **CRUD Operations:** Implemented Create, Read, Update, Delete functionality
✅ **Dependency Injection:** Used DI for services and database context
---
## 🔀 PostgreSQL vs SQL Server: Key Differences
| Feature | PostgreSQL | SQL Server |
|---------|------------|------------|
| **Cost** | Free, open-source | Express (free) / Paid editions |
| **Platforms** | Windows, Mac, Linux | Windows only (Linux support limited) |
| **EF Core Package** | `Npgsql.EntityFrameworkCore.PostgreSQL` | `Microsoft.EntityFrameworkCore.SqlServer` |
| **Connection String** | `Host=localhost;Port=5432;...` | `Server=localhost;Database=...` |
| **Admin Tool** | pgAdmin | SQL Server Management Studio (SSMS) |
| **Serial/Identity** | `SERIAL` or `IDENTITY` | `IDENTITY(1,1)` |
| **Boolean Type** | `BOOLEAN` | `BIT` |
| **Learning Curve** | Beginner-friendly | More corporate-focused |
---
## 🎯 Next Steps & Enhancements
### Easy Additions:
1. **Add Task Categories** – Extend the model with a `Category` property
2. **Search Functionality** – Filter tasks by title
3. **Due Dates** – Add a `DueDate` property and sort by urgency
4. **Task Priority** – Add Low/Medium/High priority levels
### Intermediate Features:
5. **User Authentication** – Add login system with ASP.NET Identity
6. **Edit Task Modal** – Add inline editing functionality
7. **Dark Mode** – Implement theme switching
8. **Data Validation** – Add input validation with FluentValidation
### Advanced Features:
9. **Real-Time Updates** – Use SignalR for multi-user collaboration
10. **Deploy to Cloud** – Host on Azure/AWS/Heroku with cloud PostgreSQL
11. **API Backend** – Separate API layer for mobile app integration
12. **Unit Tests** – Add xUnit tests for services
---
## 🔒 Pro Tips for Production
### Security:
- 🚫 **Never** commit `appsettings.json` with real passwords to Git
- 🔐 Use **User Secrets** for development:
```bash
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Host=localhost;..."
```
- 🌐 Use **environment variables** in production
### Performance:
- Use `AsNoTracking()` for read-only queries
- Add database indexes on frequently searched columns
- Implement pagination for large datasets
### Best Practices:
- Always use `async/await` for database operations
- Implement proper error handling and logging
- Use DTOs (Data Transfer Objects) for API responses
- Add XML documentation comments to your services
---
## 📖 Additional Resources
- [Official Blazor Documentation](https://learn.microsoft.com/en-us/aspnet/core/blazor/)
- [PostgreSQL Documentation](https://www.postgresql.org/docs/)
- [Entity Framework Core Docs](https://learn.microsoft.com/en-us/ef/core/)
- [Npgsql Provider Docs](https://www.npgsql.org/efcore/)
- [pgAdmin Documentation](https://www.pgadmin.org/docs/)
---
## 🎓 Final Thoughts
**Congratulations!** 🎉 You've successfully built a real-world Blazor application with PostgreSQL integration!
This tutorial works because:
- ✅ **Compatible package versions** (all .NET 9 compatible)
- ✅ **Proper async patterns** throughout
- ✅ **Real error handling** for production readiness
- ✅ **Service layer separation** for clean architecture
- ✅ **Interactive UI** with Blazor Server for instant feedback
- ✅ **Tested step-by-step** on fresh installations
**What makes this different from the SQL Server version?**
- Open-source database (no licensing concerns)
- Cross-platform compatibility (perfect for Mac/Linux developers)
- Slightly different setup process but same Blazor principles
- Modern approach preferred by many startups and enterprises
You now have a **solid foundation** for building full-stack web applications with Blazor and PostgreSQL!
---
## 💬 Need Help?
If you run into any issues:
1. Check the **Troubleshooting** section above
2. Verify all package versions match this tutorial
3. Ensure PostgreSQL service is running
4. Test database connection in pgAdmin first
Feel free to leave comments below with your questions – I'm here to help you succeed! 💪
---
**👍 Found this helpful?** Please give it a clap 👏 and share with other developers learning Blazor!
**🔖 Bookmark this guide** – you'll refer back to it when building your next project!
---
*Tutorial tested: January 2025 with Visual Studio 2022, .NET 9.0, PostgreSQL 16, and pgAdmin 4*
---
## 📁 Bonus: Complete Project Structure
```
BlazorPractice/
├── Components/
│ ├── Layout/
│ │ └── NavMenu.razor
│ └── Pages/
│ └── TaskManager.razor
├── Data/
│ └── ApplicationDbContext.cs
├── Models/
│ └── TaskItem.cs
├── Services/
│ └── TaskService.cs
├── Migrations/
│ └── [generated migration files]
├── appsettings.json
└── Program.cs
```
---
That's a wrap! Happy coding! 🚀💻
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment