How would you inject a worker service in a controller class and perhaps a repository in a worker service? The most obvious way is by letting controllers and services create a fresh new instance of the dependent objects. This route, however, creates a tight dependency between objects that potentially hinders extensibility and testability. For this reason, many suggest inversion of control and IoC containers.
While there’s nothing to say about the effectiveness of this approach which is also clean and nifty, I question its wide applicability. Do you really need it all the time? Or are you just applying it victim of some form of geekiness? I now prefer having far simpler code that can evolve to tool-based inversion of control in a few clicks.
public class HomeController : Controller
private readonly IHomeService _workerService;
public HomeController() : this(new HomeService())
public HomeController(IHomeService service)
_workerService = service;
When the default constructor is used to instantiate a controller, the worker service member points to a freshly created instance of a default worker service class. A second constructor is available to manually inject any instance you like, at least for testability reasons. Likewise, you do the same for injecting the repository dependency into the worker service.
ASP.NET MVC, however, always uses the default constructor for each controller class, unless you gain control of the controller factory.
To jump to tool-based inversion of control, you just add IoC initialization and configuration. And a controller factory.
Responsibility-Driven Design defines two concepts that work very well in ASP.NET MVC: controller and coordinator. Needless to say, an RDD controller has little to do with an ASP.NET MVC controller. In RDD, a controller orchestrates the behavior of other objects, and decides what other objects should do. In one word, it suggests a chatty communication model. An RDD coordinator, instead, adds one more layer around controllers. A coordinator, in fact, solicited by events delegates work to other objects. In doing so, it applies a chunky communication model.
Great. What about ASP.NET MVC controllers? Should they be controllers or coordinators? Should they be chatty or chunky?
An ASP.NET MVC controller that chats with the site’s backend is not really better than a so much snubbed code-behind class. An ASP.NET MVC controller that behaves like an RDD coordinator groups all of the steps that form the implementation of the action within a single worker object. You place a single call to the worker object and use its output to feed the view-model object.
You break down the complexity of the task requested into steps and code them into a worker service that is 1:1 with the controller. The controller method is then as simple as
public ActionResult Index()
var model = _workerService.GetIndexViewModel();
You have no need to test controllers any more and, better, pass any information down to the worker service which is completely isolated from the HTTP context.
ASP.NET MVC comes with the promise that it makes it easier for you to write cleaner and more testable code. This is great, except that it doesn’t come out of the box.
For sure, ASP.NET MVC is based on some infrastructure that makes this possible and easier than in Web Forms. A lot, however, is left to you—the developer—and to your programming discipline and design vision.
Architecturally speaking, the controller is just the same as the code-behind class in Web Forms. It is part of the presentation layer, and in some way it exists to forward requests to the back end of the application.
Without development discipline, the controller can easily grow as messy and inextricable as an old-fashioned code-behind class. So it isn’t just choosing ASP.NET MVC that determines whether you’re safe with regard to code cleanness and quality.
It is design skills. It is about an embedded implementation of the Separation of Concerns principle. It is education. It is ability of using brains and thinking. It is keeping pure software technology to the corner to bring it back when design is clear. And clean.