Data Persistence on ASP.NET MVC Applications with EntityFramework

Posted by – February 27, 2009

There’s no doubt, ASP.NET is an amazing technology, very productive and easy to use, but it isn’t perfect, his architecture doesn’t help enough when you need add unit tests in your project and you can’t see a clean separation of concerns, some of its urls used to access pages isn’t so intuitive, if you need pass some data over browser address bar it will only read by accessing the old QueryString object.

As completly opposite we have ASP.NET MVC, some of its urls are very intuitive, you don’t need use something like QueryString object to read parameters passed via GET method, you can see a clear separation between model, view and controller layers, all ASP.NET MVC applications can be easily tested using the most famous unit tests frameworks.

In this article I’ll give a small introduction to web development with ASP.NET MVC and data persistence using ADO.NET EntityFramework, a simple contacts application will show how to accomplish this.

We need consider the following requirements before start our project:

1. Visual Studio Web Developer Express 2008 SP 1

The IDE to be used in this article, you can download the online installer here, please run this installer to install Visual Studio Express 2008 and all additional software like the .NET Framework 3.5 and SQL Server Express 2008.

2. ASP.NET MVC 1.0

You can download the installer here, the installer contains ASP.NET MVC assemblies and Visual Studio Express project templates.

Project setup:

Once all required software is installed, it’s time to run Visual Studio Express to create our first ASP.NET MVC project, please go to File ->New Project like we see in the picture below:

new_project_menu

A dialog window will be opened allowing the developer to select the project template, please select “ASP.NET MVC Web Application” like below:

new_aspnetmvc_project

It will create a sample project based on the selected template, this project has the following solution layout:

solution_layout

Please remove View/Account folder, Views/Shared/LogOnUserControl.ascx and Controllers/AccountController.cs files from project solution since they won’t be used in this project.

Creating SQL Server database:

There’s absolutelly no way to give a introduction to entityframework without setup a SQL Server database first, I’m assuming that you have successfully installed SQL Server 2008 during Visual Studio Web Developer Express 2008 SP 1 setup, if yes, you can manage databases using SQL Server Management Studio that can be found at Microsoft SQL Server 2008 program group in start menu.

start_menu_managementstudio

Please login and go to the Object Explorer at the left side of management studio window and then do a right click in Databases node of server tree to select New Database… option of context menu.

database_context_menu

Call the database as registration like below and click on “OK” button:

new_database_dialog

Now expand registration database in tree and do a right click on Tables node to select “New Table…” option in context menu:

table_context_menu

Our table has 3 fields: Id, name and address, the id field will be out entity column, you can set a column as identity column in column properties tab exactly like the image below:

new_table_identity_column

We will also set the id column as primary key of this table, you can set a column as primary key by just doing a right click on column name and select “Set Primary Key” in context menu.

set_primary_key_table

Now click on save button in toolbar, this will create the table in database, please call this table as “Contact” and press “OK” button.

save_table

Creating entityframework model:

At this point we can add a entityframework model to our project, please right click on model folder and select Add->New Item on popup menu.

add_new_item

Please select “ADO.NET Entity Data Model” in the project templates.

new_entitymodel

Now you must choose the database connection to be used by this model.

generate_model_choose_connection

Select the server and database and click in “OK” button.

generate_model_connection_properties

Once you have selected the server and database a entityframework provider connection string is show in the wizard main window.

generate_model_selected_connection

Click in the next button to select the tables to be added on entityframework model.

generate_model_choose_tables

You can change entities properties/mappings in entityframework model designer.

entityframework_model_designer

With entityframework support in our application we will can easily persist contact info, but it isn’t everything, we also need implement contact view and controller. Let’s start write contact view first.

Creating ASP.NET MVC master pages:

ASP.NET MVC allows the use of master pages, with this feature you can create a template for several pages in your application, helping on reduce the amount of code required to write you application views.

Please do a right click on Views/Shared folder and select Add -> New item… on context menu, a dialog window will be opened and you must select “MVC View Master Page” exactly like below:

new_masterpage

Here’s what you must copy and paste into the file created above:

BasicForm.master

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <link href="../../Content/theme/ui.all.css" rel="stylesheet" type="text/css" />
    <script src="../../Scripts/jquery-1.3.1.js" type="text/javascript"></script>
    <script src="../../Scripts/jquery-ui-personalized-1.6rc6.min.js" type="text/javascript"></script>
    <asp:ContentPlaceHolder ID="pageHeader" runat="server"/>
</head>
<body>
    <table border="0" cellspacing="0" cellpadding="0" width="100%" height="100%">
        <tr>
            <td valign="top">
                <table width="600px" border="0" cellspacing="0" cellpadding="0" align="center">
                    <tr>
                        <td valign="top" height="23">
                            &#160;&#160;&#160;<big><asp:ContentPlaceHolder ID="title" runat="server"/></big>
                        </td>  
                    </tr>
                    <tr>
                        <td>
                            <%= Html.ValidationSummary() %>
                        </td>                              
                    </tr>
                </table>
                <asp:ContentPlaceHolder ID="form" runat="server"/>
            </td>
        </tr>
    </table>
</body>
</html>

BasicForm.master is a master page that contains the layout of page used to show a form where the user can enter data, you can define which portions of this master page can be customized by inserting one or more <asp:ContentPlaceHolder/> tags on it (lines 10, 19 and 28), each <asp:ContentPlaceHolder/> tag will be replaced by the contents of <asp:Content tag/> that is declared on the page that uses this master page.

Repeat the same steps as above to create another master page called BasicList.master, this master page contains the structure of all pages that will list contacts or any other kind of data to the user.

BasicList.master

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <asp:ContentPlaceHolder ID="pageHeader" runat="server"/>
</head>
<body>
    <table align="center" border="0" cellspacing="0" cellpadding="0"
        height="100%">
        <tr>
            <td align="left">
                <big>
                    <big>
                        <asp:ContentPlaceHolder ID="title" runat="server"/>
                    </big>
                </big>
                <br />
                <br />
                <br />
                <asp:ContentPlaceHolder ID="list" runat="server"/>
            </td>
        </tr>
    </table>
</body>
</html>

BasicList.master is the other master page that we are using to provide the layout of all pages that just display data to the user.

Creating ASP.NET MVC views:

Now we must implement the view, this view will use the master page above, we only need provide the html content to the content placeholders inserted in master page code.

Please create Views/Contact folder and then do a right click on this folder and select Add -> View… in context menu:

new_view

new_view_dialog

Contact.aspx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/BasicForm.Master" Inherits="System.Web.Mvc.ViewPage<Registration.Models.Contact>" %>

<asp:Content ID="pageHeader" ContentPlaceHolderID="pageHeader" runat="server">
    <title>Contact Registration</title>
    <!-- Preparing input field to work with jQuery datepicker -->
    <script type="text/javascript">
        jQuery(function() {
            jQuery("#Birthdate").datepicker({ dateFormat: 'dd/mm/yy' });
        });
    </script>      
</asp:Content>

<asp:Content ID="title" ContentPlaceHolderID="title" runat="server">
    Contact Registration
</asp:Content>

<asp:Content ID="form" ContentPlaceHolderID="form" runat="server">
    <%using (Html.BeginForm("Save", "Contact", FormMethod.Post))
     {%>
        <table align="center" border="0" cellspacing="0" cellpadding="1" width="600px"
            bgcolor="#F7F7F7">
            <tr>
                <td colspan="2">&nbsp;</td>
            </tr>
            <tr>
                <td colspan="2">Contact Details:</td>
            </tr>
            <tr>
                <td colspan="2">&nbsp;</td>
            </tr>
            <tr>
                <td>
                    <label for="Nome">Name</label>
                </td>
                <td>
                    <%=Html.TextBox("Name", ViewData.Model.Name,
                        new
                       {
                           maxlength = "80",
                           size = "45",
                           title = "Please type contact name."
                       })%>
                    <font color="#990000" size="1">(full name)</font>
                </td>
            </tr>
            <tr>
                <td>
                    <label for="Address">Address</label>
                </td>
                <td>
                    <%=Html.TextBox("Address", ViewData.Model.Address,
                        new
                       {
                           maxlength = "255",
                           size = "60",
                           title = "Please type contact address."
                       })%>
                </td>
            </tr>
            <tr>
                <td>
                    <label for="Birthdate">Data Nascimento</label>
                </td>
                <td>
                    <%=Html.TextBox("Birthdate", ViewData.Model.Birthdate.HasValue ? ViewData.Model.Birthdate.Value.ToString("dd/MM/yyyy") : null,
                        new
                       {
                           maxlength = "10",
                           Readonly = "readonly",
                           size = "15",
                           title = "Please select the bithdate."
                       })%>
                </td>
            </tr>          
            <tr>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td colspan="2" align="right">
                    <br />
                    <input type="submit" value="Save" />
                </td>
            </tr>
            <tr>
                <td>&nbsp;</td>
            </tr>
        </table>
    <%}%>  
</asp:Content>

The contents of Contact.aspx give to us an idea about how to use master pages in a ASP.NET MVC based application, the Page directive contains a MasterPageFile attribute where we can provide the path to master page (line 1), the contents of page header are defined by <asp:Content/> tag (lines 3 to 11), we are also using this tag to insert form title (lines 13 to 15) and the contents of the form on master page (lines 17 to 89).

ASP.NET MVC comes with several helper classes that can be used to facilitate the view definition, the contents of the page above shows how we can use the Html helper class to generate form and all input fields on it, all of then are generated in a way that can provide and easy interaction between view and framework controller (lines 18, 36, 51 and 65).

You must also create the view used to list contacts using the same steps described above, call this view as List and replace the generated code by this code below:

List.aspx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<!-- The view above uses the Contact entity as its data model -->
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/BasicList.Master" Inherits="System.Web.Mvc.ViewPage<List<Registration.Models.Contact>>" %>

<asp:Content ID="pageHeader" ContentPlaceHolderID="pageHeader" runat="server">
    <title>Contacts List</title>
</asp:Content>

<asp:Content ID="title" ContentPlaceHolderID="title" runat="server">
    Contacts List
</asp:Content>

<asp:Content ID="list" ContentPlaceHolderID="list" runat="server">
    <%if (ViewData.Model.Count > 0)
      {%>
        <table>
          <tr>
            <th></th>
            <th></th>
            <th>Id</th>
            <th>Name</th>
          </tr>
          <%foreach (var contact in ViewData.Model)
           {%>
               <tr>
                <td>
                    <%using (Html.BeginForm("Edit", "Contact", new { id = contact.Id }, FormMethod.Get))
                     {%>
                        <div>
                            <input type="submit" value="Edit"/>
                        </div>
                    <%}%>
                </td>
                <td>
                    <%using (Html.BeginForm("Delete", "Contact", new { id = contact.Id }, FormMethod.Post))
                     {%>
                        <div>
                            <input type="submit" value="Delete"/>
                        </div>
                    <%}%>
                </td>
                <td><%= contact.Id%></td>
                <td><%= contact.Name%></td>
               </tr>
           <%}%>
        </table>
    <%}
     else
     {%>
        <big>
            <span>There's no contacts registered!</span>           
        </big>
    <%}%>    
    <br />
    <br />
    <center>
        <%using (Html.BeginForm("Novo", "Contact", FormMethod.Get))
         {%>
            <input type="submit" value="New Contact" />
        <%}%>
    </center>
</asp:Content>

List.aspx also uses a master page, here we are inserting the code necessary to display a contact list to the user, this page takes advantage of a the same html helper class described previously that provides an easy way to read model properties.

Creating a controller:

We need a controller to handle data at server side, the controller is the key piece in ASP.NET MVC, it contains the majority of application logic of our application.

You can add a controller in your project by doing a right click on Controllers folder and then select Add->Controller on context menu:

new_controller

Call this controller as ContactController and click on Add button:

new_controller_dialog

This will create a file named ContactController.cs in Controllers folder of project solution.

The following code block contains the implementation of ContactController, you can copy and paste it in the file created in the step above.

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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Registration.Models;

namespace Contacts.Controllers
{

    [HandleError]
    public class ContactController : Controller
    {
        /*
        The action bellow will be called to list all existing contacts.
        */

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult List()
        {
            //Retrieving EntityFramework context
            RegistrationEntities registration = new RegistrationEntities();

            //Storing a list of contact in view model
            ViewData.Model = registration.Contact.ToList();

            //Return the view used to list contacts to the user.
            return View("List");
        }

        /*
        This action is called to add a new contact to database.
        */

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult New()
        {
            ViewData.Model = new Contact();

            return View("Contact");
        }

        /*
        This action is called to persist a contact to database.
        */

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Save(Contact contact)
        {
            //Retrieving EntityFramework context
            RegistrationEntities registration = new RegistrationEntities();

            var contact = new Contact();
            contact = registration.Contact.First(c => c.Id == id);
            TryUpdateModel(contact, new string[] { "Name", "Address" }, form.ToValueProvider());

            //Validating user entered data
            if (String.IsNullOrEmpty(contact.Name))
                ModelState.AddModelError("Name", "Name required!");
            if (String.IsNullOrEmpty(contact.Address))
                ModelState.AddModelError("Address", "Address required!");

            //If data is valid then persist contact info to database
            if (ModelState.IsValid)
            {
                registration.AddToContact(contact);
                registration.SaveChanges();
                //Return to contacts list
                return RedirectToAction("List");
            }

            ViewData.Model = contact;
            return View("Contact");
        }

        /*
        This action is called to edit contact info.
        */

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Edit(int id)
        {
            //Retrieving EntityFramework context
            RegistrationEntities registration = new RegistrationEntities();

            var contact = registration.Contact.First(c => c.Id == id);

            ViewData.Model = contact;

            return View("Contact");
        }

        /*
        This action is called to remove a contact from database.
        */

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Delete(int id)
        {
            //Retrieving EntityFramework context
            RegistrationEntities registration = new RegistrationEntities();

            //Retrieve contact instance from database by its id
            var contact = registration.Contact.First(c => c.Id == id);

            //Remove contact from database and commit changes
            registration.DeleteObject(contact);
            registration.SaveChanges();

            //Return to contacts list
            return RedirectToAction("List");
        }
    }
}

In the example above we have methods to handle some actions performed by user on view, each method returns a ActionResult, with a ActionResult you can tell to ASP.NET MVC which kind of operation the framework must take to generate a response to the user.

Running application on server:

At this point we are ready to run our first ASP.NET MVC application on webserver, you can easily test your application by just clicking on “Run->Debug” menu on Visual Studio Web Developer Express 2008. Please try by yourself and let me know what you think ASP.NET MVC.

Share

1 Comment on Data Persistence on ASP.NET MVC Applications with EntityFramework

  1. VArsovski10 says:

    Yah, and ever tried to use Membership with SQL with it ?

    There are too many restrictions (Connection string can’t contain keyword “Provider” – w.t.f.) for it to work properly..

    Can anyone help me (hope at least someone knows how to do it) how to make it work with SqlMembershipProvider and SQL database ?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>