Every time I go to build a new controller, I get the funny feeling that I’m not being very dry… If I started from scratch, with the visual studio template, it creates a boilerplate controller. ThenI usually end up pasting chuncks of code from various other controllers.
MvcScaffolding automates the production of the boilerplate but its still there and I find all the duplicate code a little annoying. Let’s take a look at the standard output.
Wow, that’s a lot of boilerplate! We could use simple inhertance but that wouldn’t get us very far because the model class is littered all over the controller. Well that is a big hint that generics could be applied to all this duplicate code. Let's see what that would look like.
Since I am using Entity Framework Code First, I start by building my model, Foo.
Notice that I've inherited from ModelRoot. That's because I almost always have a primary key of "Id" so in keeping with the "DRY" principle, I extracted into the ModelRoot class below
It's not much of a savings and inheritance introduces complexity that frequently outweighs the intended benefits. But this is so simple and intuitive to me, that the additional complexity is negligible. There are also other benefits I’ll demonstrate later.
Below is a snippet of the generic controller. We end up having to some funny foot work with casting but not to much.
Notice that I made use of the ModelRoot class as a constraint to the class declaration (2nd line). That gives us access to the Id field of ModelRoot in the CRUD methods that take an Id. I told ya it had extra benefits!
Now our standard controller is completely empty, but we still have the option to override the virtual methods of the base class. Here is an example of what that would look like.
That certainly cleans thing up, but the big win is that inserting ubiquitous logic in your controllers methods is now possible. Take a gander back up to the Create method of the GController. Notice that I've implemented code to respond to an AjaxRequest and respond with json. By implementing this in the Generic controller, all my controllers get that feature for free! This is much safer than the copy and paste pattern I was using before. And, of course, I can always override the method in the derived controller if I don't want to allow Ajax.
There are quite a few more benefits of this pattern, especially when combined with a generic repository. But that is for a later post...