Creating GeoGeekTV: Domain Model, Controllers and Views
Posted by Dave Bouwman | Posted in ASP.NET MVC, GeoGeekTV, jQuery | Posted on 31-08-2009
2
Now that we have the look and feel stubbed out, it’s time to build out the rest of the site.
Since nearly every page is data driven to some extent, the best place to start is with the domain objects. If we were doing this with Linq to SQL, we’d start by creating the database, and then having that drive our Linq to SQL “domain”, but I’m planning on using this project to get my feet wet with NHibernate, so I’ll just start with the domain.
Since the site is going to be pretty simple, we really don’t have a lot in the domain – really just a ShowModel and a TagModel as shown in the class diagram below.
As we can see, these are simple data containers. I had originally thought I’d have a separate “UpComingShowModel”, but it seemed like it would be a pain to copy the info from that model into the “ShowModel”, so I just added an IsPlanned flag. This way I can keep both the upcoming and the completed shows in the same table, side-stepping this entire problem.
Some may ask – why call your domain entities “Models”. Well, that’s a good question. In some other apps I’ve been working on we started off calling the entities Models, and then realized that we needed more than just the entity in the View – so we added a set of “ViewModels” into the mix. This seemed to work pretty well on these other projects, but it does seem a little forced on a project this simple.
Repository
Now that we have the models, we need a way for the Controllers to access them. For that we implement a repository pattern using dependency injection – sounds more complex than it really is.
Essentially we define an interface for a data repository – IShowRepository in this case. This interface represents the contract between the consuming classes (the controllers) and the implementing classes (the data access layer). We then use a dependency injection framework (Castle Windsor via the mvccontrib library) to pass an implementation of the repository into the controller’s constructor. Trust me, this is really easy.
I tend to build these interfaces in an iterative manner – I’ll start with one page of the site, determine what domain objects I need in the controller (and thus the view), then I add methods to the repository interface to get these objects, and then provide the implementation. Here’s the IShowRepository as it currently stands…
After futzing with Visual Studio to show the full signatures (Class Diagram –> Change Member Format –> Display Full Signature), we can see that this is a very simple data contract.
Fakes
Since I want to “prove” the design before getting into actually creating a real data access layer, I start by cooking up a simple fake implementation of the repository. As far as the Controller knows, this is a full blown real-deal repository, but it’s just returning junk. As you can see by hitting the site right now, we are showing lists of shows, but they’re all the same thing – that’s because behind the scenes pretty much everything hits this private method:
private ShowModel CreateFakeShow() { return new ShowModel(){ Description = @"Dave and Brian talking about recent work, building GeoGeekTV.com, Flex, and NBB Hoptober", Title = "Friday Streaming from DTSAgile", ImageName="123abc.png", IsPlanned = false, DateLocation= "August 28th, Fort Collins", StreamedLive = true, ViewCount = 3, ShowNumber = 323 }; }
Dependency Injection
Ok, so we have the interface and a fake implementation, and now we need to get this into the controllers. Since we will be using constructor based injection, the first thing to do is knock in some constructors for our controllers. This is pretty much the pattern for all the controllers.
private IShowRepository _showRepository; public HomeController(IShowRepository showRepository) { _showRepository = showRepository; }
Next, we need to register our “fake” with Castle Windsor so it can do the injection. I’ve already setup the basic Castle Windsor infrastructure in Global.asax.cs, so all I need to do is register the fake with the WindsorContainer…
protected virtual void InitializeWindsor() { if (_container == null) { _container = new WindsorContainer(); ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container)); //add in the components... _container.AddComponent<IShowRepository, GeoGeekTV.Fakes.ShowRepository>(); //Add the controllers... _container.RegisterControllers(typeof(LoginController).Assembly); } }
You can get the basic Castle Windsor for MVC setup from looking at either the source code for this project, or from mvccontib’s examples.
That’s about it! With the Windsor container in place, ASP.NET MVC will use it’s factory to create the controller, and along the way all the dependencies get injected. See – I told you it was easy!
Controllers and Views
I’m not going to go the basics of ASP.NET MVC – I’d suggest reading the NerdDinner example from Scott Guthrie, Phil Haak, Scott Hanselman and Rob Conery. I’ll also throw out a pitch for their book, as it is quite good.
In the earlier post I defined the routes, which helped map out the controllers, and the needed methods. Since I’ve built a few sites, and have some handy code lying around, I also inherited my controllers from a BaseController than has some logging capabilities baked in.
Most of the controller methods are very simple – just populate a ViewModel from the repository, and pass that to the view.
This is pretty representative – it’s the Home Controller’s Index method, which is the main page of the site…
public ActionResult Index() { HomeViewModel model = new HomeViewModel(); model.MostViewedShows = _showRepository.GetMostViewedShows(); model.RecentShows = _showRepository.GetRecentShows(5); return View("index",model); }
In some projects I’ve had the repository build up the ModelViews, but in this one, it’s easier to have the controller’s handle this, as it results in much less code in the repository.
Summary
So – the project is coming together. Almost all the pages are built out – the Contact page needs serious CSS attention, as well as a back-end implementation. Looking forward, I still have a fair bit of work left to polish everything off. Luckily, I think the enhanced HtmlHelpers in ASP.NET MVC 2.0 will help out. Next up: The Admin Pages

