Step by step guide on how to create an Asp.Net Core MVC CRUD, Ef Core code first approach
Mohamad Lawand
Posted on January 12, 2021
In this article we will be exploring how to create an Asp.Net Core MVC CRUD, Ef Core code first approach you can watch the full tutorial on Youtube as well
Source code: https://github.com/mohamadlawand087/v4-Phonebook
The 3 things that we will need before we start:
- Visual Studio code (https://code.visualstudio.com)
- Dotnet core SDK (https://dotnet.microsoft.com/download)
- Download sqllite browser https://sqlitebrowser.org/dl/
For this sample application we will be using SQLite as our local database. After installing all of requirements, we need to make sure that the dotnet SDK has been installed successfully, we need to open the terminal and check if the dotnet SDK is installed successfully by checking the dotnet version.
Open the terminal type the command below
dotnet --version
Now we need to install the entity framework tool
dotnet tool install --global dotnet-ef
Now we need to create an asp.net core application using the following command
dotnet new mvc -n "Phonebook" -lang "C#" -au none
Now we need to add the required packages to utilise SQLLite and Entity Framework Core
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet add package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Once we add the packages we need to update the appsettings.json to include the connection string to our database
"ConnectionStrings": {
"DefaultConnection": "DataSource=app.db;Cache=Shared"
}
We open visual studio code, we need to open the terminal from within visual studio code.You can go to Views ⇒ Terminal. Now we need to make sure that the application is building by running the code below
dotnet build
dotnet run
Once we make sure that the application is running we will start by creating our ApplicationDbContext. We need to create a Data folder in he root directory, and then will create the ApplicationDbContext class
using Microsoft.EntityFrameworkCore;
namespace Phonebook.Data
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
}
Once we add our ApplicationDbContext we need to update the startup class to utilise the DbContext
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
Once we have add the DbContext middleware we need to add the initial migration to create the database.
dotnet ef migrations add "Initial Migrations"
dotnet ef database update
lets now check our solution and see if we have the database file create, we can now see the database is there.
So our next step is to create our Model, we will call it Contact.
Inside the model folder create a new C# class and call it Contact, inside the Contact class we will define 5 properties "Id", "First Name", "Last Name", "Email", "Mobile".
public class Contact
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
}
Now we need to add our Model to the application DbContext by adding the code below
public class ApplicationDbContext : DbContext
{
// The DbSet property will tell EF Core tha we have a table that needs to be created
public virtual DbSet<Contact> Contacts { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
// On model creating function will provide us with the ability to manage the tables properties
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
Once we update the ApplicationDbContext we need to create a new migration script to prepare the EF Core to update our database
dotnet ef migrations add "Adding the Contact table"
dotnet ef database update
After the database update is completed, we can check our sqlite db with the SQLite browser, we can see that the table has been created for us.
Now we need to create the controller and create the actions. Right click on the controller folder and add a new class calling it ContactsController and we need to inherit from the controller class
public class ContactsController : Controller
{
}
We need to create and initiate the ApplicationDbContext inside our new Contacts controller and create the action index, and get all of the contacts from the database
public class ContactsController : Controller
{
private ApplicationDbContext _context;
public ContactsController(ApplicationDbContext context)
{
_context = context;
}
public async Task<IActionResult> Index()
{
var contacts = await _context.Contacts.ToListAsync();
return View(contacts);
}
}
Now we need to create the view folder for the controller, under the views folder we need to create a folder called Contacts.
once we create the folder we need to create a view for the index, within the index we need to create a table which will list all of the contacts that we have.
@model List<Phonebook.Models.Contact>
<div class="row">
<div class="col-md-12">
<a asp-action="Create" asp-controller="Contacts" class="btn btn-success">Create</a>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table">
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Email</td>
<td>Mobile</td>
<td>Manage</td>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>@item.FirstName</td>
<td>@item.LastName</td>
<td>@item.Email</td>
<td>@item.Mobile</td>
<td>
<a asp-action="Edit" asp-controller="Contacts" asp-route-id="@item.Id">
Edit
</a>
<a asp-action="Delete" asp-controller="Contacts" asp-route-id="@item.Id">
Delete
</a>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
Once we create it we need to build and run the application to make sure everything is running as it should be
dotnet build
dotnet run
When we go to the ContactsController we can see there is nothing in our table since we didnt add any record yet which is the correct behaviour, now lets start creating the Create action to add information to our database.
[HttpGet]
public IActionResult Create()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Create(Contact contact)
{
// validate that our model meets the requirement
if (ModelState.IsValid)
{
try
{
// update the ef core context in memory
_context.Add(contact);
// sync the changes of ef code in memory with the database
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
catch(Exception ex)
{
ModelState.AddModelError(string.Empty, $"Something went wrong {ex.Message}");
}
}
ModelState.AddModelError(string.Empty, $"Something went wrong, invalid model");
// We return the object back to view
return View(contact);
}
@model Phonebook.Models.Contact
<form asp-action="Create" asp-area="Contacts" method="post">
<div class="row">
<div class="col-lg-12">
<div class="form-group">
<label>First Name:</label>
<input asp-for="FirstName" type="text" class="form-control required" placeholder="Enter first name" tabindex="1">
</div>
<div class="form-group">
<label>Last Name:</label>
<input asp-for="LastName" type="text" class="form-control required" placeholder="Enter last name" tabindex="2">
</div>
<div class="form-group">
<label>Email:</label>
<input asp-for="Email" type="text" class="form-control required" placeholder="Enter email" tabindex="3">
</div>
<div class="form-group">
<label>Mobile:</label>
<input asp-for="Mobile" type="text" class="form-control required" placeholder="Enter mobile" tabindex="4">
</div>
<div class="form-group">
<div asp-validation-summary="All" class="text-danger"></div>
</div>
<div class="card-footer">
<center>
<button type="submit" class="btn btn-primary">Create Contact</button>
<a asp-action="Index" asp-controller="Contacts" class="btn btn-secondary">Cancel</a>
</center>
</div>
</div>
</div>
</form>
Once we create it we need to build and run the application to make sure everything is running as it should be
dotnet build
dotnet run
lets navigate to the create page and add some records we can now see the data is being populated as it should from the database
Now we need to add the edit functionality so we can update our contacts, in order for us to do that we need to add the Edit action as well the Edit View.
[HttpGet]
public async Task<IActionResult> Edit(int id)
{
var exist = await _context.Contacts.Where(x => x.Id == id).FirstOrDefaultAsync();
return View(exist);
}
[HttpPost]
public async Task<IActionResult> Edit(Contact contact)
{
// validate that our model meets the requirement
if (ModelState.IsValid)
{
try
{
// Check if the contact exist based on the id
var exist = _context.Contacts.Where(x => x.Id == contact.Id).FirstOrDefault();
// if the contact is not null we update the information
if(exist != null)
{
exist.FirstName = contact.FirstName;
exist.LastName = contact.LastName;
exist.Mobile = contact.Mobile;
exist.Email = contact.Email;
// we save the changes into the db
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
}
catch(Exception ex)
{
ModelState.AddModelError(string.Empty, $"Something went wrong {ex.Message}");
}
}
ModelState.AddModelError(string.Empty, $"Something went wrong, invalid model");
return View(contact);
}
@model Phonebook.Models.Contact
<form asp-action="Edit" asp-area="Contacts" method="post">
<input type="hidden" asp-for="Id" />
<div class="row">
<div class="col-lg-12">
<div class="form-group">
<label>First Name:</label>
<input asp-for="FirstName" type="text" class="form-control required" placeholder="Enter first name" tabindex="1">
</div>
<div class="form-group">
<label>Last Name:</label>
<input asp-for="LastName" type="text" class="form-control required" placeholder="Enter last name" tabindex="2">
</div>
<div class="form-group">
<label>Email:</label>
<input asp-for="Email" type="text" class="form-control required" placeholder="Enter email" tabindex="3">
</div>
<div class="form-group">
<label>Mobile:</label>
<input asp-for="Mobile" type="text" class="form-control required" placeholder="Enter mobile" tabindex="4">
</div>
<div class="form-group">
<div asp-validation-summary="All" class="text-danger"></div>
</div>
<div class="card-footer">
<center>
<button type="submit" class="btn btn-warning">Update Contact</button>
<a asp-action="Index" asp-controller="Contacts" class="btn btn-secondary">Cancel</a>
</center>
</div>
</div>
</div>
</form>
lets run the application now and test the functionality
dotnet build
dotnet run
And finally we need to add the Delete action and view to be able to remove contacts
[HttpGet]
public async Task<IActionResult> Delete(int id)
{
var exist = await _context.Contacts.Where(x => x.Id == id).FirstOrDefaultAsync();
return View(exist);
}
[HttpPost]
public async Task<IActionResult> Delete(Contact contact)
{
if (ModelState.IsValid)
{
try
{
var exist = _context.Contacts.Where(x => x.Id == contact.Id).FirstOrDefault();
if(exist != null)
{
_context.Remove(exist);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
}
catch(Exception ex)
{
ModelState.AddModelError(string.Empty, $"Something went wrong {ex.Message}");
}
}
ModelState.AddModelError(string.Empty, $"Something went wrong, invalid model");
return View();
}
@model Phonebook.Models.Contact
<form asp-action="Delete" asp-area="Contacts" method="post">
<input type="hidden" asp-for="Id" />
<div class="row">
<div class="col-lg-12">
<div class="form-group">
<label>First Name:</label>
<input asp-for="FirstName" type="text" disabled class="form-control required" placeholder="Enter first name" tabindex="1">
</div>
<div class="form-group">
<label>Last Name:</label>
<input asp-for="LastName" type="text" disabled class="form-control required" placeholder="Enter last name" tabindex="2">
</div>
<div class="form-group">
<label>Email:</label>
<input asp-for="Email" type="text" disabled class="form-control required" placeholder="Enter email" tabindex="3">
</div>
<div class="form-group">
<label>Mobile:</label>
<input asp-for="Mobile" type="text" disabled class="form-control required" placeholder="Enter mobile" tabindex="4">
</div>
<div class="form-group">
<div asp-validation-summary="All" class="text-danger"></div>
</div>
<div class="card-footer">
<center>
<button type="submit" class="btn btn-danger">Delete Contact</button>
<a asp-action="Index" asp-controller="Contacts" class="btn btn-secondary">Cancel</a>
</center>
</div>
</div>
</div>
</form>
now lets run the application now and test the functionality
dotnet build
dotnet run
the last thing we need to do is to add a link to the contacts page in the menu, to do that we need to go to Views ⇒ Shared ⇒ _Layout.cshtml and add the code below
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Contacts" asp-action="Index">Contacts</a>
</li>
Posted on January 12, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
January 12, 2021