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

Making SharpArch 2.0: Introduction

by Geoffrey.Smith 9. April 2011 03:15

 

Welcome to the first part of an ongoing series, Making Sharp Architecture 2.0. The goal of this series is to walk through the development of the next iteration of Sharp Architecture as it happens. We hope that increased transparency will give insight to design decisions and, more importantly, foster discussion on how to improve a great framework.

The series begins in medias res, as much work has already gone into the 2.0. To recap the current status of 2.0.

Project Structure Renaming

The current project structure follows the tenants of a properly layered design, but through accidents of history, does call itself by any standard naming scheme. This a quick one to knock out:

1.0 2.0
Application Services Tasks
Core Domain
Data Infrastructure
Web Presentation
Web.Controllers Merged with Presentation

Why tasks and not application services? Services is, unfortunately, a loaded term. There’s Windows' Domain Services, Service Oriented Architecture, web services, and menagerie of other jargon that pulls and tugs at the meaning of service. Let’s go back to Eric Evans' definition:

“[The Application layer] Defines the jobs the software is supposed to do and directs the expressive domain objects to work out problems. The tasks (emphasis mine) this layer is responsible for are meaningful to the business or necessary for interaction with the application layers of other systems.

"This layer is kept thin. It does not contain business rules or knowledge, but only coordinates tasks and delegates work to collaborations of domain objects in the next layer down. It does not have state reflecting the business situation, but it can have state that reflects the progress of a task for the user or the program.“ (Evans 70)

The idea that the presentation layer calls tasks to be performed seems a much more natural fit for this.

The reasoning behind moving controllers from a separate assembly are two-fold. First, given that controllers are tightly integrated to the views they show, the separation seemed like a bit of needless abstraction. Second, rather pragmatically, moving controllers to co-habitate with views allows the built-in Visual Studio tools to function correctly. Moving controllers to a separate assembly, if you so desire, is a trivial task nonetheless.

Introduction of SharpArch.Features

One of the ideas presented by Sharp is that the persistence technologies themselves are fungible. There’s quite a bit of debate as to whether or not this is actually necessary. I will concede that most projects do not move from a traditional RDBMS to a document store without a major refactoring. If a project were to use a lot of different database technologies, due to its size or complexity, it would probably benefit from a more robust service bus and a move away from the repository pattern.

What would be beneficial, would be to start a new Sharp project with whichever database technology you want to use in easiest manner possible. This is the idea behind moving NHibernate and persistence frameworks to their own assembly with SharpArch itself being persistence ignorant.

Stepping back a minute, does pulling the persistence framework out of the core project violate good design principles? After much research, I don’t think so. In fact, it allows the other layers in Sharp Architecture to be even more loosely coupled. Larman prefers to put frameworks entirely as a “subsystem within the technical services layer,” (Larman 623) not tightly coupled with the rest of the project.

How tightly coupled is SharpArchitecture to NHibernate? As tight as one could be, even where it logically shouldn’t be. For example, since there is an NHibernateRepository and a Repository, you might conclude that the latter is a generic version of the former. That would be wrong, there’s plenty of pernicious little references to NHibernate everywhere. Take SharpArch / SharpArch.Data / NHibernate / Repository.cs:

public virtual IList<t> GetAll() {

            ICriteria criteria = Session.CreateCriteria(typeof(T));

            return criteria.List<t>();

        }

Session is not a generic session manager, but instead belongs to NHibernate.Session, and obviously CreateCriteria exists only in the context of NHibernate. This would make more sense if NHibernateRepository.cs didn’t also exist, which it does. Cleaning this up should go along way to creating a more persistence independent framework.

Conclusion

We moved to a better, more precisely named project structure. This has the advantage of allowing the built-in features of Visual Studio to work out of the box. We also looked at a major restructuring involving moving the persistence subsystem to its own assembly and keeping it from polluting the rest of the framework. Next time, we’ll look at implementing Udi Dahan’s Query<T> as a way of passing Linq fetch queries down to the persistence layer.

References

Craig Larman. 2001. Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and the Unified Process (2nd ed.). Prentice Hall PTR, Upper Saddle River, NJ, USA.

Eric Evans. 2004. Domain-driven design: tackling complexity in the heart of software. Addison-Wesley

This is cross-posted from my blog

Tags:

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