C# Tricks: Slimming down your controllers

This blog post is dedicated to my colleague Seminda who has been experimenting with how to create simple and powerful web applications. Thank you for showing me your ideas and discussing improvements with me, Seminda.

I find many C# applications have much unnecessary code. This is especially true as the weight of the business logic of many applications are shifting from the backend to JavaScript code in the web pages. When the job of your application is to provide data to a front-end, it’s important to keep it slim.

In this article, I set out to simplify a standard MVC 4 API controller by generalizing the functionality, centralizing exception handling and adding extension methods to the DB set that is used to fetch my data.

If you generate an API controller based on an existing Entity and remove some of the noise, your code may look like this:

This code is a simplified version of what the API 4 Controller wizard will give you. It includes a GetPerson method that returns a person by Id, PostPerson which saves a new person, GetPeople which returns all people in the database, GetAdminsInCity, which filters people on city and type and DeletePerson which finds the person with the specified Id and deletes it.

I have replaced DbContext and IDbSet with interfaces instead of the concrete subclass of DbContext makes it easy to create tests that use a double for the database, for example MockDbSet.

Generify the controller

This is easy and safe as long as things are simple. As a general tip, rename you methods to “Get”, “Post” and “Index” rather than “GetPerson”, “PostPerson” and “GetPeople”. This will make it possible to generalize the controller thus:

The generic EntityController can be used for any class that is managed with EntityFramework.

Exception handling

I will dare to make a bold generalization: Most of the bugs that remain in production software are in error handling. Therefore I have a very simple guideline: No catch blocks that don’t rethrow another exception.

The actual handling of exceptions should be centralized. This both makes the code easier to read and it ensures that exceptions are handled consistently. In MVC 4, the place to do this is with a ExceptionFilterAttribute.

We can thus simplify the EntityController:

The HandleApplicationException looks like this:

This code code of course add special handling of other types of exceptions, logging etc.

DbSet as a repository

But one piece remains in PersonController: The rather complex use of LINQ to do a specialized query. This is where many developers would introduce a Repository with a specialized “FindAdminsByCity” and perhaps even a separate service layer with a method for “FindSummaryOfAdminsByCity”.

If you start down that path, many teams will choose to introduce the same layers (service and repository) even when these layers do nothing and create a lot of bulk in their applications. From my personal experience, this is worth fighting against! Needless layers is the cause of a huge amount of needless code in modern applications.

Instead, you can make use of C# extension methods:

The resulting controller method becomes nice and encapsulated:

The extension methods can easily be reused and can be freely combined.

Conclusions

With these tricks, most of your controllers would look something like this:

That’s pretty minimal and straightforward!

I’ve showed three tricks to reduce the complexity in your controllers: First, parts of your controllers can be generalized, especially if you avoid the name of the entity in action method names; second, exception handling can be centralized, removing noise from the main application flow and enforcing consistency; finally, using extension methods on IQueryable<Person> gives my DbSet domain specific methods without having to implement extra layers in the architecture.

I’d love to hear if you’re using these approach or if you’ve tried something like it but found it lacking.

Copyright © 2014 Johannes Brodwall. All Rights Reserved.

About Johannes Brodwall

Johannes is Principal Software Engineer in SopraSteria. In his spare time he likes to coach teams and developers on better coding, collaboration, planning and product understanding.
This entry was posted in C#, Code, English, Software Development. Bookmark the permalink.
  • quesa

    I tested the generification of my controller but had issues when trying to ‘keep things simple’ as my return needed to include multple tables joined or included. I needed to make custom modifications to the generified controller and that didn’t seem to mix well with what you are trying to accomplish.

    PS. I’m nowhere near an expert coder, such as yourself, so it could be that I’m trying to do the modifications in the wrong place.

  • http://www.johannesbrodwall.com/ Johannes Brodwall

    A good question. This approach is in the spirit of “make simple things simple”. When things get more complicated, other approaches are needed.

    A query that requires joins or other operators that are on DbSets, but not on IQueryable can still be made into an extension method on PersonCollections (but this time, on IQueryable). I would start my experimentation there.

    If that becomes cumbersome, I would revert to the old repository pattern.

    The most important thing to remember is that different problems have different solutions. Don’t solve simple problems in a complex way just to be consistent with the complex problems. :-)

  • neil scales

    In a professional application, you must always do server side validation of inputs. With your controller, once I’ve got a login to your site, I can delete someone else’s records !

  • http://www.johannesbrodwall.com/ Johannes Brodwall

    You’re right, but authorization (not validation!) is a cross-cutting concern and should not be done in the specific controller. I drafted a blog post on it, but never finished it, sadly. :-(