.NET core + ASP.NET core integration

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

This article shows you how to integrate .NET core + ASP.NET core backend application with MDB Vue 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. Navigate to your project directory, i.e. mdb-vue-aspnet-app and follow the steps below.

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 -db 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 webapi template and call it MDBASPNETMongoDB (or whatever you like) ...

        
            
            dotnet new webapi -o MDBASPNETMongoDB
    
        
    

... and add MongoDB.Driver package. Also let's remove files that are not necessary for our project: WeatherForecast.cs and Controllers/WeatherForecastController.cs.

        
            
            cd MDBASPNETMongoDB
            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 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 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();
        }
    
    }
    
        
    

Step 9

Run your backend app and go to https://localhost:YOUR_BACKEND_PORT/swagger/index.html and test your endpoints with Try it out button. If everything works fine we can start creating a new vue project.

        
            
        dotnet run
        
        
    

Creating MDB Vue application

If our backend is working correctly we should start creating a new Vite application. If you have encountered any problems, you should go back and try each step again.

Note: Don't forget to go back to your root folder before next step. Folders MDBASPNETMongoDB and mdb5-free-vue should be in the same directory.

Step 1

Create a new vite project with our MDB starter. Run the command below and select MDB5 Free Vue starter.

        
            
            mdb init
      
        
    

Your folder structure should look like this

        
          mdb-vue-express-app/
          ├── mdb5-free-vue
          └── MDBASPNETMongoDB
        
      

Step 2

Let's make some changes to the created vue app. First we need to install axios inside our mdb5-free-vue directory.

        
            
            npm install axios
      
        
    

Remove style.css file (don't forget to delete it from main.ts file) and remove HelloWorld file from components directory.

Step 3

Let's create a .env file inside a mdb5-free-vue directory. We have to add VITE_ before the name of your variable, because it's the only way to expose them to Vite-processed code. Don't forget to change YOUR_BACKEND_PORT to the port your backend is running right now.

        
            
            VITE_API = "LINK_TO_YOUR_BACKEND_APP"
      
        
    

Step 4

Add new content to Home.vue file inside the views directory.

Since our starter database contains some sample models and routes, let's use them. We will create an application that will show a list of tasks. We also intend to create a functonality for adding new tasks, changing their content and removing them.

We have already prepared the code for you, so go ahead and copy and paste it into App.vue.

Ok, so what's actually going on there. We use MDB components, MDBBtn, MDBModal, MDBListGroup, MDBInputs and few other. The modal will be responsible to show inputs that will allow you to add, edit and send tasks to the database. The Manage tasks button, gives possibilty to modify or remove tasks. At the end, the list group will display our data.

        
            
      <template>
        <MDBContainer class="mt-5">
          <MDBRow class="pt-5">
            <MDBCol class="text-center">
              <MDBBtn color="primary" @click="taskModal = true">Add task</MDBBtn>
            </MDBCol>
          </MDBRow>
          <MDBRow class="mt-3 p-5" style="min-height: 40vh">
            <MDBCol class="d-flex justify-content-center align-items-center">
              <div v-if="taskList.length === 0">
                Nothing to display. Add a few tasks.
              </div>
              <MDBListGroup v-else class="list-group-light" style="min-width: 22rem">
                <MDBListGroupItem
                  class="d-flex justify-content-between align-items-center gap-5"
                  v-for="task in taskList"
                  :key="task.id"
                >
                  <div>
                    <div class="fw-bold">
                      {{ task.name }}
                    </div>
                    <div class="text-muted">{{ task.desc }}</div>
                  </div>
                  <div>
                    <MDBIcon
                      class="text-primary me-3"
                      title="edit"
                      icon="pen"
                      style="cursor: pointer"
                      @click="() => editModal(task)"
                    />
                    <MDBIcon
                      class="text-danger"
                      title="delete"
                      icon="trash"
                      style="cursor: pointer"
                      @click="() => deleteTask(task.id)"
                    />
                  </div>
                </MDBListGroupItem>
              </MDBListGroup>
            </MDBCol>
          </MDBRow>
        </MDBContainer>
        <MDBModal
          id="addNewTaskModal"
          tabindex="-1"
          labelledby="addNewTaskModalLabel"
          v-model="taskModal"
        >
          <MDBModalHeader>
            <MDBModalTitle id="exampleModalLabel">{{
              isEdited.edited ? "Edit task" : "Add task"
            }}</MDBModalTitle>
          </MDBModalHeader>
          <MDBModalBody>
            <form>
              <div class="my-4">
                <MDBInput
                  label="Name"
                  type="text"
                  v-model="newTaskName"
                  counter
                  :maxlength="60"
                />
              </div>
              <div class="my-4">
                <MDBInput
                  label="Description"
                  type="text"
                  v-model="newTaskDesc"
                  counter
                  :maxlength="255"
                />
              </div>
            </form>
          </MDBModalBody>
          <MDBModalFooter>
            <MDBBtn
              color="secondary"
              @click="
                {
                  resetInputs();
                  taskModal = false;
                }
              "
              >Close</MDBBtn
            >
            <MDBBtn
              color="primary"
              @click="handleSaveChanges"
              :disabled="!canSendData"
              >{{ isEdited.edited ? "Save changes" : "Add task" }}</MDBBtn
            >
          </MDBModalFooter>
        </MDBModal>
      </template>
      
        
    
        
            
      <script setup lang="ts">
        import { ref, onMounted, computed } from "vue";
        import {
          MDBContainer,
          MDBRow,
          MDBCol,
          MDBListGroup,
          MDBListGroupItem,
          MDBBtn,
          MDBModal,
          MDBModalTitle,
          MDBModalHeader,
          MDBModalBody,
          MDBModalFooter,
          MDBInput,
          MDBIcon,
        } from "mdb-vue-ui-kit";
        import axios from "axios";
        
        interface SingleTask {
          id: number;
          name: string;
          desc: string;
        }
        
        const taskList = ref<SingleTask[]>([]);
        const taskModal = ref(false);
        const newTaskName = ref("");
        const newTaskDesc = ref("");
        const isEdited = ref({ edited: false, value: -1 });
        const API_URL = ref("");
        
        const canSendData = computed(() => {
          if (newTaskName.value.trim() === "" || newTaskDesc.value.trim() === "") {
            return false;
          }
          return true;
        });
        
        const resetInputs = () => {
          newTaskName.value = "";
          newTaskDesc.value = "";
          isEdited.value = { edited: false, value: -1 };
        };
        
        const handleSaveChanges = async () => {
          if (!canSendData.value) {
            return;
          }
        
          isEdited.value.edited
            ? updateTask(isEdited.value.value, newTaskName.value, newTaskDesc.value)
            : createTask(newTaskName.value, newTaskDesc.value);
          resetInputs();
          taskModal.value = false;
        };
        
        const editModal = (task: SingleTask) => {
          newTaskName.value = task.name;
          newTaskDesc.value = task.desc;
          isEdited.value = { edited: true, value: task.id };
        
          taskModal.value = true;
        };
        
        const getTaskList = () => {
          axios.get(`${API_URL.value}tasks`).then((res) => (taskList.value = res.data));
        };
        
        const createTask = (name: string, desc: string) => {
          const data = { name, desc };
          axios.post(`${API_URL.value}tasks`, data).then(() => {
            getTaskList();
          });
        };
        
        const deleteTask = (id: number) => {
          axios.delete(`${API_URL.value}tasks/${id}`).then(() => {
            getTaskList();
          });
        };
        
        const updateTask = (id: number, name: string, desc: string) => {
          const data = { name, desc };
          axios.put(`${API_URL.value}tasks/${id}`, data).then(() => {
            getTaskList();
          });
        };
        
        onMounted(() => {
          API_URL.value = import.meta.env.VITE_API;
          getTaskList();
        });
        </script>
      
        
    

Step 5

The app should be fully functional and should work correctly with backend

        
            
        npm start
      
        
    

Optimization

If you want to further optimize your application please visit:


Backend features

ASP.NET core:

This example was created with use of ASP.NET core 6. By creating new endpoints, we can pass or receive data from MDB Vue front-end 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 Home.vue file, created by the Vite tool in which we placed our vue code. We have successfully integrated the backend with the MDB Vue package and can send basic requests to ASP.NET core application.