Вы находитесь на странице: 1из 28

How To Write Simple Todo CRUD ASP.

NET MVC Application

Download color pdf version of this article with pictures.

Note - If you need to copy and paste the code, download the pdf file locally.

Introduction

In this session, we will learn the following.

 How to consume Todo in-memory database using TodoRepository.


 How to create custom ASP.NET MVC custom controller with CRUD operations.
 List of Objects
 Create a new insert object via View
 Update an object via Edit View
 Delete an Item via Delete View.
 Write HttpPost Create API method.
 Write Httppost Edit API method.
 Write HttpPost Delete API method.
 SmartIT DebugTraceHelper tool
 A lab exercise for you to demonstrate what have you learned from this training material to create your own Employee
CRUD operation using EmployeeRepository included in this training material.
UI - User Interface

We will have 5 Views,

 Index
 Create
 Edit
 Detail
 Delete

Controller

TodoController

Wire the Controller to Database and Views.

Database

We will be using in-memory Todo repository to simplify the database.

Create a new solution and name it TodoSolution.


Add a new .NET Core Console application called "DatabaseTest".
Install the SmartIT.DebugTraceHelper package's latest version from nuget.org and install the SmartIT.Employee.MockDB 1.0.4
package's latest version too.
Let's test from MockDB test to get the Todo list.

1. using SmartIT.DebugHelper;
2. using SmartIT.Employee.MockDB;
3. using System;
4.
5. namespace DatabaseTest
6. {
7. class Program
8. {
9. static void Main(string[] args)
10. {
11. TodoRepository _todoRepository = new TodoRepository();
12. var todoList=_todoRepository.GetAll();
13. todoList.CDump("Todos");
14. Console.ReadLine();
15. }
16. }
17. }

You will see that SmartIT.DebugHelper object extension CDump() method writes Todo list as JSON format to the console below.
Note

SmartIT.DebugHelper also has DDump() object extension method writing the Output debug window.

1. namespace SmartIT.DebugHelper
2. {
3. public static class DebugHelper
4. {
5. public static void CDump(this object obj, string message);
6. public static void DDump(this object obj, string message);
7. }
8. }
9. class Program
10. {
11. static void Main(string[] args)
12. {
13. TodoRepository _todoRepository = new TodoRepository();
14. var todoList=_todoRepository.GetAll();
15. todoList.DDump("Todos");
16.
17. Console.ReadLine();
18. }
19. }

SmartIT.DebugHelper DDump() extension method is useful when you are using other project types as given below because
other projects may not have console output functionally.
In Database CRUD operation, we need to use the below TodoRepository functionalities.

1. _todoRepository.GetAll();
2. _todoRepository.FindById()
3. _todoRepository.Add()
4. _todoRepository.Add(new SmartIT.Employee.MockDB.Todo() { Name = collection["Name"] });
5. _todoRepository.Update(newTodo);
6. _todoRepository.Delete(deleteTodo)

Let's test these functionalities before we use them.

1. static void Main(string[] args)


2. {
3. TodoRepository _todoRepository = new TodoRepository();
4. var todoList = _todoRepository.GetAll();
5. todoList.CDump("_todoRepository.GetAll()");
6. var findById = _todoRepository.FindById(2);
7. findById.CDump("_todoRepository.FindById(2)");
8. var newTodo = _todoRepository.Add(new Todo { Name = "Call a friend" });
9. _todoRepository.GetAll().CDump("Check if Call a friend todo added?");
10. newTodo.Name = newTodo.Name + " Updated";
11. _todoRepository.Update(newTodo);
12. _todoRepository.GetAll().CDump("Check if Call a friend todo updated with Updated?");
13. _todoRepository.Delete(_todoRepository.FindById(1));
14. _todoRepository.GetAll().CDump("Check if Id=1 todo is Deleted?");

We can see from the below output that all Todo functionality was passed for GetAll, FindById, Update, and Delete.
Part 2

Add a new Todo.Mvc.Ui ASP.NET Core web application project.

Add nuGet packages to newly created Todo.Mvc.Ui project. Install the latest versions of SmartIT.DebugTraceHelper and
SmartIT.Employee.MockDB 1.0.4 packages from nuget.org.
Rebuild the Todo.Mvc.Ui project.
Right-click on the Controllers directory and select "Add Controller".

Select MVC Controller with read/write actions like below.

Name the Controller as "TodoController".

Add the namespaces to the TodoController file.

1. using SmartIT.DebugHelper;
2. using SmartIT.Employee.MockDB;

Add todo repository on the top of the TodoController class as a private member.

TodoRepository _todoRepository = new TodoRepository();


Update the public ActionResult Index() method return value with all todo list calling GetAll() method.

return View(_todoRepository.GetAll());

Here, you can see the changes in the below code section.

1. public class TodoController : Controller


2. {
3. TodoRepository _todoRepository = new TodoRepository();
4. // GET: Todo
5. public ActionResult Index()
6. {
7.
8. return View(_todoRepository.GetAll());
9. }

Right-click on the View in Index() method and select "Add View" like in the below screenshot.

Choose default View name as "Index".

Our Todo class is not in Model class drop-down list. So, we need a workaround.

Work around

Inside Models directory, add a new Workaround class.


And temporarily, write a new Todo class that inherits from SmartIT.Employee.MockDB.Todo class.

1. namespace Todo.Mvc.Ui.Models
2. {
3. public class Todo : SmartIT.Employee.MockDB.Todo{}
4. }

Now, add a View to Index and chose Todo model class.

Index.html page changes the model namespace to SmartIT.Employee.MockDB.

Let's change the Route tempale from template: "{controller=Home}/{action=Index}/{id?}"); to todo.

1. app.UseMvc(routes =>
2. {
3. routes.MapRoute(
4. name: "default",
5. template: "{controller=Todo}/{action=Index}/{id?}");
6. });

And, run the project.

From Index page, click the "Create New" link.


Update the HttpPost Create method like below.

1. [HttpPost]
2. [ValidateAntiForgeryToken]
3. public ActionResult Create(IFormCollection collection)
4. {
5. try
6. {
7. _todoRepository.Add(new SmartIT.Employee.MockDB.Todo() { Name=collection["Name"});
8.
9. return RedirectToAction(nameof(Index));
10. }
11. catch
12. {
13. return View();
14. }
15. }

Add a new todo.


1. @model IEnumerable<SmartIT.Employee.MockDB.Todo>
2. @{
3. ViewData["Title"] = "Index";
4. }
5. <h2>Index</h2>
6. <p>
7. <a asp-action="Create">Create New</a>
8. </p>
9. <table class="table">
10. <thead>
11. <tr>
12. <th>
13. @Html.DisplayNameFor(model => model.Id)
14. </th>
15. <th>
16. @Html.DisplayNameFor(model => model.Name)
17. </th>
18. <th></th>
19. </tr>
20. </thead>
21. <tbody>
22. @foreach (var item in Model)
23. {
24. <tr>
25. <td>
26. @Html.DisplayFor(modelItem => item.Id)
27. </td>
28. <td>
29. @Html.DisplayFor(modelItem => item.Name)
30. </td>
31. <td>
32. @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
33. @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
34. @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
35. </td>
36. </tr>
37. }
38. </tbody>
39. </table>

Press F5 and run the project. Then, go to todo like below.

http://localhost:63274/todo

Add a "Create page". Go to TodoController Create() Method, right click on the method, and select "Add View".

Select View name and View Model like in the below picture and click the "Add" button.
Inside Create.html, change the first line from Todo.Mvc.Ui.Models.Todo to SmartIT.Employee.MockDB.Todo. Delete the id
section.

1. <div class="form-group">
2. <label asp-for="Id" class="control-label"></label>
3. <input asp-for="Id" class="form-control" />
4. <span asp-validation-for="Id" class="text-danger"></span>
5. </div>

We delete the id because it is automatically added by the TodoRepository.

1. @model SmartIT.Employee.MockDB.Todo
2.
3. @{
4. ViewData["Title"] = "Create";
5. }
6.
7. <h2>Create</h2>
8.
9. <h4>Todo</h4>
10. <hr />
11. <div class="row">
12. <div class="col-md-4">
13. <form asp-action="Create">
14. <div asp-validation-summary="ModelOnly" class="text-danger"></div>
15. <div class="form-group">
16. <label asp-for="Name" class="control-label"></label>
17. <input asp-for="Name" class="form-control" />
18. <span asp-validation-for="Name" class="text-danger"></span>
19. </div>
20. <div class="form-group">
21. <input type="submit" value="Create" class="btn btn-default" />
22. </div>
23. </form>
24. </div>
25. </div>
26.
27. <div>
28. <a asp-action="Index">Back to List</a>
29. </div>
30.
31. @section Scripts {
32. @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
33. }

Add an "Edit" View page.


Go to the Index.cshtml page.

1. <td>
2. @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
3. @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
4. @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
5. </td>

Update the Edit, Details, and Delete links.

1. @Html.ActionLink("Edit", "Edit", new { id=item.Id }) |


2. @Html.ActionLink("Details", "Details", new { id=item.Id }) |
3. @Html.ActionLink("Delete", "Delete", new { id=item.Id })

Go to the TodoController page and update the public ActionResult Edit(int id) method, and pass the findTodo to the View.

1. // GET: Todo/Edit/5
2. public ActionResult Edit(int id)
3. {
4. var findTodo = _todoRepository.FindById(id);
5. return View(findTodo);
6. }

Add a new "Edit" View to the Edit method like below. The template is Edit and Model class is Todo.

Click "Add" button.

This will create the Edit.cshtml page like below.

1. @model Todo.Mvc.Ui.Models.Todo
2. @{
3. ViewData["Title"] = "Edit";
4. }
5. <h2>Edit</h2>
6. <h4>Todo</h4>
7. <hr />
8. <div class="row">
9. <div class="col-md-4">
10. <form asp-action="Edit">
11. <div asp-validation-summary="ModelOnly" class="text-danger"></div>
12. <div class="form-group">
13. <label asp-for="Id" class="control-label"></label>
14. <input asp-for="Id" class="form-control" />
15. <span asp-validation-for="Id" class="text-danger"></span>
16. </div>
17. <div class="form-group">
18. <label asp-for="Name" class="control-label"></label>
19. <input asp-for="Name" class="form-control" />
20. <span asp-validation-for="Name" class="text-danger"></span>
21. </div>
22. <div class="form-group">
23. <input type="submit" value="Save" class="btn btn-default" />
24. </div>
25. </form>
26. </div>
27. </div>
28. <div>
29. <a asp-action="Index">Back to List</a>
30. </div>
31. @section Scripts {
32. @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
33. }

Delete the Id section because we don’t want to update the primary key Id.

1. <div class="form-group">
2. <label asp-for="Id" class="control-label"></label>
3. <input asp-for="Id" class="form-control" />
4. <span asp-validation-for="Id" class="text-danger"></span>
5. </div>

Update Todo reference from @model Todo.Mvc.Ui.Models.Todo to SmartIT.Employee.MockDB.Todo

Below is the final updated version of Edit View.

1. @model SmartIT.Employee.MockDB.Todo
2. @{
3. ViewData["Title"] = "Edit";
4. }
5. <h2>Edit</h2>
6. <h4>Todo</h4>
7. <hr />
8. <div class="row">
9. <div class="col-md-4">
10. <form asp-action="Edit">
11. <div asp-validation-summary="ModelOnly" class="text-danger"></div>
12. <div class="form-group">
13. <label asp-for="Name" class="control-label"></label>
14. <input asp-for="Name" class="form-control" />
15. <span asp-validation-for="Name" class="text-danger"></span>
16. </div>
17. <div class="form-group">
18. <input type="submit" value="Save" class="btn btn-default" />
19. </div>
20. </form>
21. </div>
22. </div>
23. <div>
24. <a asp-action="Index">Back to List</a>
25. </div>
26. @section Scripts {
27. @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
28. }

Press F5 and run the project. From the Index page, click "Edit".
Let's wire the Edit/Save button.

Go back to TodoController HttpPost Edit method and update the // TODO: Add update logic here section.

1. [HttpPost]
2. [ValidateAntiForgeryToken]
3. public ActionResult Edit(int id, IFormCollection collection)
4. {
5. try
6. {
7. // TODO: Add update logic here
8.
9. return RedirectToAction(nameof(Index));
10. }
11. catch
12. {
13. return View();
14. }
15. }

Here is the updated edit section. Using id, we find the todo item and using form collection with name key, findTodo.Name =
collection["Name"];

We can update the Name value.

1. [HttpPost]
2. [ValidateAntiForgeryToken]
3. public ActionResult Edit(int id, IFormCollection collection)
4. {
5. try
6. {
7. var findTodo = _todoRepository.FindById(id);
8. findTodo.Name = collection["Name"];
9.
10. return RedirectToAction(nameof(Index));
11. }
12. catch
13. {
14. return View();
15. }
16. }

Press F5 and run the project. From the Index page, click "Edit".

Click on the Id=2 Do Dishes Edit link.

Update name to "Do dishes-DONE".

Click "Save" button and we can see the value is updated in the Index View.
Let's create the Details View.

Go to TodoController Details method below.

Add a View named as Details, select the template as Details, and set the Model class as Todo.
Click "Add" button and Detail.cshtml will be created like below.

Detail.cshtml

1. @model Todo.Mvc.Ui.Models.Todo
2. @{
3. ViewData["Title"] = "Details";
4. }
5. <h2>Details</h2>
6. <div>
7. <h4>Todo</h4>
8. <hr />
9. <dl class="dl-horizontal">
10. <dt>
11. @Html.DisplayNameFor(model => model.Id)
12. </dt>
13. <dd>
14. @Html.DisplayFor(model => model.Id)
15. </dd>
16. <dt>
17. @Html.DisplayNameFor(model => model.Name)
18. </dt>
19. <dd>
20. @Html.DisplayFor(model => model.Name)
21. </dd>
22. </dl>
23. </div>
24. <div>
25. @Html.ActionLink("Edit", "Edit", new { /* id = Model.PrimaryKey */ }) |
26. <a asp-action="Index">Back to List</a>
27. </div>

As usual, update your workaround change from Todo.Mvc.Ui.Models.Todo name space to SmartIT.Employee.MockDB.Todo.

Update Edit link id from @Html.ActionLink("Edit", "Edit", new { /* id = Model.PrimaryKey */ }) to new { id = Model.Id })

Here is the updated Details View.

1. @model SmartIT.Employee.MockDB.Todo
2. @{
3. ViewData["Title"] = "Details";
4. }
5. <h2>Details</h2>
6. <div>
7. <h4>Todo</h4>
8. <hr />
9. <dl class="dl-horizontal">
10. <dt>
11. @Html.DisplayNameFor(model => model.Id)
12. </dt>
13. <dd>
14. @Html.DisplayFor(model => model.Id)
15. </dd>
16. <dt>
17. @Html.DisplayNameFor(model => model.Name)
18. </dt>
19. <dd>
20. @Html.DisplayFor(model => model.Name)
21. </dd>
22. </dl>
23. </div>
24. <div>
25. @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
26. <a asp-action="Index">Back to List</a>
27. </div>

Let's update the Details method that returns the selected Todo item to the Details view.

1. // GET: Todo/Details/5
2. public ActionResult Details(int id)
3. {
4. return View();
5. }

Using the id Details method parameter find the Todo item and sent to the View.

Here is the updated Details method.

1. public ActionResult Details(int id)


2. {
3. var findTodo = _todoRepository.FindById(id);
4. return View(findTodo);
5. }

Press F5 and run the project.

Pick "Call Boss" Todo item and see the Detail View like below.
Add Delete View.

Go to TodoController and Update the Delete method from

1. // GET: Todo/Delete/5
2. public ActionResult Delete(int id)
3. {
4. return View();
5. }

To find delete Todo item using passed id number, pass to the View as argument like below.

1. public ActionResult Delete(int id)


2. {
3. return View(_todoRepository.FindById(id));
4. }

Add "Delete" View like below by selecting View name as Delete, Template as Delete, and Model class as Todo.
Click the "Add" button.

Using out workaround update Todo name space from @model Todo.Mvc.Ui.Models.Todo to SmartIT.Employee.MockDB.Todo.

Here is the updated Delete.cshtml View page.

1. @model SmartIT.Employee.MockDB.Todo
2. @{
3. ViewData["Title"] = "Delete";
4. }
5. <h2>Delete</h2>
6. <h3>Are you sure you want to delete this?</h3>
7. <div>
8. <h4>Todo</h4>
9. <hr />
10. <dl class="dl-horizontal">
11. <dt>
12. @Html.DisplayNameFor(model => model.Id)
13. </dt>
14. <dd>
15. @Html.DisplayFor(model => model.Id)
16. </dd>
17. <dt>
18. @Html.DisplayNameFor(model => model.Name)
19. </dt>
20. <dd>
21. @Html.DisplayFor(model => model.Name)
22. </dd>
23. </dl>
24.
25. <form asp-action="Delete">
26. <input type="submit" value="Delete" class="btn btn-default" /> |
27. <a asp-action="Index">Back to List</a>
28. </form>
29. </div>

Update the HttpPost Delete method section // TODO: Add delete logic here

1. // POST: Todo/Delete/5
2. [HttpPost]
3. [ValidateAntiForgeryToken]
4. public ActionResult Delete(int id, IFormCollection collection)
5. {
6. try
7. {
8. // TODO: Add delete logic here
9.
10. return RedirectToAction(nameof(Index));
11. }
12. catch
13. {
14. return View();
15. }
16. }

With the following code.

1. public ActionResult Delete(int id, IFormCollection collection)


2. {
3. try
4. {
5. var findTodo = _todoRepository.FindById(id);
6. _todoRepository.Delete(findTodo);
7.
8. return RedirectToAction(nameof(Index));
9. }
10. catch
11. {
12. return View();
13. }
14. }

Press F5 and run the project again.

Select Do Dishes link and below, the Delete View shows.


Click on the "Delete" button.

We can see that "Do Dishes" Todo item has been deleted.

Finally, comment out the workaround class which we don’t need anymore.

Summary

In this article, we have learned,

 How to consume Todo in-memory database using TodoRepository


 How to create custom ASP.NET MVC custom controller with CRUD operations.
 List of Objects
 How to create a new insert object via View
 How to update an object via Edit View
 How to delete an Item via Delete View.
 How to write HttpPost and create API method.
 How to write Httppost and edit API method.
 How to write HttpPost and delete API method.
 About the SmartIT DebugTraceHelper tool

Download source code from GitHub.

Вам также может понравиться