How to enable HTTP/2 on an Azure App Service web app

Azure app service uses HTTP/1.1 by default. HTTP/2 brings a number of performance benefits and thankfully switching your app over is easy.

First, open up developer tools and hit your app to see your HTTP/1.1 baseline…


then in the Azure portal navigate to your App Service instance and visit the Configuration page. The HTTP version setting is available on the General settings tab as shown below…

Don’t forget to click Save after making the change. The protocol might not changeover immediately but after a couple of minutes you should see h2 in the Network tab in Chrome/Edge developer tools…

Note… to use HTTP/2 you need to use SSL. Azure has a wildcard certificate bound to *, but if you’re using a custom domain you’ll need to get a cert.

What are Proximity Placement Groups and how to create them in the Azure Portal

From an architectural point of view, it’s recommended to place any VMs which need to communicate with each other in the same region and availability zone to lower latency. Note that lower latency is a side effect not a design goal of using AZs.

One further level of latency optimisation possible in Azure is called Proximity Placement Groups.

What are Proximity Placement Groups?

While Availability zones allow resources to be placed in the same group of physical data centers, this still could mean they’re in different data centres perhaps many kilometers apart…

Availability Zones with PPGsProximity Placement Groups assure that resources are placed in the same data centre

Availability Zones with PPGs

By using PPGs absolute physical distance which is one of the main factors impacting network latency between VMs can be reduced.

PPGs can benefit all multi-tiered apps but are ideal in very latency sensitive applications such as those used in banking, trading etc. When combined with accelerated networking sub-millisecond latency times between VMs can be achieved.

The data centre associated with a PPG is allocated when the first VM is added to the group. All subsequent VMs added to the PPG will get added to the same data centre as the first VM. A subsequent request for a different virtual machine SKU may fail since it’s not available in the data centre already selected. For this reason Microsoft recommends adding the most exotic SKU to your PPG first.

Creating Proximity Placement Groups in Azure Portal

Adding PPGs in the Azure portal is easy. Search for ‘proximity placement groups’, visit the default listing page and click new.

All that’s needed is resource group, region and name. Obviously your region must be the same as where your virtual machines are located.

You can create PPGs via ARM templates, the CLI and PowerShell too.

Note that you need to create the PPG first using one of the above approaches before you can place a new or existing VM into it, there is no ability to create a new PPG inline (as you might with resource groups).

When creating a new VM, the PPG section is found near the end of the page on the Advanced tab.

When editing an existing VM the PPG section is found in Settings -> Configuration. Note the virtual machine needs to be stopped/deallocated to amend its PPG config.


Create Windows VM with accelerated networking – Azure PowerShell | Microsoft Docs

0.09 ms latency using Azure Proximity Placement Groups (

How to use Azure Cache for Redis in a .NET Core web app

If you need a distributed cache and are planning on deploying your .NET Core web app to Azure, using Azure Cache for Redis as your cache provider is a good choice.

The steps below show you how to get started…

Create an Azure Cache for Redis instance using the portal

Search for ‘azure cache for redis’ on the portal and on the create screen fill in details such as resource group, DNS name, location and cache type.

Choose the same location as whatever app will be consuming your cache to minimise latency. When you’re just getting setup I’d recommend choosing the Basic C0 cache as this is the cheapest and you can always upgrade later. For all the other tabs just accept the defaults for the moment.

Create a new Redis cache in the portal

After Azure has finished creating your new cache, navigate into it and go to the Access keys page as shown below.

Copy the primary connection string somewhere as you’ll need to put this into your appsettings.json file in the next step.

Viewing Azure Redis access keys

Setup and configure your app

Install Microsoft.Extensions.Caching.StackExchangeRedis from NuGet.

Amend Startup.cs…

Amend startup.cs to use caching

Add a connection string pointing to your Redis instance on Azure into your appsettings.json file. Remember you can get this from the Access keys page as shown above. In our real apps we’d likely store this value in Azure Key Vault.


Create a cache wrapper or helper class

At this stage your app should be able to set and read items in Azure Redis by instantiating a concrete instance of the IDistributedCache instance. The next step is to create a simple thin wrapper around this interface. It’s not 100% needed but it helps keep code that is using the cache a little bit neater.

Since .NET Core 3.0 Microsofts default JSON deserializer has been System.Text.Json, however it doesn’t support circular references so in the below example I’ve fallen back to using Newtonsoft.

Note… according to Microsoft System.Text.Json will support circular references from .NET 6.0.

Cache wrapper

Inject IDistributedCache into your controller or service class

Since dependency injection is built into .NET Core and because we’ve registered the Redis Cache service in our Startup.cs file we can inject an instance of the IDistributedCache into our controller class…

Inject IDistributedCache

Check the cache when retrieving data

Finally to use the cache when getting data… we can implement the cache-aside pattern. In this pattern we…

First check the cache for a particular key.
If it does not exist we read data from the DB and store it in the cache.
If it does exist in cache we use the cached version of the data.

Below I’m checking the cache for a list of products…

Example of cache-aside pattern

In this case I’ve not set any DistributedCacheEntryOptions meaning items will not expire. If you need to set absolute or sliding expirations on items you can set the relevant options when adding them to the cache.

Remove items from cache after they’ve been updated

When some data change occurs which means previously cached items are now stale we can remove items from the cache as below…

Invalidate items in cache by removing them

In this case the list of products I previously cached is no longer valid as I’ve deleted one of them.

Depending on the situation we might not have to explicitly remove certain items from the cache like above. In many cases some staleness is acceptable so in this case we might set a sliding expiration of 1 hour or depending on the data just re-cache certain items overnight.

How to test your app is storing items in and reading from Azure Cache for Redis

To confirm everything is working as expected we can run the monitor command in the Redis console direct on the Azure portal.

How to monitor Azure Redis cache activity in real time from the Azure portal

Being able to see what items Redis is saving to and serving from its cache in real-time is very useful from a debugging point of view. Thankfully this is easy to do from the Azure portal.

First go to your Redis instance and click on Console as shown below…

Go to Redis Console

… and then run the monitor command. The below example shows that Redis cache has served two requests for the cache item “products” since we started monitoring.

Monitor Redis from Azure portal

An exception has been raised that is likely due to a transient failure when accessing an Azure SQL Database with Auto-pause on from Entity Framework Core

When you create an Azure SQL Database with the Serverless (pay per second of usage) pricing model there’s an auto-pause option which will pause the DB after a period of inactivity. This option is intended to save you money. One problem with enabling it is connection failures when activity re-starts again as the DB has to go through a cold start.

When you’re connecting to a paused DB from Entity Framework Core you’ll often see an error like below…

An exception has been raised that is likely due to a transient failure. Consider enabling transient error resiliency by adding ‘EnableRetryOnFailure()’ to the ‘UseSqlServer’ call.

As suggested by the error we can handle this by including EnableRetryOnFailure in our DbContext configuration as shown below…

EnableRetryOnFailure setting for Entity Framework

When the above options are set and the DB is in a paused state the first request of the app will take longer than normal but the user won’t see an error as the DB will be accessible after one or two connect retries.

Testing EnableRetryOnFailure when Azure SQL DB is paused

Unfortunately at the moment there doesn’t seem to be a way to simulate the paused state for Azure SQL Databases so you’ll need to wait an hour (min auto-pause time) to test. You can confirm the DB is in a paused state from the portal…

Azure SQL DB state

… and after hitting your app if you’re logging debug and info messages you should see some failed connection attempts (first yellow box below) and finally a successful connection and query execution (second yellow box below) in your logs.

The sample log output below (click for a larger view in a new window) is taken from the App Service Log stream page which allows you to view your application logs in real-time direct from the portal.

Viewing app service logs