Introduction
In this article, we will be creating a personal expense manager using ASP.NET Core 2.1 and Entity Framework Core code-first approach. An expense manager tracks your daily expenses and provides comparative charts to show an expense summary. Since we are using modal dialog to handle user inputs and to show monthly and weekly expense summary charts using Highcharts, hence this application will be a single-page application (SPA).
We will be using Visual Studio 2017 and SQL Server 2017 for our demo.
Let us look at the final application.

Prerequisites
- Install .NET Core 2.1 SDK from here
- Install the latest version of Visual Studio 2017 from here
- SQL Server 2008 or above
Source Code
Before proceeding, I would recommend you get the source code from Github.
Create ASP.NET Core Project
Open Visual Studio and select File >> New >> Project.
After selecting the project, a “New Project” dialog will open. Select .NET Core inside the Visual C# menu from the left panel.
Then, select “ASP.NET Core Web Application” from the available project types. Put the name of the project as ExpenseManager and press OK.

After clicking on OK, a new dialog will open asking to select the project template. You can observe two drop-down menus at the top left of the template window. Select “.NET Core” and “ASP.NET Core 2.1” from these dropdowns. Then, select the “Web application (Model-View-Controller)” template and press OK to create the ASP.NET Core Project.

Adding the Model to the Application
Since we are using the Entity Framework Code-First approach, first, we will create our model class and then generate our database tables using the model.
Right-click on the Models folder and select Add >> Class. Name your class ExpenseReport.cs. This class will contain our Employee model properties.
Open the ExpenseReport.cs file and put the following code into it.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace ExpenseManager.Models
{
public class ExpenseReport
{
[Key]
public int ItemId { get; set; }
[Required]
public string ItemName { get; set; }
[Required]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(10, 2)")]
public decimal Amount { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[Required]
public DateTime ExpenseDate { get; set; } = DateTime.Now;
[Required]
public string Category { get; set; }
}
}
We have used the [Key] attribute with ItemId to consider it as the primary key while creating the database table.
Creating the database table using EF Core code first approach
In order to create our tables using the EF Core code first approach, we need to install a few NuGet packages.
Navigate to Tools >> NuGet Package Manager >> Package Manager Console.
We have to install the package for the database provider that we are targeting which is SQL Server in this case. Hence, run the following command.
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Since we are using Entity Framework Tools to create a table from the existing model, we will install the tools package as well. Hence, run the following command.
Install-Package Microsoft.EntityFrameworkCore.Tools
After the package installations are successful, we will create a dbcontext class. Add a file ExpenseDBContext.cs in the Modals folder and put the following code into it.
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ExpenseManager.Models
{
public class ExpenseDBContext : DbContext
{
public virtual DbSet<ExpenseReport> ExpenseReport { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Your connection string");
}
}
}
}
Do not forget to put your own connection string (inside ” “).
We will create a dataset migration which is used to keep the database schema in sync with the model. There is no database at this moment, so the first migration will create it and add tables for the entities represented by the DbSet properties on the ExpenseDBContext that we have created.
To create the dataset migration, navigate to the project folder and open the Powershell window. Execute the following command in it.
dotnet ef migrations add ExpenseMigration
Refer to the image below
This will create a folder named Migrations in our project, which contains the code for the migration and a model snapshot. Refer to the image below,

Enter the following command in the Powershell window to execute the migration.
dotnet ef database update
Refer to the image below.

This will create the table “ExpenseReport” in our database that we have mentioned in the connection string. You can observe that the column ItemId is the primary key here.

Hence, the database creation is completed successfully using the Entity Framework code first approach.
Adding the Data Access layer to our application
Add a class file ExpensesDataAcessLayer.cs into the Modals folder and put the following code into it.
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ExpenseManager.Models
{
public class ExpensesDataAcessLayer
{
ExpenseDBContext db = new ExpenseDBContext();
public IEnumerable<ExpenseReport> GetAllExpenses()
{
try
{
return db.ExpenseReport.ToList();
}
catch
{
throw;
}
}
// To filter out the records based on the search string
public IEnumerable<ExpenseReport> GetSearchResult(string searchString)
{
List<ExpenseReport> exp = new List<ExpenseReport>();
try
{
exp = GetAllExpenses().ToList();
return exp.Where(x => x.ItemName.IndexOf(searchString, StringComparison.OrdinalIgnoreCase) != -1);
}
catch
{
throw;
}
}
//To Add new Expense record
public void AddExpense(ExpenseReport expense)
{
try
{
db.ExpenseReport.Add(expense);
db.SaveChanges();
}
catch
{
throw;
}
}
//To Update the records of a particular expense
public int UpdateExpense(ExpenseReport expense)
{
try
{
db.Entry(expense).State = EntityState.Modified;
db.SaveChanges();
return 1;
}
catch
{
throw;
}
}
//Get the data for a particular expense
public ExpenseReport GetExpenseData(int id)
{
try
{
ExpenseReport expense = db.ExpenseReport.Find(id);
return expense;
}
catch
{
throw;
}
}
//To Delete the record of a particular expense
public void DeleteExpense(int id)
{
try
{
ExpenseReport emp = db.ExpenseReport.Find(id);
db.ExpenseReport.Remove(emp);
db.SaveChanges();
}
catch
{
throw;
}
}
// To calculate last six months expense
public Dictionary<string, decimal> CalculateMonthlyExpense()
{
ExpensesDataAcessLayer objexpense = new ExpensesDataAcessLayer();
List<ExpenseReport> lstEmployee = new List<ExpenseReport>();
Dictionary<string, decimal> dictMonthlySum = new Dictionary<string, decimal>();
decimal foodSum = db.ExpenseReport.Where
(cat => cat.Category == "Food" && (cat.ExpenseDate > DateTime.Now.AddMonths(-7)))
.Select(cat => cat.Amount)
.Sum();
decimal shoppingSum = db.ExpenseReport.Where
(cat => cat.Category == "Shopping" && (cat.ExpenseDate > DateTime.Now.AddMonths(-7)))
.Select(cat => cat.Amount)
.Sum();
decimal travelSum = db.ExpenseReport.Where
(cat => cat.Category == "Travel" && (cat.ExpenseDate > DateTime.Now.AddMonths(-7)))
.Select(cat => cat.Amount)
.Sum();
decimal healthSum = db.ExpenseReport.Where
(cat => cat.Category == "Health" && (cat.ExpenseDate > DateTime.Now.AddMonths(-7)))
.Select(cat => cat.Amount)
.Sum();
dictMonthlySum.Add("Food", foodSum);
dictMonthlySum.Add("Shopping", shoppingSum);
dictMonthlySum.Add("Travel", travelSum);
dictMonthlySum.Add("Health", healthSum);
return dictMonthlySum;
}
// To calculate last four weeks expense
public Dictionary<string, decimal> CalculateWeeklyExpense()
{
ExpensesDataAcessLayer objexpense = new ExpensesDataAcessLayer();
List<ExpenseReport> lstEmployee = new List<ExpenseReport>();
Dictionary<string, decimal> dictWeeklySum = new Dictionary<string, decimal>();
decimal foodSum = db.ExpenseReport.Where
(cat => cat.Category == "Food" && (cat.ExpenseDate > DateTime.Now.AddDays(-7)))
.Select(cat => cat.Amount)
.Sum();
decimal shoppingSum = db.ExpenseReport.Where
(cat => cat.Category == "Shopping" && (cat.ExpenseDate > DateTime.Now.AddDays(-28)))
.Select(cat => cat.Amount)
.Sum();
decimal travelSum = db.ExpenseReport.Where
(cat => cat.Category == "Travel" && (cat.ExpenseDate > DateTime.Now.AddDays(-28)))
.Select(cat => cat.Amount)
.Sum();
decimal healthSum = db.ExpenseReport.Where
(cat => cat.Category == "Health" && (cat.ExpenseDate > DateTime.Now.AddDays(-28)))
.Select(cat => cat.Amount)
.Sum();
dictWeeklySum.Add("Food", foodSum);
dictWeeklySum.Add("Shopping", shoppingSum);
dictWeeklySum.Add("Travel", travelSum);
dictWeeklySum.Add("Health", healthSum);
return dictWeeklySum;
}
}
}
This file will have methods to handle CRUD operations on our database. We are also calculating the last six months' expenses and the last four weeks' expenses for each category.
Adding the Controller to the Application
Right-click on the Controllers folder and select Add >> New Item. An “Add New Item” dialog box will open. Select “ASP.NET Core” from the left panel, then select “Controller class” from the templates panel, and put the name as ExpenseController.cs. Press OK.

This will create our controller ExpenseController inside the Controllers folder. Open the ExpenseController.cs file and put in the following code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ExpenseManager.Models;
using Microsoft.AspNetCore.Mvc;
namespace ExpenseManager.Controllers
{
public class ExpenseController : Controller
{
ExpensesDataAcessLayer objexpense = new ExpensesDataAcessLayer();
public IActionResult Index(string searchString)
{
List<ExpenseReport> lstEmployee = new List<ExpenseReport>();
lstEmployee = objexpense.GetAllExpenses().ToList();
if (!String.IsNullOrEmpty(searchString))
{
lstEmployee = objexpense.GetSearchResult(searchString).ToList();
}
return View(lstEmployee);
}
public ActionResult AddEditExpenses(int itemId)
{
ExpenseReport model = new ExpenseReport();
if (itemId > 0)
{
model = objexpense.GetExpenseData(itemId);
}
return PartialView("_expenseForm", model);
}
[HttpPost]
public ActionResult Create(ExpenseReport newExpense)
{
if (ModelState.IsValid)
{
if (newExpense.ItemId > 0)
{
objexpense.UpdateExpense(newExpense);
}
else
{
objexpense.AddExpense(newExpense);
}
}
return RedirectToAction("Index");
}
[HttpPost]
public IActionResult Delete(int id)
{
objexpense.DeleteExpense(id);
return RedirectToAction("Index");
}
public ActionResult ExpenseSummary()
{
return PartialView("_expenseReport");
}
public JsonResult GetMonthlyExpense()
{
Dictionary<string, decimal> monthlyExpense = objexpense.CalculateMonthlyExpense();
return new JsonResult(monthlyExpense);
}
public JsonResult GetWeeklyExpense()
{
Dictionary<string, decimal> weeklyExpense = objexpense.CalculateWeeklyExpense();
return new JsonResult(weeklyExpense);
}
}
}
The controller will have the methods that will call our data access layer methods to handle database operations.
Adding Views to the Application
We will create three view files,




Choo JasonPosted Jan 11, 2021, 1:57 PM
Hi, May i know how to add the pagination in this project?
Krishna MohanPosted Oct 26, 2020, 2:18 AM
Hai ankit ,its a very nice article, im getting amount value in $, how to remove this dollar sign in the expense table can u please tell?
Ano MepaniPosted Aug 18, 2018, 11:37 AM
Another article at 9:49 Minute reference in ASP.NET Community Standup - July 31, 2018https://www.youtube.com/watch?v=_kUekGQVMKQ
Naveen KumarPosted Jul 30, 2018, 7:07 AM
Hey Ankit thanks got it.
Naveen KumarPosted Jul 24, 2018, 5:51 AM
Hey Ankit great stuff thanks for sharing, but due to the date format difference in Model and the datetime picker making model invalid. So i have changed DateFormatString to {0:yyyy-MM-dd} (ISO format) and it's working fine.
Hadshana KamalanathanPosted Jul 19, 2018, 4:39 AM
Thanks for sharing