.NET core + ASP.NET core integration

MDB backend integration with .NET core + ASP.NET core for Standard

This article shows you how to integrate .NET core + ASP.NET core backend application with MDB UI Kit.


Prerequisites

Before starting the project make sure to install the following utilities:


Creating a new ASP.NET application

In this tutorial we will create a fresh ASP.NET application with MongoDB database and we will see how to use MDB in such app.

Note: The latest versions of ASP.NET don't have a Startup.cs class. In this tutorial we are using version 6 where dependencies and middleware are registered inside the Program.cs class.

Step 1

Creating MongoDB database.

In order to create a new database you need to run the following command:

        
            
        mdb database init
    
        
    
  • Choose MongoDB
  • Create a new user
  • Provide username, password, database name and description.

Note: the password must contain at least one uppercase letter, one lowercase letter, one number, one special symbol and have minimum length of 8.

Important Do not close your terminal window until you save your credentials somewhere. This is the only time we will show you your database password. If you won't save it you'll loose it.

Step 2

Create a new project with a webapp template and call it MDBASPNETMongoDB (or whatever you like) ...

        
            
            dotnet new webapp -o MDBASPNETMongoDB
    
        
    

... and add MongoDB.Driver and Swashbuckle.AspNetCore package.

        
            
            cd MDBASPNETMongoDB
            dotnet add package Swashbuckle.AspNetCore
            dotnet add package MongoDB.Driver
        
        
    

Step 3

First thing we are going to do is to create a Models directory. Inside that folder create a file named MongoDBSettings.cs where we will define ConnectionURI, DatabaseName and CollectionName.

        
            
    namespace MDBASPNETMongoDB.Models;

    public class MongoDBSettings
    {
    
        public string ConnectionURI { get; set; } = null!;
        public string DatabaseName { get; set; } = null!;
        public string CollectionName { get; set; } = null!;
    
    }
    
        
    

Step 4

Go to appsettings.json and create a new MongoDB object with 3 fields: ConnectionURI, DatabaseName and CollectionName. In first two you have to provide the info from the database you created earlier. In the last one let's put tasks as a value.

        
            
    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*",
      "MongoDB": {
        "ConnectionURI": "Your DB_CONNECTION_STRING",
        "DatabaseName": "Your DatabaseName",
        "CollectionName": "tasks"
      }
    }
    
        
    

Step 5

Create a new model called TaskItem.cs inside a Models directory. It's time to define a TaskItem.

        
            
    using MongoDB.Bson;
    using MongoDB.Bson.Serialization.Attributes;
    
    namespace MDBASPNETMongoDB.Models;
    
    public class TaskItem
    {
    
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        public string? id { get; set; }
        public Int32? __v { get; set; }
        public string name { get; set; } = null!;
        public string desc { get; set; } = null!;
    
    
    }
    
        
    

Step 6

Create a new directory called Services and put a new file inside named MongoDBService.cs. It's going to store a service that will be responsible for connecting the app with MongoDB.

Import necessary dependency. Now we can define a MongoDBService class and create a methods that will be responsible for handling request sent to our API.

        
            
      using MDBASPNETMongoDB.Models;
      using Microsoft.Extensions.Options;
      using MongoDB.Driver;
      using MongoDB.Bson;

      namespace MDBASPNETMongoDB.Services;

      public class MongoDBService
      {

          private readonly IMongoCollection<TaskItem> _taskCollection;

          public MongoDBService(IOptions<MongoDBSettings> mongoDBSettings)
          {
              MongoClient client = new MongoClient(mongoDBSettings.Value.ConnectionURI);
              IMongoDatabase database = client.GetDatabase(mongoDBSettings.Value.DatabaseName);
              _taskCollection = database.GetCollection<TaskItem>(mongoDBSettings.Value.CollectionName);
          }

          public async Task<List<TaskItem>> GetAsync()
          {
              return await _taskCollection.Find(new BsonDocument()).ToListAsync();
          }
          public async Task<List<TaskItem>> GetAsync(string id)
          {
              FilterDefinition<TaskItem> filter = Builders<TaskItem>.Filter.Eq("id", id);
              return await _taskCollection.Find(filter).ToListAsync();
          }

          public async Task CreateAsync(TaskItem task)
          {
              await _taskCollection.InsertOneAsync(task);
              return;
          }

          public async Task UpdateAsync(string id, string name, string desc)
          {
              FilterDefinition<TaskItem> filter = Builders<TaskItem>.Filter.Eq("id", id);
              UpdateDefinition<TaskItem> update = Builders<TaskItem>.Update.Set("name", name).Set("desc", desc);

              await _taskCollection.FindOneAndUpdateAsync(filter, update);
              return;
          }

          public async Task DeleteAsync(string id)
          {
              FilterDefinition<TaskItem> filter = Builders<TaskItem>.Filter.Eq("id", id);
              await _taskCollection.DeleteOneAsync(filter);
              return;
          }

      }
    
        
    

Step 7

Let's go to Program.cs file and import a few MongoDB dependencies on top of that file. We also have to to bind our settings and MongoDBService after init of a builder variable. Lastly, we are going to add some code to remove CORS problems that would appear later.

        
            
    using MDBASPNETMongoDB.Models;
    using MDBASPNETMongoDB.Services;
    
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddControllers(); // for CORS to work properly 
    builder.Services.Configure<MongoDBSettings>(builder.Configuration.GetSection("MongoDB"));
    builder.Services.AddSingleton<MongoDBService>();
    
    ...
    
    var app = builder.Build();
    app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin()); // for CORS to work properly 
    
    ...
    
    app.Run();
    
    
        
    

Step 8

Create a new controller inside a Controllers directory. Our default API route will be /tasks. If you look at the code below, we are defining get, post, put and delete endpoints that will be necessary for a basic front-end app.

        
            
    using System;
    using Microsoft.AspNetCore.Mvc;
    using MDBASPNETMongoDB.Services;
    using MDBASPNETMongoDB.Models;
    
    namespace MDBASPNETMongoDB.Controllers;
    
    [Controller]
    [Route("tasks/")]
    public class TaskController : Controller
    {
    
        private readonly MongoDBService _mongoDBService;
    
        public TaskController(MongoDBService mongoDBService)
        {
            _mongoDBService = mongoDBService;
    
        }
    
        [HttpGet]
        public async Task<List<TaskItem>> Get()
        {
            return await _mongoDBService.GetAsync();
        }
    
        [HttpPost]
        public async Task<IActionResult> Post([FromBody] TaskItem task)
        {
            await _mongoDBService.CreateAsync(task);
            return CreatedAtAction(nameof(Get), new { id = task.id }, task);
        }
    
    
        [HttpPut("{id}")]
        public async Task<IActionResult> AddToTask(string id, [FromBody] TaskItem response, [FromBody] string desc)
        {
            await _mongoDBService.UpdateAsync(id, response.name, response.desc);
            return NoContent();
        }
    
        [HttpDelete("{id}")]
        public async Task<IActionResult> Delete(string id)
        {
            await _mongoDBService.DeleteAsync(id);
            return NoContent();
        }
    
    }
    
        
    

Install MDB

After configuration of our backend we should add MDB Standard to the project and create the page to display.

Download MDB Standard using mdb-cli. Run the commands below and select MDB5 Free Standard starter. It's important to run mdb init from the wwwroot folder.

        
            
            cd wwwroot
            mdb init
      
        
    

Your folder structure should look like this:

        
          MDBASPNETMongoDB/
          ├── wwwroot/
          |    ├── mdb5-free-standard
          |    |
          |  (...)
          |
        (...)
        
      

Creating client side code

Step 1

Let's include MDB in the cshtml file. Doing it in pages/shared/_Layout.cshtml will automatically incldue MDB in every page in this project. If for some reason we need MDB only in one page, we could do the same for certain page.

        
            
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="utf-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0" />
            <title>@ViewData["Title"] - MDBASPNETMongoDB</title>
            <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
            <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
            <link rel="stylesheet" href="~/MDBASPNETMongoDB.styles.css" asp-append-version="true" />

            <!-- MDB -->
            <link href="~/mdb5-free-standard/css/mdb.min.css" rel="stylesheet"/>
        </head>
        <body>
            <header>
                <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
                    <div class="container">
                        <a class="navbar-brand" asp-area="" asp-page="/Index">MDBASPNETMongoDB</a>
                        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                                aria-expanded="false" aria-label="Toggle navigation">
                            <span class="navbar-toggler-icon"></span>
                        </button>
                        <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                            <ul class="navbar-nav flex-grow-1">
                                <li class="nav-item">
                                    <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
                                </li>
                                <li class="nav-item">
                                    <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
                                </li>
                            </ul>
                        </div>
                    </div>
                </nav>
            </header>
            <div class="container">
                <main role="main" class="pb-3">
                    @RenderBody()
                </main>
            </div>

            <footer class="border-top footer text-muted">
                <div class="container">
                    &copy; 2022 - MDBASPNETMongoDB - <a asp-area="" asp-page="/Privacy">Privacy</a>
                </div>
            </footer>

            <script src="~/lib/jquery/dist/jquery.min.js"></script>
            <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
            <script src="~/js/site.js" asp-append-version="true"></script>
            <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
            <!-- MDB -->
            <script type="text/javascript" src="~/mdb5-free-standard/js/mdb.min.js"></script>

            @await RenderSectionAsync("Scripts", required: false)


            
        </body>
        </html>
      
        
    

Step 2

Run dotnet run from project's main directory to assign localhost port.

        
            
        dotnet run
      
        
    

Step 3

Open Pages/Index.cshtml and paste the code from the snippet

The code contains the basic layout and requests that use Axios in this example. Don't forget to change value of the API_URL variable. It should point to the /task endpoint, e.g. "https://localhost:7201/tasks" if your project is not published yet

        
            
        @page
        @model IndexModel
        @{
            var API_URL=YOUR_URL ;
        }
        @{
            ViewData["Title"] = "MDB Integration";
        }

          <div class="container mt-5">
            <div class="row pt-5">
              <div class="col text-center">
                <button class="btn btn-primary" data-mdb-toggle="modal" data-mdb-target="#addTaskModal">ADD TASK</button>
              </div>
            </div>
            <div class="row mt-3 p-5" style="min-height: 40vh;">
              <div class="col d-flex justify-content-center align-items-center">
                <ul class="list-group list-group-light taskList" style="min-width: 22rem;">
                </ul>
              </div>
            </div>

            <div class="modal fade" id="addTaskModal" tabindex="-1" aria-labelledby="addTaskModalLabel"
            aria-hidden="true">
            <div class="modal-dialog">
              <div class="modal-content">
                <div class="modal-header">
                  <h5 class="modal-title" id="addTaskModalLabel">Add task</h5>
                  <button type="button" class="btn-close" data-mdb-dismiss="modal" aria-label="Close"></button>
                </div>
                  <form id="addTaskForm" action="/" method="post">
                    <div class="modal-body">
                    <div class="form-outline mb-4">
                      <input name='name' type="text" id="nameInput" class="form-control" />
                      <label class="form-label" for="form7Example1">Name</label>
                    </div> 
                    <div class="form-outline mb-4">
                      <input name="desc" type="text" id="descInput" class="form-control" />
                      <label class="form-label" for="form7Example2">Email address</label>
                    </div>
                    </div>
                  <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-mdb-dismiss="modal">
                      Close
                    </button>
                    <button type="button" class="btn btn-primary modalConfirmBtn">Confirm</button>
                  </div>
                </form>
              </div>
            </div>
            </div>
            <div class="modal fade" id="editTaskModal" tabindex="-1" aria-labelledby="editTaskModalLabel"
            aria-hidden="true">
              <div class="modal-dialog">
                <div class="modal-content">
                  <div class="modal-header">
                    <h5 class="modal-title" id="editTaskModalLabel">Edit Task</h5>
                    <button type="button" class="btn-close" data-mdb-dismiss="modal" aria-label="Close"></button>
                  </div>
                    <form id="editTaskForm" action="/" method="post">
                    <div class="modal-body">
                      <div class="form-outline mb-4">
                        <input name='name' type="text" id="editNameInput" class="form-control" />
                        <label class="form-label" for="editNameInput">Name</label>
                      </div>
                      <div class="form-outline mb-4">
                        <input name="desc" type="text" id="editDescInput" class="form-control" />
                        <label class="form-label" for="editDescInput">Email address</label>
                      </div>
                    </div>
                    <div class="modal-footer">
                      <button type="button" class="btn btn-secondary" data-mdb-dismiss="modal">
                        Close
                      </button>
                      <button type="button" class="btn btn-primary modalConfirmBtn">Confirm</button>
                    </div>
                  </form>
                </div>
              </div>
            </div>
          </div>

          <script type="module"> 
          let taskToEditID
          let taskList
          const modalConfirmBtn = document.querySelector('.modalConfirmBtn');
          const editTaskModal = document.querySelector('#editTaskModal');
          const addTaskModal = document.querySelector('#addTaskModal');
          const modalEditConfirmBtn = editTaskModal.querySelector('.modalConfirmBtn');
          const addTaskForm = document.querySelector('#addTaskForm');
          const editTaskForm = document.querySelector('#editTaskForm');
          const addTaskModalInstance = mdb.Modal.getOrCreateInstance(document.querySelector('#addTaskModal'))
          const editTaskModalInstance = mdb.Modal.getOrCreateInstance(document.querySelector('#editTaskModal'))

          const createAndReloadTasks = (taskData) => {
            const taskListElement = document.querySelector('.taskList')
            taskListElement.innerHTML = ''
            for (let i = 0; i < taskData.length; i++) {
              const taskToAdd = 
              `<li class="list-group-item d-flex justify-content-between align-items-center gap-5">
                <div>
                  <div class="fw-bold">${taskData[i].name}</div>
                  <div class="fw-bold">${taskData[i].desc}</div>
                </div>
                <div>
                  <a class="editBtn" id="${taskData[i].id}" style="cursor: pointer;">
                    <span class="fas fa-pen text-primary me-3" title="edit" data-mdb-toggle="modal" data-mdb-target="#editTaskModal"></span>
                  </a>
                  <a class="deleteBtn" id="${taskData[i].id}" style="cursor: pointer;">
                    <span class="fas fa-trash text-danger" title="delete"></span>
                  </a>
                </div>
              </li>`
              taskListElement.insertAdjacentHTML('beforeend', taskToAdd)
            }
            const deleteBtns = document.querySelectorAll('.deleteBtn');
            const editBtns = document.querySelectorAll('.editBtn');

            deleteBtns.forEach((btn)=> {
              btn.addEventListener('click', ()=> {
                deleteTask(btn.id)
              })
            })
            editBtns.forEach((btn)=> {
              btn.addEventListener('click', ()=> {
                openEditModal(btn.id);
                taskToEditID = btn.id;
              })
            })
          }

          const openEditModal = (id) => {
            axios.get(`@API_URL/${id}`).then((res) => {
              const taskData = res.data[0]
              
              editTaskForm.querySelector('#editNameInput').value = taskData.name;
              editTaskForm.querySelector('#editDescInput').value = taskData.desc;
            })
          }

          const getTasks = () => {
            axios.get('@API_URL').then((res) => {
              taskList = res.data
              createAndReloadTasks(taskList)
            });
          };

          const deleteTask = (id) => {
            axios.delete(`@API_URL/${id}`).then((res) => {
              getTasks()
            });
          }

          const addNewTask = () => {
            let formDataObject = {}
            const formData = new FormData(addTaskForm)

            formData.forEach((value, key) => {
              formDataObject[key] = value;
            });
            axios({url: '@API_URL', method: 'POST', data: formDataObject}).then((res, err) => {
              getTasks()
            }).catch((err) => {
              console.log(err)
            })
            addTaskForm.reset()
          }

          modalEditConfirmBtn.addEventListener('click', () => {
            const editedData = {
              name: editTaskForm.querySelector('#editNameInput').value,
              desc: editTaskForm.querySelector('#editDescInput').value
            }
            axios({url: `@API_URL/${taskToEditID}`, method: 'PUT', data: editedData}).then((res, err) => {
              getTasks()
            }).catch((err) => {
              console.log(err)
            })
            editTaskModalInstance.hide()
          })

          modalConfirmBtn.addEventListener('click', () => {
            addNewTask()
            addTaskModalInstance.hide()
          })
          
          getTasks()
        </script>
      
        
    

Optimization

If you want to further optimize your application please visit:


Backend features

ASP.NET core:

This example was created with ASP.NET core 6. By creating new endpoints, we can pass or receive data from this application.


Frontend features

MDB UI KIT:

To create the project we used our ui kit, with which we can build basic views very quickly.

Views and Layouts:

In this project we used the Index.cshtml file, created by the ASP .NET in which we placed our MDB code. We have successfully integrated the backend with the MDB Standard package and can send basic requests to ASP.NET core application.