ASP.NET MVC 3 Hosting :: How to Deploy Web Apps Using ASP.NET MVC 3, Razor and EF Code First - Part I
Posted
by mbridge
on Geeks with Blogs
See other posts from Geeks with Blogs
or by mbridge
Published on Wed, 23 Feb 2011 02:43:44 GMT
Indexed on
2011/02/23
7:26 UTC
Read the original article
Hit count: 726
Filed under:
First, you can download the source code from http://efmvc.codeplex.com. The following frameworks will be used for this step by step tutorial.
public class Category
{
public int CategoryId { get; set; }
[Required(ErrorMessage = "Name Required")]
[StringLength(25, ErrorMessage = "Must be less than 25 characters")]
public string Name { get; set;}
public string Description { get; set; }
public virtual ICollection<Expense> Expenses { get; set; }
}
Expense Class
public class Expense
{
public int ExpenseId { get; set; }
public string Transaction { get; set; }
public DateTime Date { get; set; }
public double Amount { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
{
public int CategoryId { get; set; }
[Required(ErrorMessage = "Name Required")]
[StringLength(25, ErrorMessage = "Must be less than 25 characters")]
public string Name { get; set;}
public string Description { get; set; }
public virtual ICollection<Expense> Expenses { get; set; }
}
Expense Class
public class Expense
{
public int ExpenseId { get; set; }
public string Transaction { get; set; }
public DateTime Date { get; set; }
public double Amount { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
Define Domain Model
Let’s create domain model for our simple web application
Category Class
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. In this post, we will be focusing on CRUD operations for the entity Category and will be working on the Expense entity with a View Model object in the later post. And the source code for this application will be refactored over time.
The above entities are very simple POCO (Plain Old CLR Object) classes and the entity Category is decorated with validation attributes in the System.ComponentModel.DataAnnotations namespace. Now we want to use these entities for defining model objects for the Entity Framework 4. Using the Code First approach of Entity Framework, we can first define the entities by simply writing POCO classes without any coupling with any API or database library. This approach lets you focus on domain model which will enable Domain-Driven Development for applications. EF code first support is currently enabled with a separate API that is runs on top of the Entity Framework 4. EF Code First is reached CTP 5 when I am writing this article.
Creating Context Class for Entity Framework
We have created our domain model and let’s create a class in order to working with Entity Framework Code First. For this, you have to download EF Code First CTP 5 and add reference to the assembly EntitFramework.dll. You can also use NuGet to download add reference to EEF Code First.
public class MyFinanceContext : DbContext
{
public MyFinanceContext() : base("MyFinance") { }
public DbSet<Category> Categories { get; set; }
public DbSet<Expense> Expenses { get; set; }
}
{
public MyFinanceContext() : base("MyFinance") { }
public DbSet<Category> Categories { get; set; }
public DbSet<Expense> Expenses { get; set; }
}
The above class MyFinanceContext is derived from DbContext that can connect your model classes to a database. The MyFinanceContext class is mapping our Category and Expense class into database tables
Categories and Expenses using DbSet<TEntity> where TEntity is any POCO class. When we are running the application at first time, it will automatically create the database. EF code-first look for a connection string in web.config or app.config that has the same name as the dbcontext class. If it is not find any connection string with the convention, it will automatically create database in local SQL Express database by default and the name of the database will be same name as the dbcontext class. You can also define the name of database in constructor of the the dbcontext class.
Categories and Expenses using DbSet<TEntity> where TEntity is any POCO class. When we are running the application at first time, it will automatically create the database. EF code-first look for a connection string in web.config or app.config that has the same name as the dbcontext class. If it is not find any connection string with the convention, it will automatically create database in local SQL Express database by default and the name of the database will be same name as the dbcontext class. You can also define the name of database in constructor of the the dbcontext class.
Unlike NHibernate, we don’t have to use any XML based mapping files or Fluent interface for mapping between our model and database. The model classes of Code First are working on the basis of conventions and we can also use a fluent API to refine our model. The convention for primary key is ‘Id’ or ‘<class name>Id’. If primary key properties are detected with type ‘int’, ‘long’ or ‘short’, they will automatically registered as identity columns in the database by default. Primary key detection is not case sensitive. We can define our model classes with validation attributes in the System.ComponentModel.DataAnnotations namespace and it automatically enforces validation rules when a model object is updated or saved.
Generic Repository for EF Code First
We have created model classes and dbcontext class. Now we have to create generic repository pattern for data persistence with EF code first. If you don’t know about the repository pattern, checkout Martin Fowler’s article on Repository
Let’s create a generic repository to working with DbContext and DbSet generics.
public interface IRepository<T> where T : class
{
void Add(T entity);
void Delete(T entity);
T GetById(long Id);
IEnumerable<T> All();
}
{
void Add(T entity);
void Delete(T entity);
T GetById(long Id);
IEnumerable<T> All();
}
RepositoryBasse – Generic Repository class
protected MyFinanceContext Database
{
get { return database ?? (database = DatabaseFactory.Get()); }
}
public virtual void Add(T entity)
{
dbset.Add(entity);
}
public virtual void Delete(T entity)
{
dbset.Remove(entity);
}
public virtual T GetById(long id)
{
return dbset.Find(id);
}
public virtual IEnumerable<T> All()
{
return dbset.ToList();
}
}
{
get { return database ?? (database = DatabaseFactory.Get()); }
}
public virtual void Add(T entity)
{
dbset.Add(entity);
}
public virtual void Delete(T entity)
{
dbset.Remove(entity);
}
public virtual T GetById(long id)
{
return dbset.Find(id);
}
public virtual IEnumerable<T> All()
{
return dbset.ToList();
}
}
DatabaseFactory class
public class DatabaseFactory : Disposable, IDatabaseFactory
{
private MyFinanceContext database;
public MyFinanceContext Get()
{
return database ?? (database = new MyFinanceContext());
}
protected override void DisposeCore()
{
if (database != null)
database.Dispose();
}
}
{
private MyFinanceContext database;
public MyFinanceContext Get()
{
return database ?? (database = new MyFinanceContext());
}
protected override void DisposeCore()
{
if (database != null)
database.Dispose();
}
}
Unit of Work
If you are new to Unit of Work pattern, checkout Fowler’s article on Unit of Work . According to Martin Fowler, the Unit of Work pattern "maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems."
Let’s create a class for handling Unit of Work
public interface IUnitOfWork
{
void Commit();
}
{
void Commit();
}
UniOfWork class
public class UnitOfWork : IUnitOfWork
{
private readonly IDatabaseFactory databaseFactory;
private MyFinanceContext dataContext;
public UnitOfWork(IDatabaseFactory databaseFactory)
{
this.databaseFactory = databaseFactory;
}
protected MyFinanceContext DataContext
{
get { return dataContext ?? (dataContext = databaseFactory.Get()); }
}
public void Commit()
{
DataContext.Commit();
}
}
{
private readonly IDatabaseFactory databaseFactory;
private MyFinanceContext dataContext;
public UnitOfWork(IDatabaseFactory databaseFactory)
{
this.databaseFactory = databaseFactory;
}
protected MyFinanceContext DataContext
{
get { return dataContext ?? (dataContext = databaseFactory.Get()); }
}
public void Commit()
{
DataContext.Commit();
}
}
The Commit method of the UnitOfWork will call the commit method of MyFinanceContext class and it will execute the SaveChanges method of DbContext class.
Repository class for Category
Repository class for Category
In this post, we will be focusing on the persistence against Category entity and will working on other entities in later post. Let’s create a repository for handling CRUD operations for Category using derive from a generic Repository RepositoryBase<T>.
public class CategoryRepository: RepositoryBase<Category>, ICategoryRepository
{
public CategoryRepository(IDatabaseFactory databaseFactory)
: base(databaseFactory)
{
}
}
public interface ICategoryRepository : IRepository<Category>
{
}
{
public CategoryRepository(IDatabaseFactory databaseFactory)
: base(databaseFactory)
{
}
}
public interface ICategoryRepository : IRepository<Category>
{
}
If we need additional methods than generic repository for the Category, we can define in the CategoryRepository.
Dependency Injection using Unity 2.0
If you are new to Inversion of Control/ Dependency Injection or Unity, please have a look on my articles at http://weblogs.asp.net/shijuvarghese/archive/tags/IoC/default.aspx. I want to create a custom lifetime manager for Unity to store container in the current HttpContext.
public class HttpContextLifetimeManager<T> : LifetimeManager, IDisposable
{
public override object GetValue()
{
return HttpContext.Current.Items[typeof(T).AssemblyQualifiedName];
}
public override void RemoveValue()
{
HttpContext.Current.Items.Remove(typeof(T).AssemblyQualifiedName);
}
public override void SetValue(object newValue)
{
HttpContext.Current.Items[typeof(T).AssemblyQualifiedName] = newValue;
}
public void Dispose()
{
RemoveValue();
}
}
{
public override object GetValue()
{
return HttpContext.Current.Items[typeof(T).AssemblyQualifiedName];
}
public override void RemoveValue()
{
HttpContext.Current.Items.Remove(typeof(T).AssemblyQualifiedName);
}
public override void SetValue(object newValue)
{
HttpContext.Current.Items[typeof(T).AssemblyQualifiedName] = newValue;
}
public void Dispose()
{
RemoveValue();
}
}
Let’s create controller factory for Unity in the ASP.NET MVC 3 application.
404, String.Format(
"The controller for path '{0}' could not be found" +
"or it does not implement IController.",
reqContext.HttpContext.Request.Path));
if (!typeof(IController).IsAssignableFrom(controllerType))
throw new ArgumentException(
string.Format(
"Type requested is not a controller: {0}",
controllerType.Name),
"controllerType");
try
{
controller= container.Resolve(controllerType) as IController;
}
catch (Exception ex)
{
throw new InvalidOperationException(String.Format(
"Error resolving controller {0}",
controllerType.Name), ex);
}
return controller;
}
}
"The controller for path '{0}' could not be found" +
"or it does not implement IController.",
reqContext.HttpContext.Request.Path));
if (!typeof(IController).IsAssignableFrom(controllerType))
throw new ArgumentException(
string.Format(
"Type requested is not a controller: {0}",
controllerType.Name),
"controllerType");
try
{
controller= container.Resolve(controllerType) as IController;
}
catch (Exception ex)
{
throw new InvalidOperationException(String.Format(
"Error resolving controller {0}",
controllerType.Name), ex);
}
return controller;
}
}
Configure contract and concrete types in Unity
Let’s configure our contract and concrete types in Unity for resolving our dependencies.
private void ConfigureUnity()
{
//Create UnityContainer
IUnityContainer container = new UnityContainer()
.RegisterType<IDatabaseFactory, DatabaseFactory>(new HttpContextLifetimeManager<IDatabaseFactory>())
.RegisterType<IUnitOfWork, UnitOfWork>(new HttpContextLifetimeManager<IUnitOfWork>())
.RegisterType<ICategoryRepository, CategoryRepository>(new HttpContextLifetimeManager<ICategoryRepository>());
//Set container for Controller Factory
ControllerBuilder.Current.SetControllerFactory(
new UnityControllerFactory(container));
}
{
//Create UnityContainer
IUnityContainer container = new UnityContainer()
.RegisterType<IDatabaseFactory, DatabaseFactory>(new HttpContextLifetimeManager<IDatabaseFactory>())
.RegisterType<IUnitOfWork, UnitOfWork>(new HttpContextLifetimeManager<IUnitOfWork>())
.RegisterType<ICategoryRepository, CategoryRepository>(new HttpContextLifetimeManager<ICategoryRepository>());
//Set container for Controller Factory
ControllerBuilder.Current.SetControllerFactory(
new UnityControllerFactory(container));
}
In the above ConfigureUnity method, we are registering our types onto Unity container with custom lifetime manager HttpContextLifetimeManager. Let’s call ConfigureUnity method in the Global.asax.cs for set controller factory for Unity and configuring the types with Unity.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ConfigureUnity();
}
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ConfigureUnity();
}
Developing web application using ASP.NET MVC 3
We have created our domain model for our web application and also have created repositories and configured dependencies with Unity container. Now we have to create controller classes and views for doing CRUD operations against the Category entity.
Let’s create controller class for Category
Category Controller
public class CategoryController : Controller
{
private readonly ICategoryRepository categoryRepository;
private readonly IUnitOfWork unitOfWork;
public CategoryController(ICategoryRepository categoryRepository, IUnitOfWork unitOfWork)
{
this.categoryRepository = categoryRepository;
this.unitOfWork = unitOfWork;
}
public ActionResult Index()
{
var categories = categoryRepository.All();
return View(categories);
}
[HttpGet]
public ActionResult Edit(int id)
{
var category = categoryRepository.GetById(id);
return View(category);
}
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
var category = categoryRepository.GetById(id);
if (TryUpdateModel(category))
{
unitOfWork.Commit();
return RedirectToAction("Index");
}
else return View(category);
}
[HttpGet]
public ActionResult Create()
{
var category = new Category();
return View(category);
}
[HttpPost]
public ActionResult Create(Category category)
{
if (!ModelState.IsValid)
{
return View("Create", category);
}
categoryRepository.Add(category);
unitOfWork.Commit();
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Delete(int id)
{
var category = categoryRepository.GetById(id);
categoryRepository.Delete(category);
unitOfWork.Commit();
var categories = categoryRepository.All();
return PartialView("CategoryList", categories);
}
}
{
private readonly ICategoryRepository categoryRepository;
private readonly IUnitOfWork unitOfWork;
public CategoryController(ICategoryRepository categoryRepository, IUnitOfWork unitOfWork)
{
this.categoryRepository = categoryRepository;
this.unitOfWork = unitOfWork;
}
public ActionResult Index()
{
var categories = categoryRepository.All();
return View(categories);
}
[HttpGet]
public ActionResult Edit(int id)
{
var category = categoryRepository.GetById(id);
return View(category);
}
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
var category = categoryRepository.GetById(id);
if (TryUpdateModel(category))
{
unitOfWork.Commit();
return RedirectToAction("Index");
}
else return View(category);
}
[HttpGet]
public ActionResult Create()
{
var category = new Category();
return View(category);
}
[HttpPost]
public ActionResult Create(Category category)
{
if (!ModelState.IsValid)
{
return View("Create", category);
}
categoryRepository.Add(category);
unitOfWork.Commit();
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Delete(int id)
{
var category = categoryRepository.GetById(id);
categoryRepository.Delete(category);
unitOfWork.Commit();
var categories = categoryRepository.All();
return PartialView("CategoryList", categories);
}
}
Creating Views in Razor
Now we are going to create views in Razor for our ASP.NET MVC 3 application. Let’s create a partial view CategoryList.cshtml for listing category information and providing link for Edit and Delete operations.
CategoryList.cshtml
@using MyFinance.Helpers;
@using MyFinance.Domain;
@model IEnumerable<Category>
<table>
<tr>
<th>Actions</th>
<th>Name</th>
<th>Description</th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.ActionLink("Edit", "Edit",new { id = item.CategoryId })
@Ajax.ActionLink("Delete", "Delete", new { id = item.CategoryId }, new AjaxOptions { Confirm = "Delete Expense?", HttpMethod = "Post", UpdateTargetId = "divCategoryList" })
</td>
<td>
@item.Name
</td>
<td>
@item.Description
</td>
</tr>
}
</table>
<p>
@Html.ActionLink("Create New", "Create")
</p>
@using MyFinance.Domain;
@model IEnumerable<Category>
<table>
<tr>
<th>Actions</th>
<th>Name</th>
<th>Description</th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.ActionLink("Edit", "Edit",new { id = item.CategoryId })
@Ajax.ActionLink("Delete", "Delete", new { id = item.CategoryId }, new AjaxOptions { Confirm = "Delete Expense?", HttpMethod = "Post", UpdateTargetId = "divCategoryList" })
</td>
<td>
@item.Name
</td>
<td>
@item.Description
</td>
</tr>
}
</table>
<p>
@Html.ActionLink("Create New", "Create")
</p>
The delete link is providing Ajax functionality using the Ajax.ActionLink. This will call an Ajax request for Delete action method in the CategoryCotroller class. In the Delete action method, it will return Partial View CategoryList after deleting the record. We are using CategoryList view for the Ajax functionality and also for Index view using for displaying list of category information.
Let’s create Index view using partial view CategoryList
Index.chtml
@model IEnumerable<MyFinance.Domain.Category>
@{
ViewBag.Title = "Index";
}
<h2>Category List</h2>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<div id="divCategoryList">
@Html.Partial("CategoryList", Model)
</div>
@{
ViewBag.Title = "Index";
}
<h2>Category List</h2>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<div id="divCategoryList">
@Html.Partial("CategoryList", Model)
</div>
We can call the partial views using Html.Partial helper method. Now we are going to create View pages for insert and update functionality for the Category.
Both view pages are sharing common user interface for entering the category information. So I want to create an EditorTemplate for the Category information. We have to create the EditorTemplate with the same name of entity object so that we can refer it on view pages using @Html.EditorFor(model => model) . So let’s create template with name Category.
Category.cshtml
@model MyFinance.Domain.Category
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Description)
@Html.ValidationMessageFor(model => model.Description)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Description)
@Html.ValidationMessageFor(model => model.Description)
</div>
Let’s create view page for insert Category information
@model MyFinance.Domain.Category
@{
ViewBag.Title = "Save";
}
<h2>Create</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Category</legend>
@Html.EditorFor(model => model)
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@{
ViewBag.Title = "Save";
}
<h2>Create</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Category</legend>
@Html.EditorFor(model => model)
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
ViewStart file
In Razor views, we can add a file named _viewstart.cshtml in the views directory and this will be shared among the all views with in the Views directory. The below code in the _viewstart.cshtml, sets the Layout page for every Views in the Views folder.
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
Layout = "~/Views/Shared/_Layout.cshtml";
}
Tomorrow, we will cotinue the second part of this article. :)
© Geeks with Blogs or respective owner