Deploy Azure App Service via Azure CLI

Azure CLI (or Bash) is a cross-platform command-line interface with commands to create and manage Azure resources. It’s an easy-to-use to use, cross-platform alternative for Powershell.
Further reading: docs.microsoft.com

For me, the reason to look at Azure CLI, was an upgrade of Powershell. The deployment scripts I was using no longer worked, so I either had to rewrite my Powershell scripts or move to Bash. I chose the latter. One further note. I started working for the client in 2016. That’s the reason why we don’t use Azure DevOps and YAML pipelines. Those technologies were not mature at the time. Moreover, Azure DevOps pipelines are not exactly easy to use.

Anyhow. Here is the script to deploy an Azure App Service. Note that I manually create a deployment package (*.zip) in Visual Studio first. Also, we don’t use service principals, which would be an obvious improvement. Less relevant by the way, since we run the deployment scripts by hand and not unattended. Suboptimal indeed, I know.

#!/bin/bash

if [ “$1” == “Dev” ]; then
AppServiceName=DevService
ResourceGroup=appservices-dev
ZipFile=Service.zip
ParameterFile=@ParametersDev.json
echo “Start Deploy $AppServiceName”
fi

az login -u <username> -p <password>

# AppService Deploy
az webapp deployment source config-zip –resource-group $ResourceGroup –name $AppServiceName –src $ZipFile

# Add ApplicationSettings
az webapp config appsettings set -g $ResourceGroup -n $AppServiceName –settings $ParameterFile

We cannot run bash scripts from the command line just like that. I used Visual Studio Code, but I’m sure there are alternatives.

  • Open Visual Studio Code
  • Select Bash as the default Shell
    Menu View / Command Pallette / Terminal: Select Default Shell / Git Bash
  • If the Terminal Window is not open yet:
    View / Terminal
  • Run Command from Terminal window (wait for prompt, may take a while):
    Bash DeployDevService.sh Dev (after change directory/cd)

Deploy .Net Core WebApp to Azure

I created a .Net Core 2.2 Web App in Visual Studio and was able to access the Swagger and resource operations in IIS Express after hitting F5. Next I published the web app to Azure, but first it wouldn’t even run and then it said neither the Swagger page nor the resource methods could be found. Example:

I made two changes. First I added a web.config file and uncommented the System.webServer section (which was added by default).

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <!-- To customize the asp.net core module uncomment and edit the following section. 
  For more info see https://go.microsoft.com/fwlink/?linkid=838655 -->
  <system.webServer>
    <handlers>
      <remove name="aspNetCore" />
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="InProcess">
      <environmentVariables>
        <environmentVariable name="ASPNETCORE_HTTPS_PORT" value="44361" />
        <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
      </environmentVariables>
    </aspNetCore>
  </system.webServer>
</configuration>

Next, after receiving the message the ProductService.xml file could not be accessed, I changed the build action of the file to Embedded Resource so that the file was actually copied to the wwwroot file of the Azure Web App

Note that the ProductService.xml file must be recreated on every build. You can achieve this by setting the following Build property on a Visual Studio project:

When neither of these changes work, you can also open the project file via the Windows Explorer and check if the following property group is present. This property section should be added automatically when creating a .Net Core Web Application, but you can double check. If not present , you could add it.

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
    <UserSecretsId>See properties window of Visual Studio project</UserSecretsId>
  </PropertyGroup>

After making those changes, it also worked in Azure. Joehoe! In my case, I forgot to generate documentation file ProductService.xml. You might be wondering why the .Net Core service was still running in IIS Express. The reason for this is, that there’s also a copy of ProductService.xml created in folder bin\Debug\netcoreapp2.2.

A final sidenote has to do with the creation of the publish profile. For some reason I could not select my subscription anymore. Apparently this is a bug. The workaround is to create an empty web app via the Azure Portal. Next save the Publish Profile from the Portal. Now create a new Publish Profile. Select the file type you want to create, ie an Azure App Service. In the bottom left corner of the Publish dialog, you will see a link to import the Publish Profile saved from the Azure Portal. Now your publish profile is actually created.

Deploy Azure Functions using Powershell and FTP

Deploying an Azure Function to Azure to a large extent resembles deploying an API App. See Link:  Deploy Api App. The only problem is, we can’t create a deployment package for Azure Functions via Visual Studio. Instead, go to the Azure Portal. Open the relevant Function container and click Download App Content.

You will now get a zip file with subfolders per Azure Function. Each Azure Function folder contains a csx file with the Azure Function code and a json file for configuration settings. Also note we can define parameters at the Function Container level. An example is a queue trigger function where the address from the Logic App is taken from the settings. Below you will see the ps1 file and an example psx file.

DeployTriggerFunctions.ps1:
param (
[parameter(Mandatory = $true)][string] $paramFileName
)

Import-Module AzureRM.Resources

Write-Host “Login to Azure” –fore gray;
Login-AzureRmAccount

# $PSScriptRoot is null when you run from Powershell ISE
# Run from cmd file
$baseDir = $PSScriptRoot
$pos = $basedir.LastIndexOf(‘\’)
$baseDirParam = $baseDir.Substring(0,$pos)
$dirParam = $baseDirParam + “\AAA-DeployResources\” + $paramFileName
$dirUtils = $baseDirParam + “\AAA-DeployResources\Utils.psm1”
Write-Host “BaseDir: ” $baseDir –fore gray;
Write-Host “Dir ParameterFile: ” $dirParam –fore gray;
Write-Host “Dir UtilsFile: ” $dirUtils –fore gray;

#region Load Parameter file
. $dirParam
#endregion

#region Import Utils file
Import-Module “$dirUtils”
#endregion

Write-Host “Functions Container: ” $nameFunctionsContainer –fore gray
$result=’false’
$result = UploadToFTP -webAppName $nameFunctionsContainer -rg $resourcegroupFunctions -sourceDir $sourceDirTriggerFunctions

if ($result=’true’)
{
Write-Host $(Get-Date).ToString(“yyyyMMdd_HHmss”) ” Add Azure Function Container ” $nameFunctionsContainer ” to Azure succeeded” –fore green
}
else
{
Write-Host $(Get-Date).ToString(“yyyyMMdd_HHmss”) ” Add Azure Function Container ” $nameFunctionsContainer ” to Azure failed” –fore red
}

# Add ApplicationSettings
$appSettingsTriggerFunctions = @{“AzureWebJobsDashboard”=$azureWebJobsDashboard;”AzureWebJobsStorage”=$azureWebJobsStorage;”FUNCTIONS_EXTENSION_VERSION”=$FUNCTIONS_EXTENSION_VERSION; `
“WEBSITE_NODE_DEFAULT_VERSION”=$WEBSITE_NODE_DEFAULT_VERSION_FUNC;”ahakstorage_STORAGE”=$storageConnectionString;”ProcessAGAEventsURI”=$ProcessAGAEventsURI; `
“ProcessAGABeoordelingURI”=$ProcessAGABeoordelingURI;”ProcessAGPURI”=$ProcessAGPURI;”ProcessAGPBeoordelingURI”=$ProcessAGPBeoordelingURI;”ProcessAnnuleringenURI”=$ProcessAnnuleringenURI; `
“ProcessAnnuleringGereedURI”=$ProcessAnnuleringGereedURI;”ProcessBijstellingURI”=$ProcessBijstellingURI;”ProcessOpdrachtenURI”=$ProcessOpdrachtenURI;”ProcessOpdrachtInfoURI”=$ProcessOpdrachtInfoURI; `
“ProcessPlanningURI”=$ProcessPlanningURI;”ProcessStatusUpdateURI”=$ProcessStatusUpdateURI;”ProcessTGEventsURI”=$ProcessTGEventsURI;”ProcessWorkOrderURI”=$ProcessWorkOrderURI}
Set-AzureRmWebApp -Name $nameFunctionsContainer -AppSettings $appSettingsTriggerFunctions -ResourceGroupName $resourcegroupFunctions

run.cxs:
using System;
using System.Threading.Tasks;
using System.Net.Http;
using System.Text;

private static string logicAppUri = Environment.GetEnvironmentVariable(“ProcessAnnuleringenURI”);

public static void Run(string myQueueItem, TraceWriter log)
{
log.Info($”C# Queue trigger function processed: {myQueueItem}”);
using (var client = new HttpClient())
{
var response = client.PostAsync(logicAppUri, new StringContent(myQueueItem, Encoding.UTF8, “application/json”)).Result;
}
}

Again we upload the files using FTP. We can use the same FTP script we saw when deploying the API App. There’s one gotcha. If we deploy the Azure Function this way and we go the Integrate tab, we will note that the storage account connection name (in case of a queue trigger) is not selected. We have to select this setting manually.

Deploy API App using Powershell and FTP

//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js

(adsbygoogle = window.adsbygoogle || []).push({
google_ad_client: “ca-pub-1655089477432243”,
enable_page_level_ads: true
});

Deploying an API App to Azure to a large extent resembles deploying a Logic App. See link: Deploy Logic App. The difference is that an API App contains executable code that needs to be built. The trick here is to build a web deploy package in Visual Studio. From that web deploy package we get the files that need to be uploaded to apiappname.scm.azurewebsites.net (kudu). We upload these files using FTP. For FTP to work we need to know the FTP URL to publish to, the FTP userand the FTP password. This information is contained in the so-called Publish Profile of the API App. We can get the publish profile of the API App via Powershell.

For reusability I have created a Powershell module (*.psm) with a function named UploadToFTP. This function contains functionality to retrieve the publish profile, to create the necessary folders and upload the dll’s, configs and other content files. The code is shown below:

function UploadToFTP
{
param (
[parameter(Mandatory = $true)][string] $webAppName,
[parameter(Mandatory = $true)][string] $rg,
[parameter(Mandatory = $true)][string] $sourceDir
)

# Get publishing profile for the web app
[xml]$xml = (Get-AzureRmWebAppPublishingProfile -Name $webAppName -ResourceGroupName $rg -OutputFile null)
#Write-Host “PublishingProfile: ” $xml –fore gray;

# Extract connection information from publishing profile
$username = $xml.SelectSingleNode(“//publishProfile[@publishMethod=’FTP’]/@userName”).value
$password = $xml.SelectSingleNode(“//publishProfile[@publishMethod=’FTP’]/@userPWD”).value
$url = $xml.SelectSingleNode(“//publishProfile[@publishMethod=’FTP’]/@publishUrl”).value
Write-Host “FTP Url: ” $url –fore gray;

# Upload files recursively
Write-Host “Source Directory: ” $sourceDir –fore gray;
Set-Location $sourceDir
$webclient = New-Object -TypeName System.Net.WebClient
$webclient.Credentials = New-Object System.Net.NetworkCredential($username,$password)

# Get folders and files
$SrcEntries = Get-ChildItem $sourceDir -Recurse
$Srcfolders = $SrcEntries | Where-Object{$_.PSIsContainer}
$SrcFiles = $SrcEntries | Where-Object{!$_.PSIsContainer}

# Create subdirectories
foreach($folder in $Srcfolders)
{

$SrcFolderPath = $sourceDir -replace “\\”,”\\” -replace “\:”,”\:”
$DesFolder = $folder.Fullname -replace $SrcFolderPath,($url+’\’)
Write-Host “FTP folder fullname: ” $folder.Fullname –fore gray;
$DesFolder = $DesFolder -replace “\\”, “/”
Write-Host “FTP folder: ” $DesFolder –fore gray;

try
{
$makeDirectory = [System.Net.WebRequest]::Create($DesFolder);
$makeDirectory.Credentials = New-Object System.Net.NetworkCredential($username,$password);
$makeDirectory.Method = [System.Net.WebRequestMethods+FTP]::MakeDirectory;
$makeDirectory.GetResponse();
Write-Host “FTP folder: ” $DesFolder –fore gray;
}
catch [Net.WebException]
{
Write-Host “FTP folder not created. Possibly it already existed: ” $DesFolder –fore gray;
}
}

# Upload files from deployment package
foreach($file in $SrcFiles)
{
$SrcFullname = $file.fullname
$SrcName = $file.Name
$SrcFilePath = $sourceDir -replace “\\”,”\\” -replace “\:”,”\:”
$DesFile = $SrcFullname -replace $SrcFilePath,($url+’\’)
$DesFile = $DesFile -replace “\\”, “/”
Write-Host “SrcFile: ” $SrcFullname –fore yellow;
Write-Host “DesFile: ” $DesFile –fore yellow;

$uri = New-Object System.Uri($DesFile)
$webclient.UploadFile($uri, $SrcFullname)
#Write-Host “File uploaded: ” $SrcFullname –fore yellow;
}

$webclient.Dispose()

return ‘true’

}

Another thing that is important for API Apps is to automatically set the App Settings. Below is the necessary Powershell script:

# Add ApplicationSettings
$appSettingsNav4PSGatewayClient = @{“WEBSITE_NODE_DEFAULT_VERSION”=$WEBSITE_NODE_DEFAULT_VERSION;”Nav4PSGatewayUrl”=$nav4PSGatewayUrl;”Nav4PSUser”=$nav4PSGatewayUser;”Nav4PSPassword”=$nav4PSGatewayPassword}
Set-AzureRmWebApp -Name $nameNav4PSGatewayClient -AppSettings $appSettingsNav4PSGatewayClient -ResourceGroupName $resourcegroup
Write-Host $(Get-Date).ToString(“yyyyMMdd_HHmss”) ” App settings ” $nameNav4PSGatewayClient” updated” –fore green

Beware. You have to use unique names for Appsetting variables. In my case I had two apps: a DSPGateway (for incoming traffic) and a DSPConnector (for outgoing traffic). Both apps needed a username/password for authentication. I named these variabeles DSPUserName and DSPPassword for both apps. That’s wrong. You have to use unique names. So, for example: DSPGatewayUser, DSPConnectorUser, DSPGatewayPassword and DSPConnectorPassword.

Logic App error using workflow parameters

I received the following error when deploying a Logic App via Powershell/ARM:
InvalidTemplate. Unable to process template language expressions in action ‘HTTP’ inputs at line ‘1’ and column ‘1420’: ‘The workflow parameter ‘ahakStorageConnectorName’ is not found.’.

At the top of the Logic App Json file, I defined the parameters. The parameter values were contained in a separate parameters.json file. I thought it would work when using a deploy statement in Powershell referencing both the json template file and the parameter file, like this:
$logicAppTemplate = $baseDir + ‘\ProcessAGP.json’
$logicAppParameter = $baseDir + ‘\ProcessAGP.parameters.json’
New-AzureRmResourceGroupDeployment -Name ‘DeployAGPTst’ -ResourceGroupName $resourcegroup -TemplateFile $logicAppTemplate -TemplateParameterFile $logicAppParameter

As I received an error I took a different approach. If you scroll down the json template file, you’ll notice there are an additional two parameter sections.
In the first parameter section I copied the parameter definitions from the top of the json template file. In the second parameter section I copied the parameter values from the parameters.json file.
This is apparantly the way, you can make parameters available to a Logic App.

Example:
{
“$schema”: “https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#&#8221;,
“contentVersion”: “1.0.0.0”,

“parameters”: {
“ahakStorageConnectorName”: {
“type”: “string”,
“metadata”: {
“description”: “Name of the AHakStorageConnector”
}
},
“dspConnectorName”: {
“type”: “string”,
“metadata”: {
“description”: “Name of the DSPConnector”
}
},
“logicAppUploadToSharepoint”: {
“type”: “string”,
“metadata”: {
“description”: “LogicApp UploadToSharepoint”
}
},
“rg”: {
“type”: “string”,
“metadata”: {
“description”: “Resourcegroup”
}
},
“rgFunctions”: {
“type”: “string”,
“metadata”: {
“description”: “Resourcegroup Functions”
}
},
“functionContainer”: {
“type”: “string”,
“metadata”: {
“description”: “Function Container”
}
}
},
“triggers”: {
“manual”: {
“type”: “Request”,
“kind”: “Http”,
“inputs”: {
“schema”: {
“$schema”: “http://json-schema.org/draft-04/schema#&#8221;,
“properties”: {
“Event”: {
“type”: “string”
},
“Id”: {
“type”: “string”
}
},
“required”: [
“Event”,
“Id”
],
“type”: “object”
}
}
}
},
“contentVersion”: “1.0.0.0”,
“outputs”: {}
},
“parameters”: {
“ahakStorageConnectorName”: {
“value”: “tstahakstorageconnector”
},
“dspConnectorName”: {
“value”: “tstdspconnector”
},
“logicAppUploadToSharepoint”: {
“value”: “TstUploadToSharePoint”
},
“rg”: {
“value”: “ahak-appservices-tst”
},
“rgFunctions”: {
“value”: “ahak-appfunctions-tst”
},
“functionContainer”: {
“value”: “ahak-functions-tst”
}
}
}
}
],
“outputs”: {}
}

Deploy Logic App using Powershell and ARM

To deploy a logic app via Powershell, I used the following approach;
Create a directory structure with two folders, i.e.:
C:\Sources\PBaars\Deployment\Release1.5\AAA-DeployResources
C:\Sources\PBaars\Deployment\Release1.5\ProcessPlanning

Folder AAA-DeployResources contains reusable artefacts like a parameter file and a Powershell module with reusable code. In this case the reusable code uploads files for a Web App or API App to a FTP folder. I will come back to that later.The parameters file is named ParametersTst.ps1. That’s because I want to deploy a Logic App to a test environment. The parameters file can also be used for AppSettings. AppSettings are relevant for Web Apps and API Apps. I will come back to that later.
The folder ProcessPlanning contains artefacts related to Logic App ProcessPlanning. The artefacts are:DeployProcessPlanning.cmdDeployProcessPlanning.ps1ProcessPlanning.jsonProcessPlanningTst.parameters.json
DeployProcessPlanning.cmd has just one purpose: call DeployProcessPlanning.ps1 passing a parameter for the environment specific parameter file. Note that we can pass a different parameter file for different environments like Acc and Prod.


@Echo Off

Echo Changing PowerShell Execution policy…

powershell Get-Execution

Policypowershell Set-ExecutionPolicy Unrestricted
powershell %~dpn0.ps1 -paramFileName “ParametersTst.ps1”
pause


DeployProcessPlanning.ps1 is the Powershell script that kicks off the Logic App deployment using both ProcessPlanning.json and ProcessPlanningTst.parameters.json. As we will see later ProcessPlanningTst.parameters.json – as the name suggests – is used for parameterization of the json file. In this case we renamed the file to ProessPlanningTst.parameters.json (note the Tst prefix), because this file performs paramterization of the Test version of the Logic App.
To use DeployProcessPlanning.ps1, we first have to add a parameter for the name of the Logic App to ParametersTst.ps1 in folder AAA-DeployResources.
# ProcessPlanning
$nameProcessPlanning = ‘TstProcessPlanning’

Now we can edit the contents of DeployProcessPlanning.ps1:


param (
[parameter(Mandatory = $true)][string] $paramFileName
)

Import-Module AzureRM.Resources

Write-Host “Login to Azure” –fore gray;
Login-AzureRmAccount

# $PSScriptRoot is null when you run from Powershell ISE
# Run from cmd file
$baseDir = $PSScriptRoot
$pos = $basedir.LastIndexOf(‘\’)
$baseDirParam = $baseDir.Substring(0,$pos)
$paramFile = $baseDirParam + “\AAA-DeployResources\” + $paramFileName

#region Load Parameter file
. $paramFile
#endregion

$logicAppTemplate = $baseDir + ‘\ProcessPlanning’ + $environment + ‘.json’
$logicAppParameter = $baseDir + ‘\ProcessPlanning’ + $environment + ‘.parameters.json’

Write-Host “BaseDir: ” $baseDir –fore gray;
Write-Host “LogicAppTemplate: ” $logicAppTemplate –fore gray;
Write-Host “LogicAppParameter: ” $logicAppParameter –fore gray;
Write-Host “ParameterFile: ” $paramFile -fore gray;

# New-AzureRmResourceGroup -Name ahak-appservices-tst -Location “westeurope”
Write-Host $(Get-Date).ToString(“yyyyMMdd_HHmss”) ” Add logic app ” $nameProcessPlanning ” to Azure” –fore gray;
New-AzureRmResourceGroupDeployment -Name ‘DeployPlanningTst’ -ResourceGroupName $resourcegroup -TemplateFile $logicAppTemplate -TemplateParameterFile $logicAppParameter

# Check status of last command, i.e. deployment to Azure
if ($?)
{
Write-Host $(Get-Date).ToString(“yyyyMMdd_HHmss”) ” Add logic app ” $nameProcessPlanning ” to Azure succeeded” –fore green
}
else
{
Write-Host $(Get-Date).ToString(“yyyyMMdd_HHmss”) ” Add logic app ” $nameProcessPlanning ” to Azure failed” –fore red
}

# List Swagger
#Invoke-AzureRmResourceAction -ResourceGroupName ahak-appservices-tst -ResourceType Microsoft.Logic/workflows -ResourceName TstProcessAGPBeoordeling -Action listSwagger -ApiVersion 2016-06-01 -Force
# GET DevProcessAGPBeoordeling
Get-AzureRmResource -ResourceGroupName $resourcegroup -ResourceType Microsoft.Logic/workflows -ResourceName $nameProcessPlanning -ApiVersion 2016-06-01


There are a few things to note:

  • First you see how the parameter file can be passed to the ps1 script.
  • Next you see the LogicAppTemplate and the LogicAppParameter file is specified. Both the template file and the parameter file have a variable $environment which makes the parameter file specific per environment. If we pass parameter ParametersPrd.ps1 to theps1 file. We can add a file ParamterPrd.ps1 to folder AAA-DeployResources and files ProcessPlanningPrd.json and ProcessPlanningPrd.parameters.json to folder ProcessPlanning.
  • Next you see, I added parameter $nameProcessPlanning at multiple places.
  • Finally I renamed the deployment to DeployProcessPlanning in command New-AzureRmResourceGroupDeployment.

Now, let’s turn our attention to ProcessPlanning.json and ProcessPlanningTst.parameters.json. Both files are copied from the original ResourceGroup project containing the Logic App.In the json file we see there are some environment-specific settings:
Custom Api App: “https://devdspconnector.azurewebsites.net/api/Planning&#8221;
Custom Api App: “https://devahakstorageconnector.azurewebsites.net/api/Storage/OpdrachtGegevens/@{triggerBody()[‘Id’]}”
Reusable Workflow: “/subscriptions/1ea9735d-00df-4375-86d5-d0d35362dd7f/resourceGroups/ahak-appservices-dev/providers/Microsoft.Logic/workflows/DevUploadToSharePoint”

It’s obvious that you want one version of the Logic App.json file, but – depending on the environment – this Logic App has to call different Api Apps (Dev/Tst/Prd) and different child workflows. To make this possible we will have to definea few parameters at the top of the json file in section parameters:


“ahakStorageConnectorName”: {
“type”: “string”,
“metadata”: {        “description”: “Name of  the AHakStorageConnector”      }
},
“dspConnectorName”: {
“type”: “string”,
“metadata”: {        “description”: “Name of  the DSPConnector”      }
},
“logicAppUploadToSharepoint”: {
“type”: “string”,
“metadata”: {        “description”: “LogicApp UploadToSharepoint”      }
},
“rg”: {
“type”: “string”,
“metadata”: {        “description”: “Resourcegroup”      }
}


Note that we have to enter the definitions of the custom parameters twice. Look for the Parameter section between the sections Resources and Triggers. If we don’t enter the parameter definitions here, we will receive an error like: ‘The only declared parameters for this definition are ‘$connections’ (i.e. there are no custom parameters).

Also note that we added a variable rg to the variables section. I can’t tell why exactly this is necessary, but otherwise it won’t work.


“variables”:
{ “rg”: “[parameters(‘rg’)]”
}


The values for these parameters we have to add the environment specific parameters file, in this case: ProcessPlanningTst.parameters.json


{
“$schema”: “https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#&#8221;,
“contentVersion”: “1.0.0.0”,
“parameters”:
{
“logicAppName”: {      “value”: “TstProcessPlanning”    },
“logicAppLocation”: {      “value”: “westeurope”    },
“ahakStorageConnectorName”: { “value”: “tstahakstorageconnector”      },
“dspConnectorName”: { “value”: “tstdspconnector”      },
“rg”: { “value”: “ahak-appservices-tst”
},
“logicAppUploadToSharepoint”: { “value”: “TstUploadToSharePoint”
}  }}


The final step, is to use the parameters in the json file:
Custom Api App: “https://@{encodeURIComponent(parameters(‘dspConnectorName’))}.azurewebsites.net/api/Planning”
Custom Api App: “https://@{encodeURIComponent(parameters(‘ahakStorageConnectorName’))}.azurewebsites.net/api/Storage/OpdrachtGegevens/@{triggerBody()[‘Id’]}”
Reusable Workflow: “[concat(‘/subscriptions/1ea9735d-00df-4375-86d5-d0d35362dd7f/resourceGroups/’, variables(‘rg’), ‘/providers/Microsoft.Logic/workflows/’, parameters(‘logicAppUploadToSharepoint’))]”

We are almost done now. Go to directory ProcessPlanning, right-click DeployProcessPlanning.cmd and Run As Administrator. When things go well, the Logic App will be deployed.

Useful link Microsoft Azure site: ARM template for Logic App

Old version of Web App (2)

In an earlier post (see: Link), I discussed the problem that – right after deployment – an old version of a web app was activated where I expected the new version. This problem could be solved via app_setting DYNAMIC_CACHE. Recently I had a similar issue, despite the fact that DYNAMIC_CACHE was set to 0. I pinpointed the problem by accessing the wsdl. Here I saw there was an old version of the web app deployed.

In this case the last resort is to do a FTP deploy from Visual Studio instead of a web deploy. The steps are as follows:

Step 1: Create a deployment package via Visual Studio Publish.

Unzip the deployment package and locate the directory with the files you need to upload via FTP.

Step 2: Get the Publish Profile of the web app

The publish profile is needed in order to get the FTP host name, the FTP username and the FTP password.

Step 3: Upload via FileZilla (or another FTP client)

Enter the PublishUrl, username and password from the Publish Profile and click [Quick Connect].

In the right bottom side window you will see the contents of the wwwroot directory in Azure. Delete all folders and files. Next drag/drop the files and folders from the left bottom side window.
Your webapp is now redeployed. If you open the wsdl via Internet Explorer, you will see the latest version, which is correct.

Use Visual Studio to deploy Logic App

Some people prefer to use Visual Studio for all development purposes, also for Logic Apps. In Visual Studio 2013, Windows Azure SDK 2.6, a new project Azure Resource Group has been added. After clicking this project you can choose a template, for instance the Logic App template.

VS Project

VS Azure Templates

When you look at the project created, you will see a directory Scripts and a directory Templates. I have to check out the scripts directory, but I expect it to contain .ps1 files for deploying the resource(s). In the templates folder is a json file for your logic app.

VS Logic App Template

Note, there’s currently no visual designer for logic apps in Visual Studio. You can only build logic apps in JSON. When we zoom in to the template, you can see there are four main sections: parameters, variables, resources and outputs.

VS Logic App Template Zoom

When we open Resources we see a section labeled definition. Here is a default Logic App definition. We can change this definition to our needs, or we can throw away the definition and copy/paste the Json Logic App definition from the Azure Portal. Remember. When you design a Logic App via the Azure Portal, you can click in the Logic App Designer to go to code view. Here you find the json you need.

After changing the Logic App definition in the Json file, you can right-click the project and select Deploy. You get a page where you can set some config data. You can also add some parameters, for instance to set a specific name for the Logic App. See the screen shots below.

VS Deploy

VS Deploy Params

Now you have deployed a Logic App from Visual Studio.