Integrating MVCScaffolding and SharpArchitecture

by Geoffrey.Smith 11. April 2011 07:14

N.B. This article isn’t meant to get you up and running with MVCScaffolding and Sharp, but merely as an exploratory article on editing MvcScaffolding T4 templates.

Steven Anderson has a pretty interesting series on MVCScaffolding. It is not a novel idea, Rails does it, Django sort of does it, even JavaScriptMVC does it, so let’s do it, let’s fall in love, err, scaffold.

I went ahead and created a project based on 1.9.6, and in keeping with Steve Anderson’s example, I’m going to go ahead and call our project “Football.” First thing, I blew out the existing code generation and the controllers project, then added a controller folder to Football.Web.

As in the aforementioned example, let’s bring up the Package Manager Console, and set the default project to Football.Web (NB, MvcScaffolding requires a reference to MVC3 to work):

PM> Install-Package MvcScaffolding
'EntityFramework 4.1.10311.0' already installed
'T4Scaffolding 0.9.9' already installed
'MvcScaffolding 0.9.9' already installed
Successfully added 'EntityFramework 4.1.10311.0' to Football.Web
Successfully added 'T4Scaffolding 0.9.9' to Football.Web
Successfully added 'MvcScaffolding 0.9.9' to Football.Web

We won’t be needing EntityFramework and a lot of the automatic wiring is already done via the Templify package. That doesn’t really matter right now, let’s create a model and see if it can correctly find a model in another assembly and generate the scaffolding:

namespace Football.Core
{
   using System.ComponentModel.DataAnnotations;
   using SharpArch.Core.DomainModel;

   public class Team : Entity
   {
       [Required]
       public virtual string Name { get; set; }

       public virtual string City { get; set; }

 

 [Range(1898, 2100)]

       public virtual int YearFounded { get; set; }
   }
}

Hey, those don’t look like NHValidator properties! They aren’t, they’re DataAnnotations, which is an expected feature somewhere in the 2.x release cycle. For sake of simplicity I’m going to keep them.

Steven uses DateTime for the Founded property, but who cares the date and month? No one. The first team was founded in 1898 (Arizona née Chicago Cardinals) and let’s chose 2100 as a way of telling the future they need to probably spend some money on rewriting this.

Okay, cross your fingers, let’s see if it works:

PM> Scaffold Controller Team
Scaffolding TeamsController...
Added database context 'Models\FootballWebContext.cs'
Added 'Teams' to database context 'Football.Web.Models.FootballWebContext'
Added controller Controllers\TeamsController.cs
Added Create view at 'Views\Teams\Create.cshtml'
Added Edit view at 'Views\Teams\Edit.cshtml'
Added Delete view at 'Views\Teams\Delete.cshtml'
Added Details view at 'Views\Teams\Details.cshtml'
Added Index view at 'Views\Teams\Index.cshtml'
Added _CreateOrEdit view at 'Views\Teams\_CreateOrEdit.cshtml'

No errors, and it correctly found the Id property on the inherited Entity class! I’m saying we’re about 90% of the way there. It looks like all we’ll need to do is edit the template files to get rid of those EntityFramework references and change everything to feel more like a Sharp project.

This would be part 5 of Steven’s series, “Overriding the T4 Templates,” “<yourSolutionDir>\packages\<scaffolderPackage>\tools to see the structure of scaffolders and templates.” Since Sharp gives you the Dbcontext stuff for free with IRepository<Team>, let’s focus on the controller in \MvcScaffolding.0.9.9\tools\Controller\ControllerWithContext.cs.t4. I’ve put my changes up on Gist and the resulting template looks a lot more like Sharp, doesn’t it?

namespace Football.Web.Controllers
{
   using System.Linq;
   using System.Web.Mvc;
   using Football.Core;
   using MvcContrib;
   using SharpArch.Core.PersistenceSupport;
   using SharpArch.Web.NHibernate;

   [HandleError]
   public class TeamController : Controller
   {
       private readonly IRepository<Team> teamRepository;

       public TeamController(IRepository<Team> teamRepository)
{
           this.teamRepository = teamRepository;
}

       public ViewResult Index()
       {
           return View(this.teamRepository.GetAll().ToList());
       }

       public ViewResult Details(int id)
       {
           var team = this.teamRepository.Get(id);
           return View(team);
       }

       public ActionResult Create()
       {
           return View();
       }

       [HttpPost]
[Transaction]
       public ActionResult Create(Team team)
       {
           if (ModelState.IsValid)
           {
               this.teamRepository.SaveOrUpdate(team);
               return this.RedirectToAction(c => c.Index());  
           }

           return View(team);
       }

       public ActionResult Edit(int id)
       {
           var team = teamRepository.Get(id);
           return View(team);
       }

       [HttpPost]
       public ActionResult Edit(Team team)
       {
           if (ModelState.IsValid)
           {
               this.teamRepository.SaveOrUpdate(team);
               return this.RedirectToAction(c => c.Index());
           }

           return View(team);
       }

       public ActionResult Delete(int id)
       {
           var team = this.teamRepository.Get(id);
           return View(team);
       }

       [HttpPost, ActionName("Delete")]
       [Transaction]
       public ActionResult DeleteConfirmed(int id)
       {
           var team = this.teamRepository.Get(id);
           this.teamRepository.Delete(team);
           return this.RedirectToAction(c => c.Index());  
       }
   }
}

With a bit of hacking, I’ve managed to get rid of the plural controller/view names, along with commenting out the creation of dbcontext, view it here.

If you just want to play around with the scaffolding, I also put up the entire project
here.

This just generates a controller and associated views based on a model. What abouts schema generation? I don’t like how EntityFramework acts a blackbox in this regard. I’d much rather have a method in the infrastructure layer that outputs a *.sql file:

var session = NHibernateSession.GetDefaultSessionFactory().OpenSession();

using (TextWriter stringWriter = new StreamWriter("GenerateSchema.sql")) {
           new SchemaExport(configuration).Execute(true, false, false, session.Connection, stringWriter);
           }

According to Seif it may actually be simpler than this, with just a change in the config file.

Thoughts on where this should go?

Tags:

S#arp Architecture

Comments

Comments are closed

About the Team

Sharp Architecture was originally created by Billy McCafferty.

The project is currently led by Alec Whittington and the development team currently consists of James Broome, Jon George and Howard van Rooijen

Page List