Building CRUD Apps with Blazor and MongoDB
Blazor is a free, open-source web framework from Microsoft that enables developers to create interactive web UIs using C# instead of JavaScript. It leverages the power of WebAssembly to run .NET code directly in web browsers while reusing server-side programming models.
MongoDB is a popular NoSQL database that stores data as flexible JSON-like documents. Its schema-less model is a great fit for the fast-changing requirements of web apps. MongoDB‘s rich query language, horizontal scalability and high performance make it an excellent choice for modern applications.
In this tutorial, we‘ll build a web app from scratch to demonstrate how to perform CRUD (Create, Read, Update, Delete) operations with Blazor and MongoDB. You‘ll learn how to:
- Set up a Blazor WebAssembly App with a MongoDB database
- Define data models and database context
- Implement CRUD functionalities with Blazor and MongoDB
- Handle concurrency, validation and error scenarios
- Optimize performance and scalability
By the end of this tutorial, you‘ll have a good understanding of using Blazor with MongoDB to build full-stack web apps. Let‘s get started!
Prerequisites
Before we dive in, make sure you have the following installed:
- .NET 5 SDK or later
- Visual Studio 2019 with the ASP.NET and web development workload
- MongoDB Server (Community Edition 4.4 or later)
- MongoDB client tool (e.g. MongoDB Compass, Robo 3T)
Setting up a New Blazor Project
Open Visual Studio and create a new Blazor WebAssembly App project. Let‘s call it "BlazorMongoCrud".
In the next dialog, select the "ASP.NET Core hosted" option which will create a solution with three projects:
- BlazorMongoCrud.Client – The Blazor WebAssembly app
- BlazorMongoCrud.Server – The ASP.NET Core host serving the Blazor app and API endpoints
- BlazorMongoCrud.Shared – A shared project for common code
Adding MongoDB Support
To use MongoDB with .NET, we need to install the official MongoDB driver. Right-click on the BlazorMongoCrud.Server project, select "Manage NuGet Packages" and install the MongoDB.Driver
package.
Defining Data Models
Let‘s define the data models for our application. We‘ll build a simple Task Management app where users can create, view, update and delete tasks.
Create a Models
folder in the BlazorMongoCrud.Shared project and add a new class named TaskModel
:
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System;
namespace BlazorMongoCrud.Shared.Models
{
public class TaskModel
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public bool IsComplete { get; set; }
public DateTime CreatedAt { get; set; }
}
}
The TaskModel
class defines the structure of task documents in MongoDB. The [BsonId]
attribute marks the Id
property as the document‘s primary key. We also specify the [BsonRepresentation]
attribute to store the Id
as MongoDB‘s native ObjectId
type.
Configuring Database Connection
Next, let‘s set up the connection to our MongoDB database. In the BlazorMongoCrud.Server project, open the appsettings.json
file and add the MongoDB connection string:
{
"MongoDbSettings": {
"ConnectionString": "mongodb://localhost:27017",
"DatabaseName": "TasksDb",
"TasksCollectionName": "Tasks"
}
}
Make sure to replace the ConnectionString
with your actual MongoDB server URL. The DatabaseName
and TasksCollectionName
specify the names of the database and collection to use for storing tasks.
To load these settings, create a new class named MongoDbSettings
in the BlazorMongoCrud.Server project:
namespace BlazorMongoCrud.Server.Models
{
public class MongoDbSettings
{
public string ConnectionString { get; set; }
public string DatabaseName { get; set; }
public string TasksCollectionName { get; set; }
}
}
Then add the following code to the ConfigureServices
method in Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MongoDbSettings>(
Configuration.GetSection(nameof(MongoDbSettings)));
services.AddSingleton<IMongoDbSettings>(sp =>
sp.GetRequiredService<IOptions<MongoDbSettings>>().Value);
// other services
}
This code retrieves the MongoDB configuration settings and registers the IMongoDbSettings
service for dependency injection.
Creating the Database Context
Now we need to create a database context class to interact with MongoDB. In the BlazorMongoCrud.Server project, create a new class named TaskContext
:
using BlazorMongoCrud.Server.Models;
using BlazorMongoCrud.Shared.Models;
using MongoDB.Driver;
namespace BlazorMongoCrud.Server.Data
{
public class TaskContext
{
private readonly IMongoDatabase _database;
public TaskContext(IMongoDbSettings settings)
{
var client = new MongoClient(settings.ConnectionString);
_database = client.GetDatabase(settings.DatabaseName);
}
public IMongoCollection<TaskModel> Tasks =>
_database.GetCollection<TaskModel>("Tasks");
}
}
The TaskContext
class takes an IMongoDbSettings
instance in its constructor to retrieve the connection settings. It creates a MongoClient
and gets a reference to the specified database. The Tasks
property provides access to the "Tasks" collection using the GetCollection
method.
Implementing CRUD Operations
With the setup out of the way, let‘s implement the CRUD operations for tasks. We‘ll create an API controller to handle HTTP requests from the Blazor UI.
In the BlazorMongoCrud.Server project, create a new class named TasksController
in the Controllers
folder:
using BlazorMongoCrud.Server.Data;
using BlazorMongoCrud.Shared.Models;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Driver;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace BlazorMongoCrud.Server.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class TasksController : ControllerBase
{
private readonly TaskContext _context;
public TasksController(TaskContext context)
{
_context = context;
}
[HttpGet]
public async Task<IEnumerable<TaskModel>> GetTasks()
{
return await _context.Tasks.Find(_ => true).ToListAsync();
}
[HttpGet("{id}")]
public async Task<ActionResult<TaskModel>> GetTask(string id)
{
var task = await _context.Tasks.Find(t => t.Id == id).FirstOrDefaultAsync();
if (task == null)
{
return NotFound();
}
return task;
}
[HttpPost]
public async Task<ActionResult<TaskModel>> CreateTask(TaskModel task)
{
await _context.Tasks.InsertOneAsync(task);
return CreatedAtAction(nameof(GetTask), new { id = task.Id }, task);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateTask(string id, TaskModel taskUpdate)
{
var task = await _context.Tasks.Find(t => t.Id == id).FirstOrDefaultAsync();
if (task == null)
{
return NotFound();
}
taskUpdate.Id = task.Id;
await _context.Tasks.ReplaceOneAsync(t => t.Id == id, taskUpdate);
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTask(string id)
{
var task = await _context.Tasks.Find(t => t.Id == id).FirstOrDefaultAsync();
if (task == null)
{
return NotFound();
}
await _context.Tasks.DeleteOneAsync(t => t.Id == id);
return NoContent();
}
}
}
The TasksController
defines API methods for each CRUD operation:
GetTasks
– Retrieves all tasks from the "Tasks" collection using theFind
methodGetTask
– Retrieves a single task by ID usingFind
andFirstOrDefaultAsync
CreateTask
– Inserts a new task document passed in the request body usingInsertOneAsync
UpdateTask
– Updates an existing task by ID usingReplaceOneAsync
DeleteTask
– Deletes a task by ID usingDeleteOneAsync
These methods use the injected TaskContext
to access the MongoDB collection. The controller methods return appropriate HTTP status codes and response data.
Building the Blazor UI
Finally, let‘s create the Blazor pages for the task management UI. In the BlazorMongoCrud.Client project, open the Pages
folder and add a new Razor component named TaskList.razor
:
@page "/tasks"
@inject HttpClient Http
@if (tasks == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Is Complete</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var task in tasks)
{
<tr>
<td>@task.Title</td>
<td>@task.Description</td>
<td>@task.IsComplete</td>
<td>
<button class="btn btn-primary"
@onclick="(() => ShowEditDialog(task))">
Edit
</button>
<button class="btn btn-danger"
@onclick="(() => DeleteTask(task))">
Delete
</button>
</td>
</tr>
}
</tbody>
</table>
<button class="btn btn-success"
@onclick="ShowCreateDialog">
Create New Task
</button>
}
@code {
private IEnumerable<TaskModel> tasks;
protected override async Task OnInitializedAsync()
{
tasks = await Http.GetFromJsonAsync<IEnumerable<TaskModel>>("api/tasks");
}
private async Task DeleteTask(TaskModel task)
{
await Http.DeleteAsync($"api/tasks/{task.Id}");
tasks = await Http.GetFromJsonAsync<IEnumerable<TaskModel>>("api/tasks");
}
private void ShowCreateDialog()
{
// TODO: Implement create dialog
}
private void ShowEditDialog(TaskModel task)
{
// TODO: Implement edit dialog
}
}
This component displays a list of tasks in a table. It injects the HttpClient
to make API calls to the server. The OnInitializedAsync
lifecycle method is overridden to fetch the tasks from the API when the component is initialized.
The DeleteTask
method sends a DELETE request to remove a task by ID. The ShowCreateDialog
and ShowEditDialog
methods are placeholders for displaying modal dialogs to create and edit tasks.
You can implement the create and edit dialogs by adding additional Razor components and methods to handle form submission and API calls.
Putting It All Together
With the backend API and Blazor UI in place, you can run the application and test the CRUD functionalities. Launch the BlazorMongoCrud.Server project and navigate to the "/tasks" route to see the task list.
As you interact with the app, it will make API requests to perform the corresponding database operations. MongoDB will efficiently handle these operations, allowing for seamless data persistence and retrieval.
Tips and Considerations
Here are a few additional tips and considerations to keep in mind when building Blazor apps with MongoDB:
-
Error Handling: Implement proper error handling and logging in the API controllers and Blazor components. Display user-friendly error messages and handle exceptions gracefully.
-
Validation: Add input validation on both the client-side (Blazor) and server-side (API) to ensure data integrity and prevent invalid data from being persisted.
-
Concurrency: Consider implementing optimistic or pessimistic concurrency control mechanisms to handle scenarios where multiple users may modify the same document simultaneously.
-
Pagination: For large datasets, implement pagination to load and display data in smaller chunks. This improves performance and user experience.
-
Caching: Utilize caching mechanisms, such as in-memory caching or distributed caching (e.g., Redis), to store frequently accessed data and reduce the load on the database.
-
Indexing: Create appropriate indexes on frequently queried fields in MongoDB to optimize query performance. Analyze query patterns and create indexes accordingly.
-
Security: Implement authentication and authorization mechanisms to secure your application. Use token-based authentication (e.g., JWT) to protect API endpoints and restrict access to authorized users only.
Conclusion
In this tutorial, we explored how to build a web application using Blazor and MongoDB. We set up a Blazor WebAssembly project, integrated MongoDB, and implemented CRUD operations on the backend API. We also created a basic Blazor UI to interact with the tasks data.
Blazor and MongoDB provide a powerful combination for building modern, interactive web applications. Blazor‘s component-based architecture and C# support make it easy to create dynamic UIs, while MongoDB‘s flexibility and scalability make it suitable for handling diverse data requirements.
By following the techniques and best practices outlined in this tutorial, you can create efficient and robust CRUD applications using Blazor and MongoDB. Remember to handle errors, implement validation, and optimize performance to deliver a smooth user experience.
I hope this tutorial has been helpful in getting you started with building Blazor apps with MongoDB. Happy coding!