Skip to content

Fat Controller CQRS Diet: Vertical Slices

Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.

Learn more about Software Architecture & Design.
Join thousands of developers getting weekly updates to increase your understanding of software architecture and design concepts.


This post is in my Fat Controller CQRS Diet series. It demonstrates how to thin your controllers by implementing commands and queries using the MediatR library.  Specifically in this post, I’ll look at organizing your code by vertical slices. I’m converting the MusicStore application that’s using ASP.NET Core MVC.   All the source code is available on GitHub. If you’re new to this series, here are earlier posts to get up to speed:
  1. Overview of Series
  2. Simple Query
  3. Simple Command
  4. Command Pipeline
  5. Notifications

Organize by Feature

Feature Slices or Vertical Slices are the terms I’ve heard the most for what I call Organize by Feature. I’ve just always characterized as organizing all relevant code and files from a command or query into a specific folder or hopefully single file. I generally stay away from creating layers so the term Vertical Slices does make a lot of sense. Whatever our feature slice is, it surely makes sense to keep all that code together.

Single File

If you’ve seen the code related to my Command Pipeline or Notifications posts, then you should already be able to tell where I’m heading in terms of organization. I generally like to keep the command/query and it’s associated handler all within the same file.  In the case of our logging handler, I was also keeping it in this file. Pretty simple.  One file for everything related to a command or query.

Controllers & Views

Well almost.  What I hadn’t really moved were the controllers or views.  So let’s do that now. Controllers are pretty easy since by default they can live anywhere within your project. ASP.NET MVC Core will just pick them up. Let’s work on our Home Query.  We will simply create a HomeController within our Home.cs file that currently contains our query and our handler.
Because we are no longer using the default routing, I’ve added the HttpGet attribute to the method to keep the route intact to what it was prior.

View Locator

By default, ASP.NET Core MVC will look in the ~/Views/ folder with default conventions.  But we want to put our view right along side our Home.cs file in our Features folder. So I’ve moved all of the view files into our Features folder.  Our solution now looks like this:   In order to tell ASP.NET where our views are now at, we can implement the IViewLocationExpander
Now in the  IServiceProvider ConfigureServices(IServiceCollection services) method from our Startup.cs, we can can configure to use our new locator.

That’s it!

We now have one file that contains our controller, query and handler.  And right along side it we have our associated view.

Comments

All the source code for this series is available on GitHub.GitHub I love hearing your comments, questions and recommendations as it usually leads me down to other blog posts.  Please post a comments or on Twitter.

6 thoughts on “Fat Controller CQRS Diet: Vertical Slices”

  1. Yeah I really like this approach. I’ve seen to many apps that looking at the folders/files structure tell you mostly how they do stuff instead telling you what they actually do. Nice post. If you are on ASP.NET MVC <= 5 I guess you will have to override the default view engine.

  2. Pingback: The Year in .NET – Visual Studio 2017 RC and .NET Core updated, On .NET with Stephen Cleary and Luis Valencia, Ulterius, Inferno, Bastion, LoGeek Night | .NET Blog

  3. If you have only one command/query, it’s OK to put controller in same file with command/query and handler. But if you have more than one command/query, I prefer to keep controller in separated file

  4. Thanks for these posts Derek. To me it seems that the controllers and views should be in a separate project so that the command/queries/handlers/etc. can be reused by a different project (e.g. Desktop application). Am I missing something?

    1. No, that’s possible. When I have Command/Query/Request that I want to invoke from another project, I generally create a “Contracts” project that ultimately ends up containing the Command/Query/Request, and keep all the handlers, controllers etc where they are in my example above. But I only do this when the cmd/query/request needs to be invoked from another assembly.

Leave a Reply

Your email address will not be published. Required fields are marked *