Table of contents

Last updated .

< Previous chapterNext chapter >

A simple data entry app

I am going to create a simple data-entry app to explore some more features of ASP.Net MVC. I will still be scratching the surface, though, and I will come back to it all in more depth later.

Building on the solution I worked on in the previous chapter I'll make a simple app that allows the user to create a list of his or her contacts. A Contact is simply an object with ID, Name and Email properties. In the real world, these contact objects would be stored in a database of some sort, but in order not to clutter up the picture with a lot of data access talk, I'll simply make a simple in-memory "database", implemented with a static data structure that I have defined in a new MockDatabase.cs file:

MockDatabase.cs
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
using System.Collections.Concurrent; using MVCTutorial.Models; namespace MVCTutorial { static public class MockDatabase { static public ConcurrentBag<Contact> Contacts { get; set; } = new ConcurrentBag<Contact>(); } }

I am using a collection type from the System.Collections.Concurrent namespace; in principle, any data in a web application is likely to be accessed by many concurrent threads, so it seemed the right thing to do, although it's unlikely to make any practical difference with this little sample app.

I updated the HomeController to make use of the new MockDatabase:

Controllers/HomeController.cs
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
using Microsoft.AspNet.Mvc; namespace MVCTutorial.Controllers { public class HomeController : Controller { public ViewResult Index() { ViewData["Title"] = "Contacts"; return View(MockDatabase.Contacts.ToArray()); } } }

We need a separate view, in which the user can add the values for a new contact. So, I added a Views/Contact/Index.cshtml file for the view:

Views/Contact/Index.cshtml
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
@using MVCTutorial.Models @model Contact <!doctype html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>Create a new contact</h1> @using (Html.BeginForm("AddContact", "Contact")) { <p>Name: @Html.TextBoxFor(c => c.Name)</p> <p>Email: @Html.TextBoxFor(c => c.Email)</p> <input type="submit" value="Save" /> } </body> </html>

Here, I am using a number of Html Helper methods to help me generate some html easily. ASP.Net comes with a set of Html helpers that are convenient for rendering forms, input elements and other types of content. The Html.TextBoxFor method outputs the markup for an input element of type text. I am using a strongly typed data model in this view, so I can use a lambda expression to supply the only argument needed: the property that the textbox represents. This provides the helper with sufficient information that it can generate some markup (using reflection), for example: <input id="Email" name="Email" type="text" value="" />.

Defining a @model enables Visual Studio intellisense for the model types in the view editor
Defining a @model enables Visual Studio intellisense for the model types in the view editor

I am also using a Html.BeginForm method to generate a html form tag. The two parameters are for actionName and controllerName, respectively, and determine what action is going to be invoked when the form is submitted - the two parameters are used to form the value of the action tag of the form element. In this case, the resulting form tag reads <form action="/Contact/AddContact" method="post">. Note that the using statement causes the generated form tag to be closed. In other words, a </form> tag is inserted where the using statement ends.

So, now we have a page with a form, containing two text boxes and a button to submit the form. The form submits to the AddContact method of a Contact controller. That controller doesn't exist, so we'd better create it. I added a ContactController to the Controllers folder:

Controllers/ContactController.cs
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
using Microsoft.AspNet.Mvc; using MVCTutorial.Models; namespace MVCTutorial.Controllers { public class ContactController : Controller { public ViewResult Index() { ViewData["Title"] = "Add Contact"; return View(new Contact()); } [HttpPost] public RedirectToActionResult AddContact(Contact contact) { contact.ID = MockDatabase.Contacts.Count + 1; MockDatabase.Contacts.Add(contact); return RedirectToAction("Index", "Home"); } } }

The controller contains a Index method that simply renders the Contact view and a AddContact method to add a new contact. This is the method to be called when the form that we just implemented is submitted. This method contains the code to add a new record to the in-memory database and then redirect to the Home controller to render the homepage. Notice that the method is adorned with a HttpPost attribute, telling ASP.Net that this method is only to be called in response to a HTTP POST request. The method receives a Contact object. Somehow, this object is instantiated, its properties populated with values taken from the submitted values. This is Model binding in action. ASP.Net is able to grab the submitted form values and use them for setting values on a new Contact object. This works, because we named the input elements in the view after the properties they represent.

There is only a tiny bit missing now: We need a way for the user to navigate from the homepage to the Contact page. We can do that by using another Html helper to add an ActionLink (an anchor tag) in the Home/Index.cshtml view (line 18):

Views/Home/Index.cshtml
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
@* View for the Home/Index action *@ @using MVCTutorial.Models @model Contact[] <!doctype html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>Hello from HomeController.Index !</h1> <h2>Contacts:</h2> <ul> @foreach (Contact contact in Model) { <li>@contact.Name: @contact.Email</li> } </ul> @Html.ActionLink("Create Contact", "Index", "Contact") </body> </html>

The action link specifies that the Index action of the Contact controller should be called to generate the view. In this case, the action link generates the following markup for an anchor tag: <a href="/Contact">Create Contact</a>. Now, when the user loads up the homepage, there is a link to go to another page to create a new contact:

The homepage
The homepage
The Contact create page
The Create Contact page

When the user clicks Save, the new Contact object is added to the database, and the user is directed back to the homepage to see the results:

List with the new contact
List with the new contact

A bit of work still remains before this application can go into this production. For one thing, there is no validation; for example it would be relevant to validate that a valid email address is given for a new contact. Also, there is no css styling, so the UI is far from appealing.

< Previous chapterNext : Using client-side libraries >


2016 by Niels Hede Pedersen Linked in