Using Deployment and Runtime values in Logic Apps

When using Workflow Definition Language functions in Logic Apps, you might need a combination of deployment and runtime values. This raises the questions whether to use square brackets or ampersand. Can be confusing, especially when you need both deployment and runtime values. Here’s the deal:

  • When you use functions with square brackets, you can access parameters and variables supplied at deployment time.
  • When you use functions with an ampersand, you can access runtime values such as the output of an action.
  • When you need both deployment and runtime values, you must use functions with an ampersand and store parameters and/or variables in run-time variables created in Logic Apps.
"Set_BaseAddress": {
	"inputs": {
		"name": "baseAddress",
		"value": "[parameters('BaseAddress')]"
	},
	"runAfter": {
		"Get_Medewerker": [
			"Succeeded"
		]
	},
	"type": "SetVariable"
}, 

"Update_Medewerker": {
"inputs": {
	"body": {
		...
	},
	"headers": {
		...	
	},
	"method": "PUT",
	"uri": "@concat(variables('baseAddress'), 'persons/id/', body('Get_Medewerker_from_TopDesk')[0]['id'])"
},
"type": "Http"
}

What doesn’t work are the examples below:

"uri": "@concat(parameters('baseAddress'), 'persons/id/', body('Get_Medewerker_from_TopDesk')[0]['id'])"
or
"uri": "[concat(parameters('baseAddress'), 'persons/id/', body('Get_Medewerker_from_TopDesk')[0]['id'])]"

Note that in both examples we use a deployment value (parameter) and a runtime value (body), which is not possible.

Using Parameters and Variables in Logic Apps

Using parameters and variables in Workflow Definition Language can be tempting. I already discussed the topic in the following post. The examples are chosen quite randomly, but hopefully they will help you when parameterizing your logic apps.

Using parameters in Logic Apps (basis):

“accountName”: “@parameters(‘customerName’)”
“customerName”: “First name: @{parameters(‘firstName’)} Last name: @{parameters(‘lastName’)}”
By using curly braces, you always return a string, also when the input parameter is of type integer or boolean.

Connection Parameters (no ARM templates):

@parameters(‘$connections’)[‘azureeventgrid’][‘connectionId’]
Refers to the $connections in the parameters section within your workflow definition, not in the parameters section at the top. This is an array. [‘azureeventgrid’] is the name of your connection, used as an array index. Each connection has a property connectionId.

For example:
“parameters”: {
“$connections”: {
“value”: {
“azureeventgrid”: {
“id”: “[concat(‘/subscriptions/’,subscription().subscriptionId,’/providers/Microsoft.Web/locations/westeurope/managedApis/azureeventgrid’)]”,
“connectionId”: “[resourceId(‘Microsoft.Web/connections’, parameters(‘EventGridConnectionName’))]”,
“connectionName”: “[parameters(‘EventGridConnectionName’)]”
},

Using parameters in Logic App expressions:

@concat(‘My age is ‘, string(parameters(‘myAge’)))

Parameters(‘TopicNaam’): o/[project]/[system]/[entity]/[in/out]
Parameters(‘SubscriptionName’): logicapp-[o/t/a/p]-sub with logicapp=[system]-[entity]-[protocol]-[in/out]
[concat(‘/@{encodeURIComponent(encodeURIComponent(”’, parameters(‘TopicNaam’),”’))}/subscriptions/@{encodeURIComponent(”’, parameters(‘SubscriptionNaam’), ”’)}/messages/complete’)]

Double encodeURIComponent statements are needed when the parameter used has url characters like forward slash. I’m not sure whether the ”’ notation is actually needed. Why not use string(parameters(‘TopicNaam’) or not use curly braces for the enclosed encodeURIComponent statement. So, @encodeURIComponent instead of @{encodeURIComponent}.

Using variables without concatenation:

Set Path within an Azure Storage Table Get statement.
/Tables/@{encodeURIComponent(‘Relaties’)}/entities(PartitionKey=’@{encodeURIComponent(variables(‘Source’))}’,RowKey=’@{encodeURIComponent(variables(‘RelatieNr’))}’)

Using ResourceId:

[resourceId(parameters(‘ResourceGroup’), ‘Microsoft.EventGrid/topics’,parameters(‘Topic’))]
[resourceId(subscription().subscriptionId, resourceGroup().name, ‘Microsoft.Logic/workflows’, parameters(‘logicAppNaam’))]
[resourceId(‘Microsoft.Web/connections’, parameters(‘EGTopicConnectionNaam’))]
Function ResourceId returns the unique identifier of a resource. You use this function when the resource name is ambiguous or not provisioned within the same template. Can be used at the
scope of the subscription, resource group or resource(type).

Deriving variables from parameters:

“MessageCreatorFunction”: “[concat(‘[function_name]’, parameters(‘OTAPEnvironment’),’-afu’)]”
Derive the function name from the environment, instead of using a parameter that defines the environment specific function name.

Logic App parameters in SQL

In a previous post, I explained how you can use Logic App parameters in ARM templates. This solution is quite complicated. You will have to parameterize your Logic Apps. At deployment, the parameters are substituted by actual values. But, If you lookup the logic app in the Azure Portal, you will notice that the value is not displayed. Just a reference to a parameter. Difficult for support engineers. How do they know the value of Logic App parameters without access to the parameter.json file?

At my current client, I saw an interesting alternative solution whereby the workflow settings are stored in a SQL Server table. You can use the SQL Connector to retrieve the values.
If you like, you can use the Compose Json (convert to Json) and Parse Json (validate Json and transform to typed object) actions next, but you don’t have to.

“Get_rows_-_destination_-_9000”: {
“inputs”: {
“host”: {
“connection”: {
“name”: “@parameters(‘$connections’)[‘sql_2’][‘connectionId’]”
}
},
“method”: “get”,
“path”: “/datasets/default/tables/@{encodeURIComponent(encodeURIComponent(‘[setup].[workflow_orchestration]’))}/items”,
“queries”: {
“$filter”: “active eq true and interface eq ‘9000’ and direction eq ‘to_asb'”
}
},
“runAfter”: {
“Set_variable_-_source_guid”: [
“Succeeded”
]
},
“type”: “ApiConnection”
},
“Compose_-_destination”: {
“inputs”: {
“destination_application”: “@{body(‘Get_rows_-_destination_-_9000’)?[‘value’][0][‘application’]}”,
“destination_blob_archive_path”: “@{body(‘Get_rows_-_destination_-_9000’)?[‘value’][0][‘blob_archive_path’]}”,
“destination_blob_error_path”: “@{body(‘Get_rows_-_destination_-_9000’)?[‘value’][0][‘blob_error_path’]}”,
“destination_entity”: “@{body(‘Get_rows_-_destination_-_9000’)?[‘value’][0][‘entity’]}”,
“destination_file_path”: “”,
“destination_file_server”: “”,
“destination_folder”: “@{body(‘Get_rows_-_destination_-_9000’)?[‘value’][0][‘blob_path’]}”,
“destination_ftp_path”: “@{body(‘Get_rows_-_destination_-_9000’)?[‘value’][0][‘ftp_path’]}”
},
“runAfter”: {
“Get_rows_-_destination_-_9000”: [
“Succeeded”
]
},
“type”: “Compose”
},
“Parse_JSON”: {
“inputs”: {
“content”: “@body(‘blo-asb-afas-to-totara-conversion’)”,
“schema”: {
“properties”: {
“Files”: {
“items”: {
“type”: “string”
},
“type”: “array”
},
“RecordCount”: {
“type”: “number”
}
},
“type”: “object”
}
},
“runAfter”: {
“blo-asb-afas-to-totara-conversion”: [
“Succeeded”
]
},
“type”: “ParseJson”
}

If we look the SQL table, we see the following setup:

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [setup].[workflow_orchestration](
[id] [bigint] IDENTITY(1,1) NOT NULL,
[active] [bit] NOT NULL,
[interface] [varchar](10) NOT NULL,
[application] [varchar](250) NOT NULL,
[entity] [varchar](250) NOT NULL,
[direction] [varchar](50) NOT NULL,
[ftp_server] [varchar](250) NULL,
[ftp_path] [varchar](250) NULL,
[storage_account] [varchar](250) NULL,
[blob_container] [varchar](250) NULL,
[blob_path] [varchar](250) NOT NULL,
[blob_archive_path] [varchar](250) NOT NULL,
[blob_error_path] [varchar](250) NOT NULL,
[file_extention] [varchar](250) NULL,
[storage_queue_s10] [varchar](250) NULL,
[storage_queue_s20] [varchar](250) NULL,
[storage_queue_s40] [varchar](250) NULL,
[environment] [varchar](250) NULL,
[ftp_interval] [varchar](250) NULL,
[connection_type] [varchar](50) NULL,
[destination_server] [varchar](250) NULL,
[destination_path] [varchar](max) NULL,
[comment] [varchar](max) NULL,
[retry] [bit] NOT NULL,
[blob_retry_path] [varchar](250) NULL,
PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

Interface is equal to the interface number of the client. By setting Active to 0, we can invalidate the logic app. No settings will be found as active needs to be true (see where clause of logic apps connector).

In this case, the values from the database are put in a queue message which triggers other logic apps. These logic apps use the config values.

As an example:
“destination_path”: “@{body(‘Parse_JSON_-_destination’)?[‘destination_folder’]}”

Advantages of this solution:

  • You don’t have to parameterize your logic apps.
  • Deployment of logic apps doesn’t require a parameters file.
  • Parameter values can easily be visualized by querying SQL Server.

Parameterize logic apps

When trying to deploy a logic app via VSTS, I got an error stating: The workflow parameter ‘APIM_URL_Suffix’
is not found. I checked the LogicApp.parameters.json file and actually found the parameter in the parameter
file. So, how come it doesn’t work?

I found a very valuable post at: Kloud.com.au

From this link I learned there is a difference between ARM template parameters and logic app parameters. The parameters stored in LogicApp.parameters.json are ARM template parameters. To use those you need to work use the following syntax: [parameters(‘myparameter’)]. So, you need to use square brackets.

If you try to use ARM template parameters as a part of a workflow definition language statement, you have
to use the ARM template concat function. For example:
“template”: “[concat(‘/’, uriComponent(uriComponent(parameters(‘APIM_URL_Suffix’))), ‘/’, uriComponent
(uriComponent(parameters(‘MessageConnector’))), ‘/api/message/GetClienteleSyncDateTime’)]”

As we can see, the existing Workflow Definition Language function of encodeURIComponent() has been replaced with template function uriComponent().

[box type=”warning”] Although ARM template parameters from the parameters.json file are used, you still have to add the parameters to the parameter section in the json file. Double-click the json file to get to the parameters section (don’t open with the Logic App Designer). [/box]