Master ASP.NET Core 2.1 : Instructor-led online course conducted by Bipin Joshi. Next batch starting from 30 December 2018. Limited seats. More details are available here.

Use MongoDB in ASP.NET Core (Part - 2, CRUD operations)

In Part 1 of this article we discussed how to perform CRUD operations using MongoDB console client. In this part we will learn to perform CRUD operations using ASP.NET Core and MongoDB driver for .NET Core.

Ok. Let's begin.

Our ASP.NET Core application that we are going to develop in this article looks like this :

The Index view shown above renders a list of employees in a MongoDB database (FirstDatabase that we created in Part - 1). You can then add new employees, modify existing employees, or delete an employee.

Begin by creating a new ASP.NET Core MVC application. To work with MongoDB database we need to add a NuGet package - MongoDB.Driver. The following figure shows this package in Manage NuGet Packages dialog.

This package provides a MongoDB driver that you can use to connect with the database and perform database operations.

Creating Employee model

Next, add a model class named Employee in the Models folder. This class represents the document that you wish to store in a MongoDB collection.

public class Employee
{
    [BsonId]
    public ObjectId Id { get; set; }

    [BsonElement]
    public int EmployeeID { get; set; }

    [BsonElement]
    public string FirstName { get; set; }

    [BsonElement]
    public string LastName { get; set; }
}

The Employee class consists of four properties namely Id, EmployeeID, FirstName, and LastName. The Id property is the _id value assigned by MongoDB and hence it is decorated with [BsonId] attribute. The EmployeeID, FirstName, and LastName properties are decorated with [BsonElement] attribute indicating that they are BSON (binary representation of JSON data) elements.

Now open the HomeController and add the following code to it :

public class HomeController : Controller
{
    private IMongoCollection<Employee> collection;

    public HomeController()
    {
        var client = new MongoClient("mongodb://localhost:27017");
        IMongoDatabase db = client.GetDatabase("FirstDatabase");
        this.collection = db.GetCollection<Employee>("Employees");
    }
}

The code declares a class level variable of IMongoCollection<Employee>. The IMongoCollection interface represents a MongoDB collection.

The constructor creates an instance of MongoClient. As the name suggests the MongoClient class acts as a client to the MongoDB database server. We pass a URI that specifies a port where MongoDB server is listening. The default port is 27017 and you can also see it on the Mongod console window (read Part -1 for more details).

Then we call GetDatabase() method on the MongoClient and specify the database name to connect (FirstDatabase in this case). The GetDatabase() return an IMongoDatabase object. Then Employees collection is retrieved using the GetCollection() method of IMongoDatabase.

Now that we have access to the Employees collection, we can use it to perform CRUD operations.

Displaying a list of employees

Modify the Index() action of HomeController as shown below :

public IActionResult Index()
{
    var model = collection.Find
(FilterDefinition<Employee>.Empty).ToList();

    return View(model);
}

The above code calls the Find() method on the Employees collection to retrieve a list of all employees. The Find() method accepts a FilterDefination object representing a find criteria. Since we want to fetch all the records we pass Empty there. The List of Employee objects is then passed to the Index view.

The Index.cshtml that renders the Employee list is shown below :

@model List<MongoDBDemo.Models.Employee>


<h1>List of Employees</h1>

<h2>@TempData["Message"]</h2>

<a asp-controller="Home" asp-action="Insert">
Add New Employee</a>

<br /><br />


<table border="1" cellpadding="10">
    @foreach(var item in Model)
    {
    <tr>
        <td>@item.EmployeeID</td>
        <td>@item.FirstName</td>
        <td>@item.LastName</td>
        <td>
            <a asp-controller="Home" asp-action="Update" 
asp-route-id="@item.Id">Edit</a>
        </td>
        <td>
            <a asp-controller="Home" asp-action="ConfirmDelete" 
asp-route-id="@item.Id">Delete</a>
        </td>

    </tr>
    }
</table>

The Index view is quite straightforward and hence I won't go into too much details. Note that ObjectId of an Employee is passed in the route parameter in the Edit and Delete links.

Adding a new Employee

When you click Add New Employee link on the Index view, you are taken to the Insert view :

Here you can enter an Employee details such as EmployeeID, FirstName, and LastName and hit the Save button to add the Employee.

The following markup shows how Insert.cshtml does its job :

@model MongoDBDemo.Models.Employee


<h1>Insert Employee</h1>

<h2>@ViewBag.Message</h2>

<form asp-controller="Home" asp-action="Insert" 
method="post">
<table border="1" cellpadding="10">
    <tr>
        <td>Employee ID :</td>
        <td><input asp-for="EmployeeID" /></td>
    </tr>
    <tr>
        <td>First Name :</td>
        <td><input asp-for="FirstName" /></td>
    </tr>
    <tr>
        <td>Last Name :</td>
        <td><input asp-for="LastName" /></td>
    </tr>
    <tr>
        <td colspan="2">
            <button type="submit">Save</button>
        </td>
    </tr>
</table>
</form>

Notice that the <form> POSTs to Insert() action.

The two Insert() actions responsible for adding the Employee are shown below :

public IActionResult Insert()
{
    return View();
}

[HttpPost]
public IActionResult Insert(Employee emp)
{
    collection.InsertOne(emp);
    ViewBag.Message = "Employee added successfully!";
    return View();
}

Notice t he code shown in bold letters. We call InsertOne() method on Employees collection to add a new employee. A success message is also displayed on the Insert view.

Modifying an existing Employee

When you click on the Edit link of a particular employee from the listing, you are taken to the Update view shown below :

The Update view looks similar to the Insert view but it shows an existing Employee details for editing.

The markup of Update,cshtml is shown below :

@model MongoDBDemo.Models.Employee


<h1>Update Employee</h1>

<h2>@ViewBag.Message</h2>

<form asp-controller="Home" asp-action="Update" method="post">

    <input type="hidden" name="Id" value="@Model.Id.ToString()" />

    <table border="1" cellpadding="10">
        <tr>
            <td>Employee ID :</td>
            <td><input asp-for="EmployeeID" 
readonly="readonly" /></td>
        </tr>
        <tr>
            <td>First Name :</td>
            <td><input asp-for="FirstName" /></td>
        </tr>
        <tr>
            <td>Last Name :</td>
            <td><input asp-for="LastName" /></td>
        </tr>
        <tr>
            <td colspan="2">
                <button type="submit">Save</button>
            </td>
        </tr>
    </table>
</form>

Notice the code marked in bold letters. We store the Id property of the Employee being edited into a hidden form field. This is required for model binding to work as expected. We need Id during update operation and hence we store it this way.

Also notice that EmployeeID textbox is marked as readonly since we don't want to modify this field.

The Update <form> submits to Update() action. The two Update() actions responsible for the update operation are shown below :

public IActionResult Update(string id)
{
    ObjectId oId = new ObjectId(id);
    Employee emp = collection.Find(e => e.Id 
== oId).FirstOrDefault();

    return View(emp);
}

[HttpPost]
public IActionResult Update(string id,Employee emp)
{
    emp.Id = new ObjectId(id);
    var filter = Builders<Employee>.
Filter.Eq("Id", emp.Id);
    var updateDef = Builders<Employee>.Update.
Set("FirstName", emp.FirstName);
    updateDef = updateDef.Set("LastName", emp.LastName);
    var result = collection.UpdateOne(filter, updateDef);

    if (result.IsAcknowledged)
    {
        ViewBag.Message = "Employee updated successfully!";
    }
    else
    {
        ViewBag.Message = "Error while updating Employee!";
    }
    return View(emp);
}

The GET Update() action converts the string id into an ObjectId and then passes to the Find() method. This way we retrieve an Employee whose Id matches with what was passed in the id route parameter.

The POST Update() action updates the modified Employee into the database. To accomplish this task we prepare a FilterDefinition and an UpdateDefinition. The FilterDefinition specifies a criteria used while updating a document. In our case the criteria specifies that Id property should match with the specified Employee's Id value. The UpdateDefinition specifies the modified properties and their new values.

Then we call UpdateOne() method on the Employees collection and pass the FilterDefinition and UpdateDefinition objects we just constructed.

The result.IsAcknowledged property tells us whether the update operation was successful or now.

Deleting an existing Employee

When you click on the Delete link on the Index view, you are taken to the ConfirmDelete view. This view is shown below :

Upon clicking the Delete button Delete() action is called and the Employee is removed from the database. The markup of ConfirmDelete.cshtml is shown below :

@model MongoDBDemo.Models.Employee


<h2>Do you want to delete this employee?</h2>

<form asp-controller="Home" asp-action="Delete" method="post">

    <input type="hidden" name="Id" 
value="@Model.Id.ToString()" />

    <table border="1" cellpadding="10">
        <tr>
            <td>Employee ID :</td>
            <td>@Model.EmployeeID</td>
        </tr>
        <tr>
            <td>First Name :</td>
            <td>@Model.FirstName</td>
        </tr>
        <tr>
            <td>Last Name :</td>
            <td>@Model.LastName</td>
        </tr>
        <tr>
            <td colspan="2">
                <button type="submit">Delete</button>
            </td>
        </tr>
    </table>
</form>

The ConfirmDelete view also stores the ObjectId into a hidden form field. The ConfirmDelete() action and the Delete() action is shown below :

public IActionResult ConfirmDelete(string id)
{
    ObjectId oId = new ObjectId(id);
    Employee emp = collection.Find(e => 
e.Id == oId).FirstOrDefault();
    return View(emp);
}


[HttpPost]
public IActionResult Delete(string id)
{
    ObjectId oId = new ObjectId(id);
    var result = collection.DeleteOne<Employee>
(e => e.Id == oId);

    if (result.IsAcknowledged)
    {
        TempData["Message"] = "Employee deleted successfully!";
    }
    else
    {
        TempData["Message"] = "Error while deleting Employee!";
    }
    return RedirectToAction("Index");
}

The ConfirmDelete() action is quite similar to Update() GET action. The Delete() action accepts the Id of an Employee to be deleted and converts it into an ObjectId. The DeleteOne() method of Employees collection specifies the deletion criteria to be the matching Id value.

This completes all that is required to perform CRUD operations. Before you run the ASP.NET Core application make sure to start the MongoDB server using the mongod.exe (see Part - 1 for more details). Then start the ASP.NET Core application and try performing all the operations. 

That's it for now! Keep coding!!


Bipin Joshi is a software consultant, trainer, author, yoga mentor, and spiritual guide having 23+ years of experience in software development, consulting, and training. He conducts instructor-led online training courses in ASP.NET Core, ASP.NET MVC, and Design Patterns for individuals and small groups. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 03 December 2018


Tags : ASP.NET ASP.NET Core Data Access MVC C# Visual Studio


Subscribe to our newsletter

Get monthly email updates about new articles, tutorials, code samples, and how-tos getting added to our knowledge base.