Today, we’ll explore how to make a CRUD application in ASP.NET MVC. In this application, we’ll explore how to write the code manually for each action. So, CRUD stands for (Create, Read, Update, Delete).
- Let’s make an ‘MVC’ application named ‘CRUDDemo’.
- Change Authentication set to ‘No Authentication’.
- ‘MVC Template’ with ‘MVC References’.
- First of all, let’s us add ‘Employee’ model class in our project.
We’ve already discussed when we’re working with Entity Framework (which actually helps us to make the database under the hood), then it is important that our model class should have a primary key.
Entity Framework converts our model class into the database table. So, think like you’re making the database.
Approaches To Make Primary Key in Model Class
We have 3 different approaches to make the primary key in our class.
- Just make a property named ‘Id’ in your class. Entity Framework will automatically detect it and make it primary key for the database.
- namespace CRUDDemo.Models
- {
- public class Employee
- {
- public int Id { get; set; }
- }
- }
- Let’s say you named your property anything, now you want to make it primary key for the table. Then you need to add [Key] attribute for this property. And [Key] attribute needs ‘System.ComponentModel.DataAnnotations’ assembly.
- using System.ComponentModel.DataAnnotations;
-
- namespace CRUDDemo.Models
- {
- public class Employee
- {
- [Key]
- public int EmpId { get; set; }
- }
- }
- But this third approach is more preferable. Make the property named as
- namespace CRUDDemo.Models
- {
- public class Employee
- {
- public int EmployeeId { get; set; }
- }
- }
Here, in this case, EF also detects it and automatically set this property as primary key in the table.
Now let’s come to the point. And make our final model class.
- namespace CRUDDemo.Models
- {
- public class Employee
- {
- public int EmployeeId { get; set; }
- public string Name { get; set; }
- public string Email { get; set; }
- public string Phone { get; set; }
- public string Addres { get; set; }
- }
- }
Now we need to make our bridge class which means ‘context class’ to make the connection between our model and database.
- Right-click on the Models folder and add context class ‘CrudContext’
- Now we’ll inherit this class from ‘DbContext’ but as we can see Visual Studio has no reference to this base class.
So we need to add the Entity Framework manually in our project. Right Click on your project and ‘Manage NuGet Packages’
![CRUD Application in ASP.Net]()
Now, we can inherit our Context class with DbContext.
- And create the property of our model class.
- using System.Data.Entity;
-
- namespace CRUDDemo.Models
- {
- public class CrudContext : DbContext
- {
- public DbSet<Employee> Employees { get; set; }
- }
- }
Now open the Application’s Web.config file which is at root level. And write the connection string. These configurations file are actually in the form XML.
We can set connection string inside ‘configuration’ XML tag wherever we want. But we normally place connection string after ‘system.web’ XML tag.
Look if you see the IntelliSense support in any file like C#, XML, HTML then it means that you’re working correctly.
And finally, this is our connection string.
- <connectionStrings>
- <add name="CrudContextDemo" connectionString="Server=.;Database=CRUDDemo;Trusted_Connection=True;"
- providerName="System.Data.SqlClient" />
- </connectionStrings>
Let me tell you one more important thing about connection string if you’ve installed standalone SQL server in your machine then if you write only dot (.) anywhere else in the visual studio environment where you need to input SQL server name then it will ok, no need to worry about that. It will work fine.
Purpose of Connection String Name Attribute
You might be thinking about what is actually the purpose of name attribute here. Actually, we might have multiple connection strings. And we write them for our local application, for the server, and for different databases. So, we can name the connection string and use it in our application we want.
Another thing, if the context class name and connection string name matches then the application automatically detects this connection string and uses it.
But in our case, we named our connection string ‘CrudContextDemo’ which is different than our context class name. Then we need to manually write it into our context class.
- public class CrudContext : DbContext
- {
- public CrudContext() : base("CrudContextDemo")
- {
-
- }
-
- public DbSet<Employee> Employees { get; set; }
- }
Now, build the application. And press Visual Studio Key
Alt + /, Alt + . (To Open Package Manager Console)
And write the command to enable the migration in the project.
PM> Enable-Migrations
It will generate the folder ‘Migrations’ and ‘Configuration.cs’ class in it. We’ll discuss it later on.
Why Do We Enable the Migrations?
Actually, we need to update our database during development on the basis of our requirements. So we need to change our model and apply it to the database and it would have happened if we are using migrations. We need to enable the migrations once in our project.
We’ve already discussed in our previous tutorial that to make the database on the application running is not the good approach. The database should be ready before running the application. So, with the help of migrations, we can make our database ready for our application.
Now, it is the time to make the table with the help of migrations. So, write in the Package Manager Console and name the migration which you want to save thos changes into your project, it will become easy for you to know which changes are important and what was the purpose of the changes later in the project.
PM> Add-Migration AnyNameYouWant
Apply
PM> Add-Migration EmployeeAdded
![CRUD Application in ASP.Net]()
Now a new class ‘EmployeeAdded’ has been added to our Migrations folder which is actually the script to generate the table.
We’ll discuss it in depth later.
Now we’ve just generated the script. Now we need to implement this script to generate our ‘Employee’ table. So,
Write in Package Manager Console
PM> Update-Database
And now we’ve successfully created our ‘Employee’ table and our database is ready to use.
Package Manager Console uses the commands of Windows PowerShell. They are not case sensitive. You can write as
add-migrations
Add-Migrations
Whatever way you want.
Let’s open SQL Server Management Studio and try to find out our generated database.
Look our database has been generated.
Now, it is the time of development.
Now, add the Empty ‘EmployeesController’ into the project. Here we have by default ‘Index’ action.
Now, create the context class object.
- using CRUDDemo.Models;
- using System.Web.Mvc;
-
- namespace CRUDDemo.Controllers
- {
- public class EmployeesController : Controller
- {
- private readonly CrudContext _context = new CrudContext();
-
-
- public ActionResult Index()
- {
- return View();
- }
- }
- }
Index
As we already know that ‘Index’ action is used to show all the records on the screen. So, we’re using linq to retrieve all the methods and render it into the view.
- public ActionResult Index()
- {
- var employees = _context.Employees.ToList();
- return View(employees);
- }
We’re passing our employees list into the view and we’ll use this list into our ‘Index’ view.
![CRUD Application in ASP.Net]()
Now, click on ‘Add’ Button and the view has been created.
Now, first of all, catch the list into our this new ‘Index’ view.
- @model IEnumerable<CRUDDemo.Models.Employee>
-
- @{
- ViewBag.Title = "Index";
- }
-
- <h2>Index</h2>
And now add the ‘Create’ hyperlink after ‘Index’ heading.
- <p>
- @Html.ActionLink("Create New", "Create")
- </p>
And now let’s add the table to display the data on the screen.
- <table class="table">
- <tr>
- <th>
- @Html.DisplayNameFor(x => x.Name)
- </th>
- <th>
- @Html.DisplayNameFor(x => x.Email)
- </th>
- <th>
- @Html.DisplayNameFor(x => x.Phone)
- </th>
- <th>
- @Html.DisplayNameFor(x => x.Addres)
- </th>
- </tr>
- </table>
But these are just the headings. Now, let’s add the records but these are more than 1 so we should foreach loop here. And we already know how foreach loop and lambda expression works. So, don’t get confused about how these HTML helper lambda expressions are working.
- @foreach (var emp in Model)
- {
- <tr>
- <td>
- @Html.DisplayFor(x => emp.Name)
- </td>
- <td>
- @Html.DisplayFor(x => emp.Email)
- </td>
- <td>
- @Html.DisplayFor(x => emp.Phone)
- </td>
- <td>
- @Html.DisplayFor(x => emp.Addres)
- </td>
- </tr>
- }
Every property which comes from the header statement can be accessed through ‘Model’. So think like, ‘Model’ is an object of your header class statement (view).
- @model IEnumerable<CRUDDemo.Models.Employee>
Now, one thing still remains in our view. We need to ‘Edit’, ‘Delete’ and ‘Detail’ hyperlinks in our view. So,
- <td>
- @Html.ActionLink("Edit", "Edit", new { id = emp.EmployeeId }) |
- @Html.ActionLink("Detail", "Detail", new { id = emp.EmployeeId }) |
- @Html.ActionLink("Delete", "Delete", new { id = emp.EmployeeId })
- </td>
This is the way we pass the data from our view to our Controller actions.
- new { id = emp.EmployeeId }
Now, make sure that you should use ‘id’ named parameter in your actions.
You might be worried about .DisplayFor() and .DisplayNameFor()
Actually these are 2 different things.
.DisplayNameFor()
It is used to display the names which we set in our attributes like we do below, if we didn't specify then it will use the default name which is of the property.
.DisplayFor()
it is used to show the values of the property.
- [Display(Name=”Current Name”]
- Public string Name { get; set; }
- Public string Price { get; set; }
And finally our ‘Index’ view looks like,
- @model IEnumerable<CRUDDemo.Models.Employee>
-
- @{
- ViewBag.Title = "Index";
- }
-
- <h2>Index</h2>
-
- <p>
- @Html.ActionLink("Create New", "Create")
- </p>
-
- <table class="table">
- <tr>
- <th>
- @Html.DisplayNameFor(x => x.Name)
- </th>
- <th>
- @Html.DisplayNameFor(x => x.Email)
- </th>
- <th>
- @Html.DisplayNameFor(x => x.Phone)
- </th>
- <th>
- @Html.DisplayNameFor(x => x.Addres)
- </th>
- </tr>
- @foreach (var emp in Model)
- {
- <tr>
- <td>
- @Html.DisplayFor(x => emp.Name)
- </td>
- <td>
- @Html.DisplayFor(x => emp.Email)
- </td>
- <td>
- @Html.DisplayFor(x => emp.Phone)
- </td>
- <td>
- @Html.DisplayFor(x => emp.Addres)
- </td>
- <td>
- @Html.ActionLink("Edit", "Edit", new { id = emp.EmployeeId }) |
- @Html.ActionLink("Detail", "Detail", new { id = emp.EmployeeId }) |
- @Html.ActionLink("Delete", "Delete", new { id = emp.EmployeeId })
- </td>
- </tr>
- }
- </table>
- Our Actions [Edit, Details, Delete] has no heading. And we don’t need any heading there. So just add blank <th></th> tags there.
- <tr>
- <th>
- @Html.DisplayNameFor(x => x.Name)
- </th>
- <th>
- @Html.DisplayNameFor(x => x.Email)
- </th>
- <th>
- @Html.DisplayNameFor(x => x.Phone)
- </th>
- <th>
- @Html.DisplayNameFor(x => x.Addres)
- </th>
- <th></th>
- </tr>
Create
Now it is the time to Create action. As we already know that Create GET Request is all about showing the form on the screen and when user fills in the form then it comes to the POST request of Create action
-
- public ActionResult Create()
- {
- return View();
- }
We don’t need to pass any data to our ‘Create’ form. Because we get data from the form. Now again create the empty view for Create action.
Here, we need to bind our textboxes with our class properties. So, we again use the header statement.
- @model CRUDDemo.Models.Employee
Let’s create the form.
Here, we should be good enough in bootstrap 3 or 4. Visual Studio by default is using bootstrap 3. Read
- @using (Html.BeginForm())
- {
- <div class="form-horizontal">
- <h4>Employees</h4>
- <hr />
- @Html.ValidationSummary(true, "", new { @class= "text-danger" })
- <div class="form-group">
- @Html.LabelFor(x => x.Name, new { @class = "control-label col-md-2" })
- <div class="col-md-10">
- @Html.TextBoxFor(x => x.Name, new { @class = "form-control" })
- @Html.ValidationMessageFor(x => x.Name, "", new { @class = "text-danger" })
- </div>
- </div>
- </div>
- }
We’ve written this code, first of all let’s discuss it and then we’ll make our next fields.
Why do we use using statement for forms?
Actually, BeginForm() renders into just opening <form> tag but as we know that when we open any tag then we also need to close the tag as well. And when we use using() statement and use the HTML.BeginForm() into using() statement then our using() statement automatically closes the form tag.
Validation Messages
There are 2 ways to display the validation message on the screen.
- ValidationSummary
It is used to print all the validation messages at once. It displays the error messages in an unordered list.
- ValidationMessage, ValidationMessageFor
These HTML helpers are responsible to display the validation messages individually of the specified field.
Now, you might be confused about the parameters of ValidationSummary() and ValidationMessageFor(). Actually, sometimes when we want to specify the special parameter of any function then we need to completely follow the overloaded function parameters.
Like in our scenario, actually the intent is we need to set the CSS class of our validation messages but we need also to specify the other parameters as well which comes before. And you can know the purpose of these parameters with the help of IntelliSense.
- @model CRUDDemo.Models.Employee
-
- @{
- ViewBag.Title = "Create";
- }
-
- <h2>Create</h2>
-
- @using (Html.BeginForm())
- {
- <div class="form-horizontal">
- <h4>Employees</h4>
- <hr />
- @Html.ValidationSummary(true, "", new { @class = "text-danger" })
- <div class="form-group">
- @Html.LabelFor(x => x.Name, new { @class = "control-label col-md-2" })
- <div class="col-md-10">
- @Html.TextBoxFor(x => x.Name, new { @class = "form-control" })
- @Html.ValidationMessageFor(x => x.Name, "", new { @class = "text-danger" })
- </div>
- </div>
- <div class="form-group">
- @Html.LabelFor(x => x.Email, new { @class = "control-label col-md-2" })
- <div class="col-md-10">
- @Html.TextBoxFor(x => x.Email, new { @class = "form-control" })
- @Html.ValidationMessageFor(x => x.Email, "", new { @class = "text-danger" })
- </div>
- </div>
- <div class="form-group">
- @Html.LabelFor(x => x.Phone, new { @class = "control-label col-md-2" })
- <div class="col-md-10">
- @Html.TextBoxFor(x => x.Phone, new { @class = "form-control" })
- @Html.ValidationMessageFor(x => x.Phone, "", new { @class = "text-danger" })
- </div>
- </div>
- <div class="form-group">
- @Html.LabelFor(x => x.Addres, new { @class = "control-label col-md-2" })
- <div class="col-md-10">
- @Html.TextBoxFor(x => x.Addres, new { @class = "form-control" })
- @Html.ValidationMessageFor(x => x.Addres, "", new { @class = "text-danger" })
- </div>
- </div>
- <div class="form-group">
- <div class="col-md-offset-2 col-md-10">
- <input type="submit" value="Create" class="btn btn-default" />
- </div>
- </div>
- </div>
- }
In this statement, actually we’re setting the bootstrap class to our textboxes and labels.
- @Html.TextBoxFor(x => x.Addres, new { @class = "form-control" })
Difference of .TextBoxFor() and .EditorFor(). Read Link
And in the last to this form ‘Index’ view link,
- <div>
- @Html.ActionLink("Back to List", "Index")
- </div>
Now, as we know that when we’ll fill out this form it will post it to the POST ‘Create’ action. So in the POST action, we need to add our form data into the database.
- [HttpPost]
- public ActionResult Create(Employee employee)
- {
- if (ModelState.IsValid)
- {
- _context.Employees.Add(employee);
- _context.SaveChanges();
- }
- return View(employee);
- }
And if the data is not valid it means our ModelState is not valid and this form data will pass again to the view as we do above.
Our final look at Create.cshtml file is
- @model CRUDDemo.Models.Employee
-
- @{
- ViewBag.Title = "Create";
- }
-
- <h2>Create</h2>
-
- @using (Html.BeginForm())
- {
- <div class="form-horizontal">
- <h4>Employees</h4>
- <hr />
- @Html.ValidationSummary(true, "", new { @class = "text-danger" })
- <div class="form-group">
- @Html.LabelFor(x => x.Name, new { @class = "control-label col-md-2" })
- <div class="col-md-10">
- @Html.TextBoxFor(x => x.Name, new { @class = "form-control" })
- @Html.ValidationMessageFor(x => x.Name, "", new { @class = "text-danger" })
- </div>
- </div>
- <div class="form-group">
- @Html.LabelFor(x => x.Email, new { @class = "control-label col-md-2" })
- <div class="col-md-10">
- @Html.TextBoxFor(x => x.Email, new { @class = "form-control" })
- @Html.ValidationMessageFor(x => x.Email, "", new { @class = "text-danger" })
- </div>
- </div>
- <div class="form-group">
- @Html.LabelFor(x => x.Phone, new { @class = "control-label col-md-2" })
- <div class="col-md-10">
- @Html.TextBoxFor(x => x.Phone, new { @class = "form-control" })
- @Html.ValidationMessageFor(x => x.Phone, "", new { @class = "text-danger" })
- </div>
- </div>
- <div class="form-group">
- @Html.LabelFor(x => x.Addres, new { @class = "control-label col-md-2" })
- <div class="col-md-10">
- @Html.TextBoxFor(x => x.Addres, new { @class = "form-control" })
- @Html.ValidationMessageFor(x => x.Addres, "", new { @class = "text-danger" })
- </div>
- </div>
- <div class="form-group">
- <div class="col-md-offset-2 col-md-10">
- <input type="submit" value="Create" class="btn btn-default" />
- </div>
- </div>
- </div>
- }
-
- <div>
- @Html.ActionLink("Back to List", "Index")
- </div>
Now, let’s run our application and see how it works,
- When the form Create Button is clicked and data is Ok, then it should redirect to the ‘Index’ page.
Solution
- [HttpPost]
- public ActionResult Create(Employee employee)
- {
- if (ModelState.IsValid)
- {
- _context.Employees.Add(employee);
- _context.SaveChanges();
- return RedirectToAction("Index");
- }
- return View(employee);
- }
Let me tell you another important thing here to keep in your mind. Here we don't have any HTML controls of ‘EmployeeId’ property in our ‘Create.cshtml’ view. And when we submit the form, then don’t be confused about id during debugging. The id is actually initialized when the record is submitted to the table in the database. And database auto increments our Id as it is the primary key and it can’t be null.
Edit
Now we’re enough familiar with views. Now let’s just focus on the business logic code.
- public ActionResult Edit(int? id)
- {
- if (id == null)
- {
- return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
- }
-
- var employee = _context.Employees.SingleOrDefault(e => e.EmployeeId == id);
- if (employee == null)
- {
- return HttpNotFound();
- }
- return View(employee);
- }
Look we’re following the defensive approach in our programming. What parameters value is coming, either it is null or not, to check the record against that value if it is null or not -- these kind of things are important for a good developer.
Now, let’s create its view with the help of scaffolding.
Now you have got this view.
![CRUD Application in ASP.Net]()
Remove thHTMLml helper (AntiForgeryToken) from here, we’ll discuss it later on. Another thing is the hidden field is really very important.
Why Is Hidden Field Important?
Comment the hidden field which is actually the property of ‘Employee’ class and when we post the form back to the ‘Edit’ action. Our Edit post action catch the complete ‘Employee’ entity in which it doesn’t find ‘EmployeeId’ so by default application makes the integer property value 0. But we’re working on a specific value of the record to make it modified. And we already know database doesn’t contain primary key value 0, so we face the error.
Now look,
Do you observe in this gif that we got no exception at ModelState level because on this check according to our model instructions the data was valid but when we save the changes into the database, we have got the error because the database doesn’t contain 0 EmployeeId records in the table?
Important Note
Another important thing is as we know that when we submit the form we always catch the entity, so entity should be filled completely with valid values. Don’t be confused about the form action attribute which you see in the gif and it has the action name with the value, this value is because of Edit get request.
Now, let’s create the post ‘edit’ action.
We have 2 techniques to update the data. But we are using the simplest one.
- [HttpPost]
- public ActionResult Edit(Employee employee)
- {
- if (ModelState.IsValid)
- {
- _context.Entry(employee).State = EntityState.Modified;
- _context.SaveChanges();
- return RedirectToAction("Index");
- }
-
- return View(employee);
- }
You can see the other technique to modify the data as well here.
Now let’s run the application and check its implementation. And you’ll observe it is working fine.
Details
Now in the details section, we’ve nothing to post back the data (form) on the server. We just need to show the information on the screen. So,
- public ActionResult Detail(int? id)
- {
- if (id == null)
- {
- return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
- }
-
- var employee = _context.Employees.SingleOrDefault(e => e.EmployeeId == id);
- if (employee == null)
- {
- return HttpNotFound();
- }
- return View(employee);
- }
The code is so simple actually. And now add its view with the help of scaffolding.
![CRUD Application in ASP.Net]()
And now run the application and if you hover the mouse on details hyper link, you’ll see the link in the browser.
Delete
So let’s write the code of Delete Get request.
- public ActionResult Delete(int? id)
- {
- if (id == null)
- {
- return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
- }
-
- var employee = _context.Employees.SingleOrDefault(e => e.EmployeeId == id);
- if (employee == null)
- {
- return HttpNotFound();
- }
- return View(employee);
- }
Now create its view. You can explore the views on your own and you should be.
But remove this line from here.
![CRUD Application in ASP.Net]()
Now create the Delete Post Action.
- [HttpPost]
- public ActionResult Delete(int id)
- {
- var employee = _context.Employees.SingleOrDefault(x => x.EmployeeId == id);
- _context.Employees.Remove(employee ?? throw new InvalidOperationException());
- _context.SaveChanges();
- return RedirectToAction("Index");
- }
Run the application and make a try. Now might be you’re thinking about how the id goes from get request to post request, here in the Delete view we don't have any code to specify the id and catch it from the Delete POST action. We don't even have any hidden field in the Delete View --- then how is it working?
Actually, it looks the value is in different places like a query string, form data, route data. And in our case, we have the value in our route data with the help of Delete get request. And we’ve not specified anything in the view or in Html.BeginForm(). So when the view is postback to the Delete post action, it will be posted on the same Delete action and there we’ve given the id parameter in post action. So the parameter name matches from the route data parameter name, which we’ve configured in RouteConfig and here we have got the value.
localhost:50120/Employees/Delete/1
So we can get the employees here to apply the Delete operation on it?
Dispose of the object
Now it is important to dispose of the context class object. Because context class object opens the database connection. And it is also very important to close the database connection. So override the dispose action.
- protected override void Dispose(bool disposing of)
- {
- if (disposing)
- {
- _context.Dispose();
- }
- base.Dispose(disposing);
- }
Everytime whenever you request the action in the browser like ‘index’ action after completing the index action the control automatically moves to the ‘Dispose’ action and executes it and now again if you request the ‘Detail’ from index page to a specific item, the control moves to the ‘Detail’ action and after executing the ‘Detail’ action ‘Dispose’ action again executes.
Every time you request the action context object creates it and after completing the action again the Dispose of action executes to dispose of the context object. This is how Dispose works.
Conclusion
Here, we saw how we can use the scaffolding, and how we write the CRUD code manually. We also saw how the code works and how the dispose pattern executes. The purpose of this article was to give you better understanding of the code and help you get started very shortly with the code.
See Also
| | | | | | | | | |
Text-to-speech function is limited to 200 characters