We posted a complete Contact Manager sample ASP.NET MVC Application at the www.ASP.net/mvc website. The source code is available in both C# and VB.NET.

The application is intentionally simple. The goal was to provide members of the ASP.NET community with an application that they could use to quickly learn how to build new applications with ASP.NET MVC.

The Contact Manager application is an address book application. The application enables you to list, create, edit, and delete contacts.

ScreenShot

I built the application over multiple iterations. With each iteration, I gradually improved the application. The goal of this multiple iteration approach was to enable you to understand the reason for each change.

Iteration #1 – Create the application. In the first iteration, we create the Contact Manager in the simplest way possible. We add support for basic database operations: Create, Read, Update, and Delete (CRUD).

Iteration #2 – Make the application look nice. In this iteration, we improve the appearance of the application by modifying the default ASP.NET MVC view master page and cascading style sheet.

Iteration #3 – Add form validation. In the third iteration, we add basic form validation. We prevent people from submitting a form without completing required form fields. We also validate email addresses and phone numbers.

Iteration #4 – Make the application loosely coupled. In this third iteration, we take advantage of several software design patterns to make it easier to maintain and modify the Contact Manager application. For example, we refactor our application to use the Repository pattern and the Dependency Injection pattern.

Iteration #5 – Create unit tests. In the fifth iteration, we make our application easier to maintain and modify by adding unit tests. We mock our data model classes and build unit tests for our controllers and validation logic.

Iteration #6 – Use test-driven development. In this sixth iteration, we add new functionality to our application by writing unit tests first and writing code against the unit tests. In this iteration, we add contact groups.

Iteration #7 – Add Ajax functionality. In the seventh iteration, we improve the responsiveness and performance of our application by adding support for Ajax.

Each iteration has an associated tutorial. You also can download the Visual Studio Solution associated with each iteration. Here is a direct link to the Contact Manager tutorials:

http://www.asp.net/learn/mvc/#MVC_SampleApp

If you liked this blog post then please Subscribe to this blog.
posted on Friday, February 27, 2009 7:51 AM | Filed Under [ Application Building ASP.NET ASP.NET MVC TDD ]

Comments

Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Matthew
on 2/27/2009 4:26 PM

I've just done the first iteration. In the views, there was code to display/edit the id field. This was not in your code. Are you running a newer version. I'm running ( I believe) RC update.
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by JeroenH
on 2/27/2009 8:54 PM

In the sample code (first iteration), the Create/Edit methods have general catch clauses, eating all exceptions. I don't like this kind of code, especially as this is supposed to teach relatively inexperienced developers.
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Max Fraser
on 2/28/2009 2:48 AM

I am still trying to grasp this a bit but in Iteration #4 aren't your interfaces dependent on the Entity Framework objects like Customer? <br /><br />If I use a different ORM in the future wouldn't my Customer objects be different and shouldn't they then also implement say an ICustomer interface?
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by trendbender
on 2/28/2009 7:20 AM

great example, thx Stephen
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by mh415
on 2/28/2009 11:28 AM

After Iteration 1, Listing 2, I get this error when trying to build:<br /><br />The type or namespace name 'ContactManagerDBEntities' could not be found (are you missing a using directive or an assembly reference?)<br /><br />Are you missing a step to add the reference?<br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by mh415
on 2/28/2009 11:34 AM

P.S. Your blog's timezone appears to be set to UTC +12. Is that by design? Perhaps you're blogging from Tuvalu?
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by mh415
on 2/28/2009 11:39 AM

Re: 2 comments up. You meant Models.ContactManagerDBEntities in Listing 2, right?
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by mh415
on 2/28/2009 11:52 AM

I'm finding more small errors. Want them listed here, or should I contact you another way? I don't want to flood your Comments system.
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Stephen.Walther
on 2/28/2009 5:20 PM

@mh415 -- Thanks :) I changed the timezone.
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Stephen.Walther
on 2/28/2009 5:21 PM

@mh415 - Feel free to post any problems that you discover here or email me by clicking the Contact Me link at the top of the page. <br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by JoeReynolds
on 3/1/2009 11:35 AM

This is excellent example, especially iteration 7.<br /><br />You could help a lot of us if you added an iteration 8 that included paging.
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Milan
on 3/1/2009 11:52 AM

Some problems in C# version:<br />- Iteration #4, Listing 1: <br />public interface IContactRepository<br /> {<br />should be<br />public interface IContactManagerRepository<br /> {<br /><br />- ContactManagerService.cs and ContactController have compile time error:<br />Error 1 Inconsistent accessibility: parameter type 'ContactManager.Models.Validation.IValidationDictionary' is less accessible than method 'ContactManager.Models.ContactManagerService.ContactManagerService(ContactManager.Models.Validation.IValidationDictionary)' E:\My Documents\Visual Studio 2008\Projects\ContactManager\ContactManager\Models\ContactManagerService.cs 14 16 ContactManager<br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Milan
on 3/1/2009 12:07 PM

Also download is provided only in VB so I can't download Iteration #4 code and continue tutorial.
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by JB
on 3/1/2009 12:40 PM

Overall, good stuff. I only downloaded the code from the iteration 7 and it compiled and worked well. However, the AJAX browser history stuff you implemented does not appear to work in IE7. Works great in Firefox 3.x but I get no back/forward button love in IE7 when using the Ajax links. Is this an issue in the MSAjax js library?
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by JoeReynolds
on 3/1/2009 10:28 PM

I'm having a problem with your example if I want to obtain only a single column from the Group list.<br /><br />Your code is like so:<br /><br />public IEnumerable<Group> ListGroups()<br /> {<br /> return _entities.GroupSet.ToList();<br /> }<br /><br />This, of course returns everything in the Group. Let's assume th Group table has many columns and only three are needed. What would the code above look like to do that?
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by walter
on 3/2/2009 2:45 AM

It works all great if you allow to edit all fields of a contact. But if you don't want to allow the user to change the Phone (So Phone is only displayed on the view and is not editable <%=Model.Phone %> instead of <%= Html.TextBox("Phone") %>) I get problems.<br /><br />First.<br />In public ActionResult Edit(int groupId, Contact contactToEdit) contactToEdit.Phone will be null so in ValidateContact a NullReferenceException is raised.<br /><br />Second.<br />If you don't validate on Phone, ApplyPropertyChanges in EditContact() throws an exception and next a NullReferenceException is raised in the view on <%=Model.Phone %> because Model=null<br /><br /><br />So, my question is. What to do with a field that you only want to display on your view ?<br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Stephen.Walther
on 3/2/2009 8:22 AM

@Max -- That's a good point. You should strive to program against abstractions (interfaces and abstract classes) as much as possible. When using Entity Framework, it is possible to generate abstract classes instead of concrete classes. However, I don't cover this feature in the tutorial. This would be a good idea for a tip.
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Stephen.Walther
on 3/2/2009 8:25 AM

@Milan -- Thanks for pointing out the missing downloads for iteration #4 -- we are getting this fixed.
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Stephen.Walther
on 3/2/2009 8:41 AM

@Walter -- You can't use ApplyPropertyChanges()when you have read-only properties. In this situation, you must set each property by hand:<br /><br />originalContact.FirstName = contactToEdit.FirstName;<br />originalContact.LastName = contactToEdit.LastName;<br />_entities.SaveChanges();
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Stephen.Walther
on 3/2/2009 8:46 AM

@JoeReynolds -- Using LINQ to SQL, you can specify that you want to return only certain properties:<br /><br />var results = from g in _entities.GroupSet select new {Id=g.Id, Name=g.Name}<br /><br />In this case, even if the group table contained multiple columns, only the Id and Name columns would be returned.
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by achu
on 3/2/2009 10:16 AM

Patterns<br />--------<br />When we use a service layer for business logic then why not use a generic repository (just 1) with IQueriable instead of IEnumerators<br /><br />EF<br />--<br />with new sql server database desgin any advantage EF over Linq 2 SQL ?<br /><br /><a rel="nofollow external" href="http://toomanylayers.blogspot.com/2009/01/entity-framework-and-linq-to-sql.html" title="http://toomanylayers.blogspot.com/2009/01/entity-framework-and-linq-to-sql.html">toomanylayers.blogspot.com/.../...linq-to-sql.html</a><br /><a rel="nofollow external" href="http://www.chadmoran.com/blog/2009/3/1/adonet-ef-v-linq-to-sql-take-4.html" title="http://www.chadmoran.com/blog/2009/3/1/adonet-ef-v-linq-to-sql-take-4.html">www.chadmoran.com/.../...v-linq-to-sql-take-4.html</a><br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by DaveM
on 3/2/2009 10:01 PM

The browser navigation stuff in itteration#7 does not seem to be working with IE7.<br /><br />Have you tested it with IE7 or is it something in my configuration?<br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by walter
on 3/3/2009 12:57 AM

Thanks Stephen for your reply about read-only properties.<br /><br />But it’s a solution for just a part of my problem. Perhaps I should have told more about it. I want Phone only to be read-only for specific users. But an administrator may change it. Then your solution won’t work because Phone will not be saved. So should I then have to make 2 different EditContact(), one with originalContact.Phone = contactToEdit. Phone; for the administrator. And one without for other users !?<br /><br />It seems to me that that is not a nice solution. I think the problem is that if you only want to show Phone (so I use Model.Phone instead of Html.TextBox("Phone") in the view) you won’t get the value back in the controller-action (public ActionResult Edit(int groupId, Contact contactToEdit)). contactToEdit.Phone will be null. Is there a way to get values back from the view even if there read-only ? Then you can just use EditContact() as it was.<br /><br />Even so, without all of the above, you’re solution solves the exception in ApplyPropertyChanges in EditContact(), But still, if you enter a wrong value in Email, a NullReferenceException is raised in the view on Model.Phone because Model=null .<br /><br />One other thing about validation. If you have a datetime-property (RegistrationDate) and on the view you enter something completely wrong (say “%$##”) then contactToEdit. RegistrationDate will have an initial DateTime-value (1-1-0001 0:00:00). This can cause troubles in your own validation, so you should be aware of that.<br /><br />I want to say thanks for your articles and examples. They are great to help me a in learning MVC!<br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Devin
on 3/3/2009 12:59 AM

Thx for you application.<br />I accounted some problems in practice.<br />I used ajax to render the partial view,but the whole page was represented by AJAX way in 'divList'.the second time,i clicked the link in 'divList',it worked well.It surprised me for a long time.I don't know what caused the problem.PLS help me.<br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by achu
on 3/3/2009 9:52 AM

great sample. thanks
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Zazen
on 3/3/2009 11:21 AM

Steve, this last iteration of tutorials is superb. I am completely sold on your upcoming book judging by your teaching skill.
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by JIm Solderitsch
on 3/3/2009 12:15 PM

I have an asp.net mvc project that was not created with a test project in the Visual Studio solution.<br /><br />Can I add one after the fact? I think you mention in iteration #1 that it is better to create the test project at the very beginning.<br /><br />Since that is too late for me now, can I add it after the fact?<br /><br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by mh415
on 3/3/2009 9:24 PM

I couldn't get a Design Gallery template to work with your example, so I tried just a brand new (empty) project and the "Happy Forest" template: <a rel="nofollow external" href="http://www.asp.net/mvc/gallery/View.aspx?itemid=28" title="http://www.asp.net/mvc/gallery/View.aspx?itemid=28">http://www.asp.net/mvc/gallery/View.aspx?itemid=28</a>. Running the project results in a Parser Error: "Could not load type 'DeleteMe.Views.Shared.Site'." I'm new to ASP.NET, so maybe there's an obvious fix, but shouldn't this just work out of the box especially since "Happy Forest" is a template provided by MS?<br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Stephen.Walther
on 3/4/2009 8:24 AM

@mh415 -- Unfortunately, the MVC team keeps releasing new versions of ASP.NET MVC fast and furiously and there are enough changes to cause problems with the design templates that were submitted before the changes. After the final ASP.NET MVC release, I've scheduled a day of reviewing and updating all of the existing design templates to ensure compatibility. Thanks for your patience!
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Stephen.Walther
on 3/4/2009 8:27 AM

@DaveM -- I had to check on the issue of using AJAX History with IE 7 with the AJAX team. To get IE 7.0 compatibility you need to include a hidden IFrame in your page named __historyFrame. I'll update the Contact Manager sample application to include this fix. Thanks for bringing the problem to my attention!
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by mh415
on 3/4/2009 7:32 PM

I tried using your "Contact" page, but got this error:<br /><br />"Your message could not be sent, most likely due to a problem with the mail server."<br /><br />Just a heads-up.<br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Jay Scott
on 3/6/2009 6:28 PM

Thank you for your work on these tutorials. I'm a beginner with .net and they are really helping me to get my feet wet.<br /><br />I have currently made it almost through iteration #6 and I have noticed that for iterations 4-6, I have had to download the code because of build errors in the examples from the tutorial page. This has been frustrating since I'm not experienced at debugging C#. I really wanted to edit the code as I went, but found that in a few cases it was impossible to continue without copying in the downloaded code. Now I'm in a complete mess, so I will start 7 with the downloaded code from 6 and cross my fingers.<br /><br /><br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Mark
on 3/13/2009 10:04 AM

I am having the same problem as in a previous post. <br />The type or namespace name 'ContactManagerDBEntities' could not be found (are you missing a using directive or an assembly reference?)<br /><br />Is there something I am missing? I have tried to do iteration#1 twice and get the same error.
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Mark
on 3/13/2009 11:50 AM

Figured it out.<br /><br />The type or namespace name 'ContactManagerDBEntities' could not be found (are you missing a using directive or an assembly reference?)<br /><br />need to either add reference at top <br />using ContactManager.Models; <br />or full namespace<br />private ContactManagerDBEntities _entities = new ContactManager.Models.ContactManagerDBEntities();<br /><br />Hope this saves someone else some time.
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by gerry lowry
on 5/17/2009 7:59 PM

@ walter:<br /><br />something like this might solve your problem and leave you requiring one form for both your administrator and for the other users.<br /><br />I'm assuming that you'll dynamically added the readonly property to non administrators.<br /><br />I do a similar thing as follows for Html.Encode fields:<br /><br /> var originalArticle = (from m in _db.NewsArticleSet where m.Id == articleToEdit.Id select m).First();<br /><br /> articleToEdit.dateAdded = originalArticle.dateAdded;<br /><br /> articleToEdit.dateEdited = DateTime.Now;<br /><br />In your case, if your "Phone" field is null, you would do something like:<br /><br /> articleToEdit.Phone = originalArticle.Phone;<br /> // set Phone for non administrators<br /><br /><br />Regards,<br />Gerry (Lowry)<br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Steve
on 6/2/2009 7:16 AM

It seems like iteration #6 just takes a dump at "Creating the Views". <br /><br />I made it to iteration 6 with no problems at all, and even most of the way through 6 without problem.<br /><br />For example: "We need to modify the following existing views so that they include contact groups":<br /><br /> * Views\Home\Create.aspx<br /> * Views\Home\Edit.aspx<br /> * Views\Home\Index.aspx<br /><br />There is no Home directory at all in the downloaded code.<br />
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Lori
on 6/16/2009 8:46 AM

Issue with Iteration #2<br /><br />I'm following the 2nd part where the the style sheet and master are installed from the 'vendor'. I made the changes to the other files indicated in the tutorial; however, in both my solution and the downloaded solution, my visual studio is giving this error: <br /><br />The class or CssClass value is not defined<br /><br />on these four lines of code in index.aspx: <br /><br /><th class="actions edit"><br /><th class="actions delete"><br />....<br /><td class="actions edit"><br /><td class="actions delete"><br /> <br />I don't understand enough about this yet so I'm not sure where/if this class="actions delete/edit" is meant to be defined but the error seems to indicate it is not defined.<br /><br />Any thoughts?<br /><br />Thanks! Lori
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by Lori
on 6/16/2009 8:48 AM

Issue with Iteration #2<br />(Sorry for the second post, clearly my html code was interpreted rather than pasted)<br /><br />I'm following the 2nd part where the the style sheet and master are installed from the 'vendor'. I made the changes to the other files indicated in the tutorial; however, in both my solution and the downloaded solution, my visual studio is giving this error: <br /><br />The class or CssClass value is not defined<br /><br />on these four lines of code in index.aspx: <br /><br />th class="actions edit"<br />th class="actions delete"<br />....<br />td class="actions edit"<br />td class="actions delete"<br /> <br />I don't understand enough about this yet so I'm not sure where/if this class="actions delete/edit" is meant to be defined but the error seems to indicate it is not defined.<br /><br />Any thoughts?<br /><br />Thanks! Lori
Gravatar
# re: ASP.NET MVC Sample Application at www.ASP.net/MVC
Posted by James Radford
on 8/31/2009 2:59 PM

Thanks for this article.
Comments have been closed on this topic.