Easily Create Web App With MongoDB, .NET 6, And Angular 13

Introduction 

MongoDB is a document database with the scalability and flexibility that you want with the querying and indexing that you need. MongoDB stores data in versatile, JSON-like documents. This means that the fields will vary from document to document and the data structure can be changed over time. 

MongoDB has exceptionally good documentation. Please open this link to explore more features of MongoDB. 

C# Corner also has a set of good articles on MongoDB. Please refer to these articles to get started with MongoDB. 

MongoDB Atlas is a fully managed cloud database. Atlas handles all the complexity of deploying, managing, and healing your deployments on the cloud service provider of your choice (Azure, AWS, and GCP). 

Currently, MongoDB Atlas supplies 512 MB free space. I have already authored an article to create a free MongoDB cluster and connect with MVC application. Please refer to this article

In this post, we will see all the steps to connect MongoDB database with .NET 6 web application and consume this Web API in an Angular 13 application. We will use an already provisioned MongoDB Atlas cluster to create our database.  

Create ASP.NET 6 Web API in Visual Studio 2022 

We can open Visual Studio 2022 and choose ASP.NET Core Web API template. After choosing a valid name and directory we can choose .NET 6.0 framework. 

Create ASP.NET 6 Web API in Visual Studio 2022 

The new application will be ready in a few moments.  

We can install MongoDB.Driver library using NuGet Package Manager. 

install MongoDB.Driver library using NuGet Package Manager

Above is the official MongoDB .NET driver created by MongoDB Inc.  

We can create a “Models” folder and create an Employee class inside this folder.  

Employee.cs 

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;

namespace MongoDBDotNET6.Models
{
    public class Employee
    {
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        public string? Id { get; set; }

        public string Name { get; set; } = null!;

        public string Designation { get; set; } = null!;

        public string Company { get; set; } = null!;

        public string Cityname { get; set; } = null!;

        public string Address { get; set; } = null!;
    }
}

In the above class, the Id property is: 

  • Required for mapping the Common Language Runtime (CLR) object to the MongoDB collection. 
  • Annotated with [BsonId] to make this property the document's primary key. 
  • Annotated with [BsonRepresentation(BsonType.ObjectId)] to allow passing the parameter as type string instead of an ObjectId structure. Mongo handles the conversion from string to ObjectId. 

We can create a DatabaseSettings class inside the Models folder. 

DatabaseSettings.cs 

namespace MongoDBDotNET6.Models
{
    public class DatabaseSettings
    {
        public string ConnectionString { get; set; } = null!;

        public string DatabaseName { get; set; } = null!;

    }
}

The above class is used to store database connection and name inside the appsettings.json file. These connection properties will be used to set up connection between MongoDB database and .NET application. 

We can add connection properties inside the appsettings.json file as well. 

appsettings.json 

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "DatabaseSettings": {
    "ConnectionString": "mongodb+srv://<username>:<password>@sarathlal.8vuub.mongodb.net/?retryWrites=true&w=majority",
    "DatabaseName": "EmployeeDB"
  }
}

We can create an Employee service inside a new folder “Services” 

EmployeeService.cs 

using Microsoft.Extensions.Options;
using MongoDB.Driver;
using MongoDBDotNET6.Models;

namespace MongoDBDotNET6.Services
{
    public class EmployeeService
    {
        private readonly IMongoCollection<Employee> _employeeCollection;

        public EmployeeService(
            IOptions<DatabaseSettings> dabaseSettings)
        {
            var mongoClient = new MongoClient(dabaseSettings.Value.ConnectionString);

            var mongoDatabase = mongoClient.GetDatabase(dabaseSettings.Value.DatabaseName);

            _employeeCollection = mongoDatabase.GetCollection<Employee>("Employee");
        }

        public async Task<List<Employee>> GetAsync() =>
            await _employeeCollection.Find(_ => true).ToListAsync();

        public async Task<Employee?> GetAsync(string id) =>
            await _employeeCollection.Find(x => x.Id == id).FirstOrDefaultAsync();

        public async Task CreateAsync(Employee newEmployee) =>
            await _employeeCollection.InsertOneAsync(newEmployee);

        public async Task UpdateAsync(string id, Employee updatedEmployee) =>
            await _employeeCollection.ReplaceOneAsync(x => x.Id == id, updatedEmployee);

        public async Task RemoveAsync(string id) => await _employeeCollection.DeleteOneAsync(x => x.Id == id);
    }
}

In the above service we have implemented all the methods for CRUD operations with MongoDB database. We will use this service inside our API controller soon.  

We can change the Program.cs file with the code changes below. 

Program.cs 

using MongoDBDotNET6.Models;
using MongoDBDotNET6.Services;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.Configure<DatabaseSettings>(builder.Configuration.GetSection("DatabaseSettings"));
builder.Services.AddSingleton<EmployeeService>();

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var MyAllowedOrigins = "_myAllowedOrigins";
builder.Services.AddCors(options =>
{
    options.AddPolicy(MyAllowedOrigins,
                          builder =>
                          {
                              builder.WithOrigins("http://localhost:4200")
                                                  .AllowAnyHeader()
                                                  .AllowAnyMethod();
                          });
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseAuthorization();

app.MapControllers();

app.UseCors(MyAllowedOrigins);

app.Run();

The above code is used to register dependency injection with appsettings.json file’s DatabaseSettings properties. Also, EmployeeService class is registered with DI to support constructor injection in consuming classes. The singleton service lifetime is most proper because EmployeeService takes a direct dependency on MongoClient. 

We have also added the code for enabling CORS (Cross Origin Resource Sharing).  

We can create an API controller EmployeeController inside the Controllers folder and add the code below.  

EmployeeController.cs 

using Microsoft.AspNetCore.Mvc;
using MongoDBDotNET6.Models;
using MongoDBDotNET6.Services;

namespace MongoDBDotNET6.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class EmployeeController : ControllerBase
    {
        private readonly EmployeeService _employeeService;

        public EmployeeController(EmployeeService employeeService) => _employeeService = employeeService;

        [HttpGet]
        public async Task<List<Employee>> Get() => await _employeeService.GetAsync();

        [HttpGet("{id:length(24)}")]
        public async Task<ActionResult<Employee>> Get(string id)
        {
            var employee = await _employeeService.GetAsync(id);

            if (employee is null)
            {
                return NotFound();
            }

            return employee;
        }

        [HttpPost]
        public async Task<IActionResult> Post(Employee newEmployee)
        {
            await _employeeService.CreateAsync(newEmployee);

            return NoContent();
        }

        [HttpPut("{id:length(24)}")]
        public async Task<IActionResult> Update(string id, Employee updatedEmployee)
        {
            var employee = await _employeeService.GetAsync(id);

            if (employee is null)
            {
                return NotFound();
            }

            updatedEmployee.Id = employee.Id;

            await _employeeService.UpdateAsync(id, updatedEmployee);

            return NoContent();
        }

        [HttpDelete("{id:length(24)}")]
        public async Task<IActionResult> Delete(string id)
        {
            var employee = await _employeeService.GetAsync(id);

            if (employee is null)
            {
                return NotFound();
            }

            await _employeeService.RemoveAsync(id);

            return NoContent();
        }
    }
}

We have used EmployeeService class to implement CRUD operations inside the API controller.  

Controller has action methods to support GET, POST, PUT, and DELETE HTTP requests. 

We have completed the Web API application. You can use swagger to test the CRUD operations if needed.  

Create Angular 13 application using CLI and consume .NET 6 Web API 

We can use Angular CLI commands to create Angular applications and other components.  

ng new MongoDBAngular13 

We can choose routing choice as Yes.  

We can add bootstrap and font-awesome libraries to the project. 

npm install bootstrap font-awesome 

We must change “styles.css” file in the root folder with below changes to access these packages globally in the application without further references. 

styles.css 

@import "~bootstrap/dist/css/bootstrap.css";      
@import "~font-awesome/css/font-awesome.css";  

Create an environment variable inside environment class for baseUrl. This will be used across the application. 

environment.ts 

export const environment = {
  production: false,
  baseUrl: 'http://localhost:5000/'  
};

We can create an employee interface now. 

ng g class employee\employee 

Use the below code.

employee.ts

export interface Employee {
    id: string,
    name: string,
    address: string,
    company: string,
    designation: string,
    cityname: string
}

We can create an employee service now. 

ng g service employee\employee 

Use the below code.

employee.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, throwError, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { Employee } from './employee';
import { environment } from 'src/environments/environment';

@Injectable({
  providedIn: 'root'
})
export class EmployeeService {
  private employeesUrl = environment.baseUrl + 'api/employee';

  constructor(private http: HttpClient) { }

  getEmployees(): Observable<Employee[]> {
    return this.http.get<Employee[]>(this.employeesUrl)
      .pipe(
        catchError(this.handleError)
      );
  }

  getEmployee(id: string | null): Observable<Employee> {
    if (id === '') {
      return of(this.initializeEmployee());
    }
    const url = `${this.employeesUrl}/${id}`;
    return this.http.get<Employee>(url)
      .pipe(
        catchError(this.handleError)
      );
  }

  createEmployee(employee: Employee): Observable<Employee> {
    employee.id = '';
    return this.http.post<Employee>(this.employeesUrl, employee)
      .pipe(
        catchError(this.handleError)
      );
  }

  deleteEmployee(id: string): Observable<{}> {
    const url = `${this.employeesUrl}/${id}`;
    return this.http.delete<Employee>(url)
      .pipe(
        catchError(this.handleError)
      );
  }

  updateEmployee(employee: Employee): Observable<Employee> {
    const url = `${this.employeesUrl}/${employee.id}`;
    return this.http.put<Employee>(url, employee)
      .pipe(
        map(() => employee),
        catchError(this.handleError)
      );
  }

  private handleError(err: any) {
    let errorMessage: string;
    if (err.error instanceof ErrorEvent) {
      errorMessage = `An error occurred: ${err.error.message}`;
    } else {
      errorMessage = `Backend returned code ${err.status}: ${err.body.error}`;
    }
    console.error(err);
    return throwError(() => errorMessage);
  }

  private initializeEmployee(): Employee {
    return {
      id: "",
      name: "",
      address: "",
      company: "",
      designation: "",
      cityname: ""
    };
  }
}

We can create an employee list component. This component will be used to display all the employee information. This component is also used to edit and remove employee data. 

ng g component employee\EmployeeList 

We can change the class file with the code below. 

employee-list.component.ts

import { Component, OnInit } from '@angular/core';
import { Employee } from '../employee';
import { EmployeeService } from '../employee.service';

@Component({
  selector: 'app-employee-list',
  templateUrl: './employee-list.component.html',
  styleUrls: ['./employee-list.component.css']
})
export class EmployeeListComponent implements OnInit {
  pageTitle = 'Employee List';
  filteredEmployees: Employee[] = [];
  employees: Employee[] = [];
  errorMessage = '';

  _listFilter = '';
  get listFilter(): string {
    return this._listFilter;
  }
  set listFilter(value: string) {
    this._listFilter = value;
    this.filteredEmployees = this.listFilter ? this.performFilter(this.listFilter) : this.employees;
  }

  constructor(private employeeService: EmployeeService) { }

  performFilter(filterBy: string): Employee[] {
    filterBy = filterBy.toLocaleLowerCase();
    return this.employees.filter((employee: Employee) =>
      employee.name.toLocaleLowerCase().indexOf(filterBy) !== -1);
  }

  ngOnInit(): void {
    this.getEmployeeData();
  }

  getEmployeeData() {
    this.employeeService.getEmployees()
      .subscribe({
        next: (employees) => {
          this.employees = employees;
          this.filteredEmployees = employees;
        },
        error: (err) => this.errorMessage = <any>err,
        complete: () => console.info('Get employees in employee list')
      });
  }

  deleteEmployee(id: string, name: string): void {
    if (id === '') {
      this.onSaveComplete();
    } else {
      if (confirm(`Are you sure want to delete this Employee: ${name}?`)) {
        this.employeeService.deleteEmployee(id)
          .subscribe({
            next: () => this.onSaveComplete(),
            error: (err) => this.errorMessage = <any>err,
            complete: () => console.info('Delete employee in employee list')
          });
      }
    }
  }

  onSaveComplete(): void {
    this.employeeService.getEmployees()
      .subscribe({
        next: (employees) => {
          this.employees = employees;
          this.filteredEmployees = employees;
        },
        error: (err) => this.errorMessage = <any>err,
        complete: () => console.info('Get employees in employee list')
      });
  }
}    

We can change the template and style files also. 

employee-list.component.html 

<div class="card">  
    <div class="card-header">  
        {{pageTitle}}  
    </div>  
    <div class="card-body">  
        <div class="row" style="margin-bottom:15px;">  
            <div class="col-md-2">Filter by:</div>  
            <div class="col-md-4">  
                <input type="text" [(ngModel)]="listFilter" />  
            </div>  
            <div class="col-md-2"></div>  
            <div class="col-md-4">  
                <button class="btn btn-primary mr-3" [routerLink]="['/employees/0/edit']">  
                    New Employee  
                </button>  
            </div>  
        </div>  
        <div class="row" *ngIf="listFilter">  
            <div class="col-md-6">  
                <h4>Filtered by: {{listFilter}}</h4>  
            </div>  
        </div>  
        <div class="table-responsive">  
            <table class="table mb-0" *ngIf="employees && employees.length">  
                <thead>  
                    <tr>  
                        <th>Name</th>  
                        <th>Address</th>  
                        <th>Company</th>  
                        <th>Designation</th>  
                        <th></th>  
                        <th></th>  
                    </tr>  
                </thead>  
                <tbody>  
                    <tr *ngFor="let employee of filteredEmployees">  
                        <td>  
                            <a [routerLink]="['/employees', employee.id]">  
                                {{ employee.name }}  
                            </a>  
                        </td>  
                        <td>{{ employee.address }}</td>  
                        <td>{{ employee.company }}</td>  
                        <td>{{ employee.designation}} </td>  
                        <td>  
                            <button class="btn btn-outline-primary btn-sm"  
                                [routerLink]="['/employees', employee.id, 'edit']">  
                                Edit  
                            </button>  
                        </td>  
                        <td>  
                            <button class="btn btn-outline-warning btn-sm"  
                                (click)="deleteEmployee(employee.id,employee.name);">  
                                Delete  
                            </button>  
                        </td>  
                    </tr>  
                </tbody>  
            </table>  
        </div>  
    </div>  
</div>  
<div *ngIf="errorMessage" class="alert alert-danger">  
    Error: {{ errorMessage }}  
</div> 

employee-list.component.css 

thead {  
    color: #337AB7;  
}  

We can create employee edit component with the below command 

ng g component employee\EmployeeEdit 

Modify the class file with the code below. 

employee-edit.component.ts 

import { Component, OnInit, OnDestroy, ElementRef, ViewChildren } from '@angular/core';
import { FormControlName, FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Subscription } from 'rxjs';
import { ActivatedRoute, Router } from '@angular/router';
import { Employee } from '../employee';
import { EmployeeService } from '../employee.service';

@Component({
  selector: 'app-employee-edit',
  templateUrl: './employee-edit.component.html',
  styleUrls: ['./employee-edit.component.css']
})
export class EmployeeEditComponent implements OnInit, OnDestroy {
  @ViewChildren(FormControlName, { read: ElementRef }) formInputElements!: ElementRef[];
  pageTitle = 'Employee Edit';
  errorMessage!: string;
  employeeForm!: FormGroup;
  tranMode!: string;
  employee!: Employee;
  private sub!: Subscription;

  displayMessage: { [key: string]: string } = {};
  private validationMessages: { [key: string]: { [key: string]: string } };

  constructor(private fb: FormBuilder,
    private route: ActivatedRoute,
    private router: Router,
    private employeeService: EmployeeService) {

    this.validationMessages = {
      name: {
        required: 'Employee name is required.',
        minlength: 'Employee name must be at least three characters.',
        maxlength: 'Employee name cannot exceed 50 characters.'
      },
      cityname: {
        required: 'Employee city name is required.',
      }
    };
  }

  ngOnInit() {
    this.tranMode = "new";
    this.employeeForm = this.fb.group({
      name: ['', [Validators.required,
      Validators.minLength(3),
      Validators.maxLength(50)
      ]],
      address: '',
      cityname: ['', [Validators.required]],
      company: '',
      designation: '',
    });

    this.sub = this.route.paramMap.subscribe(
      params => {
        const id = params.get('id');
        const cityname = params.get('cityname');
        if (id == '0') {
          const employee: Employee = { id: "0", name: "", address: "", company: "", designation: "", cityname: "" };
          this.displayEmployee(employee);
        }
        else {
          this.getEmployee(id);
        }
      }
    );
  }

  ngOnDestroy(): void {
    this.sub.unsubscribe();
  }

  getEmployee(id: string | null): void {
    this.employeeService.getEmployee(id)
      .subscribe({
        next: (employee: Employee) => this.displayEmployee(employee),
        error: (err) => this.errorMessage = <any>err,
        complete: () => console.info('Get employee in employee edit')
      });
  }

  displayEmployee(employee: Employee): void {
    if (this.employeeForm) {
      this.employeeForm.reset();
    }
    this.employee = employee;
    if (this.employee.id == '0') {
      this.pageTitle = 'Add Employee';
    } else {
      this.pageTitle = `Edit Employee: ${this.employee.name}`;
    }
    this.employeeForm.patchValue({
      name: this.employee.name,
      address: this.employee.address,
      company: this.employee.company,
      designation: this.employee.designation,
      cityname: this.employee.cityname
    });
  }

  deleteEmployee(): void {
    if (this.employee.id == '0') {
      this.onSaveComplete();
    } else {
      if (confirm(`Are you sure want to delete this Employee: ${this.employee.name}?`)) {
        this.employeeService.deleteEmployee(this.employee.id)
          .subscribe({
            next: () => this.onSaveComplete(),
            error: (err) => this.errorMessage = <any>err,
            complete: () => console.info('Delete employee in employee edit')
          });
      }
    }
  }

  saveEmployee(): void {
    if (this.employeeForm.valid) {
      if (this.employeeForm.dirty) {
        const e = { ...this.employee, ...this.employeeForm.value };
        if (e.id === '0') {
          this.employeeService.createEmployee(e)
            .subscribe({
              next: () => this.onSaveComplete(),
              error: (err) => this.errorMessage = <any>err,
              complete: () => console.info('Create employee in employee edit')
            });
        } else {
          this.employeeService.updateEmployee(e)
            .subscribe({
              next: () => this.onSaveComplete(),
              error: (err) => this.errorMessage = <any>err,
              complete: () => console.info('Update employee in employee edit')
            });
        }
      } else {
        this.onSaveComplete();
      }
    } else {
      this.errorMessage = 'Please correct the validation errors.';
    }
  }

  onSaveComplete(): void {
    this.employeeForm.reset();
    this.router.navigate(['/employees']);
  }
}

We can change the template file also. 

employee-edit.component.html 

<div class="card">
    <div class="card-header">
      {{pageTitle}}
    </div>
  
    <div class="card-body">
      <form novalidate (ngSubmit)="saveEmployee()" [formGroup]="employeeForm">
  
        <div class="form-group row mb-2">
          <label class="col-md-3 col-form-label" for="employeeNameId">Employee Name</label>
          <div class="col-md-7">
            <input class="form-control" id="employeeNameId" type="text" placeholder="Name (required)"
              formControlName="name" />
          </div>
        </div>
  
        <div class="form-group row mb-2">
          <label class="col-md-3 col-form-label" for="citynameId">City</label>
          <div class="col-md-7">
            <input class="form-control" id="citynameid" type="text" placeholder="Cityname (required)"
              formControlName="cityname" />
          </div>
        </div>
  
        <div class="form-group row mb-2">
          <label class="col-md-3 col-form-label" for="addressId">Address</label>
          <div class="col-md-7">
            <input class="form-control" id="addressId" type="text" placeholder="Address" formControlName="address" />
          </div>
        </div>
  
        <div class="form-group row mb-2">
          <label class="col-md-3 col-form-label" for="companyId">Company</label>
          <div class="col-md-7">
            <input class="form-control" id="companyId" type="text" placeholder="Company" formControlName="company" />
          </div>
        </div>
  
        <div class="form-group row mb-2">
          <label class="col-md-3 col-form-label" for="designationId">Designation</label>
          <div class="col-md-7">
            <input class="form-control" id="designationId" type="text" placeholder="Designation"
              formControlName="designation" />
          </div>
        </div>
  
        <div class="form-group row mb-2">
          <div class="offset-md-2 col-md-6">
            <button class="btn btn-primary" style="width:80px;margin-right:10px;" type="submit"
              [title]="employeeForm.valid ? 'Save your entered data' : 'Disabled until the form data is valid'"
              [disabled]="!employeeForm.valid">
              Save
            </button>
            <button class="btn btn-outline-secondary" style="width:80px;margin-right:10px;" type="button"
              title="Cancel your edits" [routerLink]="['/employees']">
              Cancel
            </button>
            <button class="btn btn-outline-warning" *ngIf="pageTitle != 'Add Employee'"
              style="width:80px;margin-right:10px" type="button" title="Delete this product" (click)="deleteEmployee()">
              Delete
            </button>
          </div>
        </div>
      </form>
    </div>
  
    <div class="alert alert-danger" *ngIf="errorMessage">{{errorMessage}}
    </div>
  </div>

We need one more component to display the employee details in a separate window. We can create now. 

ng g component employee\EmployeeDetail 

We can change the class file with the code below. 

employee-detail.component.ts 

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Employee } from '../employee';
import { EmployeeService } from '../employee.service';

@Component({
  selector: 'app-employee-detail',
  templateUrl: './employee-detail.component.html',
  styleUrls: ['./employee-detail.component.css']
})
export class EmployeeDetailComponent implements OnInit {
  pageTitle = 'Employee Detail';
  errorMessage = '';
  employee: Employee | undefined;

  constructor(private route: ActivatedRoute,
    private router: Router,
    private employeeService: EmployeeService) { }

  ngOnInit() {
    const id = this.route.snapshot.paramMap.get('id');
    if (id) {
      this.getEmployee(id);
    }
  }

  getEmployee(id: string) {
    this.employeeService.getEmployee(id)
      .subscribe({
        next: (employee) => this.employee = employee,
        error: (err) => this.errorMessage = <any>err,
        complete: () => console.info('Get employee in employee details')
      });
  }

  onBack(): void {
    this.router.navigate(['/employees']);
  }
}  

Modify the template file with the code below. 

employee-detail.component.html 

<div class="card">    
    <div class="card-header"    
         *ngIf="employee">    
      {{pageTitle + ": " + employee.name}}    
    </div>    
    <div class="card-body"    
         *ngIf="employee">    
      <div class="row">    
        <div class="col-md-8">    
          <div class="row">    
            <div class="col-md-3">Name:</div>    
            <div class="col-md-6">{{employee.name}}</div>    
          </div>    
          <div class="row">    
            <div class="col-md-3">City:</div>    
            <div class="col-md-6">{{employee.cityname}}</div>    
          </div>    
          <div class="row">    
            <div class="col-md-3">Address:</div>    
            <div class="col-md-6">{{employee.address}}</div>    
          </div>    
          <div class="row">    
            <div class="col-md-3">Company:</div>    
            <div class="col-md-6">{{employee.company}}</div>    
          </div>    
          <div class="row">    
            <div class="col-md-3">Designation:</div>    
            <div class="col-md-6">{{employee.designation}}</div>    
          </div>    
        </div>    
      </div>    
      <div class="row mt-4">    
        <div class="col-md-4">    
          <button class="btn btn-outline-secondary mr-3"    
                  style="width:80px;margin-right:10px;"    
                  (click)="onBack()">    
            <i class="fa fa-chevron-left"></i> Back    
          </button>    
          <button class="btn btn-outline-primary"    
                  style="width:80px;margin-right:10px;"    
                  [routerLink]="['/employees', employee.id,'edit']">    
            Edit    
          </button>    
        </div>    
      </div>    
    </div>    
    <div class="alert alert-danger"    
         *ngIf="errorMessage">    
      {{errorMessage}}    
    </div>    
  </div>  

Create the navigation menu component now. 

ng g component NavMenu 

Modify the class file with the code below. 

nav-menu.component.ts 

import { Component, OnInit } from '@angular/core';  
  
@Component({  
  selector: 'app-nav-menu',  
  templateUrl: './nav-menu.component.html',  
  styleUrls: ['./nav-menu.component.css']  
})  
export class NavMenuComponent implements OnInit {  
  
  isExpanded = false;  
  
  ngOnInit() {  
  }  
  
  collapse() {  
    this.isExpanded = false;  
  }  
  
  toggle() {  
    this.isExpanded = !this.isExpanded;  
  }  
 
}  

We can change the template file with the code below. 

nav-menu.component.html 

<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" [routerLink]='["/"]'>Employee App</a>  
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse"  
          aria-label="Toggle navigation" [attr.aria-expanded]="isExpanded" (click)="toggle()">  
          <span class="navbar-toggler-icon"></span>  
        </button>  
        <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse" [ngClass]='{"show": isExpanded}'>  
          <ul class="navbar-nav flex-grow">  
            <li class="nav-item" [routerLinkActive]='["link-active"]' [routerLinkActiveOptions]='{ exact: true }'>  
              <a class="nav-link text-dark" [routerLink]='["/"]'>Home</a>  
            </li>  
            <li class="nav-item" [routerLinkActive]='["link-active"]'>  
              <a class="nav-link text-dark" [routerLink]='["/employees"]'>Employees</a>  
            </li>  
          </ul>  
        </div>  
      </div>  
    </nav>  
  </header>  
  <footer>  
    <nav class="navbar navbar-light bg-white mt-5 fixed-bottom">  
      <div class="navbar-expand m-auto navbar-text">  
        Developed with <i class="fa fa-heart"></i> by <b>Sarathlal  
          Saseendran</b>  
      </div>  
    </nav>  
  </footer>  

We can also change the stylesheet file with the code below. 

nav-menu.component.css 

html {  
    font-size: 14px;  
}  
  
@media (min-width: 768px) {  
    html {  
        font-size: 16px;  
    }  
}  
  
.fa-heart {  
    color: hotpink;  
}  

Create the final component Home now. 

ng g component home 

There is no code change for the class file. We can change the html template file with the code below. 

home.component.html 

<div style="text-align:center;">
    <h3>Web Application with MongoDB, .NET 6, and Angular 13</h3>
    <p>Welcome to our new single-page Employee application, built with below technologies:</p>
    <img src="../../assets/MongoDB DotnetCore Angular1.png" width="700px">
</div>

We must add reference for below modules in app.module class. 

app.module class

app.module.ts 

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { FormsModule, ReactiveFormsModule } from '@angular/forms';  
import { HttpClientModule } from '@angular/common/http'; 

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { EmployeeListComponent } from './employee/employee-list/employee-list.component';
import { EmployeeEditComponent } from './employee/employee-edit/employee-edit.component';
import { EmployeeDetailComponent } from './employee/employee-detail/employee-detail.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';

@NgModule({
  declarations: [
    AppComponent,
    EmployeeListComponent,
    EmployeeEditComponent,
    EmployeeDetailComponent,
    NavMenuComponent,
    HomeComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    ReactiveFormsModule,    
    FormsModule,    
    HttpClientModule,    
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

We must add below route values in the app-routing.module class as well. 

app-routing.module.ts 

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { EmployeeDetailComponent } from './employee/employee-detail/employee-detail.component';
import { EmployeeEditComponent } from './employee/employee-edit/employee-edit.component';
import { EmployeeListComponent } from './employee/employee-list/employee-list.component';
import { HomeComponent } from './home/home.component';

const routes: Routes = [  
  { path: '', component: HomeComponent, pathMatch: 'full' },  
  {  
    path: 'employees',  
    component: EmployeeListComponent  
  },  
  {  
    path: 'employees/:id',  
    component: EmployeeDetailComponent  
  },  
  {  
    path: 'employees/:id/edit',  
    component: EmployeeEditComponent  
  },  
] 

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

We can change the app.component.html with the code below. 

app.component.html 

<body>    
  <app-nav-menu></app-nav-menu>    
  <div class="container">    
    <router-outlet></router-outlet>    
  </div>    
</body>   

We have completed the Angular code. We can run both Web API and Angular now. 

Web App With MongoDB, .NET 6, And Angular 13

Click the Employees menu and add a new employee record. 

Web App With MongoDB, .NET 6, And Angular 13

Added employees will be listed as a grid format on the screen. 

Web App With MongoDB, .NET 6, And Angular 13

You can click on the employee's name and display the details on a separate screen.

Web App With MongoDB, .NET 6, And Angular 13

We have edit and remove employee data features available in the application. 

We have filter employee's name in the grid also available. 

Web App With MongoDB, .NET 6, And Angular 13

Conclusion 

In this post, we have seen how to connect MongoDB database in ASP.NET 6 Web API and consume the API endpoints in an Angular 13 application. We have created all CRUD operations and see how it is working. We have provisioned a free MongoDB Atlas cluster and created a database on it. Please feel free to give your valuable feedback about this post.


Similar Articles