Umbraco project structure

Recently I got to lay the foundation for a new Umbraco 9 project and so I started to question and think about the setup I have been using so far and if it might be possible to improve somehow.

The old project structure

The setup I’ve been having for the last couple of years (5 maybe?) is very much influenced by the default setup you get from setting up an Umbraco Cloud project with Visual Studio. This structure is as follow:

*.Web
- Umbraco install, views, js, css, packages, configs etc.

*.Core
- All .cs functionality for my Umbraco website such as composers, components, services, controllers etc.

*.Tests
- All my tests.

*.Integration.X
- Specific integration projects against external stuff (example: payment provider).

The problem

This above setup is quite simple and has worked pretty well so far, but there are a few things that has bugged me throughout the years:

  1. I don’t necessary think that *.Core is a great name for my Umbraco backend stuff. In all the non-Umbraco projects I work in we always have a *.Core project, but that usually represents core functionallity that can be shared between several projects in the same solution regardless if they are websites or just a plain Class Library for an API Integration. An examples could be a custom JsonClient that I want to be able to use in my Umbraco site, but also in my Integration project(s), and so I dont want to store the JsonClient in a project that has a dependency on Umbraco.

    One might argue that the JsonClient could be moved to another separate project, example *.Common, but a common project for me is things like Constants, Enums and plain C# stuff, not web dependent stuff. 

    But lately I read a great article on this years 24 days of Umbraco where the author mentioned a concept of *.Web.UI and .*Web, which to me makes a lot more sense . This way I can use *.Core for core functionality and Umbraco specific backend stuff can be moved to *.Web.

  2. Lately I’ve been looking in to splitting my Integration tests away from my .Tests project so that all tests related to a specific integration is in its own test project. Lets assume we have an Integration called *.Integration.Klarna (which is a payment provider) then I would create a *.Integration.Klarna.Tests project where all tests related to this integration is handled. Since my integration projects has no dependency on other web projects or the Umbraco project, it makes no sense that all tests should be bundled up in one huge *.Tests project.

The new project structure

I know this subject has been discussed for ages and ages, and I am not saying that I’ve found the perfect setup, but I thought I would share the setup that I’ve been investigating lately
and hopefully this will spark some great discussions. I even put together a visual representation of how this might look with lines representing dependencies to figure out if this will cause any circular dependencies (which it shouldn’t). Also the size of each box should somehow be a representation of the size of each project.

*.Web.UI
This is where we have the full installation of Umbraco CMS together with all the view, javascript and css. Except from the basics (js, css, html) and some configs we backend devs barely have to touch this project in our day-to-day development. This is where the cool frontend developer hangs out. 😎

  • Views
  • Javascript
  • CSS
  • Config
  • Umbraco install
  • Packages (App_Plugins)
  • Custom backoffice extensions (Content apps js/css/html/manifest)
  • Has reference to *.Web

*.Web
The main business logic for the Umbraco site. This is where most of the day-to-day development takes place for the backend developers.

  • Controllers
  • View Models
  • Components
  • Services
  • Helpers
  • Composers
  • Url Providers
  • Content Finders
  • Routing
  • Caching
  • Extensions (Umbraco dependent, ex. PublishedContentExtensions)
  • Backend implementation for custom packages/apps (Content Apps .cs files)
  • Has reference to *.Core
  • Has reference to *.Common
  • May reference *.Integration.X
  • May NOT reference *.Web.UI
  • May NOT reference *.Web.Tests
  • May NOT reference *.Integration.X.Tests

*.Core
Core functionality that can be shared between multiple (web) projects within the same solution.

  • Cookie handling
  • Json Client / Handling
  • Xml Client / Handling
  • Extensions (web dependent, ex HtmlHelperExtensions)
  • May ONLY reference *.Common project.
  • This project should NOT have an Umbraco dependency.

*.Common
Pure C# functionallity with no Umbraco or even web dependency. This project can be references by all projects in the solution, even non web projects such as a simple console application.

  • Extensions (pure C#, ex. StringExtensions)
  • Constants
  • Enums
  • May NOT reference any other project.
  • This project should NOT have an Umbraco dependency.

*.Web.Tests
Automated testing for the *.Web project.

  • Has reference to *.Web
  • May reference *.Core
  • May reference *.Common
  • May NOT reference *.Web.UI
  • May NOT reference *.Integration.*

*.Integration.X
External integration projects. For example could be a REST/SOAP service (payment provider, external product service etc).

  • May reference *.Core
  • May reference *.Common
  • May NOT reference *.Web.UI
  • May NOT reference *.Web
  • May NOT reference *.Web.Tests
  • This project should NOT have an Umbraco dependency.

*.Integration.X.Tests
Automated testing for the *.Integration project.

  • Has reference to *.Integration.X
  • May reference *.Core
  • May reference *.Common
  • May NOT reference *.Web.UI
  • May NOT reference *.Web
  • May NOT reference *.Web.Tests
  • This project should NOT have an Umbraco dependency.

Have I missed anything or you see anything you don't like?
Share it on Twitter!

Have a great Christmas everyone, and take care of each other.

Cheers friends. ❤️