In this ASP.NET Core 2.0 Tutorial, we will follow a step by step approach and create an application performing all CRUD (Create, Retrieve, Update, Delete) operations with MongoDB. In order to keep things simple and we are using “Product” entity to perform all CRUD operations.
Getting started with ASP.NET Core 2.0 Tutorial
Pre-Requisites:
Below are the Prerequisites for understanding and executing the ASP.NET MVC Core 2.0 application.
- Microsoft Visual Studio 2017 – assuming you already have installed it.
- Please follow the below link for installing MongoDB Community Edition on windows.
https://docs.mongodb.com/getting-started/shell/tutorial/install-mongodb-on-windows - Mongo Booster (IDE for Mongo DB). (https://nosqlbooster.com/downloads)
ASP.NET Core 2.0 Tutorial with MongoDB:
Below steps guide you to creating a new project.
- Open Visual Studio 2017.
- Click on File -> New -> Project.
- Click “OK”.
Select “Empty” template and Click on “OK”. - The new empty solution will be open in your window.
- In this article, we will talk about “DotNetCoreWithMongoApplication”. The Solution Explorer window for that project is defined as below.
- For running the application, you first need to change the database connection string. Open “appsettings.json” file.
You need to be change the mongo connection as per your system. - Mongo Database snapshot is as below.
- Right click on solution, clean & rebuild the solution.
Performing CRUD Operations using ASP.NET Core 2.0 with MongoDB
Now, in this ASP.NET Core 2.0 article, we will move forward to create an Entity i.e. Product, it’s snapshot, Listing page, Creation page, Editing page and Deleting a record.
Product “Entity” Section:
- Product.cs class: Add a new class under Model. We will define the properties of Product in this class. This class is also mapped to MongoDB Collection named Product.
using MongoDB.Bson.Serialization.Attributes; using System.ComponentModel.DataAnnotations; namespace DotNetCoreWithMongoApplication.Model { public class Product { [BsonId] public string Id { get; set; } [Display(Name = "Product Name")] public string Name { get; set; } [Display(Name = "Product Code")] public string Code { get; set; } [Display(Name = "Product Category")] public string ProductCategory { get; set; } } }
- MongoSetting.cs class: In this class, We will define the ConnectionString and Database property for MongoDB connection.
namespace DotNetCoreWithMongoApplication.Model { public class MongoSetting { public string ConnectionString; public string Database; } }
- Defining Product Context class: We will define ProductContext class for accessing the database. Here we can use MongoDB C# driver for connecting to the MongoDB.
using DotNetCoreWithMongoApplication.Model; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace DotNetCoreWithMongoApplication.Data { public class ProductContext { private readonly IMongoDatabase _database = null; public ProductContext(IOptions<MongoSetting> settings) { var client = new MongoClient(settings.Value.ConnectionString); if (client != null) _database = client.GetDatabase(settings.Value.Database); } public IMongoCollection<Product> Products { get { return _database.GetCollection<Product>("Product"); } } } }
- Product Repository Interface & class: We can define Repository Interface for implementing dependency injection design pattern, so it will be easily accessible from the controller. Repository class containing all the CRUD operation logic.
using DotNetCoreWithMongoApplication.Model; using System.Collections.Generic; using System.Threading.Tasks; namespace DotNetCoreWithMongoApplication.Interface { public interface IProductRepository { Task<IEnumerable<Product>> GetAllProducts(); Task<Product> GetProduct(string id); Task AddProduct(Product item); Task<bool> RemoveProduct(string id); Task<bool> UpdateProduct(string id, Product item); } }
You can easily find the IProductRepository implementation with available source code.
- Startup and Configuration file section: We can use Startup class for configuring Mongo Setting class. Mongo Setting class is containing ConnectionString and Database property. In Startup class, we can initialize ConnectionString and Database property from the configuration (app.json) file.
using DotNetCoreWithMongoApplication.Data; using DotNetCoreWithMongoApplication.Interface; using DotNetCoreWithMongoApplication.Model; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace DotNetCoreWithMongoApplication { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddCors(options => { options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials()); }); services.AddMvc(); services.Configure<MongoSetting>(options => { options.ConnectionString = Configuration.GetSection("MongoConnection:ConnectionString").Value; options.Database = Configuration.GetSection("MongoConnection:Database").Value; }); services.AddTransient<IProductRepository, ProductRepository>(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseCors("CorsPolicy"); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Product}/{action=Index}/{id?}"); }); } } }
Listing Screen:
In this section, we can define the View, Controller logic, Repository logic and output screen for Product List page.
- Cshtml page
@model IEnumerable<DotNetCoreWithMongoApplication.Model.Product> @using DotNetCoreWithMongoApplication.Model <div class="top-buffer"></div> <div class="panel panel-primary"> <div class="panel-heading panel-head">Products</div> <div class="panel-body"> <div class="btn-group"> <a id="createEditProductModal" data-toggle="modal" asp-action="AddEditProduct" data-target="#modal-action-product" class="btn btn-primary"> <i class="glyphicon glyphicon-plus"></i> Add Product </a> </div> <div class="top-buffer"></div> <table class="table table-bordered table-striped table-condensed"> <thead> <tr> <th>Name</th> <th>Code</th> <th>Product Category</th> <th>Action</th> </tr> </thead> <tbody> @foreach (var item in Model) { <tr> <td>@Html.DisplayFor(modelItem => item.Name)</td> <td>@Html.DisplayFor(modelItem => item.Code)</td> <td>@Html.DisplayFor(modelItem => item.ProductCategory)</td> <td> <a id="editProductModal" data-toggle="modal" asp-action="AddEditProduct" asp-route-id= "@item.Id" data-target="#modal-action-product" class="btn btn-info"> <i class="glyphicon glyphicon-pencil"></i> Edit </a> <a id="deleteProductModal" data-toggle="modal" asp-action="DeleteProduct" asp-route-id= "@item.Id" data-target="#modal-action-product" class="btn btn-danger"> <i class="glyphicon glyphicon-trash"></i> Delete </a> </td> </tr> } </tbody> </table> </div> </div> @Html.Partial("_Modal", new BootstrapModel { ID = "modal-action-product", AreaLabeledId = "modal-action-product-label", Size = ModalSize.Medium }) @section scripts { <script src="~/js/product-index.js" asp-append-version="true"></script> }
- Controller Action Method
[HttpGet] public IActionResult Index() { IEnumerable<Product> model = _productRepository.GetAllProducts().Result; return View("Index", model); }
- Repository Method
public async Task<IEnumerable<Product>> GetAllProducts() { try { return await _context.Products.Find(_ => true).ToListAsync(); } catch (Exception ex) { throw ex; } }
- Output screen
Creation/Modification Screen:
In this section, we can define the View, Controller logic, Repository logic and output screen for Add/Edit product.
- Cshtml page
@model DotNetCoreWithMongoApplication.Model.Product @using DotNetCoreWithMongoApplication.Model <form asp-action="AddEditProduct" role="form"> @await Html.PartialAsync("_ModalHeader", new ModalHeader { Heading = String.Format("{0} Product", string.IsNullOrWhiteSpace(Model.Id) ? "Add" : "Edit") }) <div class="modal-body form-horizontal"> <div class="form-group"> <label asp-for="Name" class="col-lg-3 col-sm-3 control-label"></label> <div class="col-lg-6"> <input asp-for="Name" class="form-control" /> </div> </div> <div class="form-group"> <label asp-for="Code" class="col-lg-3 col-sm-3 control-label"></label> <div class="col-lg-6"> <input asp-for="Code" class="form-control" /> </div> </div> <div class="form-group"> <label asp-for="ProductCategory" class="col-lg-3 col-sm-3 control-label"></label> <div class="col-lg-6"> <input asp-for="ProductCategory" class="form-control" /> </div> </div> </div> @await Html.PartialAsync("_ModalFooter", new ModalFooter { }) </form>
- Create/Edit Controller Action Methods
[HttpGet] public IActionResult AddEditProduct(string id) { Product model = new Product(); if (!string.IsNullOrWhiteSpace(id)) { model = _productRepository.GetProduct(id).Result; } return PartialView("~/Views/Product/_AddEditProduct.cshtml", model); } [HttpPost] public ActionResult AddEditProduct(string id, Product model) { try { if (ModelState.IsValid) { bool isNew = string.IsNullOrWhiteSpace(id); if (isNew) { model.Id = ObjectId.GenerateNewId().ToString(); _productRepository.AddProduct(model); } else { _productRepository.UpdateProduct(id, model); } } } catch (Exception ex) { throw ex; } return RedirectToAction("Index"); }
- Repository Methods
public async Task AddProduct(Product item) { try { await _context.Products.InsertOneAsync(item); } catch (Exception ex) { throw ex; } }
public async Task<bool> UpdateProduct(string id, Product item) { try { ReplaceOneResult actionResult = await _context.Products .ReplaceOneAsync(n => n.Id.Equals(id) , item , new UpdateOptions { IsUpsert = true }); return actionResult.IsAcknowledged && actionResult.ModifiedCount > 0; } catch (Exception ex) { throw ex; } }
- Output screen
Delete Screen:
In this section, we can define the View, Controller logic, Repository logic and output screen for Delete product.
- Cshtml Page
@model DotNetCoreWithMongoApplication.Model.Product @using DotNetCoreWithMongoApplication.Model @using (Html.BeginForm()) { @Html.Partial("_ModalHeader", new ModalHeader { Heading = "Delete Product" }) <div class="modal-body form-horizontal"> Are you want to delete @Model.Name? </div> @Html.Partial("_ModalFooter", new ModalFooter { SubmitButtonText = "Delete" }) }
- Delete Controller Action Methods
[HttpGet] public IActionResult DeleteProduct(string id) { Product product = _productRepository.GetProduct(id).Result; return PartialView("~/Views/Product/_DeleteProduct.cshtml", product); } [HttpPost] public IActionResult DeleteProduct(string id, IFormCollection form) { _productRepository.RemoveProduct(id); return RedirectToAction("Index"); }
- Repository Methods
public async Task<Product> GetProduct(string id) { var filter = Builders<Product>.Filter.Eq("Id", id); try { return await _context.Products .Find(filter) .FirstOrDefaultAsync(); } catch (Exception ex) { throw ex; } } public async Task<bool> RemoveProduct(string id) { try { DeleteResult actionResult = await _context.Products.DeleteOneAsync( Builders<Product>.Filter.Eq("Id", id)); return actionResult.IsAcknowledged && actionResult.DeletedCount > 0; } catch (Exception ex) { throw ex; } }
- Output screen
Concluding Remarks: We have created an ASP.NET Core 2.0 application with all CRUD operations following a step by step approach. This simple application can be taken as base to further enhance your skills and develop more advanced applications on ASP.NET Core 2.0.