
Figure 5-4. Simple deployment of Azure Web App
As application needs grow, more complex and robust deployment solutions may be required. Figure 5-5 shows an example of a more complex deployment plan that supports additional capabilities.

Figure 5-5. Deploying a web app to an Azure App Service
Internally, this project’s organization into multiple projects based on responsibility improves the maintainability of the application.
This unit can be scaled up or out to take advantage of cloud-based on-demand scalability. Scaling up means adding additional CPU, memory, disk space, or other resources to the server(s) hosting your app. Scaling out means adding additional instances of such servers, whether these are physical servers or virtual machines or containers. When your app is hosted across multiple instances, a load balancer is used to assign requests to individual app instances.
The simplest approach to scaling a web application in Azure is to configure scaling manually in the application’s App Service Plan. Figure 5-6 shows the appropriate Azure dashboard screen to configure how many instances are serving an app.

Figure 5-6. App Service Plan scaling in Azure.
Applications that follow the Dependency Inversion Principle as well as the Domain-Driven Design (DDD) principles tend to arrive at a similar architecture. This architecture has gone by many names over the years. One of the first names was Hexagonal Architecture, followed by Ports-and-Adapters. More recently, it’s been cited as the Onion Architecture or Clean Architecture. The most recent name, Clean Architecture, is used to describe this architecture in this e-book.
Note: The term Clean Architecture can be applied to applications that are built using DDD Principles as well as to those that are not built using DDD. In the case of the former, this combination may be referred to as “Clean DDD Architecture”.
Clean architecture puts the business logic and application model at the center of the application. Instead of having business logic depend on data access or other infrastructure concerns, this dependency is inverted: infrastructure and implementation details depend on the Application Core. This is achieved by defining abstractions, or interfaces, in the Application Core, which are then implemented by types defined in the Infrastructure layer. A common way of visualizing this architecture is to use a series of concentric circles, similar to an onion. Figure 5-7 shows an example of this style of architectural representation.

Figure 5-7. Clean Architecture; onion view
In this diagram, dependencies flow toward the innermost circle. The Application Core takes its name from its position at the core of this diagram. It has no dependencies on other application layers. The application’s entities and interfaces are at the very center. Just outside, but still in the Application Core, are domain services, which typically implement interfaces defined in the inner circle. Outside of the Application Core, both the UI and the Infrastructure layers depend on the Application Core, but not on one another (necessarily).
Figure 5-8 shows a more traditional horizontal layer diagram that better reflects the dependency between the UI and other layers.

Figure 5-8. Clean Architecture; horizontal layer view
Note that the solid arrows represent compile-time dependencies, while the dashed arrow represents a runtime-only dependency. With the clean architecture, the UI layer works with interfaces defined in the Application Core at compile time, and ideally shouldn’t know about the implementation types defined in the Infrastructure layer. At run time, however, these implementation types are required for the app to execute, so they need to be present and wired up to the Application Core interfaces via dependency injection.
Figure 5-9 shows a more detailed view of an ASP.NET Core application’s architecture when built following these recommendations.

Figure 5-9. ASP.NET Core architecture diagram following Clean Architecture.
Because the Application Core doesn’t depend on Infrastructure, it’s very easy to write automated unit tests for this layer. Figures 5-10 and 5-11 show how tests fit into this architecture.

Figure 5-10. Unit testing Application Core in isolation.

Figure 5-11. Integration testing Infrastructure implementations with external dependencies.
Since the UI layer doesn’t have any direct dependency on types defined in the Infrastructure project, it’s likewise very easy to swap out implementations, either to facilitate testing or in response to changing application requirements. ASP.NET Core’s built-in use of and support for dependency injection makes this architecture the most appropriate way to structure non-trivial monolithic applications.