Developing web apps using ASP.NET MVC 3, Razor and EF Code First - Part 2

In my previous post Developing web apps using ASP.NET MVC 3, Razor and EF Code First - Part 1, we have discussed on how to work with ASP.NET MVC 3 and EF Code First for developing web apps. We have created generic repository and unit of work with EF Code First for our ASP.NET MVC 3 application and did basic CRUD operations against a simple domain entity. In this post, I will demonstrate on working with domain entity with deep object graph, Service Layer and View Models and will also complete the rest of the demo application. In the previous post, we have done CRUD operations against Category entity and this post will be focus on Expense entity those have an association with Category entity. You can download the source code from http://efmvc.codeplex.com .


The following frameworks will be used for this step by step tutorial.


   1. ASP.NET MVC 3 RTM
   2. EF Code First CTP 5
   3. Unity 2.0

Domain Model

Category Entity

  1. public class Category
  2.   {
  3.       public int CategoryId { get; set; }
  4.       [Required(ErrorMessage = "Name Required")]
  5.       [StringLength(25, ErrorMessage = "Must be less than 25 characters")]
  6.       public string Name { get; set;}
  7.       public string Description { get; set; }
  8.       public virtual ICollection<Expense> Expenses { get; set; }
  9.   }

Expense Entity

  1. public class Expense
  2.     {       
  3.         public int ExpenseId { get; set; }       
  4.         public string  Transaction { get; set; }
  5.         public DateTime Date { get; set; }
  6.         public double Amount { get; set; }
  7.         public int CategoryId { get; set; }
  8.         public virtual Category Category { get; set; }
  9.     }


We have two domain entities - Category and Expense. A single category contains a list of expense transactions and every expense transaction should have a Category.

Repository class for Expense Transaction


Let’s create repository class for handling CRUD operations for Expense entity

  1. public class ExpenseRepository : RepositoryBase<Expense>, IExpenseRepository
  2.     {
  3.     public ExpenseRepository(IDatabaseFactory databaseFactory)
  4.         : base(databaseFactory)
  5.         {
  6.         }           
  7.     }
  8. public interface IExpenseRepository : IRepository<Expense>
  9. {
  10. }

Service Layer

If you are new to Service Layer, checkout Martin Fowler's article Service Layer . According to Martin Fowler, Service Layer defines an application's boundary and its set of available operations from the perspective of interfacing client layers. It encapsulates the application's business logic, controlling transactions and coordinating responses in the implementation of its operations. Controller classes should be lightweight and do not put much of business logic onto it. We can use the service layer as the business logic layer and can encapsulate the rules of the application.


Let’s create a Service class for coordinates the transaction for Expense

  1. public interface IExpenseService
  2. {
  3.     IEnumerable<Expense> GetExpenses(DateTime startDate, DateTime ednDate);
  4.     Expense GetExpense(int id);        
  5.     void CreateExpense(Expense expense);
  6.     void DeleteExpense(int id);
  7.     void SaveExpense();
  8. }
  9. public class ExpenseService : IExpenseService
  10. {
  11.     private readonly IExpenseRepository expenseRepository;       
  12.     private readonly IUnitOfWork unitOfWork;
  13.     public ExpenseService(IExpenseRepository expenseRepository, IUnitOfWork unitOfWork)
  14.     {         
  15.         this.expenseRepository = expenseRepository;
  16.         this.unitOfWork = unitOfWork;
  17.     }
  18.     public IEnumerable<Expense> GetExpenses(DateTime startDate, DateTime endDate)
  19.     {
  20.         var expenses = expenseRepository.GetMany(exp => exp.Date >= startDate && exp.Date <= endDate);
  21.         return expenses;
  22.     }
  23.     public void CreateExpense(Expense expense)
  24.     {
  25.         expenseRepository.Add(expense);
  26.         unitOfWork.Commit();
  27.     }
  28.     public Expense GetExpense(int id)
  29.     {
  30.         var expense = expenseRepository.GetById(id);
  31.         return expense;
  32.     }
  33.     public void DeleteExpense(int id)
  34.     {
  35.         var expense = expenseRepository.GetById(id);
  36.         expenseRepository.Delete(expense);
  37.         unitOfWork.Commit();
  38.     }
  39.     public void SaveExpense()
  40.     {
  41.         unitOfWork.Commit();
  42.     }
  43. }

 

View Model for Expense Transactions


In real world ASP.NET MVC applications, we need to design model objects especially for our views. Our domain objects are mainly designed for the needs for domain model and it is representing the domain of our applications. On the other hand, View Model objects are designed for our needs for views. We have an Expense domain entity that has an association with Category. While we are creating a new Expense, we have to specify that in which Category belongs with the new Expense transaction. The user interface for Expense transaction will have form fields for representing the Expense entity and a CategoryId for representing the Category. So let's create view model for representing the need for Expense transactions.

  1. public class ExpenseViewModel
  2. {
  3.     public int ExpenseId { get; set; }
  4.  
  5.     [Required(ErrorMessage = "Category Required")]
  6.     public int CategoryId { get; set; }
  7.  
  8.     [Required(ErrorMessage = "Transaction Required")]
  9.     public string Transaction { get; set; }
  10.  
  11.     [Required(ErrorMessage = "Date Required")]
  12.     public DateTime Date { get; set; }
  13.  
  14.     [Required(ErrorMessage = "Amount Required")]
  15.     public double Amount { get; set; }
  16.  
  17.     public IEnumerable<SelectListItem> Category { get; set; }
  18. }


The ExpenseViewModel is designed for the purpose of View template and contains the all validation rules. It has properties for mapping values to Expense entity and a property Category for binding values to a drop-down for list values of Category.


Create Expense transaction

Let’s create action methods in the ExpenseController for creating expense transactions

  1. public ActionResult Create()
  2. {
  3.     var expenseModel = new ExpenseViewModel();
  4.     var categories = categoryService.GetCategories();
  5.     expenseModel.Category = categories.ToSelectListItems(-1);
  6.     expenseModel.Date = DateTime.Today;
  7.     return View(expenseModel);
  8. }
  9. [HttpPost]
  10. public ActionResult Create(ExpenseViewModel expenseViewModel)
  11. {
  12.             
  13.         if (!ModelState.IsValid)
  14.         {
  15.             var categories = categoryService.GetCategories();
  16.             expenseViewModel.Category = categories.ToSelectListItems(expenseViewModel.CategoryId);
  17.             return View("Save", expenseViewModel);
  18.         }
  19.         Expense expense=new Expense();
  20.         ModelCopier.CopyModel(expenseViewModel,expense);
  21.         expenseService.CreateExpense(expense);
  22.         return RedirectToAction("Index");
  23.             
  24. }


In the Create action method for HttpGet request, we have created an instance of our View Model ExpenseViewModel with Category information for the drop-down list and passing the Model object to View template. The extension method ToSelectListItems is shown below

 

  1. public static IEnumerable<SelectListItem> ToSelectListItems(
  2.         this IEnumerable<Category> categories, int  selectedId)
  3. {
  4.     return
  5.  
  6.         categories.OrderBy(category => category.Name)
  7.                 .Select(category =>
  8.                     new SelectListItem
  9.                     {
  10.                         Selected = (category.CategoryId == selectedId),
  11.                         Text = category.Name,
  12.                         Value = category.CategoryId.ToString()
  13.                     });
  14. }

In the Create action method for HttpPost, our view model object ExpenseViewModel will map with posted form input values. We need to create an instance of Expense for the persistence purpose. So we need to copy values from ExpenseViewModel object to Expense object. ASP.NET MVC futures assembly provides a static class ModelCopier that can use for copying values between Model objects. ModelCopier class has two static methods - CopyCollection and CopyModel.CopyCollection method will copy values between two collection objects and CopyModel will copy values between two model objects. We have used CopyModel method of ModelCopier class for copying values from expenseViewModel object to expense object. Finally we did a call to CreateExpense method of ExpenseService class for persisting new expense transaction.

List Expense Transactions


We want to list expense transactions based on a date range. So let’s create action method for filtering expense transactions with a specified date range.

  1. public ActionResult Index(DateTime? startDate, DateTime? endDate)
  2. {
  3.     //If date is not passed, take current month's first and last dte
  4.     DateTime dtNow;
  5.     dtNow = DateTime.Today;
  6.     if (!startDate.HasValue)
  7.     {
  8.         startDate = new DateTime(dtNow.Year, dtNow.Month, 1);
  9.         endDate = startDate.Value.AddMonths(1).AddDays(-1);
  10.     }
  11.     //take last date of start date's month, if end date is not passed
  12.     if (startDate.HasValue && !endDate.HasValue)
  13.     {
  14.         endDate = (new DateTime(startDate.Value.Year, startDate.Value.Month, 1)).AddMonths(1).AddDays(-1);
  15.     }
  16.     var expenses = expenseService.GetExpenses(startDate.Value ,endDate.Value);
  17.     //if request is Ajax will return partial view
  18.     if (Request.IsAjaxRequest())
  19.     {
  20.         return PartialView("ExpenseList", expenses);
  21.     }
  22.     //set start date and end date to ViewBag dictionary
  23.     ViewBag.StartDate = startDate.Value.ToShortDateString();
  24.     ViewBag.EndDate = endDate.Value.ToShortDateString();
  25.     //if request is not ajax
  26.     return View(expenses);
  27. }


We are using the above Index Action method for both Ajax requests and normal requests. If there is a request for Ajax, we will call the PartialView ExpenseList.


Razor Views for listing Expense information

Let’s create view templates in Razor for showing list of Expense information

ExpenseList.cshtml

  1. @model IEnumerable<MyFinance.Domain.Expense>
  2.  
  3. <table>
  4.         <tr>
  5.             <th>Actions</th>
  6.             <th>Category</th>
  7.             <th>
  8.                 Transaction
  9.             </th>
  10.             <th>
  11.                 Date
  12.             </th>
  13.             <th>
  14.                 Amount
  15.             </th>
  16.         </tr>
  17.  
  18.     @foreach (var item in Model) {
  19.     
  20.         <tr>
  21.             <td>
  22.                 @Html.ActionLink("Edit", "Edit",new { id = item.ExpenseId })
  23.                 @Ajax.ActionLink("Delete", "Delete", new { id = item.ExpenseId }, new AjaxOptions { Confirm = "Delete Expense?", HttpMethod = "Post", UpdateTargetId = "divExpenseList" })
  24.             </td>
  25.              <td>
  26.                 @item.Category.Name
  27.             </td>
  28.             <td>
  29.                 @item.Transaction
  30.             </td>
  31.             <td>
  32.                 @String.Format("{0:d}", item.Date)
  33.             </td>
  34.             <td>
  35.                 @String.Format("{0:F}", item.Amount)
  36.             </td>
  37.         </tr>
  38.     
  39.     }
  40.  
  41.     </table>
  42.     <p>
  43.         @Html.ActionLink("Create New Expense", "Create") |
  44.         @Html.ActionLink("Create New Category", "Create","Category")
  45.     </p>

Index.cshtml

  1. @using MyFinance.Helpers;
  2. @model IEnumerable<MyFinance.Domain.Expense>
  3. @{
  4.     ViewBag.Title = "Index";
  5. }
  6.    <h2>Expense List</h2>
  7.    <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
  8. <script src="@Url.Content("~/Scripts/jquery-ui.js")" type="text/javascript"></script>
  9. <script src="@Url.Content("~/Scripts/jquery.ui.datepicker.js")" type="text/javascript"></script>
  10. <link href="@Url.Content("~/Content/jquery-ui-1.8.6.custom.css")" rel="stylesheet" type="text/css" />
  11.  
  12.    @using (Ajax.BeginForm(new AjaxOptions{ UpdateTargetId="divExpenseList", HttpMethod="Get"})) {
  13.     <table>
  14.         <tr>
  15.         <td>
  16.         <div>
  17.           Start Date: @Html.TextBox("StartDate", Html.Encode(String.Format("{0:mm/dd/yyyy}", ViewData["StartDate"].ToString())), new { @class = "ui-datepicker" })
  18.         </div>
  19.         </td>
  20.         <td><div>
  21.            End Date: @Html.TextBox("EndDate", Html.Encode(String.Format("{0:mm/dd/yyyy}", ViewData["EndDate"].ToString())), new { @class = "ui-datepicker" })
  22.          </div></td>
  23.          <td> <input type="submit" value="Search By TransactionDate" /></td>
  24.         </tr>
  25.     </table>        
  26. }
  27.   <div id="divExpenseList">    
  28.         @Html.Partial("ExpenseList", Model)
  29.     </div>
  30. <script type="text/javascript">
  31.     $().ready(function () {
  32.         $('.ui-datepicker').datepicker({
  33.             dateFormat: 'mm/dd/yy',
  34.             buttonImage: '@Url.Content("~/Content/calendar.gif")',
  35.             buttonImageOnly: true,
  36.             showOn: "button"
  37.         });
  38.     });
  39. </script>

Ajax search functionality using Ajax.BeginForm


The search functionality of Index view is providing Ajax functionality using Ajax.BeginForm. The Ajax.BeginForm() method writes an opening <form> tag to the response. You can use this method in a using block. In that case, the method renders the closing </form> tag at the end of the using block and the form is submitted asynchronously by using JavaScript. The search functionality will call the Index Action method and this will return partial view ExpenseList for updating the search result. We want to update the response UI for the Ajax request onto divExpenseList element. So we have specified the UpdateTargetId as "divExpenseList" in the Ajax.BeginForm method.

Add jQuery DatePicker

Our search functionality is using a date range so we are providing two date pickers using jQuery datepicker. You need to add reference to the following JavaScript files to working with jQuery datepicker.

  • jquery-ui.js
  • jquery.ui.datepicker.js

For theme support for datepicker, we can use a customized CSS class. In our example we have used a CSS file “jquery-ui-1.8.6.custom.css”. For more details about the datepicker component, visit jquery UI website at http://jqueryui.com/demos/datepicker . In the jQuery ready event, we have used following JavaScript function to initialize the UI element to show date picker.

  1. <script type="text/javascript">
  2.     $().ready(function () {
  3.         $('.ui-datepicker').datepicker({
  4.             dateFormat: 'mm/dd/yy',
  5.             buttonImage: '@Url.Content("~/Content/calendar.gif")',
  6.             buttonImageOnly: true,
  7.             showOn: "button"
  8.         });
  9.     });
  10. </script>

 

Source Code

You can download the source code from http://efmvc.codeplex.com/ .

Summary

In this two-part series, we have created a simple web application using ASP.NET MVC 3 RTM, Razor and EF Code First CTP 5. I have demonstrated patterns and practices  such as Dependency Injection, Repository pattern, Unit of Work, ViewModel and Service Layer. My primary objective was to demonstrate different practices and options for developing web apps using ASP.NET MVC 3 and EF Code First. You can implement these approaches in your own way for building web apps using ASP.NET MVC 3. I will refactor this demo app on later time.

11 Comments

  • Thanks for sharing, I was looking after this kind of development track.

  • It's a little strange that I can not open your post by Feed source!

  • Hey,Shiju!You said Controlller class should be lightweight,but why?Definitely we need to encapsulate the bussiness logic in case other user interce will use it or other client side,but that's depend on the project,XD.Here's a question how to find out the service layer correctly?I mean we all know the service layer is important to decouple the code at the project,but the most critical thing is how to find it out with the requirements?I think they are not the thing just show up in our brain suddently but the thing depend on the requirements exactly.

  • Interesting to see how EF Code First compares to SubSonic.

  • Hi,
    You are returning View("Save", expenseViewModel); when the modelstate is not valid. Could you explain how it works, I dont see a view name "Save".

  • @Ravi - Its a mistake and fill fix it on the next release

  • good article. I like it

  • ASP.NET MVC is a comprehensive set of native MVC Architecture gives you to built dynamic website application.

  • Appreciation to my father who informed me regarding this weblog,
    this website is really remarkable.

  • I got this website from my friend who told me concerning this web
    page and at the moment this time I am visiting this web
    page and reading very informative articles here.

  • Hi,

    your article is excellent. just one question here.

    instead of writing the code in ExpenseService.cs, what if, if i have a business layer between WCF & Dal layer.

    eg. Client->WCF->BL->Repository+unitofWork->DAL

    in this scenario how will i call the BL from the WCF service where we have the repository + unit of work implemnented.

    manjerekar

Comments have been disabled for this content.