Azure Architecture Close Up: Modern .NET Web App for Azure
Modern .NET apps running in Azure can reliably operate using a design pattern known as the Modern Web Pattern for the cloud. The Modern Web Pattern relies on the usage of a message queue, a container platform, a decoupled data store, and a container registry. The focus is to truly exercise the notion of decoupling services that serve the application as a whole so that upgrades and fault handling are managed separately and independently. It moves away from the notion of monolithic principles where the application itself has singular ties to every service that it would need to use or singular chain of command whereby a failure in any part of the call chain, results in the whole or critical part of the application not working.
The typical reference architecture for such a design would look like the following:

Modern Web App for Azure
As we can see there is clear emphasis on separating of concerns in the classic software sense of loose coupling and high cohesion of systems. A classic database is not entirely relied upon to be available because there is a decoupled service data store for example allowing us to quickly repoint to that data store (say a Service Bus that can retain small amount of data for a limited) while we recover from a failure or downtime of our typically used SQL database. This practice that we call Load Levelling works to our advantage too at times when the database perhaps experiences high loads and demand from our application and is unable to respond in a timely manner.
Application version management is done through static and repeatable container images that live in a Container registry. This makes sure that at least for the application features and functionality, we can be certain of what is going to be usable once we pull and run a specific tag from our Azure Container Registry or Docker Container Registry.
For logging who our users are, Microsoft Entra ID is an easy choice that comes to mind,. They can login with social accounts for example to make simple login to our app. Notice that additional Azure Services that we add to the application are connected through Private Endpoints in a vNET subnet so that they are never directly visible to the public domain to begin with. We secure services at the network layer not at the individual application layer where it is likely that unauthorised users may knowingly or unknowingly gain access. Resources are restricted to only those who should know. Services that need to know and trust each other can do so through the use of Managed Identities.
Message brokers such as Service buses allow further decoupling between services that need each other but should not depend on each other. Messages that carry full data payloads can be sent between components. Note that we can additionally implement Event brokers, which unlike Message brokers, behave more as notifications that announce that 'something happened or updated at this location/resource/URI at this time' to services that may need to know that information. It is up to the service that is consuming that event to carry out the fetching and utilisation of the resource that has been said to have been changed or updated recently. This is useful to understand because sometimes we might be unable to carry or transmit the data itself in case it is quite large such as a large blob so we never have to carry the actual data over. We minimise latency this way and separate out data egress and CRUD duties only to components and services that absolutely need to. The app logic processor is no longer responsible for also doing CRUD activities.
For .NET we can take full advantage of feature flags and Deployment Slots available in Azure App Service (our primary deployment target platform for a modern web app), so that the app remains flexible and easy to modify to our needs.
Finally, we may also perhaps wish to utilise a cache service like Azure Cache for Redis should we opt for an overall web app that has high data availability. A Redis cache will serve 2 primary goals. The first would be that should our main data storage facility (a SQL Database or PostgresSQL Database) were to become unavailable momentarily, it can serve as an additional small data storage much like our Service Bus can do, with the difference being that for a Redis Cache, the data does not get dequeued by default and consumed once. The other goal is to lessen the load on the database for frequently used data items in our application. These could be any fixed set or list of items that our users need to see or a ranked set of items such as a Top 10 list of items that our users regularly use and is unlikely to change based on time or season for our app.
Conclusions
This set of observations is not exhaustive for the Modern Web App pattern. There are other considerations we can have that would be for high availability such as planning for multiple regions. The main difference illustrated below would be that a secondary region would have to have its own vNET peer into the primary region do that backups and synchronisation occurs while both regions are healthy. We take advantage of the Microsoft backbone for speed and efficiency between the 2 regions by doing this so that when the primary region does fail, the secondary is ready , up to date and available to carry on serving users.
