November 22, 2019

Angular 8 CRUD Using Asp.Net Web API : Basic Expense Tracker App – Part 1

In this tutorial, we will be developing an Angular 8 app to perform the basic CRUD operations using an Expense Tracker App. Asp.Net Web API will be used to implement the backend and we will also use some popular Angular elements like Ngx-Toastr, Ngx-Pagination etc to give a modern feel to client.

Below is the screenshot of the application we are building

Angular 8 CRUD Example Using Asp.Net Web API - Project Screenshot

I’m using Visual Studio Code for the client side development and Visual Studio for the server side implementation of the Api. You can use the same setup or any preferred editor of your own for this tutorial.

Building the Backend using Asp.Net Web API

Open Visual Studio >> File >> New >> Project >> Select Web Application. Select Empty and click on Web API checkbox to create our project.
 
Angular 8 CRUD Example Using Asp.Net Web API - Project Setup
 
 
Add ADO.Net Entity Data Model into your project and select Code First approach.

Creating the Model Classes

Since we will be following the Entity framework code first approach, we will first create two model classes ExpenseModel and CategoryModel.
 

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace AngularJwt_Api.Models
{
    public class CategoryModel
    {
        [Key]
        public int Id { get; set; }

        public string ExpenseCategory { get; set; }
    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;

namespace AngularJwt_Api.Models
{
    public class ExpenseModel
    {
        [Key]
        public int Id { get; set; }
        public decimal ExpenseAmount { get; set; }

        public DateTime? Date { get; set; }

        public int ExpenseCategory { get; set; }

        public string Notes { get; set; }

        [NotMapped]
        public string  CategoryName { get; set; }
    }
}

I have used the [NotMapped] attribute on the CategoryName property sinceI dont want it to be stored in the database as it is used only for displaying. We will be saving the CategoryID with each Expense record.

Also Read: Json Web Tokens in Angular 8

Updating the DbContext File to Create Tables

Update the DbContext file created on adding Entity framework to your project.
 

namespace AngularJwt_Api
{
    using System;
    using System.Data.Entity;
    using System.Linq;
    using AngularJwt_Api.Models;

    public class AngularCrudDb : DbContext
    {
        // Your context has been configured to use a 'AngularCrudDb' connection string from your application's 
        // configuration file (App.config or Web.config). By default, this connection string targets the 
        // 'AngularJwt_Api.AngularCrudDb' database on your LocalDb instance. 
        // 
        // If you wish to target a different database and/or database provider, modify the 'AngularCrudDb' 
        // connection string in the application configuration file.
        public AngularCrudDb()
            : base("name=AngularCrudDb")
        {

        }

        // Add a DbSet for each entity type that you want to include in your model. For more information 
        // on configuring and using a Code First model, see http://go.microsoft.com/fwlink/?LinkId=390109.

        public virtual DbSet<ExpenseModel> Expenses { get; set; }
        public virtual DbSet<CategoryModel> Categories { get; set; }
    }

    //public class MyEntity
    //{
    //    public int Id { get; set; }
    //    public string Name { get; set; }
    //}
}

Add/Run Migration to Create the Database

Open the Packet Manager Console from Tools >> NuGet Package Manager and then run the following three commands
  • Enable-Migration
  • Add-Migration
  • Update-Database
The above step is required to create the database and since we have not changed the default connection string the DB will be created in Visual Studio’s local DB server which can be seen through the Server Explorer.
 
But in case you are not comfortable with Entity Framework I would suggest getting accustomed to it as it is not in scope of this tutorial.
 

Creating the Expense Controller

The ExpenseController will handle all the backend operations related to creating, updating and deleting expenses.
 
 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Cors;
using AngularJwt_Api.Models;


namespace AngularJwt_Api.Controllers
{
    [Route("expenses")]
    public class ExpenseController : ApiController
    {
        AngularCrudDb dbContent = new AngularCrudDb();

        [HttpGet]
        public IHttpActionResult GetExpenses()
        {
            var expenses = dbContent.Expenses.ToList();
            var categories = dbContent.Categories.ToList(); 

            foreach(var exp in expenses)
            {
                var category = dbContent.Categories.FirstOrDefault(x => x.Id == exp.ExpenseCategory);
                exp.CategoryName = category.ExpenseCategory;
            }
            
            return Ok(expenses);
        }


        [HttpPost]
        [Route("addExpense")]
        public async Task<IHttpActionResult> AddNewExpense(ExpenseModel expense)
        {
            if (!ModelState.IsValid)
            {
                throw new HttpResponseException(HttpStatusCode.BadRequest);
            }

            var id = await AddExpensetoDb(expense);

            return Ok(id);
        }

        [HttpGet]
        [Route("expenseById")]
        public IHttpActionResult GetExpensesById(int id)
        {
            var expenses = dbContent.Expenses.FirstOrDefault(x => x.Id == id);
            return Ok(expenses);
        }


        public Task<int> AddExpensetoDb(ExpenseModel expense)
        {
            dbContent.Expenses.Add(expense);
            dbContent.SaveChanges();

            return Task.FromResult(expense.Id);
        }

      

        [HttpPut]
        public async Task<IHttpActionResult> UpdateExpenses(ExpenseModel expToUpdate)
        {
            var response = await UpdateExpense(expToUpdate);
            return Ok(response);

        }

        private Task<ExpenseModel> UpdateExpense(ExpenseModel expToUpdate)
        {
            try
            {
                var expense = dbContent.Expenses.FirstOrDefault(x => x.Id == expToUpdate.Id);
                if (expense == null)
                {
                    throw new Exception("Expense not found !!");
                }

               // expense = expToUpdate;
                //dbContent.Expenses.Attach(expense);
                //dbContent.Entry(expense).State = System.Data.Entity.EntityState.Modified;

                dbContent.Entry(expense).CurrentValues.SetValues(expToUpdate);

                dbContent.SaveChanges();
                return Task.FromResult(expToUpdate);
            }
            catch (Exception ex)
            {
                throw new Exception("Something went wrong!!");
            }
        }

        [HttpDelete]
        [Route("deleteExpense")]
        public IHttpActionResult DeleteExpense(string exp)
        {
            try
            {
                int expId = Convert.ToInt32(exp.Trim());
                var expense = dbContent.Expenses.FirstOrDefault(x => x.Id == expId);
                if (expense == null)
                {
                    throw new Exception("Expense not found!!");
                }

                dbContent.Expenses.Remove(expense);
                dbContent.SaveChanges();
                return Ok("Expense deleted successfully");
            }
            catch(Exception ex)
            {
                throw new Exception("Something went wrong!!");
            }
        }
    }
}

Creating the Category Controller

The Category Controller will have the endpoints to get categories which will be used during the expense creation.
 

using AngularJwt_Api.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Cors;

namespace AngularJwt_Api.Controllers
{
    [Route("categories")]
   
    public class CategoryController : ApiController
    {
        AngularCrudDb dbContent = new AngularCrudDb();
        

        [HttpGet]
   
        public IHttpActionResult GetCategories()
        {
            var categories = dbContent.Categories.ToList();
            return Ok(categories);
        }
    }
}

Enabling Cors in Web API

Add the following Nuget Package Microsoft.AspNet.Cors into the project using the Packet Manager which will allow our API to be accessed from cross domains i.e. simply clients which are hosted on some other servers. 
 
Now add config.EnableCors() in the WebAPIConfig file and update your controllers by adding the following attribute at class level [EnableCors(“*”, “*”, “*”)]

 

And by this we are stating that our endpoint can be accessed from any domain. In case you need to restrict it you some particular domains then you pass those specific domains as the first parameter instead of *

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Web.Http;

namespace AngularJwt_Api
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data"));
            // Web API routes
            config.MapHttpAttributeRoutes();

            config.EnableCors();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}
 

Our backend to create, update, delete and get expenses is now complete. In Part 2 of this Angular 8 CRUD tutorial we will implement the client application using Angular 8 and Bootstrap.

6 thoughts on “Angular 8 CRUD Using Asp.Net Web API : Basic Expense Tracker App – Part 1

  1. Greetings from Ohio! I?m bored to death at work so I decided to check out your blog on my iphone during
    lunch break. I enjoy the info you provide here and can?t wait
    to take a look when I get home.
    I?m surprised at how fast your blog loaded on my
    cell phone .. I?m not even using WIFI, just 3G
    .. Anyways, superb blog! https://tesgo.ca

Leave a Reply

Your email address will not be published. Required fields are marked *