{"id":37,"date":"2010-05-14T17:58:55","date_gmt":"2010-05-14T15:58:55","guid":{"rendered":"http:\/\/dev.bratched.fr\/en\/?p=37"},"modified":"2010-05-14T17:58:55","modified_gmt":"2010-05-14T15:58:55","slug":"how-we-do-asp-net-mvc","status":"publish","type":"post","link":"https:\/\/bratched.com\/en\/2010\/05\/14\/how-we-do-asp-net-mvc\/","title":{"rendered":"How we do ASP.NET MVC"},"content":{"rendered":"<h1>Sample MVC Solution<\/h1>\n<p>In this post I will show a sample ASP.NET MVC 2.0 project structure illustrating different concepts such as data access, user input validation and mapping between the domain and the view model. The project is still under construction but the <a href=\"http:\/\/github.com\/darind\/samplemvc\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">source code is available at github<\/a>.<\/p>\n<p>I will illustrate the usage of the following frameworks:<\/p>\n<ul>\n<li><a href=\"http:\/\/mvccontrib.codeplex.com\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">MvcContrib<\/a> bringing useful extension methods and strongly typed helpers to ASP.NET MVC<\/li>\n<li><a href=\"http:\/\/automapper.codeplex.com\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">AutoMapper<\/a> enabling easy mapping between the domain and the view models<\/li>\n<li><a href=\"http:\/\/fluentvalidation.codeplex.com\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">FluentValidation<\/a> &#8211; a small validation library for .NET that uses a fluent interface and lambda expressions for building validation rules for your business objects<\/li>\n<li><a href=\"http:\/\/community.jboss.org\/wiki\/NHibernateforNET\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">NHibernate<\/a> \u2013 a popular ORM in the .NET world<\/li>\n<li><a href=\"http:\/\/fluentnhibernate.org\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">FluentNHibernate<\/a> &#8211; a statically compiled alternative to NHibernate&#8217;s standard hbm xml mapping<\/li>\n<li><a href=\"http:\/\/www.springframework.net\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Spring.NET<\/a> \u2013 object container and dependency Injection framework for .NET<\/li>\n<li><a href=\"http:\/\/www.ayende.com\/projects\/rhino-mocks.aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Rhino.Mocks<\/a> &#8211; A dynamic mock object framework for the .Net platform. It&#8217;s purpose is to ease testing by allowing the developer to create mock implementations of custom objects and verify the interactions using unit testing<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>Armed with this arsenal of frameworks let\u2019s start exploring the solution structure. I\u2019ve opted for 2 projects solution but in many real world applications more levels of abstraction could be brought to the business layer. Personally I favor to have less big assemblies rather than many small assemblies into the solution. Fewer the assemblies, faster the load time and faster the IDE. In this case particular attention should be brought to bring proper separation of concerns inside the same assembly<\/p>\n<p><a href=\"http:\/\/dev.bratched.fr\/en\/wp-content\/uploads\/sites\/3\/2010\/05\/project_structure.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-141\" src=\"http:\/\/dev.bratched.fr\/en\/wp-content\/uploads\/sites\/3\/2010\/05\/project_structure.png\" alt=\"project_structure\" width=\"207\" height=\"457\" srcset=\"https:\/\/bratched.com\/en\/wp-content\/uploads\/sites\/4\/2010\/05\/project_structure.png 207w, https:\/\/bratched.com\/en\/wp-content\/uploads\/sites\/4\/2010\/05\/project_structure-136x300.png 136w\" sizes=\"(max-width: 207px) 100vw, 207px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p><!--more--><\/p>\n<p>The domain consists of a single User class and a repository interface defining the different operations on this model:<\/p>\n<p><a href=\"http:\/\/dev.bratched.fr\/en\/wp-content\/uploads\/sites\/3\/2010\/05\/Domain.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-142\" src=\"http:\/\/dev.bratched.fr\/en\/wp-content\/uploads\/sites\/3\/2010\/05\/Domain.png\" alt=\"Domain\" width=\"323\" height=\"133\" srcset=\"https:\/\/bratched.com\/en\/wp-content\/uploads\/sites\/4\/2010\/05\/Domain.png 427w, https:\/\/bratched.com\/en\/wp-content\/uploads\/sites\/4\/2010\/05\/Domain-300x124.png 300w\" sizes=\"(max-width: 323px) 100vw, 323px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<h1>Mapping<\/h1>\n<p>The next step is to define the mapping between our domain and a relational model expressed in a fluent manner:<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:9526fe5b-b6d5-41ae-929d-5e41eff7a774\">\n<pre>public class UserMap : ClassMap&lt;User&gt;\n{\n\u00a0\u00a0\u00a0 public UserMap()\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Table(\"users\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Id(x =&gt; x.Id, \"usr_id\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Map(x =&gt; x.FirstName, \"usr_firstname\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Map(x =&gt; x.LastName, \"usr_lastname\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Map(x =&gt; x.Age, \"usr_age\");\n\u00a0\u00a0\u00a0 }\n}<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>And here\u2019s the implementation of the repository:<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:37462f8d-9fff-460d-a647-36cae11a0193\">\n<pre>public class SqlUsersRepository : HibernateDaoSupport, IUsersRepository\n{\n\u00a0\u00a0 public IEnumerable&lt;User&gt; GetUsers()\n\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return HibernateTemplate.LoadAll&lt;User&gt;();\n\u00a0\u00a0 }\n\n\u00a0\u00a0 public User Get(int id)\n\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return HibernateTemplate.Get&lt;User&gt;(id);\n\u00a0\u00a0 }\n\n\u00a0\u00a0 public void Delete(int id)\n\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HibernateTemplate.Delete(new User { Id = id });\n\u00a0\u00a0 }\n\n\u00a0\u00a0 public int Save(User user)\n\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return (int)HibernateTemplate.Save(user);\n\u00a0\u00a0 }\n\n\u00a0\u00a0 public void Update(User user)\n\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HibernateTemplate.Update(user);\n\u00a0\u00a0 }\n}<\/pre>\n<\/div>\n<p><em>HibernateDaoSupport<\/em> is a base class defined by the Spring Framework managing SQL transactions and NHibernate session.<\/p>\n<p>Once we have implemented the data access layer we could move on to the web part. The application consists of a single RESTful UsersController allowing the standard CRUD operations with our users model. As all our views are strongly typed we shall define a view model for each view and a mapping between the domain model and this view model. In our simple case the view model will simply have the same structure as the domain model but in real world scenarios it will be a projection of the domain model for a particular view.<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:d379d002-9b69-47af-8707-a672190190ac\">\n<pre>[Validator(typeof(UserViewModelValidator))]\npublic class UserViewModel\n{\n\u00a0\u00a0\u00a0\u00a0 public int Id { get; set; }\n\u00a0\u00a0\u00a0\u00a0 public string FirstName { get; set; }\n\u00a0\u00a0\u00a0\u00a0 public string LastName { get; set; }\n\u00a0\u00a0\u00a0\u00a0 public int? Age { get; set; }\n}<\/pre>\n<\/div>\n<p>And the respective validator:<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:1560c438-cde5-400e-baad-7a06e010131a\">\n<pre>public class UserViewModelValidator : AbstractValidator&lt;UserViewModel&gt;\n{\n\u00a0\u00a0\u00a0 public UserViewModelValidator()\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 RuleFor(x =&gt; x.FirstName)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .NotEmpty()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .WithMessage(\"First name is required\")\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .DisplayName(\"First name *\");\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 RuleFor(x =&gt; x.LastName)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .NotEmpty()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .WithMessage(\"Last name is required\")\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .DisplayName(\"Last name *\");\n\u00a0\u00a0\u00a0 }\n}<\/pre>\n<\/div>\n<p>And mapper between the domain and view model:<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:62385ce4-e269-40f5-9152-d22cbafa7d77\">\n<pre>public class UserMapper : IMapper\n{\n\u00a0\u00a0\u00a0 static UserMapper()\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Mapper.CreateMap&lt;User, UserViewModel&gt;();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Mapper.CreateMap&lt;UserViewModel, User&gt;();\n\u00a0\u00a0\u00a0 }\n\n\u00a0\u00a0\u00a0 public object Map(object source, Type sourceType, Type destinationType)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return Mapper.Map(source, sourceType, destinationType);\n\u00a0\u00a0\u00a0 }\n}<\/pre>\n<\/div>\n<p>This bidirectional mapper will be used by our RESTful controller:<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:bafc9f0a-cb41-4155-a7c8-55ebafde97fa\">\n<pre>public class UsersController : BaseController&lt;IUsersRepository&gt;\n{\n\u00a0\u00a0\u00a0 public UsersController(IUsersRepository repository, IMapper userMapper) \n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : base(repository, userMapper)\n\u00a0\u00a0\u00a0 { }\n\n\u00a0\u00a0\u00a0 [AutoMap(typeof(IEnumerable&lt;User&gt;), typeof(IEnumerable&lt;UserViewModel&gt;))]\n\u00a0\u00a0\u00a0 public ActionResult Index()\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ return all users\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var users = Repository.GetUsers();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return View(users);\n\n\u00a0\u00a0\u00a0 }\n\n\u00a0\u00a0\u00a0 public ActionResult New()\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ return an HTML form for describing a new user\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return View();\n\u00a0\u00a0\u00a0 }\n\n\u00a0\u00a0\u00a0 [HttpPost]\n\u00a0\u00a0\u00a0 [AutoMap(typeof(User), typeof(UserViewModel))]\n\u00a0\u00a0\u00a0 public ActionResult Create(UserViewModel userView)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ create a new user\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (!ModelState.IsValid)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return View(\"New\", userView);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var user = (User)ModelMapper.Map(userView, typeof(UserViewModel), typeof(User));\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Repository.Save(user);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return RedirectToAction(\"Index\", \"Users\");\n\u00a0\u00a0\u00a0 }\n\n\u00a0\u00a0\u00a0 [AutoMap(typeof(User), typeof(UserViewModel))]\n\u00a0\u00a0\u00a0 public ActionResult Show(int id)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ find and return a specific user\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var user = Repository.Get(id);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return View(user);\n\u00a0\u00a0\u00a0 }\n\n\u00a0\u00a0\u00a0 [AutoMap(typeof(User), typeof(UserViewModel))]\n\u00a0\u00a0\u00a0 public ActionResult Edit(int id)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ return an HTML form for editing a specific user\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var user = Repository.Get(id);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return View(user);\n\u00a0\u00a0\u00a0 }\n\n\u00a0\u00a0\u00a0 [HttpPut]\n\u00a0\u00a0\u00a0 public ActionResult Update(UserViewModel userView)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ find and update a specific user\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (!ModelState.IsValid)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return View(\"Edit\", userView);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var user = (User)ModelMapper.Map(userView, typeof(UserViewModel), typeof(User));\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Repository.Update(user);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return RedirectToAction(\"Index\", \"Users\");\n\u00a0\u00a0\u00a0 }\n\n\u00a0\u00a0\u00a0 [HttpDelete]\n\u00a0\u00a0\u00a0 public ActionResult Destroy(int id)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ delete a specific user\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Repository.Delete(id);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return RedirectToAction(\"Index\", \"Users\");\n\u00a0\u00a0\u00a0 }\n}<\/pre>\n<\/div>\n<p>Notice the <em>AutoMapAttribute<\/em>. This is a custom attribute allowing us to automatically convert the domain model retrieved by the repository to a view model and present it to the view:<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:3ce37fc1-3a31-4f20-9295-4733dd639082\">\n<pre>[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]\npublic class AutoMapAttribute : ActionFilterAttribute\n{\n\u00a0\u00a0\u00a0 public Type SourceType { get; private set; }\n\u00a0\u00a0\u00a0 public Type DestType { get; private set; }\n\n\u00a0\u00a0\u00a0 public AutoMapAttribute(Type sourceType, Type destType)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 SourceType = sourceType;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 DestType = destType;\n\u00a0\u00a0\u00a0 }\n\n\u00a0\u00a0\u00a0 public override void OnActionExecuted(ActionExecutedContext filterContext)\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 base.OnActionExecuted(filterContext);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var controller = filterContext.Controller as IModelMapperController;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (controller == null)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var model = filterContext.Controller.ViewData.Model;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (model != null &amp;&amp; SourceType.IsAssignableFrom(model.GetType()))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var viewModel = controller.ModelMapper.Map(model, SourceType, DestType);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 filterContext.Controller.ViewData.Model = viewModel;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0 }\n}<\/pre>\n<\/div>\n<p>The <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.web.mvc.actionfilterattribute.onactionexecuted.aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">OnActionExecuted<\/a> method will be called after each action method has finished executing and it will use the model passed to the view and convert it to the appropriate view model. It simply substitutes the <em>ViewData.Model<\/em> property with the appropriate view model to finally pass it to the view for rendering.<\/p>\n<p>The controller follows the standard RESTful conventions for naming the action and the HTTP verbs:<\/p>\n<table border=\"1\" width=\"863\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"133\">\n<p align=\"center\"><strong>URL<\/strong><\/p>\n<\/td>\n<td valign=\"top\" width=\"96\">\n<p align=\"center\"><strong>HTTP Verb<\/strong><\/p>\n<\/td>\n<td valign=\"top\" width=\"286\">\n<p align=\"center\"><strong>Action<\/strong><\/p>\n<\/td>\n<td valign=\"top\" width=\"346\">\n<p align=\"center\"><strong>Description<\/strong><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"138\">\/users\/index<\/td>\n<td valign=\"top\" width=\"99\">GET<\/td>\n<td valign=\"top\" width=\"283\">Index()<\/td>\n<td valign=\"top\" width=\"346\">return all users<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"142\">\/users\/show\/id<\/td>\n<td valign=\"top\" width=\"101\">GET<\/td>\n<td valign=\"top\" width=\"281\">Show(int id)<\/td>\n<td valign=\"top\" width=\"346\">return a specific user<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"146\">\/users\/new<\/td>\n<td valign=\"top\" width=\"102\">GET<\/td>\n<td valign=\"top\" width=\"280\">New()<\/td>\n<td valign=\"top\" width=\"346\">return an HTML form for creating a new user<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"149\">\/users\/create<\/td>\n<td valign=\"top\" width=\"103\">POST<\/td>\n<td valign=\"top\" width=\"278\">Create(UserViewModel userView)<\/td>\n<td valign=\"top\" width=\"346\">create a new user<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"151\">\/users\/edit\/id<\/td>\n<td valign=\"top\" width=\"103\">GET<\/td>\n<td valign=\"top\" width=\"278\">Edit(int id)<\/td>\n<td valign=\"top\" width=\"346\">return an HTML form for editing a specific user<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"153\">\/users\/update<\/td>\n<td valign=\"top\" width=\"103\">PUT<\/td>\n<td valign=\"top\" width=\"277\">Update(UserViewModel userView)<\/td>\n<td valign=\"top\" width=\"346\">update a specific user<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"155\">\/users\/destroy\/id<\/td>\n<td valign=\"top\" width=\"103\">DELETE<\/td>\n<td valign=\"top\" width=\"276\">Destroy(int id)<\/td>\n<td valign=\"top\" width=\"346\">delete a specific user<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Because most browsers support submitting HTML forms only using the GET and POST verbs, there\u2019s the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee407388.aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Html.HttpMethodOverride<\/a> helper which generates a hidden field inside the form and is used by the routing engine to dispatch to the proper controller action.<\/p>\n<h1>Unit Tests<\/h1>\n<p>Unit testing our controller actions is essential. I\u2019ve been using the excellent <a href=\"http:\/\/mvccontrib.codeplex.com\/wikipage?title=TestHelper\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">MVCContrib.TestHelper<\/a> in conjunction with the <a href=\"http:\/\/www.ayende.com\/projects\/rhino-mocks.aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Rhino.Mocks<\/a> framework to test controllers in isolation by mocking the HTTP context. Here\u2019s how the test logic looks like:<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:57c3e7e1-0043-4afa-8eee-8fd1fee961bc\">\n<pre class=\"lang:default decode:true\">[TestClass]\npublic class UsersControllerTests : TestControllerBuilder\n{\n    private UsersController _sut;\n    private IUsersRepository _repositoryStub;\n    private IMapper _userMapperStub;\n\n    public UsersControllerTests()\n    {\n    }\n\n    private TestContext testContextInstance;\n\n    \/\/\/  \n    \/\/\/Gets or sets the test context which provides\n    \/\/\/information about and functionality for the current test run.\n    \/\/\/ \n    public TestContext TestContext\n    {\n        get\n        {\n            return testContextInstance;\n        }\n        set\n        {\n            testContextInstance = value;\n        }\n    }\n\n    \/\/ Use TestInitialize to run code before running each test \n    [TestInitialize()]\n    public void MyTestInitialize() \n    {\n        _repositoryStub = MockRepository.GenerateStub&lt;IUsersRepository&gt;();\n        _userMapperStub = MockRepository.GenerateStub&lt;IMapper&gt;();\n        _sut = new UsersController(_repositoryStub, _userMapperStub);\n        InitializeController(_sut);\n    }\n\n    [TestMethod]\n    public void UsersController_Index()\n    {\n        \/\/ arrange\n        var users = new User[0];\n        _repositoryStub.Stub(x =&gt; x.GetUsers()).Return(users);\n\n        \/\/ act\n        var actual = _sut.Index();\n\n        \/\/ assert\n        actual\n            .AssertViewRendered()\n            .WithViewData&lt;User[]&gt;()\n            .ShouldBe(users);\n    }\n\n    [TestMethod]\n    public void UsersController_New()\n    {\n        \/\/ act\n        var actual = _sut.New();\n\n        \/\/ assert\n        actual\n            .AssertViewRendered();\n    }\n\n    [TestMethod]\n    public void UsersController_Create_Invalid_Model_State()\n    {\n        \/\/ arrange\n        _sut.ModelState.AddModelError(\"FirstName\", \"First name is required\");\n        var userView = new UserViewModel();\n\n        \/\/ act\n        var actual = _sut.Create(userView);\n\n        \/\/ assert\n        actual\n            .AssertViewRendered()\n            .ForView(\"New\")\n            .WithViewData&lt;UserViewModel&gt;()\n            .ShouldBe(userView);\n    }\n\n    [TestMethod]\n    public void UsersController_Create_Success()\n    {\n        \/\/ arrange\n        var userView = new UserViewModel();\n        var user = new User();\n        _userMapperStub\n            .Stub(x =&gt; x.Map(userView, typeof(UserViewModel), typeof(User)))\n            .Return(user);\n\n        \/\/ act\n        var actual = _sut.Create(userView);\n\n        \/\/ assert\n        actual\n            .AssertActionRedirect()\n            .ToAction&lt;UsersController&gt;(c =&gt; c.Index());\n        _repositoryStub.AssertWasCalled(x =&gt; x.Save(user));\n    }\n\n    [TestMethod]\n    public void UsersController_Show()\n    {\n        \/\/ arrange\n        var id = 1;\n        var user = new User();\n        _repositoryStub.Stub(x =&gt; x.Get(id)).Return(user);\n\n        \/\/ act\n        var actual = _sut.Show(id);\n\n        \/\/ assert\n        actual\n            .AssertViewRendered()\n            .WithViewData&lt;User&gt;()\n            .ShouldBe(user);\n    }\n\n    [TestMethod]\n    public void UsersController_Edit()\n    {\n        \/\/ arrange\n        var id = 1;\n        var user = new User();\n        _repositoryStub.Stub(x =&gt; x.Get(id)).Return(user);\n\n        \/\/ act\n        var actual = _sut.Edit(id);\n\n        \/\/ assert\n        actual\n            .AssertViewRendered()\n            .WithViewData&lt;User&gt;()\n            .ShouldBe(user);\n    }\n\n    [TestMethod]\n    public void UsersController_Update_Invalid_Model_State()\n    {\n        \/\/ arrange\n        _sut.ModelState.AddModelError(\"FirstName\", \"First name is required\");\n        var userView = new UserViewModel();\n\n        \/\/ act\n        var actual = _sut.Update(userView);\n\n        \/\/ assert\n        actual\n            .AssertViewRendered()\n            .ForView(\"Edit\")\n            .WithViewData&lt;UserViewModel&gt;()\n            .ShouldBe(userView);\n    }\n\n    [TestMethod]\n    public void UsersController_Update_Success()\n    {\n        \/\/ arrange\n        var userView = new UserViewModel();\n        var user = new User();\n        _userMapperStub\n            .Stub(x =&gt; x.Map(userView, typeof(UserViewModel), typeof(User)))\n            .Return(user);\n\n        \/\/ act\n        var actual = _sut.Update(userView);\n\n        \/\/ assert\n        actual\n            .AssertActionRedirect()\n            .ToAction&lt;UsersController&gt;(c =&gt; c.Index());\n        _repositoryStub.AssertWasCalled(x =&gt; x.Update(user));\n    }\n\n    [TestMethod]\n    public void UsersController_Destroy()\n    {\n        \/\/ arrange\n        var id = 1;\n\n        \/\/ act\n        var actual = _sut.Destroy(id);\n\n        \/\/ assert\n        actual\n            .AssertActionRedirect()\n            .ToAction&lt;UsersController&gt;(c =&gt; c.Index());\n        _repositoryStub.AssertWasCalled(x =&gt; x.Delete(id));\n    }\n}<\/pre>\n<h1>Views<\/h1>\n<\/div>\n<p>And the last but not least part of the picture are the views:<\/p>\n<h2>Index.aspx<\/h2>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:649bb274-6f40-4fa0-b2fb-a1244a0f1076\">\n<pre class=\"lang:default decode:true\">&lt;%@ Page Title=\"\" Language=\"C#\" MasterPageFile=\"~\/Views\/Shared\/Site.Master\" Inherits=\"System.Web.Mvc.ViewPage\" %&gt;\n&lt;%@ Import Namespace=\"SampleMvc.Web.Models\" %&gt;\n&lt;%@ Import Namespace=\"SampleMvc.Web.Controllers\" %&gt;\n\n&lt;asp:Content ID=\"Content1\" ContentPlaceHolderID=\"TitleContent\" runat=\"server\"&gt;\n    Index\n&lt;\/asp:Content&gt;\n\n&lt;asp:Content ID=\"Content2\" ContentPlaceHolderID=\"MainContent\" runat=\"server\"&gt;\n    &lt;h2&gt;Index&lt;\/h2&gt;\n    &lt;%: Html.Grid&gt;(Model)\n        .Columns(column =&gt; {\n            column.For(\"TableLinks\").Named(\"\");\n            column.For(model =&gt; model.FirstName);\n            column.For(model =&gt; model.LastName);\n            column.For(model =&gt; model.Age);\n        })\n    %&gt;\n    &lt;p&gt;\n        &lt;%: Html.ActionLink&gt;(c =&gt; c.New(), \"Create New\") %&gt;\n    &lt;\/p&gt; \n&lt;\/asp:Content&gt;<\/pre>\n<\/div>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:649bb274-6f40-4fa0-b2fb-a1244a0f1076\">\n<h2>TableLinks.ascx<\/h2>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:0ebe3179-8ba3-48d8-b5f2-e1af8c248169\">\n<pre class=\"lang:default decode:true\">&lt;%@ Control Language=\"C#\" Inherits=\"System.Web.Mvc.ViewUserControl\" %&gt;\n&lt;%@ Import Namespace=\"SampleMvc.Web.Controllers\" %&gt;\n&lt;td&gt;\n    &lt;%: Html.ActionLink&gt;(c =&gt; c.Edit(Model.Id), \"Edit\") %&gt; |\n    &lt;%: Html.ActionLink&gt;(c =&gt; c.Show(Model.Id), \"Details\") %&gt; |\n    &lt;% using (Html.BeginForm&gt;(c =&gt; c.Destroy(Model.Id))) { %&gt;\n        &lt;%: Html.HttpMethodOverride(HttpVerbs.Delete) %&gt;\n        &lt;input type=\"submit\" value=\"Delete\" \/&gt;\n    &lt;% } %&gt;\n&lt;\/td&gt;<\/pre>\n<\/div>\n<h2>Edit.aspx<\/h2>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:e361d11f-3cfe-4886-8be5-2cf2029737f5\">\n<pre class=\"lang:default decode:true\">&lt;%@ Page Title=\"\" Language=\"C#\" MasterPageFile=\"~\/Views\/Shared\/Site.Master\" Inherits=\"System.Web.Mvc.ViewPage\" %&gt;\n&lt;%@ Import Namespace=\"SampleMvc.Web.Controllers\" %&gt;\n\n&lt;asp:Content ID=\"Content1\" ContentPlaceHolderID=\"TitleContent\" runat=\"server\"&gt;\n    Edit\n&lt;\/asp:Content&gt; \n\n&lt;asp:Content ID=\"Content2\" ContentPlaceHolderID=\"MainContent\" runat=\"server\"&gt;\n    &lt;h2&gt;Edit&lt;\/h2&gt;  \n    &lt;% using (Html.BeginForm&gt;(c =&gt; c.Update(null))) {%&gt;\n        &lt;%: Html.ValidationSummary(true) %&gt;\n        &lt;%: Html.HttpMethodOverride(HttpVerbs.Put) %&gt;\n        &lt;%: Html.HiddenFor(model =&gt; model.Id) %&gt;\n        &lt;%: Html.EditorForModel() %&gt;\n        &lt;p&gt;\n            &lt;input type=\"submit\" value=\"Save\" \/&gt;\n        &lt;\/p&gt;\n     &lt;% } %&gt;\n    &lt;div&gt;\n        &lt;%: Html.ActionLink&gt;(c =&gt; c.Index(), \"Back to List\") %&gt;\n    &lt;\/div&gt; \n &lt;\/asp:Content&gt;<\/pre>\n<\/div>\n<h2>New.aspx<\/h2>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:3365807c-d5f9-4c1e-9c2c-8bd3cbdbbb77\">\n<pre class=\"lang:default decode:true crayon-selected\">&lt;%@ Page Title=\"\" Language=\"C#\" MasterPageFile=\"~\/Views\/Shared\/Site.Master\" Inherits=\"System.Web.Mvc.ViewPage\" %&gt;\n&lt;%@ Import Namespace=\"SampleMvc.Web.Controllers\" %&gt;\n\n&lt;asp:Content ID=\"Content1\" ContentPlaceHolderID=\"TitleContent\" runat=\"server\"&gt;\n    New\n&lt;\/asp:Content&gt; \n\n&lt;asp:Content ID=\"Content2\" ContentPlaceHolderID=\"MainContent\" runat=\"server\"&gt;\n    &lt;h2&gt;New&lt;\/h2&gt;\n    &lt;% using (Html.BeginForm&gt;(c =&gt; c.Create(null))) {%&gt;\n        &lt;%: Html.ValidationSummary(true) %&gt;\n\n        &lt;%: Html.EditorForModel() %&gt;\n        &lt;p&gt;\n            &lt;input type=\"submit\" value=\"Create\" \/&gt;\n        &lt;\/p&gt;\n    &lt;% } %&gt;\n    &lt;div&gt;\n        &lt;%: Html.ActionLink&gt;(c =&gt; c.Index(), \"Back to List\") %&gt;\n    &lt;\/div&gt;\n&lt;\/asp:Content&gt;<\/pre>\n<\/div>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:3365807c-d5f9-4c1e-9c2c-8bd3cbdbbb77\">\n<h2>UserViewModel.ascx editor Template<\/h2>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:ac712efb-8ef5-4743-87ef-7334eb58bbb3\">\n<pre class=\"lang:default decode:true\">&lt;%@ Control Language=\"C#\" Inherits=\"System.Web.Mvc.ViewUserControl\" %&gt;\n\n&lt;fieldset&gt;\n    &lt;legend&gt;Fields&lt;\/legend &gt;\n    &lt;div class=\"editor-label\"&gt;\n        &lt;%: Html.LabelFor(model =&gt; model.FirstName) %&gt;\n     &lt;\/div&gt;\n    &lt;div class=\"editor-field\"&gt;\n        &lt;%: Html.TextBoxFor(model =&gt; model.FirstName) %&gt;\n        &lt;%: Html.ValidationMessageFor(model =&gt; model.FirstName) %&gt;\n     &lt;\/div&gt;            \n    &lt;div class=\"editor-label\"&gt;\n        &lt;%: Html.LabelFor(model =&gt; model.LastName) %&gt;  \n    &lt;\/div&gt;\n    &lt;div class=\"editor-field\"&gt;\n        &lt;%: Html.TextBoxFor(model =&gt; model.LastName) %&gt;\n        &lt;%: Html.ValidationMessageFor(model =&gt; model.LastName) %&gt;\n     &lt;\/div&gt;            \n    &lt;div class=\"editor-label\"&gt;\n        &lt;%: Html.LabelFor(model =&gt; model.Age) %&gt;\n     &lt;\/div&gt;\n     &lt;div class=\"editor-field\"&gt;\n        &lt;%: Html.TextBoxFor(model =&gt; model.Age) %&gt;\n        &lt;%: Html.ValidationMessageFor(model =&gt; model.Age) %&gt;\n     &lt;\/div&gt;\n &lt;\/fieldset&gt;<\/pre>\n<\/div>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:ac712efb-8ef5-4743-87ef-7334eb58bbb3\">\n<p>A very important aspect of the views is that they are all strongly typed to a view model and use only strongly typed helpers, even for generating the links. One day when Visual Studio becomes power enough you will be able to seamlessly refactor\/rename a property without worrying about all those <a href=\"http:\/\/en.wikipedia.org\/wiki\/Magic_string_(programming)\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">magic strings<\/a>.<\/p>\n<p>Further enchantments will include adding client side validation using the jQuery validate plugin in order to improve the user experience and preserve bandwidth.<\/p>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Sample MVC Solution In this post I will show a sample ASP.NET MVC 2.0 project structure illustrating different concepts such as data access, user input validation and mapping between the domain and the view model. The project is still under construction but the source code is available at github. I will illustrate the usage of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[263,265],"tags":[275,277,287,289,293,313,320],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts\/37"}],"collection":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/comments?post=37"}],"version-history":[{"count":0,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts\/37\/revisions"}],"wp:attachment":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/media?parent=37"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/categories?post=37"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/tags?post=37"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}