In this post I am going to talk about Onion Architecture. There are several traditional architectures that exists in web world and each one of the architecture comes with its pros and cons. But most of the traditional architectures raises fundamental issues like tight coupling and separation of concerns. I am going to talk about issues faced with traditional designs and then we will see how Onion Architecture addresses these common issues.
The traditional and most commonly used web application architecture is Model-View-Controller architecture which is one of the most widely adapted and appreciated architecture throughout the industry. If you have been using Asp.net web forms to develop web application then adopting MVC architecture even fits better, because it provides the required framework to build web apps MVC way. But things doesn’t turn out as planned and leads to very tight coupling between UI and business logic and business logic to database logic. This is because you end up writing all of your logic in server side code (mainly aspx.cs files). This scenario produces very tight coupling over the period of time and system becomes a nightmare to maintain.
Another approach to look at the problems described above is to look at the Traditional Architecture diagram below. As you see, the UI is talking to business logic and business logic is talking to data layer and all the layers are mixed up and depend heavily on each other. None of the layer stand independent, which raises separation of concerns.
In other words, if your application has several lines of code in button_submit or page_load events and if it’s doing several things in one single method, then it’s a matter of concern. Because sooner or later system will change and new developers will keep adding new business logic to these existing events, and the eventual situation would be very chaotic. Such systems are always very hard to understand and maintain.
Further, the biggest drawback of this architecture is unnecessary coupling that it creates. Each layer is coupled to the layers below it, which creates a very tight coupling between these layers, and a tightly coupled system enforces several restrictions and challenges when undergoing changes.
The biggest offender is the coupling of UI and business logic to data access. Typically, The data access changes every few years, historically, the industry has modified the data access techniques at least every three years, so naturally, and it is expected to have some flexibility with data access layer when the system undergoes changes. However, the flexibility with technology upgrades doesn’t come handy with tightly coupled systems. There are always challenges involved changing something which has lot of impact in business critical systems and that’s where these systems fall behind the technology upgrade race and eventually becomes stale and very hard to maintain.
This is where the Onion Architecture comes in. The term “Onion Architecture” was first coined by Jeffry Palermo back in 2008 in a series of blog posts. The architecture is intended to address the challenges faced with traditional architectures and the common problems like coupling and separation of concerns.
Shown above is the proposed Onion Architecture, which has layers defined from core to Infrastructure. The main premise is that it controls coupling. The fundamental rule is that all code can depend on layers more central, but code cannot depend on layers further out from the core. In other words, all coupling is toward the center. This architecture is undoubtedly biased toward object-oriented programming, and it puts objects before all others. At the very center is the domain model, which represents the business and behavior objects. Around the domain layer are other layers with more behavior. The number of layers in application will vary but domain is always at the center. The first layer around the domain is typically we would place interfaces that provides saving and retrieving behaviors, called repository interfaces. Only the interface is in the application core. Out on the edges we see UI, Infrastructure and Tests. The outer layer is reserved for things that potentially changes often, these things are intentionally isolated from the application core. Out on the edges in Infrastructure, we would find classes that implements a repository interface and these classes are coupled to particular way of Data Access, and that’s is why it resides outside the application core.
Let’s see what each of these layers represents and what should each contain.
Domain Layer – At the very core is the Domain layer which holds all of your domain objects. The idea is to have all of your domain objects at this core. Please restrict yourself by keeping just the properties or definitions inside your domain objects and not any piece of code which talks to database or has any other business functions. Besides the domain objects, you could also have domain interfaces, but just the interfaces and not any kind of implementation.
See the screenshot from the sample project that I have created using Onion Architecture, under the solution folder 01-Domain, I have got 2 projects Domain.Entities to hold domain objects and Domain.Interfaces to hold domain interfaces. The most interesting thing to notice that there are no special references in this project, and the domain objects are flat objects as they should be, without any heavy code or dependencies.
Service Interface Layer – common operations like Add, Save, Delete should go in here within interfaces. You can define your transactional interfaces like (IOrderService.SubmitOrder) here. One of the most important thing to notice here that service interfaces are kept separate from its implementation, which shows the loose coupling and separation of concerns.
Application Services Layer – the implementation of Interfaces defined in Service Interface layers comes here. The service implementation gets data from repositories and processes requests coming in from UI layer. This layer acts as a middleware to provide data from Infrastructure to UI.
Look at the references and you will realize that this layer is using domain entities, domain interfaces and service interfaces only, it has no knowledge of where the data comes and where it gets stored, the service is solely dependent on interfaces and at runtime the actual implementation objects gets assigned. Interesting? Well, look at following class to see yourself –
The service has dependency on the repository type (interface) which is injected at run time using Castle Windsor and all the methods works on the repository type to perform specific actions.
Infrastructure Layer – this is the outermost layer of onion architecture which deals with Infrastructure needs and provides the implementation of your repositories interfaces. In other words, this is where we hook up the Data access logic or logging logic or service calls logic. Only the infrastructure layer knows about the database and data access technology (Entity framework or Ado.net) and other layers don’t know anything about from where the data comes and how it is being stored.
Check out the code map feature of visual studio, which shows an excellent overview of sample solution with arrows pointing in dependency direction –
As you see from the diagram it is evident that not a single arrow is pointing upwards in the dependency graph. All the directions are downwards, towards domain or interfaces. Isn’t it cool?
The basic principle of Onion Architecture is to follow the boundaries of these layers – the inner layer can’t depend on its outer layer but can depend on layers beneath. For example, domain layer can’t depend on Infrastructure layer, but Infrastructure layer can depend on Domain layer. Imagine if you put the saveObjectToDatabase method in domain object, then you will depend on Infrastructure layer which is a violation of Onion Architecture. The strategy is to make interfaces defined in the domain layer and put the implementation in Infrastructure layer. Following this principle makes sure we have loose coupling between layers and a real implementation comes only at real time.
Additionally, the Onion Architecture relies heavily on the Dependency Inversion principle to provide the interface implementations at runtime. I have hooked up Castle Windsor in the sample project to achieve dependency inversion at run time. For those who are new to Castle Windsor, it is one of the best IoC container in market today. There are several others (like Ninject, StructreMap, and Unity ) also which are in market but Castle Windsor is personally my favorite.
Before closing my article – I’d like to leave you guys with one though – which is “loose coupling”. See the beauty of loose coupling achieved using this architecture. The advantages are not just limited to loose coupling but other features like Separation of concern and domain model approach makes it an awesome architecture to follow.
Take a look at the sample project available for free download at https://github.com/chetanvihite/OnionArchitecture.Sample to see Onion Architecture in action. If you have any questions please feel free to send me an email at email@example.com.