Site Extensions add functionality to your Azure App Service and they can be added to various other resources like Azure Function app. You can easily browse and add these site extensions from the portal by going to “Extensions” tab from your “App Service”. However, when you are automating everything with Azure DevOps, you will want to do everything via as part of resource provisioning. Using ARM templates this can be automated easily. In this small blog post we will see how to install ASP.NET Core Extensions
for you Azure App Services. The ASP.NET Core extension provides additional functionality for ASP.NET Core on Azure Websites such as enabling Azure logging.
Read more on Azure Site Extensions
ARM template
My ARM resource for deploying Azure App Services is as below. As you can see it has following things enabled already for App Service.
- It has Managed Identity enabled via
"type": "SystemAssigned"
- I am adding AppInsights instrumentation key app settings as part of provisioning .
{
"name": "[variables('myWebAppName')]",
"apiVersion": "2016-08-01",
"type": "Microsoft.Web/sites",
"location": "[resourceGroup().location]",
"identity": {
"type": "SystemAssigned"
},
"tags": "[parameters('environmentConfiguration').tags.value]",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms/', variables('webAppServicePlanName'))]"
],
"properties": {
"name": "[variables('myWebAppName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('webAppServicePlanName'))]"
},
"resources": [
{
"name": "appsettings",
"location": "[resourceGroup().location]",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[concat('Microsoft.Web/sites/', variables('myWebAppName'))]"
],
"tags": {
"displayName": "WebAppSettings"
},
"properties": {
"ApplicationInsights__InstrumentationKey": "[reference(concat('Microsoft.Insights/components/', variables('myWebAppName'))).InstrumentationKey]"
}
}
]
}
Add the ASP.NET Core site extension
To add site extension, we have to add additional resource as below under the app service’s resource array.
{
"apiVersion": "2015-04-01",
"name": "Microsoft.AspNetCore.AzureAppServices.SiteExtension",
"type": "siteextensions",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', variables('deployedWebAppName'))]"
],
"properties": {}
},
Note the site extensions name Microsoft.AspNetCore.AzureAppServices.SiteExtension
. This is the name to be used for ASP.NET Core Extensions
extension.
How to find name of the siteextension to install?
You might be wondering how I got to know the name of the extension to insert it into the ARM template. I first installed the extension manually using the portal and then browsed the resource using Azure Resource Explorer at https://resources.azure.com/.
You can see installed site extensions for the app service under resourceGroups\<your-resource-group>\providers\Microsoft.Web\sites\<your-website>\siteextensions
node.
Azure Resource Explorer a great way to understand the ARM structure of the Azure resources.
My updated ARM template looks as below now.
{
"name": "[variables('myWebAppName')]",
"apiVersion": "2016-08-01",
"type": "Microsoft.Web/sites",
"location": "[resourceGroup().location]",
"identity": {
"type": "SystemAssigned"
},
"tags": "[parameters('environmentConfiguration').tags.value]",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms/', variables('webAppServicePlanName'))]"
],
"properties": {
"name": "[variables('myWebAppName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('webAppServicePlanName'))]"
},
"resources": [
{
"apiVersion": "2015-04-01",
"name": "Microsoft.AspNetCore.AzureAppServices.SiteExtension",
"type": "siteextensions",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', variables('myWebAppName'))]"
],
"properties": {}
},
{
"name": "appsettings",
"location": "[resourceGroup().location]",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[concat('Microsoft.Web/sites/', variables('myWebAppName'))]"
],
"tags": {
"displayName": "WebAppSettings"
},
"properties": {
"ApplicationInsights__InstrumentationKey": "[reference(concat('Microsoft.Insights/components/', variables('myWebAppName'))).InstrumentationKey]"
}
}
]
}
Okay, I added that - But my deployment randomly fails now!
As you can see in the screenshot above, the error did not give much detail except The resource operation completed with terminal provisioning state 'Canceled'
. This error usually occurs when any of the deployment thread is cancelled.
It took a while to figure out that since I was also updating app settings for the app service, ARM triggered two threads - one for installing site extensions and another one for updating the app settings. Probably app settings update resulted in app service restart during siteextensions installation. This in turn cancelled the siteextension installation.
So I decided to add additional dependency to my ARM template to make the App Setting update only after site extension installation. So I modified my ARM template as below.
{
"name": "appsettings",
"location": "[resourceGroup().location]",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[concat('Microsoft.Web/sites/', variables('myWebAppName'))]",
"[resourceId('Microsoft.Web/Sites', variables('myWebAppName'))]",
"Microsoft.AspNetCore.AzureAppServices.SiteExtension"
],
"tags": {
"displayName": "WebAppSettings"
},
"properties": {
"ApplicationInsights__InstrumentationKey": "[reference(concat('Microsoft.Insights/components/', variables('myWebAppName'))).InstrumentationKey]"
}
}
As you can see under dependsOn
array I added an additional dependency for installation of the site extension. After I did that, I triggered my deployment again and resulted in successful deployment - Because with added dependency ARM ensures that the App Settings are updated only after siteextension installation thread is complete.
Thanks for reading!