<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
        <title>Mattias Lögdberg</title>
        <description>Mattias Lögdberg | </description>
        <link></link>
        <link></link>
        <lastBuildDate>2026-04-17T15:55:48+00:00</lastBuildDate>
        <pubDate>2026-04-17T15:55:48+00:00</pubDate>
        <ttl>1800</ttl>


        <item>
                <title>MSI with Service Bus</title>
                <description>&lt;p&gt;Using MSI with Service Bus is a great addition to the SaaS key that is the standard authentication mechanism.&lt;/p&gt;

&lt;p&gt;What is MSI (Managed Service Identity)? &lt;a href=&quot;/blog/2022/01/msiwhatandwhy&quot;&gt;Read more in previous post&lt;/a&gt;.
In a short summary it’s a way of giving your resources (can be a Logic App, a Function App etc.) an identity and assing permissions.&lt;/p&gt;

&lt;p&gt;In the case of using MSI with &lt;strong&gt;Service Bus&lt;/strong&gt; it can be used with our internal services accessing the &lt;strong&gt;Service Bus&lt;/strong&gt; &lt;strong&gt;queues&lt;/strong&gt;, &lt;strong&gt;topics&lt;/strong&gt; or &lt;strong&gt;topic subscriptions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The Access Roles that are available on Service Bus are the following:
&lt;img src=&quot;/assets/uploads/2022/03/servicebusroles.png&quot; alt=&quot;Azure Service Bus Roles&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Azure Service Bus Data Owner&lt;/strong&gt;: Grants access to both send and recieve&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Azure Service Bus Data Reciever&lt;/strong&gt;: Grants access to read messages from queues or topic subscriptions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Azure Service Bus Data Sender&lt;/strong&gt;: Grants access to send message on queues or topics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When assigning roles there are some things to think about:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;What are the current service suppose to be able to access? All queues or specific queues?&lt;/li&gt;
  &lt;li&gt;If you use Functions or Logic Apps as Reciever  of messages from either queue or topic subscriptions you must have assigned the &lt;strong&gt;Azure Service Bus Data Reciever&lt;/strong&gt; on the specific queue or topic subscription. It will not work to assign it on the whole namespace.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s take an example of reading messages from a queue with a Logic App.
We are creating a consumption Logic App and the first step we need to do is assignt an identity to the Logic App.
&lt;img src=&quot;/assets/uploads/2022/03/logicappassignidentity.png&quot; alt=&quot;Assign Identity to Logic Apps&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we  need to Assign Roles to the Logic Apps Identity to the Queue, remember that it has to be on the Queue in order to work with recieving messages.&lt;/p&gt;

&lt;p&gt;Go to the &lt;strong&gt;Service Bus&lt;/strong&gt; namespace and to the &lt;strong&gt;Queue&lt;/strong&gt;, in my case &lt;em&gt;Messages&lt;/em&gt; and add the role assingment &lt;strong&gt;Azure Service Bus Reciever&lt;/strong&gt; to our Logic App.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2022/03/SBAssignRole.png&quot; alt=&quot;Assign Permissions to Logic Apps&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Pick the role and then select the Managed Identity that is connected to your Logic App&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2022/03/SBassignRolepickidentity.png&quot; alt=&quot;Pick identity of Logic Apps&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we can create a trigger in the Logic Apps Designer as follows:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2022/03/designerSBTrigger.png&quot; alt=&quot;Create Trigger in Logic Apps&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you have assigned the Role on the queue you are now ready to start recieving messages.&lt;/p&gt;

&lt;h3 id=&quot;removing-the-access-saas-key&quot;&gt;Removing the access SaaS key&lt;/h3&gt;
&lt;p&gt;There is an option to remove access with the SaaS key. This is preferable if the Service Bus namespace can be used with  resources who can use Managed Idenity or Service Principal when authenticating to the Service Bus Namespace. 
If the SaaS key access is removed the whole namepsace is only accessible with a valid Aure user. This is a much securer way and moves the access control to Azure AD rather than a Service Bus specific authentication mechanism.&lt;/p&gt;

&lt;p&gt;To close the Access Key go to the namespace and press the Local Authentication: &lt;em&gt;Enabled&lt;/em&gt; link and change to &lt;em&gt;Disabled&lt;/em&gt;.
After this only access via Azure AD Roles will be working.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2022/03/localauth.png&quot; alt=&quot;Disable Local Auth&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;troubelshooting&quot;&gt;Troubelshooting&lt;/h3&gt;
&lt;p&gt;If no messages are recieved check the triggerhistory and verify that there are no errors.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2022/03/triggerhistory.png&quot; alt=&quot;Trigger History&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Using Managed Identity or Servcei Principal with Service Bus is a great feature, it’s much easier and secure. No static keys that can wander of and no unkown users. Developers accessing the namespace have to have valid Azure AD accounts that have assigned permissions.
I know it can be tricker in the start but in the long run it will help out alot.&lt;/p&gt;
</description>
                <link>/blog/2022/03/servicebusmsi</link>
                <guid>/blog/2022/03/Service Bus and MSI</guid>
                <pubDate>2022-03-29T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>MSI what and why?</title>
                <description>&lt;p&gt;MSI or &lt;em&gt;Managed Service Identity&lt;/em&gt; that it stands for has been around for some time but quite recently a new set of resources has been integrated in to this and we need to start thinking of using MSI alot more. Since this will increase security and streamline the authorization process, one place to grant access, same account and authorization process. Sadly most of Microsoft’s documentation around this is still for Virtual Machines and I want to enlighten this alot more for IPaaS services like Logic Apps, Functions, API Management, Web Apps, DataFactory Service Bus and Event Grid.&lt;/p&gt;

&lt;p&gt;So MSI is an identity of a resource just like any other user in Azure AD. The beauty of this is that with this we can assign access rights to that identity and the resource now authenticates by itself (with credentials no one else nows) and with those credentials it can use the resource.
I usually like to discribe it as a virtualization of the service and used for authorization purposes, in the image bellow we can see that an Azure Function are making requests to Cosmos. This is allowed since we have assigned the role &lt;strong&gt;Cosmos DB Built-in Data Contributor&lt;/strong&gt; to the identity of the function in a scope containing the Cosmos resource (could be on resource itself, a resource group that grants access to all cosmos resources in the resource group, or subscription granting access to all cosmos resources in that subscription).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2022/01/drawing-ad-virtualization.png&quot; alt=&quot;Result in VS Code&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What Resources can use MSI: (there are more but these are Integration focused)&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Logic Apps,&lt;/li&gt;
  &lt;li&gt;Azure Functions&lt;/li&gt;
  &lt;li&gt;API Management&lt;/li&gt;
  &lt;li&gt;Web Apps&lt;/li&gt;
  &lt;li&gt;DataFactory&lt;/li&gt;
  &lt;li&gt;Event Grid
Read the full list &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/services-support-managed-identities&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What resources can we use authenticate to with MSI.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Azure SQL&lt;/li&gt;
  &lt;li&gt;Cosmos&lt;/li&gt;
  &lt;li&gt;Service Bus&lt;/li&gt;
  &lt;li&gt;Event Hub&lt;/li&gt;
  &lt;li&gt;Azure Functions (if you use Azure AD as provider in &lt;em&gt;Authentication&lt;/em&gt;)&lt;/li&gt;
  &lt;li&gt;Web Site (if you use Azure AD as provider in &lt;em&gt;Authentication&lt;/em&gt;)&lt;/li&gt;
  &lt;li&gt;Logic Apps (If you use Oauth Authorization)
    &lt;ul&gt;
      &lt;li&gt;In Logic Apps we can use MSI to connect to resources like Event Grid for creating subscriptions.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;is-this-not-what-we-accomplished-before&quot;&gt;Is this not what we accomplished before?&lt;/h3&gt;
&lt;p&gt;No before we created a SQL account, took keys from Cosmos, Service Bus etc, create a service principal or a service user in AD to accomplish other acesses. All of these could potentially be simplified and changed to only give the resource the appropiate access rights. Note not all resources is supporting this yet, but this is an area where Microsoft has done some great gains last 6 months.&lt;/p&gt;

&lt;h3 id=&quot;but-isnt-this-making-my-development-process-a-pain&quot;&gt;But isn’t this making my development process a pain?&lt;/h3&gt;
&lt;p&gt;No on the contrary, you as a developer don’t need to gather all these credentials either, development and testing can be used with your own account. Making it easier to get started and another great benefit is that you cannot accidently keep credentials and access after an completed assignement or project. With good documentation it’s also easier to get a new teammate up to speed. Another good thing is that we know that credentials are not wandering away when members leave the team.&lt;/p&gt;

&lt;h3 id=&quot;what-should-i-think-off&quot;&gt;What should I think off&lt;/h3&gt;
&lt;p&gt;As a developer you could usually grant yourself access to diffrent resources. When using MSI this is no longer the case, since the access is now granted by Azure AD and Azure AD access is often prohibited for developers.
Authroization now need’s to be given by a user with &lt;strong&gt;Owner&lt;/strong&gt; or &lt;strong&gt;User Access Administrator&lt;/strong&gt;, to overcome this you need to create a plan for your team how this should be done.&lt;/p&gt;

&lt;p&gt;A tip here is to create a Azure AD Group and add all developers to it that need specific access, remove them when they don’t need it. An extra step would be creating a PIM group for it.&lt;/p&gt;

&lt;h3 id=&quot;read-more&quot;&gt;Read more:&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview&quot;&gt;What are managed identities for Azure resources? by Microsoft&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory/privileged-identity-management/pim-configure&quot;&gt;What is Azure AD Privileged Identity Management? by Microsoft&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/services-support-managed-identities&quot;&gt;List of resources that support Managed Identity&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</description>
                <link>/blog/2022/01/msiwhatandwhy</link>
                <guid>/blog/2022/01/MSI what and why</guid>
                <pubDate>2022-01-19T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Using MSI in APIM to Cosmos</title>
                <description>&lt;p&gt;Quite recently Microsoft finally gave us RBAC roles for data plane access to Cosmos, this means that we now can use MSI to access data in Cosmos.&lt;/p&gt;

&lt;p&gt;So what’s it all about? Well the best part is that we now can grant access to resources rather than using keys. This increases security and accessability since we don’t need to manage the key any more and only specific resources can access our data. When we have switched to RBAC as the authentication method we can switch off the possibility to access data with primary/secondary keys,&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/how-to-setup-rbac#disable-local-auth&quot;&gt;read more here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So how do we do this? &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/managed-identity-based-authentication&quot;&gt;Here is a guide from Microsoft&lt;/a&gt; on how to use MSI with an Azure Function. And we will in this post use the same technique but from API Mangement to show the potential.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;API Management instance&lt;/li&gt;
  &lt;li&gt;Identity created on your API Management instance&lt;/li&gt;
  &lt;li&gt;Cosmos DB&lt;/li&gt;
  &lt;li&gt;Azure CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First we need to grant the specific roles to our API Management identity. The role we want to assing is the &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/how-to-setup-rbac#built-in-role-definitions&quot;&gt;Cosmos DB Built-in Data Reader&lt;/a&gt;. This role has read access and that matches our &lt;em&gt;Least Previliges&lt;/em&gt; thinking, since when we only want to expose read operations we should only have read access.&lt;/p&gt;

&lt;p&gt;Adding this role is &lt;strong&gt;not&lt;/strong&gt; as straight forward as I would like it, they are not possible to set via the Azure Portal yet. So we need to do some &lt;em&gt;PowerShell&lt;/em&gt; scripting. Fortunally all scripts needed can be found at the Microsoft docs on &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/how-to-setup-rbac&quot;&gt;How to setup RBAC for Cosmos DB&lt;/a&gt;. I would recomend looking in there since they also provide how to create your own &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/how-to-setup-rbac#role-definitions&quot;&gt;custom role definitions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Anyway let’s get started and we need this script:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-PowerShell&quot;&gt;$resourceGroupName = &quot;&amp;lt;myResourceGroup&amp;gt;&quot;
$accountName = &quot;&amp;lt;myCosmosAccount&amp;gt;&quot;
$readOnlyRoleDefinitionId = &quot;&amp;lt;roleDefinitionId&amp;gt;&quot; # as fetched above
$principalId = &quot;&amp;lt;aadPrincipalId&amp;gt;&quot;
New-AzCosmosDBSqlRoleAssignment -AccountName $accountName `
    -ResourceGroupName $resourceGroupName `
    -RoleDefinitionId $readOnlyRoleDefinitionId `
    -Scope &quot;/&quot; `
    -PrincipalId $principalId
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s get the parameters, first we get the cosmos values, the resource group and the account name of the Cosmos instance (&lt;em&gt;$resourceGroupName&lt;/em&gt;,&lt;em&gt;$accountName&lt;/em&gt;) both marked in circles.
&lt;img src=&quot;/assets/uploads/2021/11/msitocosmos/get_cosmos_data.PNG&quot; alt=&quot;Get Cosmos resourcegroup and account name&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then as we saw at the &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/how-to-setup-rbac#built-in-role-definitions&quot;&gt;Built in role definitions&lt;/a&gt; the role with name &lt;strong&gt;Cosmos DB Built-in Data Reader&lt;/strong&gt; has Id &lt;strong&gt;00000000-0000-0000-0000-000000000001&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Last we need the principal id of our Api Management instance (this could be any identity created for any resource). We go to the Managed Identity in our API Management instance. There we can collect the &lt;em&gt;Object (principal) ID&lt;/em&gt;.
&lt;img src=&quot;/assets/uploads/2021/11/msitocosmos/get_apim_managed_identity_principalid.png&quot; alt=&quot;Get APIM Managed Identity Prinipal Id&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So the script ends up like this: (&lt;strong&gt;Make sure to run the latest az version&lt;/strong&gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-PowerShell&quot;&gt;$resourceGroupName = &quot;microservice&quot;
$accountName = &quot;mlogdberg&quot;
$principalId = &quot;c7b89cc3-1b27-474b-9575-cdcbc51dffcc&quot;
$readOnlyRoleDefinitionId = &quot;00000000-0000-0000-0000-000000000001&quot; # as fetched from definition list
az cosmosdb sql role assignment create --account-name $accountName --resource-group $resourceGroupName --scope &quot;/&quot; --principal-id $principalId --role-definition-id $readOnlyRoleDefinitionId
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After this we are ready to start quering, I did a simple request that collects all documents in a specific partion. This can ofcourse be expanded but this is bare minimum what is needed in the API Managemenet Policy.&lt;/p&gt;

&lt;p&gt;Some good to know things:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;authentication-managed-identity&lt;/strong&gt; is the step to get the token, make sure to have the patht to your cosmos instance.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;x-ms-documentdb-partitionkey&lt;/strong&gt; is what partion the query is targeting&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;rewrite-uri&lt;/strong&gt; this is the patht to your database and collection &lt;em&gt;/dbs/{dbname}/colls/{collectionname}/docs/&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;The url is set on the api to the path for my cosmos instance (&lt;em&gt;https://mlogdberg.documents.azure.com&lt;/em&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-XML&quot;&gt;    &amp;lt;inbound&amp;gt;
        &amp;lt;base /&amp;gt;
        &amp;lt;set-variable name=&quot;requestDateString&quot; value=&quot;@(DateTime.UtcNow.ToString(&quot;r&quot;))&quot; /&amp;gt;
        &amp;lt;authentication-managed-identity resource=&quot;https://mlogdberg.documents.azure.com&quot; output-token-variable-name=&quot;msi-access-token&quot; ignore-error=&quot;false&quot; /&amp;gt;
        &amp;lt;set-header name=&quot;Authorization&quot; exists-action=&quot;override&quot;&amp;gt;
            &amp;lt;value&amp;gt;@(&quot;type=aad&amp;amp;ver=1.0&amp;amp;sig=&quot; + context.Variables[&quot;msi-access-token&quot;])&amp;lt;/value&amp;gt;
        &amp;lt;/set-header&amp;gt;
        &amp;lt;set-header name=&quot;x-ms-date&quot; exists-action=&quot;override&quot;&amp;gt;
            &amp;lt;value&amp;gt;@(context.Variables.GetValueOrDefault&amp;lt;string&amp;gt;(&quot;requestDateString&quot;))&amp;lt;/value&amp;gt;
        &amp;lt;/set-header&amp;gt;
        &amp;lt;set-header name=&quot;x-ms-version&quot; exists-action=&quot;override&quot;&amp;gt;
            &amp;lt;value&amp;gt;2018-12-31&amp;lt;/value&amp;gt;
        &amp;lt;/set-header&amp;gt;
        &amp;lt;set-header name=&quot;x-ms-documentdb-query-enablecrosspartition&quot; exists-action=&quot;override&quot;&amp;gt;
            &amp;lt;value&amp;gt;false&amp;lt;/value&amp;gt;
        &amp;lt;/set-header&amp;gt;
        &amp;lt;set-header name=&quot;x-ms-documentdb-partitionkey&quot; exists-action=&quot;override&quot;&amp;gt;
            &amp;lt;value&amp;gt;[&quot;1&quot;]&amp;lt;/value&amp;gt;
        &amp;lt;/set-header&amp;gt;
        &amp;lt;rewrite-uri template=&quot;/dbs/staging/colls/order/docs/&quot; copy-unmatched-params=&quot;false&quot; /&amp;gt;
    &amp;lt;/inbound&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we shall be able to send a request,&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/11/msitocosmos/cosmos_result_request.png&quot; alt=&quot;Result request&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;troubelshooting-tips&quot;&gt;Troubelshooting tips:&lt;/h3&gt;
&lt;h4 id=&quot;request-blocked-by-auth&quot;&gt;Request blocked by Auth&lt;/h4&gt;
&lt;p&gt;Before the setup is completed you will get this kind of respose trying to call the cosmos rest api.&lt;/p&gt;
&lt;div class=&quot;language-R highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;HTTP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;m&quot;&gt;401&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unauthorized&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;://&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mlogdberg.documents.azure.com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dbs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;staging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;colls&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;docs&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;code&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Unauthorized&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Request blocked by Auth mlogdberg : No AAD tenant is trusted by this database account. Please create atleast one Role Assignment prior to making an AAD-based request.\r\nActivityId: 31a968bf-7652-4434-abd9-5113ea0655ae, Microsoft.Azure.Documents.Common/2.14.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;partition-key-1-is-invalid&quot;&gt;Partition key 1 is invalid&lt;/h4&gt;
&lt;p&gt;The header &lt;strong&gt;x-ms-documentdb-partitionkey&lt;/strong&gt; is important and when badly configured these kind of errors is sent back, the expected format is a json array of strings, if your partion is “1” the header should have value &lt;em&gt;[“1”]&lt;/em&gt; (like my example).
You can find your partionkey from browsing your collection.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/11/msitocosmos/cosmos_partionkey.png&quot; alt=&quot;Browsing collection to find partionkey&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-R highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;HTTP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;m&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bad&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;://&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mlogdberg.documents.azure.com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dbs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;staging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;colls&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;docs&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;code&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;BadRequest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Partition key 1 is invalid.\r\nActivityId: 6bccbf25-657b-4a71-af92-b3e998f0490a, \r\nRequestStartTime: 2021-11-21T18:24:18.9692549Z, RequestEndTime: No response recorded; Current Time: 2021-11-21T18:24:18.9792812Z,  Number of regions attempted:1\r\n{\&quot;systemHistory\&quot;:[{\&quot;dateUtc\&quot;:\&quot;2021-11-21T18:23:09.7385423Z\&quot;,\&quot;cpu\&quot;:8.902,\&quot;memory\&quot;:58190802944.000,\&quot;threadInfo\&quot;:{\&quot;isThreadStarving\&quot;:\&quot;False\&quot;,\&quot;threadWaitIntervalInMs\&quot;:0.012,\&quot;availableThreads\&quot;:32761,\&quot;minThreads\&quot;:40,\&quot;maxThreads\&quot;:32767}},{\&quot;dateUtc\&quot;:\&quot;2021-11-21T18:23:19.7586326Z\&quot;,\&quot;cpu\&quot;:7.062,\&quot;memory\&quot;:56609513472.000,\&quot;threadInfo\&quot;:{\&quot;isThreadStarving\&quot;:\&quot;False\&quot;,\&quot;threadWaitIntervalInMs\&quot;:0.0161,\&quot;availableThreads\&quot;:32764,\&quot;minThreads\&quot;:40,\&quot;maxThreads\&quot;:32767}},{\&quot;dateUtc\&quot;:\&quot;2021-11-21T18:23:29.7687307Z\&quot;,\&quot;cpu\&quot;:5.752,\&quot;memory\&quot;:56766377984.000,\&quot;threadInfo\&quot;:{\&quot;isThreadStarving\&quot;:\&quot;False\&quot;,\&quot;threadWaitIntervalInMs\&quot;:0.0173,\&quot;availableThreads\&quot;:32765,\&quot;minThreads\&quot;:40,\&quot;maxThreads\&quot;:32767}},{\&quot;dateUtc\&quot;:\&quot;2021-11-21T18:23:49.7689519Z\&quot;,\&quot;cpu\&quot;:5.634,\&quot;memory\&quot;:57133617152.000,\&quot;threadInfo\&quot;:{\&quot;isThreadStarving\&quot;:\&quot;False\&quot;,\&quot;threadWaitIntervalInMs\&quot;:0.0145,\&quot;availableThreads\&quot;:32765,\&quot;minThreads\&quot;:40,\&quot;maxThreads\&quot;:32767}},{\&quot;dateUtc\&quot;:\&quot;2021-11-21T18:23:59.7790729Z\&quot;,\&quot;cpu\&quot;:5.298,\&quot;memory\&quot;:57189658624.000,\&quot;threadInfo\&quot;:{\&quot;isThreadStarving\&quot;:\&quot;False\&quot;,\&quot;threadWaitIntervalInMs\&quot;:0.0125,\&quot;availableThreads\&quot;:32765,\&quot;minThreads\&quot;:40,\&quot;maxThreads\&quot;:32767}},{\&quot;dateUtc\&quot;:\&quot;2021-11-21T18:24:09.7891858Z\&quot;,\&quot;cpu\&quot;:8.835,\&quot;memory\&quot;:56394321920.000,\&quot;threadInfo\&quot;:{\&quot;isThreadStarving\&quot;:\&quot;False\&quot;,\&quot;threadWaitIntervalInMs\&quot;:0.0193,\&quot;availableThreads\&quot;:32764,\&quot;minThreads\&quot;:40,\&quot;maxThreads\&quot;:32767}}]}\r\n, Microsoft.Azure.Documents.Common/2.14.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;The usage of &lt;strong&gt;MSI&lt;/strong&gt; (Microsoft Service Identity) is a great feature on Cosmos, no need for storage keys. It’s a win win thing, increased simplicity and also increased security. No credentials are stored and due to that they cannot be leaked. Forcing components to use &lt;strong&gt;MSI&lt;/strong&gt; when connecting to the Cosmos could be done &lt;em&gt;disableLocalAuth&lt;/em&gt; to &lt;em&gt;true&lt;/em&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;disableLocalAuth&quot;: true&lt;/code&gt; &lt;img src=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/how-to-setup-rbac#disable-local-auth&quot; alt=&quot;read more&quot; /&gt;&lt;/p&gt;
</description>
                <link>/blog/2021/22/usingmsifromapimtocosmos</link>
                <guid>/blog/2021/22/Using MSI in APIM to Cosmos</guid>
                <pubDate>2021-11-22T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>AAD Personal Token in requests with VS Code</title>
                <description>&lt;p&gt;Two weeks ago I did a post around how I use Postman to generate AAD Oauth tokens for &lt;em&gt;Service Principals&lt;/em&gt;. Soon after released I started to get questions, &lt;strong&gt;THANKS ALOT&lt;/strong&gt; to all of you who reads and comments. One thing lead to another and an interesting discussion arised with one of you, from that dicussion I had two questions ringing in my head. First is it a good idea to give all developers &lt;em&gt;client credentials&lt;/em&gt; to access services? It takes time to create and these credentials is possible to share amongst others, even outside organisations. And second can’t we as a developer just use our own credentials and access?&lt;/p&gt;

&lt;p&gt;If we could use our own account instead of a service principal we would increae security, starting time and flexibility all at once.&lt;/p&gt;

&lt;p&gt;So I started to look around and I found a good option for this, and that is what I’m going to share today.&lt;/p&gt;

&lt;p&gt;I found that &lt;strong&gt;VS Code&lt;/strong&gt; has a nice extension that I will use in this case the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=humao.rest-client&quot;&gt;&lt;strong&gt;Rest Client&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So first install the extension in VS code.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/10/personaltoken/vscode_extension_rest_client.png&quot; alt=&quot;VsCode Rest Client Extension&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After this, let’s create a new Workspace and start testing this out. As a standard I create a folder and add the requests there, it’s easier to reuse and modify for new requests.&lt;/p&gt;

&lt;p&gt;I’ve create a folder called &lt;em&gt;D365&lt;/em&gt; and added a file &lt;em&gt;GetQuotes.http&lt;/em&gt;. the .http ending tells the Rest Client extension to VS Code it’s a http request and therefore adds a button on the top &lt;strong&gt;Send Request&lt;/strong&gt; that will trigger the request.&lt;/p&gt;

&lt;p&gt;Structure and semantics in this file is very easy, tactic is &lt;em&gt;just write the request in raw format and the press send&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let’s go thru some small exampels, simple &lt;strong&gt;GET&lt;/strong&gt; example get comment 1, write the Method URL and HTTP protocol to use, so for a &lt;em&gt;GET&lt;/em&gt; to &lt;em&gt;https://example.com/comments/1&lt;/em&gt; using standard &lt;em&gt;HTTP/1.1&lt;/em&gt; it will be written as:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GET https://example.com/comments/1 HTTP/1.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A more advanced exampel, &lt;strong&gt;POST&lt;/strong&gt; example, to create a new comment,&lt;em&gt;POST&lt;/em&gt; to &lt;em&gt;https://example.com/comments&lt;/em&gt; using standard &lt;em&gt;HTTP/1.1&lt;/em&gt; and we add the json body raw and don’t forgett the &lt;strong&gt;content-type&lt;/strong&gt; header:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;POST https://example.com/comments HTTP/1.1
content-type: application/json

{
    &quot;name&quot;: &quot;sample&quot;,
    &quot;time&quot;: &quot;Wed, 21 Oct 2015 18:27:50 GMT&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see we just write what we want to send, but enough of the basics let’s get going.&lt;/p&gt;

&lt;p&gt;When we want to use our own credentials in order to do calls to an AAD proteced resource like Dynamics D365.
We can then use the built in variable &lt;strong&gt;$aadToken&lt;/strong&gt; in the &lt;strong&gt;Rest Client&lt;/strong&gt;, read more &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=humao.rest-client#system-variables&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That is simple to use we just need to add it to our Authorization header. Let’s look at an example to get &lt;em&gt;Sales Quotation Headers&lt;/em&gt; from D365.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GET https://.cloudax.dynamics.com/data/SalesQuotationHeaders?cross-company=true&amp;amp;$top=3 HTTP/1.1
Authorization: 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When we then press the &lt;strong&gt;Send Request&lt;/strong&gt; as shown in the image:
&lt;img src=&quot;/assets/uploads/2021/10/personaltoken/requestsamplebeforesend.png&quot; alt=&quot;VS Code http file&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A login prompt will poput like the one bellow, press signin.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/10/personaltoken/loginprompt.png&quot; alt=&quot;VS Code prompt&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A browser will open and you need to paste the code from the previous promt in the code box (it’s in your clipboard at this point so just paste it)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/10/personaltoken/loginpromptbrowser.png&quot; alt=&quot;Browser Login&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Follow the login procedure and get back to VS Code to see the request been sent and you can see the data.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/10/personaltoken/requestsample.png&quot; alt=&quot;Result in VS Code&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This request is then sent to D365 with a token generated for you. As with Postman or other tools you can now start building your own collections of requests in &lt;strong&gt;VS Code&lt;/strong&gt; to share, check in with code or just for your own use. Read more in the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=humao.rest-client&quot;&gt;&lt;strong&gt;Rest Client&lt;/strong&gt;&lt;/a&gt; page to get details on advanced request building.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;As a developer we often need to query systems like D365. When using the &lt;em&gt;“normal”&lt;/em&gt; way with service principals we are using credentials anyone can use. We can share them amongst collegues and they will be stored on developers computers. But with the described approach we can stop that and start pushing developers to use their own credentials. Increasing security and control over who has access to our systems and data.&lt;br /&gt;
So not only is it awesome for a developer to get started more quicker and easier without the need of a service principal. It’s also a better practice security wise.&lt;/p&gt;

&lt;p&gt;There are probobly many more ways to solve this, but this is one way and my thoughts on it.&lt;/p&gt;
</description>
                <link>/blog/2021/10/personaltokengeneration</link>
                <guid>/blog/2021/10/Get Personal Token via VS Code</guid>
                <pubDate>2021-10-21T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Oauth Token generation with Postman</title>
                <description>&lt;p&gt;Beginning to develop solutions where ouath is used as authentication mechanism is often easy due to alot of frameworks sorting out the heavy lifting. But I prefer to go in and see the raw data and make small changes/new requests to the apis to get data in order to understand what’s going on. In those cases I use Postman and build up collections to easily get the data I want and need. And the last few days I’ve gotten questions from multiple people around how I do it so I felt I should share a blog post about it since more might be interested.&lt;/p&gt;

&lt;p&gt;First of all this is the way I’m doing it so if you have a better please fill in the chat since there are more than one way to solve this problem.
I create a new Workspace “Token generation demo” in &lt;a href=&quot;https://www.postman.com/&quot;&gt;Postman&lt;/a&gt; (Workspace is a container for i.e. a project where I need to gather all requests and settings I need when working in this project).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/10/tokengeneration/newworkspace.png&quot; alt=&quot;Postman Workspace start&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s go thru the basics needed, if you never have been working with Postman these are the areas we will use.
1) Collections, here is all our collections that contains requests that we want to group togheter, like “Sales Orders” or “D365”
2) Request area, here we will work with our requests
3) Environmnet variables, these will be used to safely store credentials and also quickly change between environments&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/10/tokengeneration/newworkspace_withnumbers.png&quot; alt=&quot;Postman Workspace info&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are some built in mechanism but I’m always finding myself in some area of trouble and spend alot of time troubelshooting and just come out confused, so the approach I’m using feels easier and you get more control over what’s going on, call me old school if you want :).&lt;/p&gt;

&lt;p&gt;So let’s start of by creating a collection, I name it &lt;strong&gt;Token Sample&lt;/strong&gt; after that we are ready to add our first request, it’s the one for creating the token, we are doing this towards Azure AD.
1) Press the new button and pick &lt;strong&gt;‘Http Request’&lt;/strong&gt;
2) Add the url and to Azure it’s always &lt;em&gt;https://login.microsoftonline.com//oauth2/token&lt;/em&gt; only switch the  to your tenant id.
3) Add the body, since this is where we will send in credentials and all other information needed.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;grant_type:client_credentials
client_id:
client_secret:
resource:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;What type to use, since we use client credentials we pick &lt;em&gt;client_credentials&lt;/em&gt; and then the id and secret of your Azure AD app. And last the audience we are targeting, in this sample it’s the Azure Management api but ut could be any resource that you have in your AD.&lt;/p&gt;

&lt;p&gt;4) Name the request so you can find it easily
5) Save it in your collection&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/10/tokengeneration/postman_new_gettoken_request.png&quot; alt=&quot;New Request&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we have added a bunch of variable, each place that looks like this  is avariable with the name that’s inside the curly brackets. Let’s add an environment to add these variables too, clikc on the &lt;strong&gt;eye&lt;/strong&gt; and then the &lt;strong&gt;Add&lt;/strong&gt; button for environment. Start populating the variables we need:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;tenantId - your tenant ID can be found in the tageted AD&lt;/li&gt;
  &lt;li&gt;client_id - the client id of the application you are authenticating with&lt;/li&gt;
  &lt;li&gt;client_secret - the client secret of the application you are authenticating with&lt;/li&gt;
  &lt;li&gt;audience - the targeted audience, meaning where do I want to have access, in my case to the Managemet Api.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/10/tokengeneration/postman_new_environment.png&quot; alt=&quot;New Environment&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If we now go back to the request we can generate a token, make sure to pick the environment at top right (see image):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/10/tokengeneration/postman_test_get_token.png&quot; alt=&quot;Test Get Token Request&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we need that token when we do request’s there are several ways to do this but my favourit one is to add a variable for it, and get it updated automatically. Under the tab &lt;strong&gt;Tests&lt;/strong&gt; we can add scripts, &lt;a href=&quot;https://learning.postman.com/docs/writing-scripts/test-scripts/&quot;&gt;read more on scripts&lt;/a&gt;. We will then add a simple script that will verify that we get a json body back, and pick out the &lt;em&gt;bearer token&lt;/em&gt; in the response and update the environment variable named &lt;em&gt;bearerToken&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;responseBody&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;tests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Get Azure AD Token&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;responseBody&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;responseBody&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;access_token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;postman&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setEnvironmentVariable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;bearerToken&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/10/tokengeneration/postman_teststab.png&quot; alt=&quot;Postman Test&apos;s tab&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And after the run we now have the token in the variable &lt;em&gt;bearerToken&lt;/em&gt; as we can see under the environment by clicking on the &lt;strong&gt;eye&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/10/tokengeneration/postman_teststab_with_environment.png&quot; alt=&quot;Token stored to Environment variables&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we can start using it and it’s very simple to start using it, let’s start of by scanning what subscriptions I have access to with this service principal from the Azure management Api.&lt;/p&gt;

&lt;p&gt;1) Create a new request
2) Name it &lt;em&gt;Get Subscriptions&lt;/em&gt;
3) Set operation to &lt;strong&gt;GET&lt;/strong&gt; and url to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://management.azure.com/subscriptions?api-version=2014-04-01-preview&lt;/code&gt;
4) Add the Authorization header with the &lt;em&gt;Bearer&lt;/em&gt; type and the token from the variable.
5) Send the Request&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/10/tokengeneration/postman_request_copmpleted.png&quot; alt=&quot;Test the setup&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As we can see there is a list of Subscriptions returned, and we can now easily setup new environments and reuse the same requests just change the enivornment and the results will be based on the new credentials. This will quickly get you up and running with wathere fun things you are doing.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;We often need the flexibility that running our own requests gives us, this is how you can use &lt;a href=&quot;https://www.postman.com/&quot;&gt;Postman&lt;/a&gt;. I often end up building request collections in Postman and distribute them over the team or use them for testing and retesting things. As I usually do I prepared a collection for you if you want to speed up the implementation, &lt;a href=&quot;../assets/uploads/2021/10/tokengeneration/Token%20Sample.postman_collection.json&quot;&gt;download it here&lt;/a&gt;&lt;/p&gt;
</description>
                <link>/blog/2021/10/oauthtokengeneration</link>
                <guid>/blog/2021/10/Create Token via Postman</guid>
                <pubDate>2021-10-05T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Troubelshooting Azure API Management</title>
                <description>&lt;p&gt;We often encounter situations where we need to troubelshoot our API’s and in this session I will go thru the different options we have. Following is the 3 different places where we can troubelshoot, here is a quick overview of the three options and here is a link to a video using all these options.
&lt;a href=&quot;https://youtu.be/0o763Yy00NM&quot; title=&quot;Troubelshooting in Azure API Management - Click to watch&quot;&gt;&lt;img src=&quot;http://youtu.be/0o763Yy00NM/0.jpg&quot; alt=&quot;Troubelshooting in Azure API Management&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;built-in-analytics&quot;&gt;Built in Analytics&lt;/h3&gt;
&lt;p&gt;In the built in Analytics we can easily see a good overview and status on our API’s. We can see hwo request’s are going, succes, failed? and so on we can also see data transfered and get an insight into response times. Filtering can be done on API’s, Products and even subscriptions to get an insight into how a specific consumer experiences our API’s. Using the Request tab we can even se the requests made, very usefull i you want to find isues like 404 responses or similar.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/01/apim-analytics-startpage.png&quot; alt=&quot;Analytics startpage&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;application-insights&quot;&gt;Application Insights&lt;/h3&gt;
&lt;p&gt;In addition we can add other tools to get deeper insight into what is happening, i.e why do the consumer get a 401? Or find the error text with that 500 response that is returned. If our backend resource also uses Applciation Insight’s you get a the full end-to-end experience where you can track all relevant information connected to the request like dependencies, logged events and so forth.
In Application Insights we can see all failures under the &lt;strong&gt;Failures&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/01/apim-appinsights-failures.PNG&quot; alt=&quot;App Insigths Failures&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Clicking you thru we can see the timeline and also the specific error text, in my case there is a &lt;strong&gt;TokenClaimValueMismatch&lt;/strong&gt; at the policy section &lt;strong&gt;validate-jwt&lt;/strong&gt; and if you watch the video we can see that this is exactly why we get the 401. The token provided is missing a permission.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/01/apim-appinsights-endtoend.png&quot; alt=&quot;App Insigths Failures&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;live-debugging-in-vscode&quot;&gt;Live Debugging in VSCode&lt;/h3&gt;
&lt;p&gt;If we need to go deeper in to your troubelshooting in your API Management Policy we can use the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-apimanagement&quot;&gt;Azure API Management VSCode extension&lt;/a&gt;. In this extension we can edit our policies for our API Management instance and upload them back when done.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/01/apim-vscode-policy.png&quot; alt=&quot;VSCode Policy&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We can start a debugg session where we can send a request and debug the policy step by step! This is awesome and so usefull! (only that request will be captured, so this can safely be done even in production). Right click the Operation and select “Start Policy Debugging”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/01/apim-vscode-policydebugging.PNG&quot; alt=&quot;VSCode Policy Debugging&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The Request is creted and you can add you settings, payload etc and then press “Send Request”.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;When using versioning please verify the URL, there is currently no support for the versioning so in my case the versioning is lost my URL is in the sample bellow &lt;em&gt;https://.azure-api.net/Orders/orders/my&lt;/em&gt; but due to versioning should be &lt;em&gt;https://.azure-api.net/Orders/v1/orders/my&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2021/01/apim-vscode-sendrequest.png&quot; alt=&quot;VSCode Send Request&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For more details and talk, see the video: &lt;a href=&quot;https://youtu.be/RiYBKqk9N3A&quot; title=&quot;Troubelshooting in Azure API Management - Click to watch&quot;&gt;&lt;img src=&quot;http://youtu.be/RiYBKqk9N3A/0.jpg&quot; alt=&quot;Troubelshooting in Azure API Management&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;Beeing a great API publisher is about building robust API’s and taking care of our API Consumers and help them to give a great experience on all fronts, specially when there is issues. We want to be able to find em, fix em and report back to the consumer with either help on what to do to fix it on the consumer side or a “we fixed it” from the API publisher side.&lt;/p&gt;
</description>
                <link>/blog/2021/01/troubelshootingazureapim</link>
                <guid>/blog/2021/01/Troubelshooting Azure API Mangement</guid>
                <pubDate>2021-01-08T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>API Management and Auth0 Consumer Friendly API's</title>
                <description>&lt;p&gt;Today we will extend our setup with API Management even further. Focusing on consumer friendly API’s and in this setup that is knowing our user more. In this example we will add the customer id to the consumer representation in Auth0 and use this id to give the consumer an operation called &lt;strong&gt;My orders&lt;/strong&gt;. No need for knowing or using or adding an id in the request. The id will be added to the token from Auth0 and then extracted in API Management and sent downstreams to filter the result set.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;An Identity provider is a service that a user/application is signing in to (just like Azure AD) and this provider has functionality to provide needed information and grant access to requested resources that the IDP is handling. Just like the fact that you have access to a resource or resource group inside your subscription in Azure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In API Management we have a trust setup as of the previus post &lt;a href=&quot;/blog/2020/05/setupauth0withapim&quot;&gt;Setup Auth0 with API Management&lt;/a&gt;. Then we added RBAC permission in the second post &lt;a href=&quot;/blog/2020/06/rbacwithapim&quot;&gt;RBAC with API Management&lt;/a&gt; where we added functionality to provide granular control over who has access to what operation. Now we will continue this and focus on extending this setup with adding a customerid to our consumer representation i Auth0 and then extract that id in API Management to enforce that they only can access these customers orders. Providing an operation to get just my orders without any additional parameters. This is achieved via the  &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/api-management/api-management-access-restriction-policies#ValidateJWT&quot;&gt;validate-jwt&lt;/a&gt; policy and then reading the JWT token custom claim and store it in a variable for later use.&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;set-variable&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;customerid&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;@(((Jwt)context.Variables[&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;token&quot;]).Claims.GetValueOrDefault(&quot;https://mlogdberg.com/customerid&quot;,&quot;-1&quot;))&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The end scenario will look like the illustration bellow where we can extract the customerid from the token and use it later down the path.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2020/06/extend-apim-auth0.png&quot; alt=&quot;Scenario image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’ve created a video that will go thru all of this a link is provided bellow.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://youtu.be/RiYBKqk9N3A&quot; title=&quot;RBAC in Azure API Management - Click to watch&quot;&gt;&lt;img src=&quot;http://youtu.be/RiYBKqk9N3A/0.jpg&quot; alt=&quot;Azure API Management and OAuth with Auth0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Links used in the video:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/api-management/api-management-access-restriction-policies#validate-jwt&quot;&gt;Validate JWT Token&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;Beeing a great API publisher is not as easy at it first looks like. Always striding for better and easier to use API’s is a good thing and here we show how to move more logic inside the setup rather than at the consumer. If we can prevent the consumer from needing to filter data and/or manage identifiers and so forth we can make it easier for the app builders that consume our api’s and provide speed and agility to those teams. At the same time we can create more secure and robust API’s with more automated testing. There are more ways to use this and interested to see what you will find most usefull.&lt;/p&gt;
</description>
                <link>/blog/2020/06/apimconsumerfriendlyapis</link>
                <guid>/blog/2020/06/API Mangement and Auth0 Consumer friendly APIS</guid>
                <pubDate>2020-06-17T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>RBAC with API Management</title>
                <description>&lt;p&gt;Extending our setup with API Management and Auth0 to create RBAC control over our operations in our API’s. The idea is to make sure that consumers can be granted access to specific operations in an API and not only to the whole API. This can be achieved in a number of ways and in this topic we will use Auth0 as the Identity Provider to help out with this, but you could use any other of your choice.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;An Identity provider is a service that a user/application is signing in to (just like Azure AD) and this provider has functionality to provide needed information and grant access to requested resources that the IDP is handling. Just like the fact that you have access to a resource or resource group inside your subscription in Azure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In API Management we have a trust setup as of the previus post &lt;a href=&quot;/blog/2020/05/setupauth0withapim&quot;&gt;Setup Auth0 with API Management&lt;/a&gt;. Then we add permissions to our representation of the &lt;strong&gt;Api Management&lt;/strong&gt; instance in Auth0 and grant the conusmer only the permissions that we want to give. After the permissions is setup and granted we willenforce these permissions in our API Management instance via the &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/api-management/api-management-access-restriction-policies#ValidateJWT&quot;&gt;validate-jwt&lt;/a&gt; policy.&lt;/p&gt;

&lt;p&gt;The end scenario will look like the illustration bellow where we can grant access to some or all operations in our API.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2020/06/apim-Auth0-RBAC.png&quot; alt=&quot;Scenario image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’ve created a video that will go thru all of this a link is provided bellow.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://youtu.be/0ItzeSiHl24&quot; title=&quot;RBAC in Azure API Management - Click to watch&quot;&gt;&lt;img src=&quot;http://youtu.be/0ItzeSiHl24/0.jpg&quot; alt=&quot;Azure API Management and OAuth with Auth0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Links used in the video:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/api-management/api-management-access-restriction-policies#validate-jwt&quot;&gt;Validate JWT Token&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;There is alot of times where extra granularity is needed in the API’s exposed. It helps out with creating easier to use and more natural API’s. I can be a good selpoint if used to show that there are more features for premium customers. Regardless adding RBAC to your API’s will increase seurity and eas of use. It will also give you a possibility to move the approving of new customer out of the API Managament instance and become more of a business thing to increas new consumer adoption. The setup used in Auth0 is very powerfull and can be reflected on end users aswell and that can be very helpfull when adding more lightweight consumers with single purposes.&lt;/p&gt;
</description>
                <link>/blog/2020/06/rbacwithapim</link>
                <guid>/blog/2020/06/RBAC with Azure API Management</guid>
                <pubDate>2020-06-12T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Setup Auth0 with API Management</title>
                <description>&lt;p&gt;API Management is an awesome API gateway with functionality to really excell in exposing API’s to consumers. When it comes to security there are several options and today we will look in to the OAuth. In order to do this we need an IDP (Identity Provider) that we can configure a trust releationship with.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;An Identity provider is a service that a user/application is signing in to (just like Azure AD) and this provider has functionality to provide needed information and grant access to requested resources that the IDP is handling. Just like the fact that you have access to a resource or resource group inside your subscription in Azure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In API Management a trust to an IDP and creation of a validation of the JWT provided from the IDP is done easily via the restrict policy called &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/api-management/api-management-access-restriction-policies#ValidateJWT&quot;&gt;validate-jwt&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s go thur how the setup looks like, we will need to set up a Trust between your API Management instance and your Auht0 instance.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2020/05/apim-Auth0-trust.png&quot; alt=&quot;Scenario image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’ve created a video that will go thru all of this a link is provided bellow.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://youtu.be/n2AJsRx3W7U&quot; title=&quot;Setup trust with APIM and Auth0 - Click to watch&quot;&gt;&lt;img src=&quot;http://img.youtube.com/vi/n2AJsRx3W7U/0.jpg&quot; alt=&quot;Azure API Management and OAuth with Auth0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Links used in the video:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/api-management/api-management-access-restriction-policies#validate-jwt&quot;&gt;Validate JWT Token&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Auth0 Openid Configuration url: https://YOUR_AUTH0_DOMAIN/.well-known/openid-configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;Adding a second security layer like this increases security and as you will see later on flexibility. It’s an awesome start in order to build a nice consumer experience for your API’s. In API Management it’s very easy to attach any IDP so you can pick and choose your favourite and the setup will be somehwat similar.&lt;/p&gt;
</description>
                <link>/blog/2020/05/setupauth0withapim</link>
                <guid>/blog/2020/05/Setup Auth0 with API Management</guid>
                <pubDate>2020-06-05T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Azure Functions logs in Application Insights part 2</title>
                <description>&lt;p&gt;In part one I covered the ILogger interface and what it’s providing for us, but sometimes we want more control of our logging, enrich oru logging or we have allready implemented alot of logging with &lt;em&gt;TelemtryClient&lt;/em&gt; and just want to connect the logging to our &lt;strong&gt;end-to-end&lt;/strong&gt; experience.&lt;/p&gt;

&lt;p&gt;We use the same Scenario, a message is recieve via API Management, sent to a Azure Function that publishes the message on a topic, a second Azure Function reads the published message and publishes the message on a second topic, a third Azure Function recieves the message and sends the message over http to a Logic App that represents a “3:e party system”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-scenario.png&quot; alt=&quot;Scenario image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Read more about the scenario background and the standard &lt;em&gt;ILogger&lt;/em&gt; interface in previous post &lt;a href=&quot;http://mlogdberg.com/2019/02/functions/understandhowlogsinai&quot;&gt;Azure Functions logs in Application Insights&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;connecting-custom-logs-from-telemetryclient&quot;&gt;Connecting custom logs from TelemetryClient&lt;/h2&gt;
&lt;p&gt;If we need more custom logging options than the provided in the standard &lt;em&gt;ILogger&lt;/em&gt; provides or we have alot of logging today with &lt;em&gt;TelemetryClient&lt;/em&gt; that is not connected to the endo to end scenario. We need attach these to our end-to-end logging experience via the &lt;strong&gt;TelemtryClient&lt;/strong&gt; to take advantage of the more advanced logging features.&lt;/p&gt;

&lt;p&gt;In order to achieve this we need to add some context properties to our instance, here is one way to do this via Service Bus, here we recieve the Message object.&lt;/p&gt;

&lt;p&gt;From the Message object we can extract the Activity, this is an extension found in the &lt;em&gt;Microsoft.Azure.ServiceBus.Diagnostics&lt;/em&gt; namespace. From the result of this operation we can get the &lt;em&gt;RootId&lt;/em&gt; and &lt;em&gt;ParentId&lt;/em&gt; wich is the values for  the current Operation Id and the parent id. &lt;a href=&quot;https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.DiagnosticSource/src/HierarchicalRequestId.md&quot;&gt;Read more on how the Operation id is built and how the hierarchy is designed&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ServiceBusTrigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;topic1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;one&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;servicebusConnection&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;activity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ExtractActivity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;telemetryClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;activity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RootId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;telemetryClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ParentId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;activity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ParentId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;telemetryClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TrackTrace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Received message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This can also be done from a HTTP call &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-monitor/app/custom-operations-tracking#http-request-in-owin-self-hosted-app&quot;&gt;read more&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// If there is a Request-Id received from the upstream service, set the telemetry context accordingly.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ContainsKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Request-Id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requestId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Request-Id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Get the operation ID from the Request-Id (if you follow the HTTP Protocol for Correlation).&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;telemetryClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetOperationId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requestId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;telemetryClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ParentId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requestId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	
&lt;span class=&quot;c1&quot;&gt;//GetOperationId method&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetOperationId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Returns the root ID from the &apos;|&apos; to the first &apos;.&apos; if any.&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rootEnd&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IndexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;&apos;.&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rootEnd&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rootEnd&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rootStart&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;&apos;|&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Substring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rootStart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rootEnd&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rootStart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we will also add this small line of code that trackes an event.&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;evt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;EventTelemetry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Function called&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;evt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;dummyUser&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;telemetryClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TrackEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;evt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And this can now be found in the end-to-end tracing.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-customEventOverview.png&quot; alt=&quot;Event in Overview&quot; /&gt;
&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-endtoendoevent.png&quot; alt=&quot;Event in Telemetrylist&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;adding-an-extra-operation&quot;&gt;Adding an Extra “Operation”&lt;/h2&gt;
&lt;p&gt;This is probobly my favorit thing in all of this, when processing messages some parts of the process are bigger and/or more important to understand, this could be a complex transformation or just a set of steps that we want to group.
Then we can use the &lt;em&gt;StartOperation&lt;/em&gt; in &lt;em&gt;TelemetryClient&lt;/em&gt;, this will start the scope for the &lt;em&gt;Operation&lt;/em&gt; and it will be open until we execute the operation &lt;em&gt;StopOperation&lt;/em&gt; it has a status and we can set some properties and get execution time of the process.&lt;/p&gt;

&lt;p&gt;An Operation is either a &lt;em&gt;DependencyOperation&lt;/em&gt;, intended to mark dependency to other resources or a &lt;em&gt;RequestOperation&lt;/em&gt; meant for marking a creation of a request.
I will use a DependencyOperation in my case since it’s the most alike operation for my purpose, I use it to mark that a more complex logic has been executed in my function and what the result of it was.&lt;/p&gt;

&lt;p&gt;I use this in several ways one is when I process alot of items in my Function to mark that they are executed, like processing a record in a list, another is when performing a complex transformation and so on.&lt;/p&gt;

&lt;p&gt;In my example bellow I’ll demonstrate the usage of an operation by doing a simple for loop and simulating processing of a line and adding some valuable metadata. As a tip set the &lt;em&gt;Data&lt;/em&gt; property to the object that is going to be processed to easier understand what data is processed.&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;++)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;telemetryClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StartOperation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DependencyTelemetry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Function2_line_{0}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()));&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Telemetry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Processing {0} and random guid {1}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Telemetry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;LineProcessor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Telemetry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Success&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Telemetry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sequence&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Telemetry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GlobalProperties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;LineID&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
	
	&lt;span class=&quot;c1&quot;&gt;//do some heavy work!&lt;/span&gt;
	
    &lt;span class=&quot;n&quot;&gt;telemetryClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;StopOperation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;                    
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will result in a mutch more detailed log in the &lt;strong&gt;End-To-End&lt;/strong&gt; overview&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-endtoendwithoperation.png&quot; alt=&quot;Operation in Overview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Custom properties is easily set on each operation for traceability or information, bellow is how we can add &lt;strong&gt;LineID&lt;/strong&gt; as a custom property.&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Telemetry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GlobalProperties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;LineID&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-operations-custom-properties.png&quot; alt=&quot;Operation and custom Property&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We can also set the Operation to have failed even if we continued the run, good for highlight parts of failure while still needing to complete the rest of the run.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-operationfailed.png&quot; alt=&quot;Operation and custom Property&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then we can find it under failures and from there start working on how to fix it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-operation-failures.png&quot; alt=&quot;Operation and failed operations&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Read more:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-monitor/app/custom-operations-tracking&quot;&gt;https://docs.microsoft.com/en-us/azure/azure-monitor/app/custom-operations-tracking&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-monitor/app/api-custom-events-metrics&quot;&gt;https://docs.microsoft.com/en-us/azure/azure-monitor/app/api-custom-events-metrics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;In this second part we have covered more advanced logging with TelemetryClient or to connect your current TelemetryClient logging to the End-To-End experience provided by Application Insights.&lt;/p&gt;

&lt;p&gt;The StartOperation is really powerfull to highlight what is happening, but I would like to have a third option for an Operation since using the Dependency sounds wrong when it’s a section of the code in the same process, but it works!&lt;/p&gt;

&lt;p&gt;This post is about how things can be done and hopefully this can be a guidance in creating a better logging experience, we want to avoid the developers “let me just attach my debugger” response to what is the problem with the flow running in production.&lt;/p&gt;
</description>
                <link>/2019/02/functions/understandhowlogsinaipart2</link>
                <guid>/2019/02/functions/Function and Application Insight part 2</guid>
                <pubDate>2019-08-23T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Azure Functions logs in Application Insights</title>
                <description>&lt;p&gt;Azure Functions is a great tool in our toolbox and as all our tools they have their strengths and flaws. When it comes to logging and monitoring Functions rely on Application Insight’s and later on Azure Monitor.
It’s also alot dependent on how the implement of your solution, and there are som &lt;strong&gt;out of box&lt;/strong&gt; features that are really amazing.&lt;/p&gt;

&lt;p&gt;If you are unfamiliar with Functions and Application Insights, read more here: &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-functions/functions-monitoring&quot;&gt;https://docs.microsoft.com/en-us/azure/azure-functions/functions-monitoring&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By just enabling application insights, without any further addons we get all the logs that are sent to the &lt;em&gt;ILogger&lt;/em&gt; object to application Insights. And we also get some &lt;strong&gt;End-To-End&lt;/strong&gt; tracking via supported SDK’s and HttpClient requests. This is very useful to get an understanding of what is happening.
So let’s look in to how this manifests in a rather complex scenario.&lt;/p&gt;

&lt;p&gt;The Scenario is that a message is recieve via API Management, sent to a Azure Function that publishes the message on a topic, a second Azure Function reads the published message and publishes the message on a second topic, a third Azure Function recieves the message and sends the message over http to a Logic App that represents a “3:e party system”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-scenario.png&quot; alt=&quot;Scenario image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After connecting all functions to the &lt;strong&gt;same&lt;/strong&gt; Application Insight instance we are sending a message! Let’s see how this can look like in Application Insights, first we go to the Performance tab:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-performancetab.png&quot; alt=&quot;Performance tab&quot; /&gt;&lt;/p&gt;

&lt;p&gt;First let’s just point out some small good to know things, the Operation Name in this view is actually the name of the function that you execute, so Function 1 in the list of Operation Names bellow:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-endtoendoverview-OperationName.png&quot; alt=&quot;Operation Name&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Has this signature in the code &lt;strong&gt;FunctionName(“Function1”)&lt;/strong&gt;, this is important as your instances grow make sure the name of the function is unique to easily find em.&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FunctionName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Function1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ServiceBus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;topic1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Microsoft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Azure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WebJobs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ServiceBus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EntityType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Topic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;servicebusConnection&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HttpTrigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AuthorizationLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;post&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Route&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then we pick one of the requests, press the &lt;em&gt;samples&lt;/em&gt; and pick one, it loads the end-to-end overivew&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-endtoendoverview.png&quot; alt=&quot;End to end Overview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We can actually see all the steps from the first function to the last function and the call to the Logic App, impressive! The message is beeing sent over Service bus topics but the correlation is all set and we can follow the message all the way!&lt;/p&gt;

&lt;p&gt;So this is truly awesome and alot of standard Properties are set out of box, but none specific to our request so it’s hard to understand what data is sent so let’s look in some special ways of adding custom information to the logs.&lt;/p&gt;

&lt;h2 id=&quot;logs-in-application-insights&quot;&gt;Logs in Application Insights&lt;/h2&gt;

&lt;p&gt;Out of box logs is sent to Application Insights via the &lt;em&gt;ILogger&lt;/em&gt; object so let’s take a short look at the interface, it contains 3 different operations, &lt;em&gt;Log&lt;/em&gt; that logs some information, there are different types and extensions on this to make it easier to use.
An isEnabled check to see if the logger is enabled and last a BeginScope operation that will create a scope for our log entries. &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-monitor/app/ilogger&quot;&gt;Read more&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ILogger&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Summary:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//     Begins a logical operation scope.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Parameters:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//   state:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//     The identifier for the scope.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Returns:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//     An IDisposable that ends the logical operation scope on dispose.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;IDisposable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BeginScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TState&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Summary:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//     Checks if the given logLevel is enabled.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Parameters:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//   logLevel:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//     level to be checked.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Returns:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//     true if enabled.&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsEnabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LogLevel&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Summary:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//     Writes a log entry.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Parameters:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//   logLevel:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//     Entry will be written on this level.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//   eventId:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//     Id of the event.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//   state:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//     The entry to be written. Can be also an object.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//   exception:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//     The exception related to this entry.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//   formatter:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//     Function to create a string message of the state and exception.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LogLevel&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EventId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eventId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TState&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;formatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s look at the simplest one just adding a Log text with &lt;em&gt;LogInformation&lt;/em&gt; (an extension on Log)some unique data this is to log our productnumber, so we can see what productnumber this request is processing:&lt;/p&gt;
&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ProductNumber {productnumber}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;productnumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s move to the collected Telemetry to see this log in Azure Portal:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-viewTelemetry.png&quot; alt=&quot;Scenario image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And now we can find our log row:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-informationlogproductnumber.png&quot; alt=&quot;ProductNumber log row&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So now we know this request is processing the specific product, this is searchable in the Search Menu, and an easy click will take you to the End-to-End tracking.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-searchProduct.png&quot; alt=&quot;ProductNumber log row&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;create-a-log-scope-with-beginscope&quot;&gt;Create a log scope with BeginScope&lt;/h2&gt;
&lt;p&gt;Sometimes we need to add some data that will be added as properties to all upcoming logs, this can be done via the &lt;em&gt;BeginScope&lt;/em&gt;, with the following line all upcoming logs will automatically have the market and productnumber added as properties, the are added as with a prefix of &lt;em&gt;prop__&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BeginScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Function3 processed message for {market} with productnumber {productnumber}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;market&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;productnumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Processing Lines&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Upcoming Log entry will have &lt;strong&gt;prop_market&lt;/strong&gt; and &lt;strong&gt;prop_productnumber&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-viewCustomPeropertiesBeginScope.png&quot; alt=&quot;Properties added with Begin Scope&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One good use is to do looping over multiple items, and therefore all entries will have these properties added, also all other properties added with the &lt;em&gt;{}&lt;/em&gt; format in &lt;em&gt;log.Information&lt;/em&gt; as &lt;strong&gt;lineNumber&lt;/strong&gt; and &lt;strong&gt;guid&lt;/strong&gt; in bellow sample will be added in the customDimension with prefix &lt;strong&gt;prop__&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	 &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Processing {lineNumber} and random guid {guid}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And if we want to loop over multiple lines we can add an extra scope to make sure we log the specific unique data for each iteration, following we log the &lt;em&gt;lineNumber&lt;/em&gt; and a random &lt;em&gt;guid&lt;/em&gt; and as you can see we still have the productnumber and market from before all with the &lt;strong&gt;prop__&lt;/strong&gt; prefix.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-viewCustomPeropertiesBeginScopeLoop.png&quot; alt=&quot;Properties added with Begin Scope&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Code sample of the loop&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BeginScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Function3 processed message for {market} with productnumber {productnumber}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;market&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;productnumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	    &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Processing Lines&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;++)&lt;/span&gt;
	    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	        &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BeginScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Function3 Processing line {lineNumber}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()))&lt;/span&gt;
	        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	            &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Processing {lineNumber} and random guid {guid}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
	        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;add-filterable-property-to-request&quot;&gt;Add Filterable Property to Request&lt;/h2&gt;
&lt;p&gt;Let’s say that we want to not just find a specific run, we want to understand overall performance or errors on a more wider term, like for a market. Let’s consider we want to understand performance or failures for a specific market. This is done via the &lt;em&gt;Performance&lt;/em&gt; or &lt;em&gt;Failures&lt;/em&gt; tabs, but in order to narrow down the data presented we need to be able to filter the data like the the image bellow adding a filter on &lt;strong&gt;Market&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-performance-expectedsearch.png&quot; alt=&quot;ProductNumber log row&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To get this working we need to add an property to our request log. (The request log is the first log event, see the telemetry for more information) the code to achieve this is super simple we just need to add this small snippet of code:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Diagnostics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Activity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddTag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Market&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;market&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The function now looks like:&lt;/p&gt;
&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Function1&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FunctionName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Function1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ServiceBus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;topic1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Microsoft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Azure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WebJobs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ServiceBus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EntityType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Topic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;servicebusConnection&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HttpTrigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AuthorizationLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;post&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Route&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;C# HTTP trigger function processed a request.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requestBody&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;StreamReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ReadToEndAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;dynamic&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DeserializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requestBody&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;productnumber&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;productnumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;market&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;marketnumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ProductNumber {productnumber}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;productnumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Diagnostics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Activity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddTag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Market&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;market&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

           
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SerializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will now give us the following result:&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;Search&lt;/em&gt; section we can pick the &lt;strong&gt;Market&lt;/strong&gt; in the filter to build our queries.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-searchMarket.png&quot; alt=&quot;Search with add filter Market&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the Search section we can pick the &lt;strong&gt;Market&lt;/strong&gt; in the filter to build our queries.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-searchMarket.png&quot; alt=&quot;Search with add filter Market&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;Performance&lt;/em&gt; and &lt;em&gt;Failures&lt;/em&gt; sections we need to add a bit more to be able to work with the filter, we need to add &lt;strong&gt;customDimensions&lt;/strong&gt; before &lt;strong&gt;Market&lt;/strong&gt; making the filter look like &lt;strong&gt;customDimensions.Market&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-perfromancecustomdimensionsearch.png&quot; alt=&quot;Search with add filter Market&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And as you can see we get the filtered result after pressing the green confirm button.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/08/functionsAi-perfromancecustomdimensionsearchafter.png&quot; alt=&quot;Search with add filter Market&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Adding more &lt;em&gt;Tags&lt;/em&gt; will allow more possibliites for search, the tag will be attached only to the request log entry and not to the following traces. But I would recomend logging both a id and a more broader value like market or similar to find errors/performace issues that span a broader range.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;I love developing in Azure Functions but in order to have a good Operations experience there is alot of things to consider in the logging strategy to make sure it’s easy to understand what is going on and how to take advantage of the statistics provided by Application Insights.&lt;/p&gt;

&lt;p&gt;This post is about how things can be done and hopefully this can be a guidance in creating a better logging and searching experience, we want to avoid the developers “let me just attach my debugger” response to what is the problem with the flow running in production.&lt;/p&gt;
</description>
                <link>/2019/02/functions/understandhowlogsinai</link>
                <guid>/2019/02/functions/Function and Application Insight</guid>
                <pubDate>2019-08-19T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>August 2019 update Logic App Template Creator</title>
                <description>&lt;p&gt;There has been some time since last updates where announced on the Logic App Template Creator, but work has been ongoing thanks to contributors so time to form out the new updates.&lt;/p&gt;

&lt;p&gt;There are some small changes and bug fixes as usual and fixed some issues reported but here is some new functionality.&lt;/p&gt;

&lt;p&gt;The github repository is found here: &lt;a href=&quot;https://github.com/jeffhollan/LogicAppTemplateCreator&quot;&gt;https://github.com/jeffhollan/LogicAppTemplateCreator&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;updates&quot;&gt;Updates&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;ISE support, you can now extract Logic Apps in ISE for deployments&lt;/li&gt;
  &lt;li&gt;Extract custom Connector, you can now extract an ARM template for Custom Connectors&lt;/li&gt;
  &lt;li&gt;Extract Integration Account Schemas, you can now extract an ARM template for Integration Account Schemas.&lt;/li&gt;
  &lt;li&gt;Get the Deployed Logic App’s URL as an output parameter from the ARM template deploy (usable when URL is needed in nested ARM templates)&lt;/li&gt;
  &lt;li&gt;Improved Get-Help method to provide more valuable help and information&lt;/li&gt;
  &lt;li&gt;Extract Logic App that will be in disabled mode when deployed&lt;/li&gt;
  &lt;li&gt;Possibility to improved security around parameters and passwords generated in the ARM template and paramter files&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;thanks-to-contributors&quot;&gt;Thanks to contributors!&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Splaxi&quot;&gt;Splaxi&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Geronius&quot;&gt;Geronius&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/bhoang&quot;&gt;bhoang&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/svenskfisk&quot;&gt;svenskfisk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/lfalck&quot;&gt;lfalck&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
                <link>/2019/08/logicapps/template-extractor-update</link>
                <guid>/2019/08/logicapps/Logic App Template Generator Update</guid>
                <pubDate>2019-08-12T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Resource Group Deployments 800 Limit fix</title>
                <description>&lt;p&gt;There is a &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#resource-group-limits&quot;&gt;limit&lt;/a&gt; of how many historical deployments that are saved for a resource group in Azure. Currently the limit is 800 and yet there are no out of box solution to start deleting these historical deployments when the limit is closing in.
So what happens is that the next deployment, the 801:st is failing error code is &lt;strong&gt;DeploymentQuotaExceeded&lt;/strong&gt; and message as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Creating the deployment &apos;cra3000_website-20190131-150417-7d5f&apos; would exceed the quota of &apos;800&apos;. The current deployment count is &apos;800&apos;, please delete some deployments before creating a new one. Please see https://aka.ms/arm-deploy for usage details.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So to solve this we manually entered the resource group and deleted some deployments, but that isent what we want to do in the long run. So I looked around and found some powershell scripts I could reuse for this purpose and created a runbbook in an automation account.&lt;/p&gt;

&lt;p&gt;I’m not no pro on automation account but I can set em up and use them, there might bsome of you who would give me a tip or 2 on this subject.&lt;/p&gt;

&lt;p&gt;So when creating the account we need to use the &lt;strong&gt;Azure Run As&lt;/strong&gt; account, since this will create an account i AAD and this will be used for access, by default the account will have contributor access on the whole subscription (if you have the permissions to create it) otherwise you need someone who can.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/02/create_automation_Account.PNG&quot; alt=&quot;Create Automation aCcount&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If we then look at the resource group we can find this account with contributor access, wich also means that if you only want it to be for sertain resource groups all you need to do is to restrict access for this user and when the script runs &lt;em&gt;Get-AzureRmResourceGroup&lt;/em&gt; only the resource groups where this user has access to is returned. (by default the whole subscription)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/02/useraccount_iam.PNG&quot; alt=&quot;Automation account contributor&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So the script is simple and there might be some improvements with parallel actions needed for big environments but after running it on schedule for a while it shouldnt be a big issue.&lt;/p&gt;

&lt;p&gt;All in all it collects all resource groups that the user has access to and start collecting deployments, in this script I always skip to run the script if there is less than 100 deployments made since it’s no pain in keeping these, it’s just painfull if we get over 800.
But if we have more the script starts deleting deployments older than 90 days (by degault) to keep some history there, this can easily be changed in the script. This is run via a Powershell Workbook.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-PowerShell&quot;&gt;$daysBackToKeep = 90

$connectionName = &quot;AzureRunAsConnection&quot;
try
{
    # Get the connection &quot;AzureRunAsConnection &quot;
    $servicePrincipalConnection = Get-AutomationConnection -Name $connectionName  

    &quot;Logging in to Azure...&quot;
    (Add-AzureRmAccount `
        -ServicePrincipal `
        -TenantId $servicePrincipalConnection.TenantId `
        -ApplicationId $servicePrincipalConnection.ApplicationId `
        -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint ) | out-null

    &quot;Obtaining Subscription information...&quot;
    $context = Get-AzureRmContext
    Write-Output (&quot;Subscription Name: &apos;{0}&apos;&quot; -f $context.SubscriptionName)
}
catch {
    if (!$servicePrincipalConnection)
    {
        $ErrorMessage = &quot;Connection $connectionName not found.&quot;
        throw $ErrorMessage
    } else {
        Write-Error -Message $_.Exception
        throw $_.Exception
    }
}

$ResourceGroups = Get-AzureRmResourceGroup

if ($ResourceGroupName)
{
    $ResourceGroups = $ResourceGroups | where { $_.ResourceGroupName -EQ $ResourceGroupName }
}

foreach( $resouregroup in $ResourceGroups) {
    $rgname = $resouregroup.ResourceGroupName
    Write-Output (&quot;Resource Group: &apos;{0}&apos;&quot; -f $rgname)

    $deployments = Get-AzureRmResourceGroupDeployment -ResourceGroupName $rgname
    Write-Output (&quot;Deployments: &apos;{0}&apos;&quot; -f $deployments.Count)

    if($deployments.Count -gt 100 ) {
        $deploymentsToDelete = $deployments | where { $_.Timestamp -lt ((get-date).AddDays(-1*$daysBackToKeep)) }
        Write-Output (&quot;Deloyments to delete: &apos;{0}&apos;&quot; -f $deploymentsToDelete.Count )
        foreach ($deployment in $deploymentsToDelete) { 

            Remove-AzureRmResourceGroupDeployment -ResourceGroupName $rgname -DeploymentName $deployment.DeploymentName -Force
            Write-Output (&quot;Deloyments deleted: &apos;{0}&apos;&quot; -f $deployment.DeploymentName )
        }
        Write-Output (&quot;Deployments deleted&quot;)
    }
    else {
        Write-Output (&quot;Less than 100 deployments to deleted, only {0}&quot; -f $deployments.Count)
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running it will start deleting deployments, so here is a pre run deployments history&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/02/preclear.PNG&quot; alt=&quot;Deployments history pre clear&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And after we can see that history is deleted (for this run I just removed the 100 check)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/02/postclear.PNG&quot; alt=&quot;Deployments history post clear&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After running it the logs will look something like this:&lt;/p&gt;

&lt;p&gt;![Runbook logs](/assets/uploads/2019/02/runbook_logs.png&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;This limit is annoying and as I understand something that should be fixed over time, but until then we need to have these kind of helping scripts in environments with alot of deployments. So hopefully this helps out in the meantime.&lt;/p&gt;

&lt;p&gt;Read more on the limits:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#resource-group-limits&quot;&gt;https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#resource-group-limits&lt;/a&gt;&lt;/p&gt;
</description>
                <link>/2019/02/arm/resourcegroupdeploymentslimit800</link>
                <guid>/2019/02/arm/Resource Group Deployments limit 800</guid>
                <pubDate>2019-02-12T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Fixing Function v2 add extension issues in portal</title>
                <description>&lt;p&gt;I’m out doing educations and it’s both fun and a great chance for me to learn new stuffs since it’s always something that just for no reason going south.&lt;/p&gt;

&lt;p&gt;So today I was out on one of these missions and we where doing some labs developing functions, when we added an extra input from a table storage the Function App just chrashed and then we just got errors that the site was offline and it dident come up. Everybody encountered it so I had to investigate.&lt;/p&gt;

&lt;p&gt;The response was a &lt;em&gt;503 Service Unavailable&lt;/em&gt; and the body was the following html content (removed the style since it just took alot of space):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-HTML&quot;&gt;&amp;lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&amp;gt;
&amp;lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; &amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Host Offline&amp;lt;/title&amp;gt;
 &amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;div&amp;gt;&amp;amp;nbsp;&amp;lt;/div&amp;gt;
    &amp;lt;div id=&quot;wrapper&quot;&amp;gt;
        
        &amp;lt;div id=&quot;page&quot;&amp;gt;
            &amp;lt;div id=&quot;content&quot;&amp;gt;

                &amp;lt;div class=&quot;box&quot;&amp;gt;
                    &amp;lt;h2&amp;gt;This Azure Functions app is down for maintenance&amp;lt;/h2&amp;gt;
                    &amp;lt;p&amp;gt;
                        Host is offline
                    &amp;lt;/p&amp;gt;
                &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
     
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So what did we do to get here? Well we just wanted to add an input to from a &lt;strong&gt;Table Storage&lt;/strong&gt; to a standard HTTP Trigger and we started from a blank new defualt function.&lt;/p&gt;

&lt;p&gt;Here is my default http function:
&lt;img src=&quot;/assets/uploads/2019/01/functions-defualt-http-trigger.png&quot; alt=&quot;Defualt Http Trigger&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then I went to the &lt;em&gt;Integrate&lt;/em&gt; pane and started to add the input from my &lt;strong&gt;Azure Table Storage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/01/functions-adding-table-storage-input.png&quot; alt=&quot;Integrate Pane&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After selecting the &lt;strong&gt;Azure Table Storage&lt;/strong&gt; we get an warning that the extension is not installed, let’s install it!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/01/functions-install-storage-extension.png&quot; alt=&quot;Install Storage Extension&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s installing and we proceed as told in the message:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/01/functions-install-storage-extension-install-msg.png&quot; alt=&quot;Install Storage Extension Message&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So we just continued and filled the other details and pressed Save.&lt;/p&gt;

&lt;p&gt;After that we went back to the function to add the input, it’s just a simple signature update from:&lt;/p&gt;
&lt;div class=&quot;language-c# highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IActionResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HttpRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To:&lt;/p&gt;
&lt;div class=&quot;language-c# highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IActionResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HttpRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Newtonsoft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Linq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JArray&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputTable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now when we run the function the inputTable should be populated from the &lt;strong&gt;Azure Table Storage&lt;/strong&gt; but when we try to execute it we just get a http error code &lt;strong&gt;503 Service Unavailable&lt;/strong&gt; and in the body I can see the text “Host Offline”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/01/functions-install-storage-host-offline.png&quot; alt=&quot;503 Service Unavailable Host Offline&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So we started to look into this and read that it could be due to extension not installed properly, to fix this we followed this guide: &lt;a href=&quot;https://github.com/Azure/azure-functions-host/wiki/Updating-your-function-app-extensions&quot;&gt;https://github.com/Azure/azure-functions-host/wiki/Updating-your-function-app-extensions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have the same problemes make sure that the extension file exists and contains atleast &lt;strong&gt;“Microsoft.Azure.WebJobs.Extensions.Storage&lt;/strong&gt; if not create and/or add &lt;strong&gt;“Microsoft.Azure.WebJobs.Extensions.Storage&lt;/strong&gt; to the file.
Sample bellow:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Sdk=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.NET.Sdk&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;netstandard2.0&lt;span class=&quot;nt&quot;&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;WarningsAsErrors&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.Azure.WebJobs.Extensions.Storage&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;3.0.0&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.0.*&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you are missing the file it can easily be created in the command prompt witb a simple script:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cmd&quot;&gt;echo.&amp;gt;extensions.csproj
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Run the build command (this takes a while to run so be patient):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cmd&quot;&gt;dotnet build extensions.csproj -o bin --no-incremental --packages D:\home\.nuget
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/01/functions-install-storage-complete-restore.png&quot; alt=&quot;Restore extension build complete&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So now the extensions is installed, let’s verify if this solves the issue completly? Start the Function App and test the function again.&lt;/p&gt;

&lt;p&gt;If you are as unlucky as me and the function is  &lt;strong&gt;not&lt;/strong&gt; working we need to do one more thing.
Let’s go back to Kudos and the CMD Prompt again, the problem is the  &lt;strong&gt;app_offline.htm&lt;/strong&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/01/functions-install-extension-offline.png&quot; alt=&quot;Restore extension build complete&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Delete it and go back and test agian, it works again!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2019/01/functions-working.png&quot; alt=&quot;Restore extension build complete&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;The problem is that the extension is not properly installed and when we add the extension in the configuration without the extension installed the Function App chrashes as produces the &lt;strong&gt;app_offline.htm&lt;/strong&gt; and if it’s present in the folder the response is defaulted to 503 and Host Offline, by removing the file the Function App starts executing as normal and if we have fixed the extensions no errors comes up. This works for all extensions.&lt;/p&gt;

&lt;p&gt;By showing the problem and the reproduce scenario we can help out improving the products! So I hope this helps anyone and leads to a fix from the prodcut team.&lt;/p&gt;

</description>
                <link>/azurefunctions/functionsv2addextensionissuesportal</link>
                <guid>/azurefunctions/Function App Extention problems</guid>
                <pubDate>2019-01-07T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Logic App Template Creator Updates Januari 2019</title>
                <description>&lt;p&gt;Updates on the &lt;a href=&quot;https://github.com/jeffhollan/LogicAppTemplateCreator&quot;&gt;Logic Apps Template Creator&lt;/a&gt; has been published:&lt;/p&gt;

&lt;p&gt;A minor thing for usage but great for consistency and quality in the generator is that there is now a build and release pipeline setup in DevOps.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Added Build &amp;amp; Release via DevOps to increase quality in merged sprints and automate release to PowerShell Gallery &lt;a href=&quot;https://www.powershellgallery.com/packages/LogicAppTemplate&quot;&gt;LogicAppTemplate&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Improved support for Connectors to Storage Tables and Queues.&lt;/li&gt;
  &lt;li&gt;Added Commandlet to generate ARM Template for Integration Account Maps&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;power-shell-gallery&quot;&gt;Power Shell Gallery&lt;/h2&gt;
&lt;p&gt;Now the LogicAppTemplate is updated more frequqntly since I’ve added Build and Release setup to publish new releases to PowerShell Gallery.&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;PS&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Install-Module&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-Name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;LogicAppTemplate&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or update to the newest version&lt;/p&gt;
&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;PS&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Update-Module&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-Name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;LogicAppTemplate&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;storage-connector-tables-and-queues&quot;&gt;Storage Connector Tables and Queues&lt;/h2&gt;
&lt;p&gt;Now generated on the same way as Storage Blob Connector, meaning that the key will be collected duirng the deployment time based on the storage account name instead of needed to be provided as parameters. This will make it simpler and more neat to do deployments.&lt;/p&gt;

&lt;p&gt;There are 3 parameters added&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;azureblob_name&quot;: {
      &quot;type&quot;: &quot;string&quot;,
      &quot;defaultValue&quot;: &quot;azureblob&quot;
    },
    &quot;azureblob_displayName&quot;: {
      &quot;type&quot;: &quot;string&quot;,
      &quot;defaultValue&quot;: &quot;myDisplayName&quot;
    },
    &quot;azureblob_accountName&quot;: {
      &quot;type&quot;: &quot;string&quot;,
      &quot;defaultValue&quot;: &quot;myStorageAccountName&quot;,
      &quot;metadata&quot;: {
        &quot;description&quot;: &quot;Name of the storage account the connector should use.&quot;
      }
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And they are later used in the connection to get the accountKey automatically during deployment.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; {
      &quot;type&quot;: &quot;Microsoft.Web/connections&quot;,
      &quot;apiVersion&quot;: &quot;2016-06-01&quot;,
      &quot;location&quot;: &quot;[parameters(&apos;logicAppLocation&apos;)]&quot;,
      &quot;name&quot;: &quot;[parameters(&apos;azureblob_name&apos;)]&quot;,
      &quot;properties&quot;: {
        &quot;api&quot;: {
          &quot;id&quot;: &quot;[concat(&apos;/subscriptions/&apos;,subscription().subscriptionId,&apos;/providers/Microsoft.Web/locations/&apos;,parameters(&apos;logicAppLocation&apos;),&apos;/managedApis/azureblob&apos;)]&quot;
        },
        &quot;displayName&quot;: &quot;[parameters(&apos;azureblob_displayName&apos;)]&quot;,
        &quot;parameterValues&quot;: {
          &quot;accountName&quot;: &quot;[parameters(&apos;azureblob_accountName&apos;)]&quot;,
          &quot;accessKey&quot;: &quot;[listKeys(resourceId(&apos;Microsoft.Storage/storageAccounts&apos;, parameters(&apos;azureblob_accountName&apos;)), providers(&apos;Microsoft.Storage&apos;, &apos;storageAccounts&apos;).apiVersions[0]).keys[0].value]&quot;
        }
      }
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All magic is in this ListKeys part, so this tells &lt;strong&gt;ARM&lt;/strong&gt; to collect the key based on a reference to the storage account. (this also means that the account doing the Resource Group Deployment also needs access to the storage account).&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[listKeys(resourceId(&apos;Microsoft.Storage/storageAccounts&apos;, parameters(&apos;azureblob_accountName&apos;)), providers(&apos;Microsoft.Storage&apos;, &apos;storageAccounts&apos;).apiVersions[0]).keys[0].value]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;new-commandlet-get-integrationaccountmaptemplate&quot;&gt;New CommandLet Get-IntegrationAccountMapTemplate&lt;/h2&gt;
&lt;p&gt;So another improvement is that we now can extract a map from an Integration Account in to a directly deployable ARM template. It work similar to the other extractions and bellow is a sample of how to get the Integration Account map as an ARM template.&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Get-IntegrationAccountMapTemplate&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-ArtifactName&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;mapname&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-IntegrationAccount&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ianame&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-ResourceGroup&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;myresourcegroup&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-SubscriptionId&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;guid()&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-TenantName&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;mattiaslogdberg.onmicrosoft.com&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;Exporting Logic Apps via the &lt;a href=&quot;https://github.com/jeffhollan/LogicAppTemplateCreator&quot;&gt;Logic App Template Extractor&lt;/a&gt; simplifies the CI/CD area of using Logic Apps. Without needing to manually add extra work, making the development inside the portal and then just extracting the work and setup the import to the next environment .&lt;/p&gt;
</description>
                <link>/logicapps/template-creator-updates-Jan-2019</link>
                <guid>/logicapps/Logic App Template Creator</guid>
                <pubDate>2019-01-02T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>API Management Template Creator Updates December 2018</title>
                <description>&lt;p&gt;Updates on the &lt;a href=&quot;https://github.com/MLogdberg/APIManagementARMTemplateCreator&quot;&gt;API Management Template Creator&lt;/a&gt; has been published:&lt;/p&gt;

&lt;p&gt;I’ve got a lot of help this time frome some awesome contributors a big thanks to them! &lt;a href=&quot;https://github.com/nilshedstrom&quot;&gt;NilsHedstrom&lt;/a&gt;, &lt;a href=&quot;https://github.com/Geronius&quot;&gt;Geronius&lt;/a&gt;, &lt;a href=&quot;https://github.com/joeyeng&quot;&gt;joeyeng&lt;/a&gt;, &lt;a href=&quot;https://github.com/lfalck&quot;&gt;Lfalk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A minor thing for usage but great for consistency and quality in the generator is that there is now a build and release pipeline setup in DevOps.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Improved support for Identity Providers, Products and more&lt;/li&gt;
  &lt;li&gt;Added automation for Build &amp;amp; Release via DevOps to increase quality in merged sprints and automate release to PowerShell Gallery&lt;/li&gt;
  &lt;li&gt;Added to PowerShell Gallery &lt;a href=&quot;https://www.powershellgallery.com/packages/APIManagementTemplate/&quot;&gt;APIManagementTemplate&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Split the Template to a template per resource to follow &lt;a href=&quot;https://github.com/Azure/azure-api-management-devops-example&quot;&gt;API Management DevOps best pratices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;power-shell-gallery&quot;&gt;Power Shell Gallery&lt;/h2&gt;
&lt;p&gt;Now it’s mutch easier to get started, just install the APIMangementTemplate modul from PowerShell Gallery.&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;PS&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Install-Module&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-Name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;APIManagementTemplate&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or update to the newest version&lt;/p&gt;
&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;PS&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Update-Module&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-Name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;APIManagementTemplate&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;split-the-template-to-a-template-per-resource&quot;&gt;Split the Template to a template per resource&lt;/h2&gt;
&lt;p&gt;In order to follow the best pratice from &lt;a href=&quot;https://github.com/Azure/azure-api-management-devops-example&quot;&gt;Azure API Management DevOps example&lt;/a&gt; we now have a new command &lt;strong&gt;Write-APIManagementTemplates&lt;/strong&gt; this command will take a template as input and split into a file per resource to make it easy to manage and handle files and create more customized deployment with a linked template. &lt;a href=&quot;https://github.com/MLogdberg/APIManagementARMTemplateCreator&quot;&gt;Read more at GitHub&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get-APIManagementTemplate&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-APIManagement&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MyApiManagementInstance&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-ResourceGroup&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;myResourceGroup&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-SubscriptionId&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;80d4fe69-xxxx-4dd2-a938-9250f1c8ab03&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write-APIManagementTemplates&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-OutputDirectory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;C:\temp\templates&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-SeparatePolicyFile&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;$true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;Exporting API’s ia the &lt;a href=&quot;https://github.com/MLogdberg/APIManagementARMTemplateCreator&quot;&gt;API Management Template Extractor&lt;/a&gt; simplifies the CI area of using API Management, here we can select a specific API and export only that API, with Operations, version sets, schemas, properties etc. Without needing to manually add extra work, making the development inside the portal and then just extracting the work and setup the import to the next environment .&lt;/p&gt;
</description>
                <link>/api-management/template-creator-updates-Dec-2018</link>
                <guid>/api-management/API Management Template Creator Updates</guid>
                <pubDate>2018-12-21T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Innovation enabled by Integration</title>
                <description>&lt;p&gt;Normally we focus on technical implementations and problem solving but from time to time we get the opportunity to expand the view and focus on innovative thinking. This is the time where we can show our customers the real &lt;strong&gt;value&lt;/strong&gt; of applying &lt;strong&gt;good architecture and principles&lt;/strong&gt;. Currently I’m having so much fun doing innovative prototyping work with one of my customers that I need to share it with you. We are using &lt;strong&gt;Power Apps&lt;/strong&gt; and &lt;strong&gt;Flow&lt;/strong&gt; for our prototyping in order to get prototypes done fast and easy, without spending too much time and effort.&lt;/p&gt;

&lt;p&gt;Power Apps is a platform where you easy can build apps in a point-and-click approach and to multiple device types at the same time, read more at: &lt;a href=&quot;https://powerapps.microsoft.com/&quot;&gt;https://powerapps.microsoft.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Flow is a lightweight integration platform that runs on top of Logic Apps, it’s designed to make it easy to create your own flows and turn repetitive tasks into automated workflows, read more at &lt;a href=&quot;https://emea.flow.microsoft.com/&quot;&gt;https://emea.flow.microsoft.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These platforms are very easy to get started with and there are several samples of applications regarding office365 and common applications. But the real power for innovation comes clear if you have a good API landscape that could be used when building these applications.&lt;/p&gt;

&lt;p&gt;We have a customer that we started to work with for almost a year ago and now when all the hard work is done, and we have a good integration landscape we can harvest the benefits of our good architecture. I started with showing the case described below and now they really hunger for more of this kind of innovation both for internal and external use. It’s so wonderful to see how our hard work pays off. Showing that we really are the “integration heroes”, we are the enablers, making this possible.&lt;/p&gt;

&lt;h2 id=&quot;architecture-that-enables-innovation&quot;&gt;Architecture that enables innovation?&lt;/h2&gt;
&lt;p&gt;In reality it’s quite simple, create a platform that contains API’s and flows that can be reused. Make sure to build domain model-based API’s and function driven API’s and focus on making them simple to use and most important reusable. Here is a Sample Architecture:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/08/integration-archtecture-sample.png&quot; alt=&quot;Integration Architecture Sample&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And in our API Management instance we have created a few domain model API’s:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/08/api-sample.png&quot; alt=&quot;API List Sample&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A few months back we helped in replacing an internal system for product information, it was a system where you could enter a serial number and get basic information about the product. The end solution was a website that used a couple of API’s to retrieve the information needed. The fun part of this was that most of the API’s where already created in other projects for other/similar needs but used from other systems/apps. All we did was fine tune an API, leaving us with time to innovate. On a computer it makes sense to write a serial number but on a mobile phone we expect to be able to scan the serial. Since we had the time we started to investigate the problems around this and if this was solvable.&lt;/p&gt;

&lt;p&gt;We started to look in to this and the first “problem” was that the serial plates on the machines had no barcodes, only pure text:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/08/serial-plate-sample.png&quot; alt=&quot;Serial Plate Sample&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Luckily this function exists in the Cognitive services in Azure read more at &lt;a href=&quot;https://westus.dev.cognitive.microsoft.com/docs/services/5adf991815e1060e6355ad44/operations/56f91f2e778daf14a499e1fc&quot;&gt;Azure Cogniative Services&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We started to test this with a Power App that used a Flow to send the image to the Cognitive Service. The Power App solution is very simple, it uses the camera to take a picture and afterwards sends the picture to a Flow that utilizes the cognitive service to identify the serial number from the plate. The result from the Flow is a URL with the serial number that we used to launch the website, making use of the web app. With this we had expanded the functionality with a Serial Plate Scanner and provided basis for the decision on investing in a mobile app.&lt;/p&gt;

&lt;p&gt;Here is the flow:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/08/microsoft-flow-overview.png&quot; alt=&quot;Microsoft Flow Overview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here is the Power App in the Power Apps Studio developed in my browser:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/08/powerapp-sample.png&quot; alt=&quot;Microsoft Power App&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As you can see there is not much going on but a &lt;em&gt;Camera&lt;/em&gt; item with a &lt;em&gt;OnSelect&lt;/em&gt; statement that launches the web browser with the URL that comes back from our &lt;em&gt;Flow&lt;/em&gt; “Get-Path-To-Product”.&lt;/p&gt;

&lt;p&gt;The flow is also quite simple:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/08/flow-overview.png&quot; alt=&quot;Microsoft Flow Solution&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The tricky part was how to send the image to the &lt;em&gt;Cognitive Services&lt;/em&gt;, in this case we created a &lt;em&gt;compose&lt;/em&gt; action with a &lt;em&gt;dataUritoBinary&lt;/em&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/08/flow-action-compose.png&quot; alt=&quot;Microsoft Flow Action Compose&quot; /&gt;
&lt;strong&gt;*dataUriToBinary(triggerBody()[‘Skapa_Indata’])&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And in the HTTP action we send the binary data to the OCR service: (in the sample below the OCR service is behind our API Management instance)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/08/flow-action-http.png&quot; alt=&quot;Microsoft Flow Action HTTP&quot; /&gt;&lt;/p&gt;

&lt;p&gt;All in all, the prototype was easy and fast to build, but most importantly it successfully gave us the power to demo the concept. Providing a visual demo to show the value of having an app that can scan the serial plate. This gave a good understanding in the benefits of the investment on a native app to decision makers without spending too much time and resources.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;The app is currently under development and we have more of these innovative prototypes coming up to prototype new or upgraded functionality in a variety of sizes. Best part of using this approach is that we can create a prototype in a day or two providing fast prototyping, giving decision makers a visual and testable solution to review. All thanks to our hard work with API’s, workflows and the amazing tools Power Apps and Flow!&lt;/p&gt;

&lt;p&gt;Become the &lt;strong&gt;Integration Hero&lt;/strong&gt; that you really can be and let that unused &lt;strong&gt;innovation power&lt;/strong&gt; free!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/08/mlogdberg-help-business-evolve.jpg&quot; alt=&quot;Help Business Evolve&quot; /&gt;&lt;/p&gt;
</description>
                <link>/innovation/enable-innovation</link>
                <guid>/innovation/Enable-Innovation</guid>
                <pubDate>2018-08-31T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>API Management Template Creator Updates August 2018</title>
                <description>&lt;p&gt;Updates on the &lt;a href=&quot;https://github.com/MLogdberg/APIManagementARMTemplateCreator&quot;&gt;API Management Template Creator&lt;/a&gt; has been published a few weeks back:&lt;/p&gt;

&lt;p&gt;A minor thing for usage but great for consistency and quality in the generator is that there are alot of tests added.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Functions support added&lt;/li&gt;
  &lt;li&gt;Updated Logic App Support&lt;/li&gt;
  &lt;li&gt;Removed some name parameter generation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;functions-support-added&quot;&gt;Functions support added&lt;/h2&gt;
&lt;p&gt;Finally the support for API’s that are generated from Functions is live, now an API generated from Functions get the appropiate automatic generation of function keys via ARM functions.
Meaning that you don’t need to supply the function kode in the parameter files they are collected automatically via Listsecrets function in ARM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
      &quot;comments&quot;: &quot;Generated for resource /subscriptions/c107df29-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/PreDemoTest/providers/Microsoft.ApiManagement/service/ibizmalo/properties/5b41934c6d0f59440d20c5ee&quot;,
      &quot;type&quot;: &quot;Microsoft.ApiManagement/service/properties&quot;,
      &quot;name&quot;: &quot;[concat(parameters(&apos;service_ibizmalo_name&apos;),&apos;/&apos;,&apos;5b41934c6d0f59440d20c5ee&apos;)]&quot;,
      &quot;apiVersion&quot;: &quot;2017-03-01&quot;,
      &quot;properties&quot;: {
        &quot;displayName&quot;: &quot;maloapimtest_HttpTriggerAdminKey_query_5b41934c6d0f59440d20c5ee&quot;,
        &quot;value&quot;: &quot;[listsecrets(resourceId(parameters(&apos;FunctionApp_maloapimtest_resourceGroup&apos;),&apos;Microsoft.Web/sites/functions&apos;, parameters(&apos;FunctionApp_maloapimtest_siteName&apos;), parameters(&apos;operations_api-HttpTriggerAdminKey-post_name&apos;)),&apos;2015-08-01&apos;).key]&quot;,
        &quot;tags&quot;: [],
        &quot;secret&quot;: true
      },
      &quot;resources&quot;: [],
      &quot;dependsOn&quot;: []
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Previously:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;parameters: {
    &quot;INT2051functionkey_value&quot;: {
      &quot;type&quot;: &quot;securestring&quot;,
      &quot;defaultValue&quot;: &quot;Aze/1W8wCwItuP8JacdyHa2vDw8YScrOkbq6uHcTXiOasb2wi3kZoQ==&quot;
    }
 }
	. . . 
 {
      &quot;comments&quot;: &quot;Generated for resource /subscriptions/1fake145-d7f4-4d0f-b406-7394a2b64fb4/resourceGroups/Api-Default-West-Europe/providers/Microsoft.ApiManagement/service/apidev/properties/int2051functionkey&quot;,
      &quot;type&quot;: &quot;Microsoft.ApiManagement/service/properties&quot;,
      &quot;name&quot;: &quot;[concat(parameters(&apos;service_cpidev_name&apos;), &apos;/&apos; ,parameters(&apos;property_INT2051functionkey_name&apos;))]&quot;,
      &quot;apiVersion&quot;: &quot;2017-03-01&quot;,
      &quot;properties&quot;: {
        &quot;displayName&quot;: &quot;INT2051functionkey&quot;,
        &quot;value&quot;: &quot;[parameters(&apos;INT2051functionkey_value&apos;)]&quot;,
        &quot;tags&quot;: null,
        &quot;secret&quot;: true
      },
      &quot;resources&quot;: [],
      &quot;dependsOn&quot;: []
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;updated-logic-app-support&quot;&gt;Updated Logic App Support&lt;/h2&gt;
&lt;p&gt;Two bigger things has been targeted to improve the export and later deployment experience for APIM API’s that uses Logic Apps.&lt;/p&gt;

&lt;h3 id=&quot;trigger-name-fix&quot;&gt;Trigger name fix&lt;/h3&gt;
&lt;p&gt;A Logic App Trigger can now have any name, previous it was hardcoded to ‘Manual’. There is now logic added to retrieve the information at extraction time, the extractor fetches the Logic App definition and finds the HTTP trigger to get the correct name.&lt;/p&gt;

&lt;p&gt;Trigger name is extracted from the Logic App and added to the ARM functions (&lt;strong&gt;customtriggername&lt;/strong&gt; in below sample):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/08/logicappimagecustomtrigger.png&quot; alt=&quot;Logic App Trigger name&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Will result in (note the &lt;strong&gt;‘customtriggername’&lt;/strong&gt;):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;[listCallbackUrl(resourceId(parameters(&apos;LogicApp_customtrigger_resourceGroup&apos;), &apos;Microsoft.Logic/workflows/triggers&apos;, parameters(&apos;LogicApp_customtrigger_logicAppName&apos;), &apos;customtriggername&apos;), &apos;2017-07-01&apos;).queries.sig]&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;add-logic-app-as-operation-to-exisitng-api-fix&quot;&gt;Add Logic App as operation to exisitng API fix&lt;/h3&gt;
&lt;p&gt;There has been diffrent behavior between API’s generated from a Logic App imported as a new operation to an existing API. The main diffrent has been that the sig has been added as a “normal” parameter and no ARM functionality added to generate the &lt;em&gt;sig&lt;/em&gt;. This is now adressed and the appropiate ARM functions will be added and generated automatically for both types.&lt;/p&gt;

&lt;p&gt;Properties will get value from the &lt;em&gt;[ListCallBackUrl]&lt;/em&gt; function:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
      &quot;comments&quot;: &quot;Generated for resource /subscriptions/1fake145-d7f4-4d0f-b406-7394a2b64fb4/resourceGroups/Api-Default-West-Europe/providers/Microsoft.ApiManagement/service/apidev/properties/int7100-payment-to-o-test_manual-invoke_5b349f2a42974a989226cf33&quot;,
      &quot;type&quot;: &quot;Microsoft.ApiManagement/service/properties&quot;,
      &quot;name&quot;: &quot;[concat(parameters(&apos;service_apidev_name&apos;), &apos;/&apos; ,parameters(&apos;property_int7100-payment-to-o-dev_manual-invoke_5b349f2a42974a989226cf33_name&apos;))]&quot;,
      &quot;apiVersion&quot;: &quot;2017-03-01&quot;,
      &quot;properties&quot;: {
        &quot;displayName&quot;: &quot;int7100-payment-to-o-dev_manual-invoke_5b349f2a42974a989226cf33&quot;,
        &quot;value&quot;: &quot;[listCallbackUrl(resourceId(parameters(&apos;LogicApp_INT7100-Payment-To-o-DEV_resourceGroup&apos;), &apos;Microsoft.Logic/workflows/triggers&apos;, parameters(&apos;LogicApp_INT7100-Payment-To-o-DEV_logicAppName&apos;), &apos;request&apos;),&apos;2017-07-01&apos;).queries.sig]&quot;,
        &quot;tags&quot;: [],
        &quot;secret&quot;: true
      },
      &quot;resources&quot;: [],
      &quot;dependsOn&quot;: []
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;removed-some-name-parameters&quot;&gt;Removed some name parameters&lt;/h2&gt;
&lt;p&gt;Parameters generated for name of resources like, Policy, version sets, operations etc has no real use case or benefits associcated with changing the name and is therefore removed to simplify the ARM templates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sample of parameters that are now removed:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &quot;versionset_5af9817ca656c6952416b779_name&quot;: {
      &quot;type&quot;: &quot;string&quot;,
      &quot;defaultValue&quot;: &quot;5af9817ca656c6952416b779&quot;
    },
    &quot;operations_GetSalesOrderById_name&quot;: {
      &quot;type&quot;: &quot;string&quot;,
      &quot;defaultValue&quot;: &quot;GetSalesOrderById&quot;
    },
    &quot;operations_policy_name&quot;: {
      &quot;type&quot;: &quot;string&quot;,
      &quot;defaultValue&quot;: &quot;policy&quot;
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;Exporting API’s ia the &lt;a href=&quot;https://github.com/MLogdberg/APIManagementARMTemplateCreator&quot;&gt;API Management Template Extractor&lt;/a&gt; simplifies the CI area of using API Management, here we can select a specific API and export only that API, with Operations, version sets, schemas, properties etc. Without needing to manually add extra work, making the development inside the portal and then just extracting the work and setup the import to the next environment .&lt;/p&gt;
</description>
                <link>/api-management/template-creator-updates-Aug-2018</link>
                <guid>/api-management/API Management Template Creator Updates</guid>
                <pubDate>2018-08-28T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>API Management Template Creator Updates May 2018</title>
                <description>&lt;p&gt;Updates on the &lt;a href=&quot;https://github.com/MLogdberg/APIManagementARMTemplateCreator&quot;&gt;API Management Template Creator&lt;/a&gt; has been dragging but now I’m pleased to have fixed the two most urgent ones.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Support for Versions, with version sets&lt;/li&gt;
  &lt;li&gt;Schemas&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;support-for-versions-with-version-sets&quot;&gt;Support for Versions, with Version Sets&lt;/h2&gt;
&lt;p&gt;If an API that is extracted has enabled the current versionset is also extracted and provided inside the ARM Template.
The version set states the version that is used and is needed byt the API to be able to support versions, it contains the information about how the verions is handled for the specific API.
The sample bellow is using a &lt;em&gt;HTTP header&lt;/em&gt; named &lt;strong&gt;API-Version&lt;/strong&gt; to set the version of the API, the version later is then set on the API itself.&lt;/p&gt;

&lt;p&gt;Read more in the documentation: &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/templates/microsoft.apimanagement/service/api-version-sets&quot;&gt;https://docs.microsoft.com/en-us/azure/templates/microsoft.apimanagement/service/api-version-sets &lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
      &quot;comments&quot;: &quot;Generated for resource /subscriptions/fake439-770d-43f3-9e4a-8b910457a10c/resourceGroups/API/providers/Microsoft.ApiManagement/service/dev/api-version-sets/5ae6f90fc96f5f1090700732&quot;,
      &quot;type&quot;: &quot;Microsoft.ApiManagement/service/api-version-sets&quot;,
      &quot;name&quot;: &quot;[concat(parameters(&apos;service_dev_name&apos;), &apos;/&apos; ,parameters(&apos;versionset_5ae6f90fc96f5f1090700732_name&apos;))]&quot;,
      &quot;apiVersion&quot;: &quot;2017-03-01&quot;,
      &quot;properties&quot;: {
        &quot;displayName&quot;: &quot;Arkivet&quot;,
        &quot;description&quot;: null,
        &quot;versioningScheme&quot;: &quot;Header&quot;,
        &quot;versionQueryName&quot;: null,
        &quot;versionHeaderName&quot;: &quot;API-Version&quot;
      },
      &quot;resources&quot;: [],
      &quot;dependsOn&quot;: []
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;support-for-schema&quot;&gt;Support for Schema&lt;/h2&gt;
&lt;p&gt;If an API has schemas added to oeprations these schemas will be extracted and added to the ARM template, all operations will also have a “dependsOn” to the specific schema to prevent errors when executing the ARM template.
The sample bellow is a simple schema that is added in the ARM template and referenced in the Operations section.&lt;/p&gt;

&lt;p&gt;Read more in the documentation: &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/templates/microsoft.apimanagement/service/apis/schemas&quot;&gt;https://docs.microsoft.com/en-us/azure/templates/microsoft.apimanagement/service/apis/schemas &lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
          &quot;comments&quot;: &quot;Generated for resource /subscriptions/fake439-770d-43f3-9e4a-8b910457a10c/resourceGroups/API/providers/Microsoft.ApiManagement/service/dev/apis/arkivet/schemas/5af038365b73730dd01453ad&quot;,
          &quot;type&quot;: &quot;Microsoft.ApiManagement/service/apis/schemas&quot;,
          &quot;name&quot;: &quot;[concat(parameters(&apos;service_dev_name&apos;),&apos;/&apos;,parameters(&apos;api_arkivet_name&apos;), &apos;/5af038365b73730dd01453ad&apos;)]&quot;,
          &quot;apiVersion&quot;: &quot;2017-03-01&quot;,
          &quot;properties&quot;: {
            &quot;contentType&quot;: &quot;application/vnd.ms-azure-apim.swagger.definitions+json&quot;,
            &quot;document&quot;: {
              &quot;definitions&quot;: {
                &quot;Body&quot;: {
                  &quot;type&quot;: &quot;object&quot;,
                  &quot;properties&quot;: {
                    &quot;No&quot;: {
                      &quot;type&quot;: &quot;string&quot;
                    },
                    &quot;ReportedDate&quot;: {
                      &quot;type&quot;: &quot;string&quot;,
                      &quot;format&quot;: &quot;date-time&quot;
                    }
                  }
                },
                &quot;BodyExists&quot;: {
                  &quot;type&quot;: &quot;object&quot;,
                  &quot;properties&quot;: {
                    &quot;CivicNo&quot;: {
                      &quot;type&quot;: &quot;string&quot;
                    }
                  }
                },
                &quot;Post400ApplicationJsonResponse&quot;: {
                  &quot;type&quot;: &quot;object&quot;,
                  &quot;properties&quot;: {
                    &quot;message&quot;: {
                      &quot;type&quot;: &quot;string&quot;
                    },
                    &quot;description&quot;: {
                      &quot;type&quot;: &quot;string&quot;
                    },
                    &quot;errors&quot;: {
                      &quot;type&quot;: &quot;array&quot;,
                      &quot;items&quot;: {
                        &quot;type&quot;: &quot;object&quot;,
                        &quot;properties&quot;: {
                          &quot;field&quot;: {
                            &quot;type&quot;: &quot;string&quot;
                          },
                          &quot;message&quot;: {
                            &quot;type&quot;: &quot;string&quot;
                          }
                        }
                      }
                    },
                    &quot;hasErrors&quot;: {
                      &quot;type&quot;: &quot;boolean&quot;
                    }
                  }
                },
                &quot;ExistsPost200ApplicationJsonResponse&quot;: {
                  &quot;type&quot;: &quot;object&quot;,
                  &quot;properties&quot;: {
                    &quot;arkivet&quot;: {
                      &quot;type&quot;: &quot;string&quot;
                    }
                  }
                }
              }
            }
          },
          &quot;resources&quot;: [],
          &quot;dependsOn&quot;: []
        }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;Exporting API’s ia the &lt;a href=&quot;https://github.com/MLogdberg/APIManagementARMTemplateCreator&quot;&gt;API Management Template Extractor&lt;/a&gt; simplifies the CI area of using API Management, here we can select a specific API and export only that API, with Operations, version sets, schemas, properties etc. Without needing to manually add extra work, making the development inside the portal and then just extracting the work and setup the import to the next environment .&lt;/p&gt;
</description>
                <link>/api-management/template-creator-updates-May-2018</link>
                <guid>/api-management/API Management Template Creator Updates</guid>
                <pubDate>2018-05-14T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Access AAD Secured Web API's from API Management</title>
                <description>&lt;p&gt;Protecting Web Apps and Web API’s by the built in &lt;em&gt;Authentication and authorization&lt;/em&gt; in Azure App Service is a great way to protect resources without adding code to handle the authorization. This means that the site or api is fully secure without the need of implementing it, which is a great example of seperation of concerns.
&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/app-service/app-service-authentication-overview&quot;&gt;Read more on how it works &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What we then need is to access the API and in this case we need to be able to access the API via  Management using &lt;em&gt;service principals&lt;/em&gt;  since the client using our API’s in API Management is outside our organization and should not be bothered by our internal security mechanisms.&lt;/p&gt;

&lt;p&gt;The scenario:
The API is protected by Azure AD and in order to access it we need to add a valid JWT token to the Auhtorization header in the request,
first(1) we need to get the JWT token and then(2) add it in the request to the API App.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/apim_to_api_app_protected.png&quot; alt=&quot;Scenario Overview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In this post we have used the standard generated API App from Visual Studio and published it to a Web API instances in Azure named &lt;strong&gt;Protected&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;enabling-the-built-in-security-authentication-and-authorization-to-the-apis&quot;&gt;Enabling the built in security Authentication and Authorization to the API’s&lt;/h2&gt;

&lt;p&gt;In the Azure Portal head to the API App and go in to the settings tab &lt;strong&gt;“Authentication/Authorization”&lt;/strong&gt;. Enable the App Service Authentication by pressing the &lt;em&gt;On&lt;/em&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/Enable_Authentaction_AppService.png&quot; alt=&quot;Enable Authentication/Ahithorization&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we can enable several diffrent providers and in this demo we will focus on the Azure Active Directory, press the Active Directory.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/Enable_Authentaction_AppService_providers.png&quot; alt=&quot;Configure Azure AD Athentication&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After chosing the Azure Active Directory, we are presented with 2 options to configure the Azure Active Directory setup. &lt;em&gt;Express&lt;/em&gt; gives some guidance and the possiblity to create or select an existing AD Application while in &lt;em&gt;Advance&lt;/em&gt; we can write in the values needed, the AAD Application clientid and the issuer, normaly &lt;em&gt;https://sts.windows.net/{tenantguid}/&lt;/em&gt; followed by the tenat guid URL. 
In this setup we will use the &lt;em&gt;Express&lt;/em&gt; option and create a new AD Application.&lt;/p&gt;

&lt;p&gt;Here we can choose to use an existing AD Application or create a new one, I will create a new one named &lt;em&gt;ProtectedAppAAD&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/Enable_Authentaction_AppService_new_aad_app.png&quot; alt=&quot;New Azure AD App&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After this is installed we can now save and test that the API is protected. If you open a new browser or log out from the account you should be forced to login and the site is now secured.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/Enable_Authentaction_AppService_login_sign.png&quot; alt=&quot;Login Sign&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So now the site is securely protected and we can access it when logged in, now we need to be able to access the API via API Managamenet.&lt;/p&gt;

&lt;h2 id=&quot;provide-access-to-the-api&quot;&gt;Provide access to the API&lt;/h2&gt;
&lt;p&gt;So the API is now protected and we need to provide a way for API Management to access it, we will need to use another AAD Application (App Registration) and provide access to the &lt;em&gt;ProtectedAppAAD&lt;/em&gt;. So we need to create a new Application, named &lt;em&gt;APIManagementAADApp&lt;/em&gt;, the sign in URL can be &lt;em&gt;http://localhost&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/create_apimanagement_aadapp.png&quot; alt=&quot;Create a new AAD Application&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After the AAD application is created we need to provide access to the &lt;em&gt;ProtectedAppAAD&lt;/em&gt; this is done via permissions; to assign permissions go to &lt;em&gt;Settings&lt;/em&gt;, press &lt;em&gt;Required Permissions&lt;/em&gt; and &lt;em&gt;Add&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/aadapp_assign_premissions.png&quot; alt=&quot;AAD Application add permission&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Under &lt;em&gt;Select an API&lt;/em&gt; we need to search for &lt;em&gt;ProtectedAppAAD&lt;/em&gt; since first the list only shows Microsoft Standard API’s. Enter the &lt;em&gt;ProtectedAppAAD&lt;/em&gt; in the text box and press &lt;em&gt;Select&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/aadapp_assign_premissions_select_api.png&quot; alt=&quot;AAD Application add permission select API&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we need to select the permission and the one we want is Access, select it and press &lt;em&gt;Select&lt;/em&gt;, finish the setup by press &lt;em&gt;Done&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/aadapp_assign_premissions_select_premission.png&quot; alt=&quot;AAD Application add permission select API&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Last step is pressing the &lt;strong&gt;Grant Permissions&lt;/strong&gt; to enable the permissions &lt;strong&gt;(do not forget this!)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/aadapp_assign_premissions_grant.png&quot; alt=&quot;AAD Application add permission select API&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;api-management-policy-for-aquiring-jwt-token&quot;&gt;API Management Policy for Aquiring JWT Token&lt;/h2&gt;
&lt;p&gt;In order to be able to expose this API we need to get a token from AAD using the Application, this will be done inside a policy and luckily for us the API Management team has provided a set of code snippets at GitHub and one of these is doing exactly that,  &lt;a href=&quot;https://github.com/Azure/api-management-policy-snippets/blob/master/Snippets/Get%20OAuth2%20access%20token%20from%20AAD%20and%20forward%20it%20to%20the%20backend.xml&quot;&gt;get it here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is more of them at the repository in GitHub and if you have a great snippet that you want to share you can add a Pull Request and if the team approves it. it will end up there. Here is the GitHub repository, https://github.com/Azure/api-management-policy-snippets/blob/master/Snippets/.&lt;/p&gt;

&lt;p&gt;The Get OAuth2 access token from AAD snipet looks like this.&lt;/p&gt;
&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- The policy defined in this file provides an example of using OAuth2 for authorization between the gateway and a backend. --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- It shows how to obtain an access token from AAD and forward it to the backend. --&amp;gt;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Send request to AAD to obtain a bearer token --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Parameters: authorizationServer - format https://login.windows.net/TENANT-GUID/oauth2/token --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Parameters: scope - a URI encoded scope value --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Parameters: clientId - an id obtained during app registration --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Parameters: clientSecret - a URL encoded secret, obtained during app registration --&amp;gt;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Copy the following snippet into the inbound section. --&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;policies&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;inbound&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;base&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;send-request&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ignore-error=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;timeout=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;20&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;response-variable-name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bearerToken&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;mode=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;new&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;set-url&amp;gt;&amp;lt;/set-url&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;set-method&amp;gt;&lt;/span&gt;POST&lt;span class=&quot;nt&quot;&gt;&amp;lt;/set-method&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;set-header&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;exists-action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;override&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;value&amp;gt;&lt;/span&gt;application/x-www-form-urlencoded&lt;span class=&quot;nt&quot;&gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/set-header&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;set-body&amp;gt;&lt;/span&gt;
          @{
          return &quot;client_id=&lt;span class=&quot;ni&quot;&gt;&amp;amp;resource=&amp;amp;client_secret=&amp;amp;grant_type=client_credentials&quot;;&lt;/span&gt;
          }
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/set-body&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/send-request&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;set-header&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Authorization&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;exists-action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;override&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;value&amp;gt;&lt;/span&gt;
          @(&quot;Bearer &quot; + (String)((IResponse)context.Variables[&quot;bearerToken&quot;]).Body.As&lt;span class=&quot;nt&quot;&gt;&amp;lt;JObject&amp;gt;&lt;/span&gt;()[&quot;access_token&quot;])
	  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/set-header&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;c&quot;&gt;&amp;lt;!--  Don&apos;t expose APIM subscription key to the backend. --&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;set-header&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;exists-action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;delete&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Ocp-Apim-Subscription-Key&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/inbound&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;backend&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;base&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/backend&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;outbound&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;base&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/outbound&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;on-error&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;base&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/on-error&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/policies&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The way it works is that two things happen before we send the request to the backend.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;First a request in the &lt;strong&gt;send-request&lt;/strong&gt; action is made to the AAD tenant and aquiring a token.&lt;/li&gt;
  &lt;li&gt;The &lt;strong&gt;set-header&lt;/strong&gt; action is adding the token in the Authroization header, by extracting it from the result from the first request.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But before we can add this snippet to our API we need to add a few values to the &lt;strong&gt;Named Values&lt;/strong&gt; section in our API Management instance.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;authorizationServer - the tenant URL
My tenant ID is &lt;em&gt;1cb87777-3df4-428b-811a-86a0f215cd35&lt;/em&gt; so the URL then is &lt;em&gt;https://login.microsoftonline.com/1cb87777-3df4-428b-811a-86a0f215cd35/oauth2/token&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;clientId - the Application id of our AAD Application in this case of &lt;em&gt;APIManagementAADApp&lt;/em&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;img src=&quot;/assets/uploads/2018/03/aadapp_get_Application_id_apim.png&quot; alt=&quot;AAD Application id APIManagementAADApp&quot; /&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;clientSecret - the key to our AAD Application in this case of &lt;em&gt;APIManagementAADApp&lt;/em&gt;
    &lt;ul&gt;
      &lt;li&gt;Create a new key  &lt;img src=&quot;/assets/uploads/2018/03/aadapp_get_Application_key.png&quot; alt=&quot;Create AAD Application key APIManagementAADApp&quot; /&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;scope - the AAD Application id of the AAD Application that is protecting our resource, in this case the id of &lt;em&gt;ProtectedAppAAD&lt;/em&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;img src=&quot;/assets/uploads/2018/03/aadapp_get_Application_id.png&quot; alt=&quot;AAD Application id ProtectedAppAAD&quot; /&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After adding these the &lt;strong&gt;Named Values&lt;/strong&gt; section of our API Managemet will end up looking like this.
Make sure to add these before adding the policy, since the policy canno be saved if the referenced &lt;em&gt;Named Value&lt;/em&gt; dosen’t exist.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/named_values.png&quot; alt=&quot;AAD Application id ProtectedAppAAD&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we just need to add the policy to our API and we will be able to access the protected API, after the &lt;em&gt;Policy&lt;/em&gt; is saved test it and you should now recieve the result from the API.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/result.png&quot; alt=&quot;AAD Application id ProtectedAppAAD&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;Todays solutions almost always accesses other resurces and when building this landscape we need to make sure that all parts are protected and secure, often even we need to combine a few of them to be compliant with requirments from customers. In this post I showed how to use one of the built in security from Web Apps with AAD that can be used standalone or as an extra layer of security above the “standard”  Basic, Oauth, API keys, Certificates etc. authentications. Another benefit is that is not part of the code so it’s not possible to “forgett” or accidently removed in a bug fix or similar.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/03/apim_to_api_app_protected.png&quot; alt=&quot;AAD Application id ProtectedAppAAD&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As a bonus the API Management Snippets is a really nice initiative with pre created advanced snippets so make sure to check this out.&lt;/p&gt;

&lt;p&gt;https://github.com/Azure/api-management-policy-snippets/blob/master/Snippets/&lt;/p&gt;
</description>
                <link>/api-management/access-secured-web-apis</link>
                <guid>/api-management/API-Management-To-Protected-API-APP</guid>
                <pubDate>2018-03-07T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Logic App Custom Connector WSDL Tips</title>
                <description>&lt;p&gt;So continue my journey with the &lt;strong&gt;Logic Apps Custom Connector&lt;/strong&gt; and this time we are doing some work with the WSDL part of the &lt;strong&gt;Logic Apps Custom Connector&lt;/strong&gt; and I thought I would share some tips and trix I’ve learned and are using when importing and using Connectors with WSDL.
Since the only way to be a good user of a resource like the &lt;em&gt;Custom Connector&lt;/em&gt; is to understand how we can investigate behaviors, tweak and fix problems and find debug/logs.&lt;/p&gt;

&lt;h2 id=&quot;import-error&quot;&gt;Import Error&lt;/h2&gt;
&lt;p&gt;There are several reasons why there will be errors when importing the WSDL and since it’s API Management functionality we can (until documentation is up to speed) see the limits on the API Management site:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/api-management/api-management-api-import-restrictions#wsdl&quot;&gt;https://docs.microsoft.com/en-us/azure/api-management/api-management-api-import-restrictions#wsdl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I encountered the “rare” error with recursive objects, apparently there where a “lazy” coder that just referenced the whole entity in a parent child situation even if the only “needed” field was the &lt;em&gt;ID&lt;/em&gt;. Anyway removing the recursive element solves the problem,alternatively manipulating the representation could have been done.&lt;/p&gt;

&lt;h2 id=&quot;runtime-problems-unexpected-behaviors-and-errors-from-the-backend-system&quot;&gt;Runtime problems, unexpected behaviors and errors from the backend system&lt;/h2&gt;
&lt;p&gt;So there are many reasons why there can be errors sent from the backend system but one of the common ones I’ve found is &lt;em&gt;System.FormatException: Input string was not in a correct format&lt;/em&gt; and that is due to a element specified as &lt;em&gt;int&lt;/em&gt; and the value sent in is &lt;strong&gt;null&lt;/strong&gt;. Now how can that be a problem?
Since the generation is done by the same logic as in API Management we can import the WSDL in API Management and see how the actual &lt;em&gt;liquid&lt;/em&gt; template looks like.&lt;/p&gt;

&lt;p&gt;Let’s look at an example.&lt;/p&gt;

&lt;p&gt;With a system I’m sent a link to the WSDL and a sample this to easy integrate with them, testing the sample works fine but importing the WSDL provides alot more than the sample as we are used to there are more fields than we need. So sending in the test file via &lt;em&gt;postman&lt;/em&gt; works good but the connector does not work.
Let’s take a look why, bellow is the sample a fairly easy message with few elements.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;soap:Envelope xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd=&quot;http://www.w3.org/2001/XMLSchema&quot; xmlns:soap=&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;&amp;gt;
  &amp;lt;soap:Body&amp;gt;
    &amp;lt;ProcessArticle xmlns=&quot;http://ongoingsystems.se/WSI&quot;&amp;gt;
      &amp;lt;GoodsOwnerCode&amp;gt;code1234&amp;lt;/GoodsOwnerCode&amp;gt;
      &amp;lt;UserName&amp;gt;user1234&amp;lt;/UserName&amp;gt;
      &amp;lt;Password&amp;gt;pass1234&amp;lt;/Password&amp;gt;
      &amp;lt;art&amp;gt;
        &amp;lt;ArticleOperation&amp;gt;CreateOrUpdate&amp;lt;/ArticleOperation&amp;gt;
        &amp;lt;ArticleIdentification&amp;gt;ArticleNumber&amp;lt;/ArticleIdentification&amp;gt;
        &amp;lt;ArticleNumber&amp;gt;6553173735310&amp;lt;/ArticleNumber&amp;gt;
		&amp;lt;ArticleName&amp;gt;Display Stand&amp;lt;/ArticleName&amp;gt;
        &amp;lt;ArticleDescription&amp;gt;Display Stand&amp;lt;/ArticleDescription&amp;gt;
        &amp;lt;ArticleUnitCode&amp;gt;St&amp;lt;/ArticleUnitCode&amp;gt;
        &amp;lt;IsStockArticle&amp;gt;1&amp;lt;/IsStockArticle&amp;gt;
      &amp;lt;/art&amp;gt;
    &amp;lt;/ProcessArticle&amp;gt;
  &amp;lt;/soap:Body&amp;gt;
&amp;lt;/soap:Envelope&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;But when using the &lt;em&gt;Custom Connector&lt;/em&gt; all the complex structures are mapped: (this is generated via API Management):&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &amp;lt;set-body template=&quot;liquid&quot;&amp;gt;
			&amp;lt;soap:Envelope xmlns:soap=&quot;http://schemas.xmlsoap.org/soap/envelope/&quot; xmlns=&quot;http://ongoingsystems.se/WSI&quot;&amp;gt;
				&amp;lt;soap:Body&amp;gt;
					&amp;lt;ProcessArticle&amp;gt;
						&amp;lt;GoodsOwnerCode&amp;gt;&amp;lt;/GoodsOwnerCode&amp;gt;
						&amp;lt;UserName&amp;gt;&amp;lt;/UserName&amp;gt;
						&amp;lt;Password&amp;gt;&amp;lt;/Password&amp;gt;
						&amp;lt;art&amp;gt;
							&amp;lt;ArticleOperation&amp;gt;&amp;lt;/ArticleOperation&amp;gt;
							&amp;lt;ArticleIdentification&amp;gt;&amp;lt;/ArticleIdentification&amp;gt;
							&amp;lt;ArticleSystemId&amp;gt;&amp;lt;/ArticleSystemId&amp;gt;
							&amp;lt;ArticleNumber&amp;gt;&amp;lt;/ArticleNumber&amp;gt;
							&amp;lt;ArticleName&amp;gt;&amp;lt;/ArticleName&amp;gt;
							&amp;lt;ProductCode&amp;gt;&amp;lt;/ProductCode&amp;gt;
							&amp;lt;BarCode&amp;gt;&amp;lt;/BarCode&amp;gt;
							&amp;lt;SupplierArticleNumber&amp;gt;&amp;lt;/SupplierArticleNumber&amp;gt;
							&amp;lt;ArticleDescription&amp;gt;&amp;lt;/ArticleDescription&amp;gt;
							&amp;lt;ArticleUnitCode&amp;gt;&amp;lt;/ArticleUnitCode&amp;gt;
							&amp;lt;CountryOfOriginCode&amp;gt;&amp;lt;/CountryOfOriginCode&amp;gt;
							&amp;lt;StatisticsNumber&amp;gt;&amp;lt;/StatisticsNumber&amp;gt;
							&amp;lt;PurchaseCurrencyCode&amp;gt;&amp;lt;/PurchaseCurrencyCode&amp;gt;
							&amp;lt;Weight&amp;gt;&amp;lt;/Weight&amp;gt;
							&amp;lt;NetWeight&amp;gt;&amp;lt;/NetWeight&amp;gt;
							&amp;lt;Volume&amp;gt;&amp;lt;/Volume&amp;gt;
							&amp;lt;Length&amp;gt;&amp;lt;/Length&amp;gt;
							&amp;lt;Width&amp;gt;&amp;lt;/Width&amp;gt;
							&amp;lt;Height&amp;gt;&amp;lt;/Height&amp;gt;
							&amp;lt;QuantityPerPallet&amp;gt;&amp;lt;/QuantityPerPallet&amp;gt;
							&amp;lt;QuantityPerPackage&amp;gt;&amp;lt;/QuantityPerPackage&amp;gt;
							&amp;lt;OrderPoint&amp;gt;&amp;lt;/OrderPoint&amp;gt;
							&amp;lt;Price&amp;gt;&amp;lt;/Price&amp;gt;
							&amp;lt;CustomerPrice&amp;gt;&amp;lt;/CustomerPrice&amp;gt;
							&amp;lt;PurchasePrice&amp;gt;&amp;lt;/PurchasePrice&amp;gt;
							&amp;lt;IsStockArticle&amp;gt;&amp;lt;/IsStockArticle&amp;gt;
							&amp;lt;ArticleGroup&amp;gt;
								&amp;lt;ArticleGroupOperation&amp;gt;&amp;lt;/ArticleGroupOperation&amp;gt;
								&amp;lt;ArticleGroupIdentification&amp;gt;&amp;lt;/ArticleGroupIdentification&amp;gt;
								&amp;lt;ArticleGroupCode&amp;gt;&amp;lt;/ArticleGroupCode&amp;gt;
								&amp;lt;ArticleGroupName&amp;gt;&amp;lt;/ArticleGroupName&amp;gt;
							&amp;lt;/ArticleGroup&amp;gt;
							&amp;lt;ArticleCategory&amp;gt;
								&amp;lt;TypeOperation&amp;gt;&amp;lt;/TypeOperation&amp;gt;
								&amp;lt;TypeIdentification&amp;gt;&amp;lt;/TypeIdentification&amp;gt;
								&amp;lt;Code&amp;gt;&amp;lt;/Code&amp;gt;
								&amp;lt;Name&amp;gt;&amp;lt;/Name&amp;gt;
							&amp;lt;/ArticleCategory&amp;gt;
							&amp;lt;VatCode&amp;gt;
								&amp;lt;VatCodeOperation&amp;gt;&amp;lt;/VatCodeOperation&amp;gt;
								&amp;lt;VatCodeIdentification&amp;gt;&amp;lt;/VatCodeIdentification&amp;gt;
								&amp;lt;VatCode&amp;gt;&amp;lt;/VatCode&amp;gt;
								&amp;lt;VatPercent&amp;gt;&amp;lt;/VatPercent&amp;gt;
							&amp;lt;/VatCode&amp;gt;
							&amp;lt;DangerousGoods&amp;gt;
								&amp;lt;UNNumber&amp;gt;&amp;lt;/UNNumber&amp;gt;
								&amp;lt;UNIsMarineHazard&amp;gt;&amp;lt;/UNIsMarineHazard&amp;gt;
								&amp;lt;UNIsDangerousGoods&amp;gt;&amp;lt;/UNIsDangerousGoods&amp;gt;
								&amp;lt;UNPackageType&amp;gt;&amp;lt;/UNPackageType&amp;gt;
								&amp;lt;UNTunnelCodes&amp;gt;
&amp;lt;/UNTunnelCodes&amp;gt;
								&amp;lt;UNClassNumber&amp;gt;&amp;lt;/UNClassNumber&amp;gt;
								&amp;lt;UNProperShippingName&amp;gt;
									&amp;lt;Name&amp;gt;&amp;lt;/Name&amp;gt;
									&amp;lt;LanguageCode&amp;gt;&amp;lt;/LanguageCode&amp;gt;
								&amp;lt;/UNProperShippingName&amp;gt;
								&amp;lt;UNLabelNumbers&amp;gt;&amp;lt;/UNLabelNumbers&amp;gt;
								&amp;lt;DangerousGoodsCoefficient&amp;gt;&amp;lt;/DangerousGoodsCoefficient&amp;gt;
								&amp;lt;EmSCode&amp;gt;&amp;lt;/EmSCode&amp;gt;
							&amp;lt;/DangerousGoods&amp;gt;
							&amp;lt;ArticleNames&amp;gt;
&amp;lt;/ArticleNames&amp;gt;
							&amp;lt;ArticleStructureSpecification&amp;gt;
&amp;lt;/ArticleStructureSpecification&amp;gt;
							&amp;lt;MainSupplier&amp;gt;
								&amp;lt;SupplierIdentificationType&amp;gt;&amp;lt;/SupplierIdentificationType&amp;gt;
								&amp;lt;SupplierOperation&amp;gt;&amp;lt;/SupplierOperation&amp;gt;
								&amp;lt;SupplierNumber&amp;gt;&amp;lt;/SupplierNumber&amp;gt;
								&amp;lt;SupplierName&amp;gt;&amp;lt;/SupplierName&amp;gt;
								&amp;lt;Address&amp;gt;
									&amp;lt;Name&amp;gt;&amp;lt;/Name&amp;gt;
									&amp;lt;Address&amp;gt;&amp;lt;/Address&amp;gt;
									&amp;lt;Address2&amp;gt;&amp;lt;/Address2&amp;gt;
									&amp;lt;Address3&amp;gt;&amp;lt;/Address3&amp;gt;
									&amp;lt;PostCode&amp;gt;&amp;lt;/PostCode&amp;gt;
									&amp;lt;City&amp;gt;&amp;lt;/City&amp;gt;
									&amp;lt;TelePhone&amp;gt;&amp;lt;/TelePhone&amp;gt;
									&amp;lt;Remark&amp;gt;&amp;lt;/Remark&amp;gt;
									&amp;lt;Email&amp;gt;&amp;lt;/Email&amp;gt;
									&amp;lt;MobilePhone&amp;gt;&amp;lt;/MobilePhone&amp;gt;
									&amp;lt;IsEuCountry&amp;gt;&amp;lt;/IsEuCountry&amp;gt;
									&amp;lt;CountryStateCode&amp;gt;&amp;lt;/CountryStateCode&amp;gt;
									&amp;lt;CountryCode&amp;gt;&amp;lt;/CountryCode&amp;gt;
									&amp;lt;DeliveryInstruction&amp;gt;&amp;lt;/DeliveryInstruction&amp;gt;
									&amp;lt;IsVisible&amp;gt;&amp;lt;/IsVisible&amp;gt;
									&amp;lt;NotifyBySMS&amp;gt;&amp;lt;/NotifyBySMS&amp;gt;
									&amp;lt;NotifyByEmail&amp;gt;&amp;lt;/NotifyByEmail&amp;gt;
									&amp;lt;NotifyByTelephone&amp;gt;&amp;lt;/NotifyByTelephone&amp;gt;
								&amp;lt;/Address&amp;gt;
								&amp;lt;comment&amp;gt;&amp;lt;/comment&amp;gt;
							&amp;lt;/MainSupplier&amp;gt;
							&amp;lt;IsGSPCertified&amp;gt;&amp;lt;/IsGSPCertified&amp;gt;
							&amp;lt;MaxStockDays&amp;gt;&amp;lt;/MaxStockDays&amp;gt;
							&amp;lt;BarCodePackage&amp;gt;&amp;lt;/BarCodePackage&amp;gt;
							&amp;lt;LinkToPicture&amp;gt;&amp;lt;/LinkToPicture&amp;gt;
							&amp;lt;BarCodePallet&amp;gt;&amp;lt;/BarCodePallet&amp;gt;
							&amp;lt;QuantityPerLayer&amp;gt;&amp;lt;/QuantityPerLayer&amp;gt;
							&amp;lt;PalletHeight&amp;gt;&amp;lt;/PalletHeight&amp;gt;
							&amp;lt;TaricNumbers&amp;gt;
&amp;lt;/TaricNumbers&amp;gt;
							&amp;lt;IsObsolete&amp;gt;&amp;lt;/IsObsolete&amp;gt;
							&amp;lt;MinDaysToExpiryDate&amp;gt;&amp;lt;/MinDaysToExpiryDate&amp;gt;
							&amp;lt;AdditionalStatisticsNumber&amp;gt;&amp;lt;/AdditionalStatisticsNumber&amp;gt;
							&amp;lt;CustomsExportConditions&amp;gt;&amp;lt;/CustomsExportConditions&amp;gt;
							&amp;lt;ArticleColor&amp;gt;
								&amp;lt;ColorCode&amp;gt;&amp;lt;/ColorCode&amp;gt;
								&amp;lt;ColorName&amp;gt;&amp;lt;/ColorName&amp;gt;
							&amp;lt;/ArticleColor&amp;gt;
							&amp;lt;ArticleSize&amp;gt;
								&amp;lt;SizeCode&amp;gt;&amp;lt;/SizeCode&amp;gt;
								&amp;lt;SizeName&amp;gt;&amp;lt;/SizeName&amp;gt;
							&amp;lt;/ArticleSize&amp;gt;
							&amp;lt;IsSerialNumberArticle&amp;gt;&amp;lt;/IsSerialNumberArticle&amp;gt;
							&amp;lt;IsBatchArticle&amp;gt;&amp;lt;/IsBatchArticle&amp;gt;
							&amp;lt;ArticleDefinitionClasses&amp;gt;
								&amp;lt;ArticleDefinitionClassesOperation&amp;gt;&amp;lt;/ArticleDefinitionClassesOperation&amp;gt;
								&amp;lt;Classes&amp;gt;
&amp;lt;/Classes&amp;gt;
							&amp;lt;/ArticleDefinitionClasses&amp;gt;
							&amp;lt;ArticleFreeDecimal1&amp;gt;&amp;lt;/ArticleFreeDecimal1&amp;gt;
							&amp;lt;ArticleFreeDecimal2&amp;gt;&amp;lt;/ArticleFreeDecimal2&amp;gt;
						&amp;lt;/art&amp;gt;
					&amp;lt;/ProcessArticle&amp;gt;
				&amp;lt;/soap:Body&amp;gt;
			&amp;lt;/soap:Envelope&amp;gt;
		&amp;lt;/set-body&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And we start running in to problems due to the fact that we are not sending in more data than earlier but the generated xml is much larger and just look at the enormous representation in the GUI:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/02/LogicAppCustomConnectorBeforeEdit.png&quot; alt=&quot;Unmodified Connector in GUI&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Therefore we get  some unwanted errors since there are some implications added when sending in starts kin complex structures, since I can’t really do much about the Logic I need to modify the data sent in, but I can modify the WSDL and reimport it.
So after changing the WSDL to only contain the elements that I needed in my request it looks alot better and the xml message sent are now matching the sample:&lt;/p&gt;

&lt;p&gt;Modified definition in the WSDL so the definition is minimal:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;s:complexType name=&quot;ArticleDefinition&quot;&amp;gt;
        &amp;lt;s:sequence&amp;gt;
          &amp;lt;s:element minOccurs=&quot;1&quot; maxOccurs=&quot;1&quot; name=&quot;ArticleOperation&quot; type=&quot;tns:ArticleOperation&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;1&quot; maxOccurs=&quot;1&quot; name=&quot;ArticleIdentification&quot; type=&quot;tns:ArticleIdentificationType&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;0&quot; maxOccurs=&quot;1&quot; name=&quot;ArticleNumber&quot; type=&quot;s:string&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;0&quot; maxOccurs=&quot;1&quot; name=&quot;ArticleName&quot; type=&quot;s:string&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;0&quot; maxOccurs=&quot;1&quot; name=&quot;ArticleDescription&quot; type=&quot;s:string&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;0&quot; maxOccurs=&quot;1&quot; name=&quot;ArticleUnitCode&quot; type=&quot;s:string&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;1&quot; maxOccurs=&quot;1&quot; name=&quot;IsStockArticle&quot; nillable=&quot;true&quot; type=&quot;s:boolean&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;0&quot; maxOccurs=&quot;1&quot; name=&quot;Weight&quot; type=&quot;s:decimal&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;0&quot; maxOccurs=&quot;1&quot; name=&quot;NetWeight&quot; type=&quot;s:decimal&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;0&quot; maxOccurs=&quot;1&quot; name=&quot;Volume&quot; type=&quot;s:decimal&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;0&quot; maxOccurs=&quot;1&quot; name=&quot;Length&quot; type=&quot;s:decimal&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;0&quot; maxOccurs=&quot;1&quot; name=&quot;Width&quot; type=&quot;s:decimal&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;0&quot; maxOccurs=&quot;1&quot; name=&quot;Height&quot; type=&quot;s:decimal&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;0&quot; maxOccurs=&quot;1&quot; name=&quot;QuantityPerPallet&quot; type=&quot;s:int&quot; /&amp;gt;
          &amp;lt;s:element minOccurs=&quot;0&quot; maxOccurs=&quot;1&quot; name=&quot;QuantityPerPackage&quot; type=&quot;s:int&quot; /&amp;gt;
        &amp;lt;/s:sequence&amp;gt;
      &amp;lt;/s:complexType&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Sample from the GUI:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2018/02/LogicAppCustomConnectorEdited.png&quot; alt=&quot;Unmodified Connector in GUI&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The request can now be sent to the backend without any problems.
This approach can be used to both detect problems and also understand the behavior of the &lt;strong&gt;Custom Connector&lt;/strong&gt; and changeing the WSDL can help us to easier use the Connector even if the maintainance is heavier and we need to keep track of these changes and do the again if a update WSDL would be imported.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;As stated we need to find the ways of understanding the resource before beeing good users of it, so I hope this will help out and give ideas around workarounds for some troublesome scenarios and that more debug and customization properties is coming along the way.
When more power is needed I would advise using API Management for now until there is more customization properties but most of the time it works like a charm!&lt;/p&gt;

</description>
                <link>/logicapps/custom-connector-wsdl-tips</link>
                <guid>/logicapps/Logic App Custom Connector Tips</guid>
                <pubDate>2018-02-02T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>CI with Logic App Custom Connector</title>
                <description>&lt;p&gt;Just had some fortune to work with some projects using the &lt;strong&gt;Logic App Custom Connector&lt;/strong&gt; it’s alot of fun now with all new capabilites on prem connectivity and all and as allways we end upp with setting up CI deployments via TFS.&lt;/p&gt;

&lt;p&gt;That is when I found that the &lt;em&gt;On Prem Data Gateway&lt;/em&gt; &lt;strong&gt;ARM template&lt;/strong&gt; is poorly documented and the generated template from &lt;em&gt;automation script&lt;/em&gt; are missing some important properties.
So I thought I’ll gather the information needed here, provide som pitfalls and so on.&lt;/p&gt;

&lt;p&gt;The schema for the ARM template can be found at GitHub: &lt;a href=&quot;https://github.com/Azure/azure-resource-manager-schemas/blob/master/schemas/2016-06-01/Microsoft.Web.json&quot;&gt;https://github.com/Azure/azure-resource-manager-schemas/blob/master/schemas/2016-06-01/Microsoft.Web.json&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It’s inside the Web schema and not that &lt;em&gt;“easy”&lt;/em&gt; to get that you are in the correct definition but go down to row 119  and you find the &lt;strong&gt;customApis&lt;/strong&gt; part, this is good for reference.&lt;/p&gt;

&lt;p&gt;So  let’s see how a ARM template for the &lt;strong&gt;On Premise Data Gateway&lt;/strong&gt; looks like when complete: ( I’m actually adding a fully working connector for &lt;a href=&quot;https://billogram.com/&quot;&gt;https://billogram.com/&lt;/a&gt;)
The full represenatation of the swagger can also be found at my GitHub repository &lt;a href=&quot;https://github.com/MLogdberg/LogicAppCustomConnectors/tree/master/Billogram&quot;&gt;https://github.com/MLogdberg/LogicAppCustomConnectors/tree/master/Billogram&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;$schema&quot;: &quot;https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#&quot;,
  &quot;contentVersion&quot;: &quot;1.0.0.0&quot;,
  &quot;parameters&quot;: {
    &quot;customApis_name&quot;: {
      &quot;defaultValue&quot;: &quot;Billogram&quot;,
      &quot;type&quot;: &quot;String&quot;
    },
    &quot;location&quot;: {
      &quot;defaultValue&quot;: &quot;westeurope&quot;,
      &quot;type&quot;: &quot;String&quot;
    },
    &quot;serviceUrl&quot;: {
      &quot;defaultValue&quot;: &quot;https://sandbox.billogram.com/api/v2&quot;,
      &quot;type&quot;: &quot;String&quot;
    }
  },
  &quot;variables&quot;: {},
  &quot;resources&quot;: [
    {
      &quot;type&quot;: &quot;Microsoft.Web/customApis&quot;,
      &quot;name&quot;: &quot;[parameters(&apos;customApis_name&apos;)]&quot;,
      &quot;apiVersion&quot;: &quot;2016-06-01&quot;,
      &quot;location&quot;: &quot;[parameters(&apos;location&apos;)]&quot;,
      &quot;properties&quot;: {
        &quot;connectionParameters&quot;: {
          &quot;username&quot;: {
            &quot;type&quot;: &quot;securestring&quot;,
            &quot;uiDefinition&quot;: {
              &quot;displayName&quot;: &quot;API USer&quot;,
              &quot;description&quot;: &quot;The API User for this api&quot;,
              &quot;tooltip&quot;: &quot;Provide the API User&quot;,
              &quot;constraints&quot;: {
                &quot;tabIndex&quot;: 2,
                &quot;clearText&quot;: true,
                &quot;required&quot;: &quot;true&quot;
              }
            }
          },
          &quot;password&quot;: {
            &quot;type&quot;: &quot;securestring&quot;,
            &quot;uiDefinition&quot;: {
              &quot;displayName&quot;: &quot;API Password&quot;,
              &quot;description&quot;: &quot;The API Password for this api&quot;,
              &quot;tooltip&quot;: &quot;Provide the API Apssword&quot;,
              &quot;constraints&quot;: {
                &quot;tabIndex&quot;: 3,
                &quot;clearText&quot;: false,
                &quot;required&quot;: &quot;true&quot;
              }
            }
          }
        },
        &quot;backendService&quot;: {
          &quot;serviceUrl&quot;: &quot;[parameters(&apos;serviceUrl&apos;)]&quot;
        },
        &quot;swagger&quot;: {
          &quot;swagger&quot;: &quot;2.0&quot;,
          &quot;info&quot;: {
            &quot;description&quot;: &quot;The Billogram API is built according to RESTful principles, which means it uses HTTP as an application protocol rather than just as a transport layer for a custom protocol, like SOAP does. In other words, HTTP features such as the various request types (GET, PUT, POST, DELETE), response codes (403 Forbidden, 404 Not Found, 500 Internal Server Error) and standard headers (Accept, Authorization, Cache-Control) are a part of the API.&quot;,
            &quot;version&quot;: &quot;1.0.0&quot;,
            &quot;title&quot;: &quot;Swagger Invoice/Billogram&quot;,
            &quot;termsOfService&quot;: &quot;http://swagger.io/terms/&quot;,
            &quot;contact&quot;: {
              &quot;email&quot;: &quot;billogram@billogram.se&quot;
            }
          },
          &quot;host&quot;: &quot;sandbox.billogram.com&quot;,
          &quot;basePath&quot;: &quot;/api/v2&quot;,
          &quot;schemes&quot;: [
            &quot;https&quot;
          ],
          &quot;consumes&quot;: [],
          &quot;produces&quot;: [],
          &quot;paths&quot;: {
            ...removed for simplicity display...
              }
            }
          },
          &quot;parameters&quot;: {},
          &quot;responses&quot;: {},
          &quot;securityDefinitions&quot;: {
            &quot;basic_auth&quot;: {
              &quot;type&quot;: &quot;basic&quot;
            }
          },
          &quot;security&quot;: [
            {
              &quot;basic_auth&quot;: []
            }
          ],
          &quot;tags&quot;: [
            {
              &quot;name&quot;: &quot;Billogram Invoice&quot;,
              &quot;description&quot;: &quot;Handling Billogram/Invoices&quot;,
              &quot;externalDocs&quot;: {
                &quot;description&quot;: &quot;Billogram structure&quot;,
                &quot;url&quot;: &quot;https://billogram.com/api/documentation#billogram_structure&quot;
              }
            }
          ],
          &quot;externalDocs&quot;: {
            &quot;description&quot;: &quot;Find out more about Swagger&quot;,
            &quot;url&quot;: &quot;http://swagger.io&quot;
          }
        },
        &quot;description&quot;: &quot;My ARM deployed Custom Connector&quot;,
        &quot;displayName&quot;: &quot;[parameters(&apos;customApis_name&apos;)]&quot;,
        &quot;iconUri&quot;: &quot;/Content/retail/assets/default-connection-icon.6296199fc1d74aa45ca68e1253762025.2.svg&quot;
      },
      &quot;dependsOn&quot;: []
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Make sure to add both the swagger &lt;strong&gt;and&lt;/strong&gt; the &lt;strong&gt;backendService&lt;/strong&gt; object since the url specified in the &lt;strong&gt;serviceUrl&lt;/strong&gt; since this is mandator and the URL that the Custom Connector are using during runtime, not the one specified in the swagger, this is good for easier management of dev/test/prod environments.&lt;/p&gt;

&lt;p&gt;The Custom Connector is a great addon to Logic Apps and by been able to easily manage and deploy them is crusial, so even if this is great to be able to manage my Custom Connector via ARM I’m still missing the possibility to reference my swagger via a url since that would be most suitable way of deploying and kkeping the ARM template and swagger separated.&lt;/p&gt;
</description>
                <link>/logicapps/ci-with-logic-apps-custom-connector</link>
                <guid>/logicapps/Logic App Template Custom Connector CI</guid>
                <pubDate>2018-01-29T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Januari update Logic App Template Creator</title>
                <description>&lt;p&gt;A new year comes with new updates, as you might now there is now a Custom Connector option for Logic  Apps and earlier this had some changes in the reource id handling in comparision with the managed api’s. So this has now been updated and fixed.&lt;/p&gt;

&lt;p&gt;Also there where some issues regarding names that could not contain . (dot) and ohter special characters that has been fixed, a new way of handlign reource id now prevent problems related to naming restrictions.&lt;/p&gt;

&lt;p&gt;The last part added was an option to be able to save the incoming body of the requested resources, this was done to be able to easier to debugg when developing, thanks to this and a Mock resource collector class  that can replay the saved files we  now can create full test runs that are replaying the whole collection of resources.&lt;/p&gt;

&lt;p&gt;The github repository is found here: &lt;a href=&quot;https://github.com/jeffhollan/LogicAppTemplateCreator&quot;&gt;https://github.com/jeffhollan/LogicAppTemplateCreator&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;updates&quot;&gt;Updates&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Now supporting extraction of Logic Apps containg Custom Connectors and generating working importable Connection resources with the Logic App.&lt;/li&gt;
  &lt;li&gt;Updates to resource id handling, now able to handle resource groups, resouirce names with .(dot) and other special characters that previously was not supported&lt;/li&gt;
  &lt;li&gt;Added a resource handler to be able to print out the incoming requests, to be able to build complete test suites with full replay of a extraction of a Logic App&lt;/li&gt;
&lt;/ul&gt;
</description>
                <link>/logicapps/template-extractur-update-januari</link>
                <guid>/logicapps/Logic App Template Generator Update Januari</guid>
                <pubDate>2018-01-16T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Logic App Custom Connector via On Prem Gateway</title>
                <description>&lt;p&gt;In an ever growing hybrid world the need of exposing services that are hosted On Premise are growing and so are the limitations and requirments aswell, the newest way of exposing HTTP based services in Logic Apps is via the &lt;strong&gt;Logic App Custom Connector&lt;/strong&gt; via the &lt;strong&gt;On Premise Data Gateway&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So previusly when having the task of calling on-premise firewall protected services from our Logic App’s it wasent possible without firewall openings or other resources to help connecting.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/12/logica-app-to-custom-webservice.png&quot; alt=&quot;Task Overview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;But now it’s possible and let’s solve it with the newly updated &lt;strong&gt;On Premise Data Gateway&lt;/strong&gt; and a  &lt;strong&gt;Logic App Custom Connector&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;h3 id=&quot;install-the-gateway&quot;&gt;Install the Gateway&lt;/h3&gt;
&lt;p&gt;First of make sure you have the latest version installed, follow the &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/logic-apps/logic-apps-gateway-install&quot;&gt;install instructions found here.&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;Rememeber the name of the installed Gateway if you have many.&lt;/p&gt;

&lt;h3 id=&quot;create-the-api&quot;&gt;Create the API&lt;/h3&gt;
&lt;p&gt;In this scenario I will expose a swagger api endpoint, the simple standard &lt;em&gt;Values&lt;/em&gt; Api, that are created default in a new Web App project with type &lt;em&gt;Api App&lt;/em&gt; after enabling &lt;em&gt;Swagger&lt;/em&gt; we can browse the swagger definition, as follows:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/12/values-controller-swagger.png&quot; alt=&quot;Values Controller Swagger&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Copy the URL to the swagger defintion, shown in the middle bo in the image above ( &lt;em&gt;http://localhost:51921/swagger/docs/v1&lt;/em&gt;  ) and save the content as a text file. (Simplest way is to browse it and copy the swagger definition to a text file)&lt;/p&gt;

&lt;h2 id=&quot;create-custom-logic-app-connector&quot;&gt;Create Custom Logic App Connector&lt;/h2&gt;
&lt;p&gt;Now we are prepared and can start of with creating the &lt;strong&gt;Logic App Custom Connector&lt;/strong&gt; based on the swagger file, note that it’s also possible to use WSDL files as source.&lt;/p&gt;

&lt;p&gt;In the Azure Portal create a &lt;strong&gt;Logic Apps Custom Connector&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/12/azure-portal-create-custom-connector.png&quot; alt=&quot;Azure Portal Create Logic Apps Custom Connector&quot; /&gt;&lt;/p&gt;

&lt;p&gt;No definition is added during the creation time, sp we will have to edit the Custom Connector once it’s created. Start edit the newly created Custom Connector and let’s add the swagger definition:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/12/azure-portal-custom-connector-deployed.png&quot; alt=&quot;Go to Resource&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Press the &lt;strong&gt;Edit&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/12/azure-portal-custom-connector-deployed-edit.png&quot; alt=&quot;Press the edit button&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Upload the swagger file:
&lt;img src=&quot;/assets/uploads/2017/12/azure-portal-custom-connector-deployed-upload.png&quot; alt=&quot;Upload swagger file&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now the API Connection is generated based on the swagger file, scroll down and make changes as you see them neeed &lt;strong&gt;but&lt;/strong&gt; dont’ fotgett to check the &lt;em&gt;“Connect via on-premises data gateway”&lt;/em&gt; checkbox and if needed change the URL’s to match the URL’s to the server exposing the service (I’ll just keep em same since it’s on the same machine for me)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/12/azure-portal-custom-connector-deployed-check-onpremgateway.png&quot; alt=&quot;Check the checkbox for on-premise data gateway&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now press Continue and move on with the process, once you are finished make sure to update the &lt;em&gt;Logic Apps Custom Connector&lt;/em&gt; by pressing the check mark at the top:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/12/azure-portal-custom-connector-deployed-save.png&quot; alt=&quot;Save the updates&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After the &lt;em&gt;Logic Apps Custom Connector&lt;/em&gt; is saved we can now use it in our Logic Apps, so lets’ create a Logic App and start using our newly created Custom Connector. (Make sure to create the Logic App in the same Location as your on-premise data gateway is installed otherwise it wont be available in the Logic App).&lt;/p&gt;

&lt;p&gt;Inside the Logic App we can now find our &lt;strong&gt;Custom Connector&lt;/strong&gt; among all the others and if I start searching for it I can easily select the appropiate action I want to use:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/12/azure-portal-custom-connector-logic-app-browse.png&quot; alt=&quot;Logic App browse the Custom Connector&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After I pick my operation, I just took the &lt;em&gt;Get All&lt;/em&gt; I need to create the API Connection that will be connected to my Custom Connector, here is where I can pcik authentication method and also the Gateway I want to use.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/12/azure-portal-custom-connector-logic-app-create-connection.png&quot; alt=&quot;Logic App create the API Connection for the Custom Connector&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Pressing create will create the API Connection and the Logic App is completed for this sample, let’s save the Logic App and test run it, the result is that we will get the “values” returned as promised:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/12/azure-portal-custom-connector-logic-app-run.png&quot; alt=&quot;Logic App run result&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The flow is now completed and since we have installed an &lt;em&gt;On Premise Data Gateway&lt;/em&gt; on our webservice we can use the &lt;strong&gt;Logic App Custom Connector&lt;/strong&gt; definition in our calls to our on-premise webservice, when creating the Logic App we are creating a &lt;em&gt;API Connection&lt;/em&gt; based on the  &lt;strong&gt;Logic App Custom Connector&lt;/strong&gt; that holds credentials and Gateway information to be used when executing the Logic App run and we can now connect to our firewall protected on-premise webservice!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/12/logica-app-to-custom-webservice-completed.png&quot; alt=&quot;Ovreview result&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary:&lt;/h2&gt;
&lt;p&gt;I think this is an amasing new feature that we really have wanted for a long time. This enables so mutch simpler exposure of services on-premises and in a secure and reliable way.
No need for fireall openings, vpn’s, express routes or reverse proxies in a DMZ, we can just install the gateway and use it as our entry point.&lt;/p&gt;

&lt;p&gt;Remember this is still in preview and I’ve encountered some issues when working with SOAP so there are some fixes needed, but it looks good so far!&lt;/p&gt;
</description>
                <link>/logicapps/custom-connector-via-onpremgateway</link>
                <guid>/logicapps/Custom-LogicApp-Connector-via-OnPremiseDataGateway</guid>
                <pubDate>2017-12-28T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Centralize secrets in Azure Key Vault</title>
                <description>&lt;p&gt;When working with usernames, passwords or api keys these need to be stored in a secure and manageble way. Usually I find that these are added to Application Settings and manually handled in several places, this is &lt;strong&gt;not&lt;/strong&gt; a desirable way of working and may look something like this, secrets spread out in all areas with red circle:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/11/password-username-keys.png&quot; alt=&quot;Normal setup&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The first step is to centralize the Values and there I find that &lt;strong&gt;Azure Key Vault&lt;/strong&gt; Vault is a superb place for storage, we got RBAC support for granular security, making it possible for a developer to access the values via code or when deploying via ARM template but not to see or edit the value. So with this we can make sure that passwords/usernames and other secrets are not spread via email’s, stored in dropbox or other “safe” places when distributed to the developers to add them to the &lt;em&gt;App Settings&lt;/em&gt; or store them in &lt;em&gt;parameter files&lt;/em&gt; for our ARM templates. 
It also adds reusability so if the value is needed in a &lt;em&gt;Function&lt;/em&gt; and in a &lt;em&gt;Logic App&lt;/em&gt; we can make sure it’s the same value that is used and we can manage it in one place.&lt;/p&gt;

&lt;p&gt;So let’s have this sample in our KeyVault where sqluser and sqlpassword should be used in both a Function and when creating a Logic App Connector.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/11/key-vault-secrets.png&quot; alt=&quot;Key Vault sample secrets&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Finding the Key vault Resource id:
&lt;img src=&quot;/assets/uploads/2017/11/key-vault-resourceid.png&quot; alt=&quot;Key Vault resource id&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;arm-deployment-logic-app-connector&quot;&gt;ARM Deployment Logic App Connector&lt;/h2&gt;
&lt;p&gt;Using &lt;strong&gt;KeyVault&lt;/strong&gt; with ARM deployment requires that the KeyVault has enabled access for &lt;em&gt;Azure Resource Manager for template demployment&lt;/em&gt; and that the principal (AAD Application) that is used when deploying has permissions to access the secrets.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/11/key-vault-enable-ARM-deployments.png&quot; alt=&quot;Enable ARM Deployment with Key Vault&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After this secrets are accessible via the ARM Template Parameter file, (only from the parameter file or from a Wrapping ARM Template) here is a sample how it would look like in a parameter file:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;$schema&quot;: &quot;https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#&quot;,
  &quot;contentVersion&quot;: &quot;1.0.0.0&quot;,
  &quot;parameters&quot;: {
    &quot;name&quot;: {
      &quot;value&quot;: &quot;INT001-SQL&quot;
    },
    &quot;location&quot;: {
      &quot;value&quot;: &quot;West Europe&quot;
    }
    &quot;sqlusername&quot; :{
      &quot;reference&quot;: {
        &quot;keyVault&quot;: {
          &quot;id&quot;: &quot;/subscriptions/fake-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/testenvironment/providers/Microsoft.KeyVault/vaults/ibizmalotest&quot;
        },
        &quot;secretName&quot;: &quot;sqluser&quot;
      }
    },
	&quot;sqlpassword&quot; :{
      &quot;reference&quot;: {
        &quot;keyVault&quot;: {
          &quot;id&quot;: &quot;/subscriptions/fake-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/testenvironment/providers/Microsoft.KeyVault/vaults/ibizmalotest&quot;
        },
        &quot;secretName&quot;: &quot;sqlpassword&quot;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When doing a &lt;em&gt;Resource Group Deployment&lt;/em&gt; the value is collected from Key Vault during deployment time and then stored in the API Connection. (Remember deployment time means that if the value is changed a new deployment is needed to reflect the change to the API Connection)&lt;/p&gt;

&lt;p&gt;Now secrets are stored in Key Vault and the developer setting this up don’t know the actual values in test/prod just what the secret’s name is. The deployment flow looks as follows below where during deployment the secrets is collected from &lt;em&gt;KeyVault&lt;/em&gt; (1) and used when creating/updating the &lt;em&gt;API Connection&lt;/em&gt; (2) ) this also means that no secrets are stored in the ARM template parameters file and that is great!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/11/key-vault-deployment-ARM-layout.png&quot; alt=&quot;ARM Deployment with Key Vault&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt; if the value in &lt;em&gt;Key Vault&lt;/em&gt; is changed a new deployment is required to &lt;strong&gt;update&lt;/strong&gt; the &lt;em&gt;API Connection&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;accessing-secrets-from-functionsweb-apps-or-other-c-applications&quot;&gt;Accessing Secrets from Functions/Web Apps or other c# applications&lt;/h2&gt;

&lt;p&gt;Any c# application can easily use the &lt;em&gt;KeyVault SDK&lt;/em&gt; to retrieve secrets from &lt;em&gt;Key Vault&lt;/em&gt; during runtime, but we do need some things in order to make this possible, from code we need an AAD Application in order to grant access to the secrets, I will not go through how to create one here but &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications&quot;&gt;read more here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When it’s created we need to get the &lt;em&gt;Application ID&lt;/em&gt; (clientId) and one &lt;em&gt;Key&lt;/em&gt; (clientSecret).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/11/functions-key-vault-get-AAD-Application-values.png&quot; alt=&quot;Get AAD Application information&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now that we have collected the information needed we also need to make sure that our AAD Application has access to the secrets, that is something we are adding to the &lt;em&gt;Key Vault&lt;/em&gt; under the “Access Policies”:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/11/functions-key-vault-set-access-policies.png&quot; alt=&quot;Set Access Policies&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Press the “Add new”, select the principal (AAD Application) in my case the &lt;em&gt;KeyVaultApp&lt;/em&gt;, in the &lt;em&gt;Secret Permissions&lt;/em&gt; we only want and need &lt;strong&gt;Get&lt;/strong&gt; and no more privileges should be given to the Policy.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/11/functions-key-vault-set-access-policies-settings.png&quot; alt=&quot;Set Access Policies Settings&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now to start coding we need some nuget packages:
*Microsoft.Azure.KeyVault;
*Microsoft.IdentityModel.Clients.ActiveDirectory&lt;/p&gt;

&lt;p&gt;And a bit of code, sample bellow, for more indept about how to use in &lt;em&gt;Functions&lt;/em&gt; read more at &lt;a href=&quot;https://medium.com/@jeffhollan/getting-key-vault-secrets-in-azure-functions-37620fd20a0b&quot;&gt;Jeff Holan’s blog post:&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code to retrieve a secret thesecrets&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public static class KeyVaultFunction
{

    private static string clientID = Environment.GetEnvironmentVariable(&quot;clientId&quot;, EnvironmentVariableTarget.Process);
    private static string clientSecret = Environment.GetEnvironmentVariable(&quot;clientSecret&quot;, EnvironmentVariableTarget.Process);       
    private static string keyvaultname = Environment.GetEnvironmentVariable(&quot;keyvaultname&quot;, EnvironmentVariableTarget.Process);    

    [FunctionName(&quot;KeyVaultFunction&quot;)]
    public static async Task&amp;lt;HttpResponseMessage&amp;gt; Run([HttpTrigger(AuthorizationLevel.Function, &quot;get&quot;, &quot;post&quot;, Route = null)]HttpRequestMessage req, TraceWriter log)
    {
        log.Info(&quot;C# HTTP trigger function processed a request.&quot;);

        string secretUri = $&quot;https://{keyvaultname}.vault.azure.net/secrets/&quot;;

        var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetToken));
        log.Info(&quot;Token aquired&quot;);
        var sqlusernameSecret = await kv.GetSecretAsync(secretUri + &quot;sqluser&quot;);
		var sqlpasswordSecret = await kv.GetSecretAsync(secretUri + &quot;sqlpassword&quot;);
		
		//do some code here

        return req.CreateResponse(HttpStatusCode.OK, &quot;SQL credentials collected ok&quot;);
    }

    public static async Task&amp;lt;string&amp;gt; GetToken(string authority, string resource, string scope)
    {
        var authContext = new AuthenticationContext(authority);
        ClientCredential clientCred = new ClientCredential(clientID, clientSecret);
        AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);

        if (result == null)
            throw new System.Exception(&quot;Failed to obtain the JWT token&quot;);

        return result.AccessToken;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;First the settings are added to the Function App Application Settings:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;private static string clientID = Environment.GetEnvironmentVariable(&quot;clientId&quot;, EnvironmentVariableTarget.Process);
private static string clientSecret = Environment.GetEnvironmentVariable(&quot;clientSecret&quot;, EnvironmentVariableTarget.Process);       
private static string keyvaultname = Environment.GetEnvironmentVariable(&quot;keyvaultname&quot;, EnvironmentVariableTarget.Process);
private static string secretname = Environment.GetEnvironmentVariable(&quot;secretname&quot;, EnvironmentVariableTarget.Process);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To handle the authentication we need a method to send i to the &lt;em&gt;AuthenticationCallback&lt;/em&gt; object that takes 3 parameters, authority is the login authroity i.e: &lt;em&gt;“https://login.windows.net/1cb87777-3df4-428b-811a-86a0f215cd35”&lt;/em&gt; the resoruce is what resource we are trying to access (KeyVault): &lt;em&gt;“https://vault.azure.net”&lt;/em&gt; and scope is the scope we are accessing with normaly empty string.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public static async Task&amp;lt;string&amp;gt; GetToken(string authority, string resource, string scope)
{
    var authContext = new AuthenticationContext(authority);
    ClientCredential clientCred = new ClientCredential(clientID, clientSecret);
    AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);

    if (result == null)
        throw new System.Exception(&quot;Failed to obtain the JWT token&quot;);

    return result.AccessToken;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then the code part that is actually collecting the secret is the following, we need the URI to the secret that we compose of the Key Vault name and the secret name, and the &lt;strong&gt;GetToken&lt;/strong&gt; function to send in to the &lt;em&gt;AuthenticationCallback&lt;/em&gt; object.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;string secretUri = $&quot;https://{keyvaultname}.vault.azure.net/secrets/&quot;;
var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetToken));
var sqlusernameSecret = await kv.GetSecretAsync(secretUri + &quot;sqluser&quot;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After this setup is completed we now are collecting the secrets from Key Vault during runtime and therefore there are no more secrets stored in application settings or in code and we have reused the same secrets in diffrent areas.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/11/key-vault-runtime-code.png&quot; alt=&quot;Secrets accessed from KeyVault in code&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I really like to remove username and passwords from code and settings since it’s always a mess to manage and in handling them, also there are a few security aspects to consider as well. 
Making it possible to get username/password or other secrets from &lt;em&gt;Key Vault&lt;/em&gt; inside your Function, Web App and at the same time use them when deploying ARM templates like with Logic Apps API Connections or API Management is really the true win, since we now only need to manage these in one place and can use them wherever needed.&lt;/p&gt;

&lt;p&gt;In the end we are creating a solution as the image bellow and this gives us a centralized place for our secrets and we only spreading them if we really need to like to an &lt;em&gt;API Connection&lt;/em&gt; and that is done integrated with ARM.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/11/password-username-keys-with-keyvault.png&quot; alt=&quot;Secrets centralised in KeyVault&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBS!&lt;/strong&gt; Make note that if we access Key vault via code an update is reflected emediatly while used via ARM a new deployment is needed in order for the new value to be deployed to i.e. password for a API Connection, making it vital to have good Build and Release processes).&lt;/p&gt;
</description>
                <link>/keyvault/centralize-secrets</link>
                <guid>/keyvault/Manage-Secrets-in-Azure</guid>
                <pubDate>2017-11-27T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Azure Functions npm install via VSTS</title>
                <description>&lt;p&gt;When setting upp build and release cycles for diffrent Azure resources we bump in to diffrent challenges, this post will cover the challenge of npm install of node modules in to a Function App when doing deployments.&lt;/p&gt;

&lt;p&gt;When we are working with our development enviornment it’s okay to go in and run kudo commands and so on to make sure our Function App has the correct packages installed, but as we are adding speed and agility to our processes our &lt;strong&gt;Release&lt;/strong&gt; pipelines in &lt;strong&gt;VSTS&lt;/strong&gt; has to automate more of these processes.
It’s not that it’s hard to go in to &lt;em&gt;Kudo&lt;/em&gt; and run the command but it’s a manual step that takes time and knowledge when doing a release, I prefer to have everything prepped so that I know things are working when the Release is installed.&lt;/p&gt;

&lt;p&gt;So let’s look in to how we can run &lt;em&gt;Kudu&lt;/em&gt; commands from VSTS, since &lt;em&gt;Kudu&lt;/em&gt; has a REST API we can use it for these kind of tasks, read more on it here &lt;a href=&quot;https://github.com/projectkudu/kudu/wiki/REST-API&quot;&gt;Kudu Rest API&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When looking in to the API documentation we easily find a function for executing commands:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;POST /api/command
{
    &quot;command&quot;: &apos;echo Hello World&apos;,
    &quot;dir&quot;: &apos;site\\repository&apos;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This means that we could create a message that looked like this for a npm install of the &lt;em&gt;request&lt;/em&gt; package:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
    &quot;command&quot;: &quot;npm install request&quot;,
    &quot;dir&quot;: &quot;site\\wwwroot&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So let’s start figuring out the rest, how to execute this from VSTS?&lt;/p&gt;

&lt;p&gt;As good as it’s get this can be executed via PowerShell explained and sampled at the bottom of the API reference (I changed the sample in the following code snippet to execute the command for npm install):&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$username = &quot;`$website&quot;
$password = &quot;pwd&quot;
# Note that the $username here should look like `SomeUserName`, and **not** `SomeSite\SomeUserName`
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes((&quot;{0}:{1}&quot; -f $username,$password)))

$userAgent = &quot;powershell/1.0&quot;
$apiUrl = &quot;https://$functionAppName.scm.azurewebsites.net/api/command&quot;
$command = &apos;{&quot;command&quot;: &quot;npm install &apos; + $npmpackage + &apos;&quot;,&quot;dir&quot;: &quot;site\\wwwroot&quot;}&apos;

Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization=(&quot;Basic {0}&quot; -f $base64AuthInfo)} -UserAgent $userAgent -Method POST -Body $command -ContentType &quot;application/json&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The credentials is now needed and that is somewhat messy, but since it’s the same as the deployment credentials we can add a commands to get that information via &lt;em&gt;AzureRmResourceAction&lt;/em&gt; command:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$creds = Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroup -ResourceType Microsoft.Web/sites/config `
            -ResourceName $functionAppName/publishingcredentials -Action list -ApiVersion 2015-08-01 -Force
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So with this information we can now build a more generic script that will only need three (3) parameters to execute a npm install command on our Function App:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;functionAppName&lt;/strong&gt;: the name of the Function App&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;resourceGroupName&lt;/strong&gt;: the name of the resource group that contains the Function App&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;npmpackage&lt;/strong&gt;: the npm package to install&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
param([string] $functionAppName, [string] $resourceGroup, [string] $npmpackage)

$creds = Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroup -ResourceType Microsoft.Web/sites/config `
            -ResourceName $functionAppName/publishingcredentials -Action list -ApiVersion 2015-08-01 -Force

$username = $creds.Properties.PublishingUserName
$password = $creds.Properties.PublishingPassword


$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes((&quot;{0}:{1}&quot; -f $username,$password)))

$userAgent = &quot;powershell/1.0&quot;
$apiUrl = &quot;https://$functionAppName.scm.azurewebsites.net/api/command&quot;
$command = &apos;{&quot;command&quot;: &quot;npm install &apos; + $npmpackage + &apos;&quot;,&quot;dir&quot;: &quot;site\\wwwroot&quot;}&apos;

Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization=(&quot;Basic {0}&quot; -f $base64AuthInfo)} -UserAgent $userAgent -Method POST -Body $command -ContentType &quot;application/json&quot;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now all we have left is to execute this script in a Azure Powershell Task that will install the npm pacakge during the release, image bellow shows the Release setup and as you can see the parameters are added in the &lt;strong&gt;“Script Arguments”&lt;/strong&gt; input area. I’ve also added the zcript to a shared repo andlinked the build setup to be able to share the script and manage it in one place.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/11/functions-vsts-release-run-script-png.PNG&quot; alt=&quot;VSTS Release Setup&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you are using &lt;strong&gt;package.json&lt;/strong&gt; files we can make sure all packages are installed via &lt;em&gt;npm install&lt;/em&gt; command, let’s see how the following could look like with a &lt;strong&gt;package.json&lt;/strong&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/uploads/2017/11/functions-package.josn-sample.png&quot; alt=&quot;package.json file in project&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Modifying the PowerShell script will then give us the following:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;functionAppName&lt;/strong&gt;: the name of the Function App&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;resourceGroupName&lt;/strong&gt;: the name of the resource group that contains the Function App&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;functionfolder&lt;/strong&gt;: the name of the folder that the function is in (same name as the function)&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;param([string] $functionAppName, [string] $resourceGroup, [string] $functionfolder)

$creds = Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroup -ResourceType Microsoft.Web/sites/config `
            -ResourceName $functionAppName/publishingcredentials -Action list -ApiVersion 2015-08-01 -Force

$username = $creds.Properties.PublishingUserName
$password = $creds.Properties.PublishingPassword

$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes((&quot;{0}:{1}&quot; -f $username,$password)))

$userAgent = &quot;powershell/1.0&quot;
$apiUrl = &quot;https://$functionAppName.scm.azurewebsites.net/api/command&quot;
$command = &apos;{&quot;command&quot;: &quot;npm install&quot;,&quot;dir&quot;: &quot;site\\wwwroot\\&apos;+ $functionfolder +&apos;&quot;}&apos;

Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization=(&quot;Basic {0}&quot; -f $base64AuthInfo)} -UserAgent $userAgent -Method POST -Body $command -ContentType &quot;application/json&quot;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I like to automate these tasks since it will give me a “easier” Release and a more reliable Release, but as for now it’s hard to verify that the package is installed and if it’s installed previously so a verification step that the function is loaded correctly is something that might be needed.&lt;/p&gt;

&lt;p&gt;Recomended is to use the &lt;strong&gt;package.json&lt;/strong&gt; approach since it shows the dependencies and allow to easyily add new packages, but jeep in mind that it also gives some delays when running the &lt;em&gt;npm install&lt;/em&gt; command since it will install alot of packages the first time.&lt;/p&gt;
</description>
                <link>/azurefunctions/vsts-npm-install</link>
                <guid>/azurefunctions/AzureFunctions-npm-install-via-vsts</guid>
                <pubDate>2017-11-01T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Azure Functions - Manage Application Settings via ARM</title>
                <description>&lt;p&gt;One of the most common task when working with deployments is the need to handle is application settings. This is where we are adding environment variables to the current Azure Function App, the environment variables often has diffrent values in diffrent environmnets (Dev/Test/Prod).
So we need to manage them to make sure that they have the correct values.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/10/azure_functions_application_settings.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/10/azure_functions_application_settings.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These can be managed manually since they are rarely changed but it requires dicipline and good release documentation and sometimes quite advanced procedures to get the information, some of these cases are i.e. getting the &lt;em&gt;URL&lt;/em&gt; of a &lt;em&gt;Logic App&lt;/em&gt;, a value from &lt;em&gt;Key Vault&lt;/em&gt; or we might just walue &lt;strong&gt;quality&lt;/strong&gt; and &lt;strong&gt;reliable&lt;/strong&gt; deployments.&lt;/p&gt;

&lt;p&gt;I prefer to manage these settings via ARM templates since it gives me the possiblity to get values from Key Vault or automate the process to get values from other Azure resources and at the same time gives me control and robustness so I know that the settings are set and that the values are correct.
A note to this, make sure that operations persons are aware that settings are been set from ARM template deployment since if they do changes directly in the Azure functions Application Settings tab they will be overwriten at the next deployment and that might cause problems.&lt;/p&gt;

&lt;p&gt;Let’s look in to the ARM template, I’ve just copied this from the Azure Portal (automation option when creating a new Azure Function).&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;parameters&quot;: {
    &quot;name&quot;: {
      &quot;type&quot;: &quot;string&quot;
    },
    &quot;storageName&quot;: {
      &quot;type&quot;: &quot;string&quot;
    },
    &quot;location&quot;: {
      &quot;type&quot;: &quot;string&quot;
    }
  },
  &quot;resources&quot;: [
    {
      &quot;name&quot;: &quot;[parameters(&apos;name&apos;)]&quot;,
      &quot;type&quot;: &quot;Microsoft.Web/sites&quot;,
      &quot;dependsOn&quot;: [
        &quot;[resourceId(&apos;Microsoft.Storage/storageAccounts&apos;, parameters(&apos;storageName&apos;))]&quot;,
        &quot;[resourceId(&apos;microsoft.insights/components/&apos;, parameters(&apos;name&apos;))]&quot;
      ],
      &quot;properties&quot;: {
        &quot;siteConfig&quot;: {
          &quot;appSettings&quot;: [
            {
              &quot;name&quot;: &quot;AzureWebJobsDashboard&quot;,
              &quot;value&quot;: &quot;[concat(&apos;DefaultEndpointsProtocol=https;AccountName=&apos;,parameters(&apos;storageName&apos;),&apos;;AccountKey=&apos;,listKeys(resourceId(&apos;Microsoft.Storage/storageAccounts&apos;, parameters(&apos;storageName&apos;)), &apos;2015-05-01-preview&apos;).key1)]&quot;
            },
            {
              &quot;name&quot;: &quot;AzureWebJobsStorage&quot;,
              &quot;value&quot;: &quot;[concat(&apos;DefaultEndpointsProtocol=https;AccountName=&apos;,parameters(&apos;storageName&apos;),&apos;;AccountKey=&apos;,listKeys(resourceId(&apos;Microsoft.Storage/storageAccounts&apos;, parameters(&apos;storageName&apos;)), &apos;2015-05-01-preview&apos;).key1)]&quot;
            },
            {
              &quot;name&quot;: &quot;FUNCTIONS_EXTENSION_VERSION&quot;,
              &quot;value&quot;: &quot;~1&quot;
            },
            {
              &quot;name&quot;: &quot;WEBSITE_CONTENTAZUREFILECONNECTIONSTRING&quot;,
              &quot;value&quot;: &quot;[concat(&apos;DefaultEndpointsProtocol=https;AccountName=&apos;,parameters(&apos;storageName&apos;),&apos;;AccountKey=&apos;,listKeys(resourceId(&apos;Microsoft.Storage/storageAccounts&apos;, parameters(&apos;storageName&apos;)), &apos;2015-05-01-preview&apos;).key1)]&quot;
            },
            {
              &quot;name&quot;: &quot;WEBSITE_CONTENTSHARE&quot;,
              &quot;value&quot;: &quot;[concat(toLower(parameters(&apos;name&apos;)), &apos;a217&apos;)]&quot;
            },
            {
              &quot;name&quot;: &quot;WEBSITE_NODE_DEFAULT_VERSION&quot;,
              &quot;value&quot;: &quot;6.5.0&quot;
            },
            {
              &quot;name&quot;: &quot;APPINSIGHTS_INSTRUMENTATIONKEY&quot;,
              &quot;value&quot;: &quot;[reference(resourceId(&apos;microsoft.insights/components/&apos;, parameters(&apos;name&apos;)), &apos;2015-05-01&apos;).InstrumentationKey]&quot;
            }
          ]
        },
        &quot;name&quot;: &quot;[parameters(&apos;name&apos;)]&quot;,
        &quot;clientAffinityEnabled&quot;: false
      },
      &quot;apiVersion&quot;: &quot;2016-03-01&quot;,
      &quot;location&quot;: &quot;[parameters(&apos;location&apos;)]&quot;,
      &quot;kind&quot;: &quot;functionapp&quot;
    },
    {
      &quot;apiVersion&quot;: &quot;2015-05-01-preview&quot;,
      &quot;type&quot;: &quot;Microsoft.Storage/storageAccounts&quot;,
      &quot;name&quot;: &quot;[parameters(&apos;storageName&apos;)]&quot;,
      &quot;location&quot;: &quot;[parameters(&apos;location&apos;)]&quot;,
      &quot;properties&quot;: {
        &quot;accountType&quot;: &quot;Standard_LRS&quot;
      }
    },
    {
      &quot;apiVersion&quot;: &quot;2015-05-01&quot;,
      &quot;name&quot;: &quot;[parameters(&apos;name&apos;)]&quot;,
      &quot;type&quot;: &quot;microsoft.insights/components&quot;,
      &quot;location&quot;: &quot;West Europe&quot;,
      &quot;tags&quot;: {
        &quot;[concat(&apos;hidden-link:&apos;, resourceGroup().id, &apos;/providers/Microsoft.Web/sites/&apos;, parameters(&apos;name&apos;))]&quot;: &quot;Resource&quot;
      },
      &quot;properties&quot;: {
        &quot;ApplicationId&quot;: &quot;[parameters(&apos;name&apos;)]&quot;,
        &quot;Request_Source&quot;: &quot;IbizaWebAppExtensionCreate&quot;
      }
    }
  ],
  &quot;$schema&quot;: &quot;http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#&quot;,
  &quot;contentVersion&quot;: &quot;1.0.0.0&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The interesting section is the &lt;strong&gt;appSettings&lt;/strong&gt; under the &lt;strong&gt;siteConfig&lt;/strong&gt; shown bellow.&lt;/p&gt;

&lt;p&gt;Here is the standard properties that are used when deploying a Azure Function and here we can add new Application Settings. (note that ARM functions are used to get keys to the storage account)&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;properties&quot;: {
        &quot;siteConfig&quot;: {
          &quot;appSettings&quot;: [
            {
              &quot;name&quot;: &quot;AzureWebJobsDashboard&quot;,
              &quot;value&quot;: &quot;[concat(&apos;DefaultEndpointsProtocol=https;AccountName=&apos;,parameters(&apos;storageName&apos;),&apos;;AccountKey=&apos;,listKeys(resourceId(&apos;Microsoft.Storage/storageAccounts&apos;, parameters(&apos;storageName&apos;)), &apos;2015-05-01-preview&apos;).key1)]&quot;
            },
            {
              &quot;name&quot;: &quot;AzureWebJobsStorage&quot;,
              &quot;value&quot;: &quot;[concat(&apos;DefaultEndpointsProtocol=https;AccountName=&apos;,parameters(&apos;storageName&apos;),&apos;;AccountKey=&apos;,listKeys(resourceId(&apos;Microsoft.Storage/storageAccounts&apos;, parameters(&apos;storageName&apos;)), &apos;2015-05-01-preview&apos;).key1)]&quot;
            },
            {
              &quot;name&quot;: &quot;FUNCTIONS_EXTENSION_VERSION&quot;,
              &quot;value&quot;: &quot;~1&quot;
            },
            {
              &quot;name&quot;: &quot;WEBSITE_CONTENTAZUREFILECONNECTIONSTRING&quot;,
              &quot;value&quot;: &quot;[concat(&apos;DefaultEndpointsProtocol=https;AccountName=&apos;,parameters(&apos;storageName&apos;),&apos;;AccountKey=&apos;,listKeys(resourceId(&apos;Microsoft.Storage/storageAccounts&apos;, parameters(&apos;storageName&apos;)), &apos;2015-05-01-preview&apos;).key1)]&quot;
            },
            {
              &quot;name&quot;: &quot;WEBSITE_CONTENTSHARE&quot;,
              &quot;value&quot;: &quot;[concat(toLower(parameters(&apos;name&apos;)), &apos;a217&apos;)]&quot;
            },
            {
              &quot;name&quot;: &quot;WEBSITE_NODE_DEFAULT_VERSION&quot;,
              &quot;value&quot;: &quot;6.5.0&quot;
            },
            {
              &quot;name&quot;: &quot;APPINSIGHTS_INSTRUMENTATIONKEY&quot;,
              &quot;value&quot;: &quot;[reference(resourceId(&apos;microsoft.insights/components/&apos;, parameters(&apos;name&apos;)), &apos;2015-05-01&apos;).InstrumentationKey]&quot;
            }
          ]
        },
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Adding a new property to the list is easy and adding a new key &lt;strong&gt;customkey&lt;/strong&gt; looks like this, and we also add a new ARM parameter so we can change the value between environments&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    {
      &quot;name&quot;: &quot;APPINSIGHTS_INSTRUMENTATIONKEY&quot;,
      &quot;value&quot;: &quot;[reference(resourceId(&apos;microsoft.insights/components/&apos;, parameters(&apos;name&apos;)), &apos;2015-05-01&apos;).InstrumentationKey]&quot;
    },
    {
      &quot;name&quot;: &quot;customkey&quot;,
      &quot;value&quot;: &quot;[parameters(&apos;customkeyparam&apos;)]&quot;
    }
  ]
},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Added parameter:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;location&quot;: {
  &quot;type&quot;: &quot;string&quot;
},
&quot;customkeyparam&quot; :{
  &quot;type&quot;: &quot;string&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And now we can use this with a parameter file, I copied the paramter file the same way and now we can update this parameter file and adding the new parameter:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;$schema&quot;: &quot;https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#&quot;,
  &quot;contentVersion&quot;: &quot;1.0.0.0&quot;,
  &quot;parameters&quot;: {
    &quot;name&quot;: {
      &quot;value&quot;: &quot;ibizmalotest&quot;
    },
    &quot;storageName&quot;: {
      &quot;value&quot;: &quot;ibizmalotest912c&quot;
    },
    &quot;location&quot;: {
      &quot;value&quot;: &quot;West Europe&quot;
    }
    &quot;customkeyparam&quot; :{
      &quot;value&quot;: &quot;MyCustomValueSetViaARM&quot;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After doing a Resource Group Deployment, we can go in and see the new setting in the Application Setting on the Azure Function App and start using it.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/10/azure_functions_application_settings_customkey_value.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/10/azure_functions_application_settings_customkey_value.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I like this approach since we can make sure that parameters are set and prepare before deployment without needing to change values in the Function App, I also love the ARM functions that we can use during deployments to automate processes or just get values from &lt;em&gt;Azure Key Vaults&lt;/em&gt; to make it easier to manage secrets (note that secrets are in plain text in application settings for the users who has access).&lt;/p&gt;

&lt;p&gt;The ARM functions can really speed up and automate the deployment processes even further, here we can as shown aboive get keys to storage account or get the URL of a Logic App during deployment time, wich is a complex/time consuming task and when using ARM functions there is also a garantee that the Logic App is deployed and ready to be used.&lt;/p&gt;

&lt;p&gt;Creating a good ARM template will make it easier to move between environments and it will add quality to your deployments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But remember&lt;/strong&gt; to make sure that changes that are made directly to the &lt;em&gt;Function App&lt;/em&gt; Application Settings are reflected to the parameter files and arm templates aswell to prevent changes to be overwriten.&lt;/p&gt;

&lt;p&gt;Sample getting the URL of a Locic App (assumes added parameters for &lt;em&gt;Resource Group&lt;/em&gt; and &lt;em&gt;Logic App&lt;/em&gt; name and the trigger name). (template file)&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    {
      &quot;name&quot;: &quot;APPINSIGHTS_INSTRUMENTATIONKEY&quot;,
      &quot;value&quot;: &quot;[reference(resourceId(&apos;microsoft.insights/components/&apos;, parameters(&apos;name&apos;)), &apos;2015-05-01&apos;).InstrumentationKey]&quot;
    },
    {
      &quot;name&quot;: &quot;LogicAppUrl&quot;,
      &quot;value&quot;: &quot;[listCallbackUrl(resourceId(parameters(&apos;logicApp_resourcegroup&apos;),&apos;Microsoft.Logic/workflows/triggers&apos;, parameters(&apos;logicApp_name&apos;),parameters(&apos;logicApp_trigger&apos;)), providers(&apos;Microsoft.Logic&apos;, &apos;workflows&apos;).apiVersions[0]).value]&quot;
    }
  ]
},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sample &lt;em&gt;Azure Key Vault&lt;/em&gt; get a specific Value from Key Vault. (parameter file)&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;$schema&quot;: &quot;https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#&quot;,
  &quot;contentVersion&quot;: &quot;1.0.0.0&quot;,
  &quot;parameters&quot;: {
    &quot;name&quot;: {
      &quot;value&quot;: &quot;ibizmalotest&quot;
    },
    &quot;storageName&quot;: {
      &quot;value&quot;: &quot;ibizmalotest912c&quot;
    },
    &quot;location&quot;: {
      &quot;value&quot;: &quot;West Europe&quot;
    }
    &quot;customkeyparam&quot; :{
      &quot;reference&quot;: {
        &quot;keyVault&quot;: {
          &quot;id&quot;: &quot;/subscriptions/fake-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/testenvironment/providers/Microsoft.KeyVault/vaults/ibizmalotest&quot;
        },
        &quot;secretName&quot;: &quot;customkeysecretname&quot;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/10/azure_functions_key_vault_customsecretname.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/10/azure_functions_key_vault_customsecretname.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

</description>
                <link>/azurefunctions/arm-manage-application-settings</link>
                <guid>/azurefunctions/AzureFunctions-applicationsettings-arm</guid>
                <pubDate>2017-10-23T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>API Management ARM Template Creator</title>
                <description>&lt;p&gt;ARM support was release in the July rlease of API Management (&lt;a href=&quot;https://blogs.msdn.microsoft.com/apimanagement/2017/07/14/release-notes-july-14th-2017/&quot;&gt;read more here&lt;/a&gt;) and this is relly a great improvement on the deployment experience of API Management.
For samples on ARM templates released by the product group got the &lt;a href=&quot;https://github.com/Azure/azure-quickstart-templates/tree/master/201-api-management-create-all-resources&quot;&gt;Sample Github page&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But there is some “blocking” things here, we are not using ARM templates when devloping, so how do we get the ARM Templates?
First you can download the entire API Management instance ARM specification directly in the portal, &lt;strong&gt;Automation Script&lt;/strong&gt;
&lt;a href=&quot;/assets/uploads/2017/09/apim-arm-template-creator-automation-script.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-arm-template-creator-automation-script.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But when starting to look into this I got a little dissapointed, it’s to mutch hardcoded values like backend URL’s parameters and there is for me unwanted things aswell as Users, Groups, Subscriptions etc. All that could be sorted out and scripted (alot of work but could be done) but the real deal breaker using the automation script was the missing request/response representation and the missing &lt;em&gt;queryParameters&lt;/em&gt; wich lead to crahsing imports.&lt;/p&gt;

&lt;p&gt;It’s import to understand the Environment reference and boundries, we don’t want cross reference communcation that is not intended:
&lt;a href=&quot;/assets/uploads/2017/09/apim-arm-template-creator-environments.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-arm-template-creator-environments.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When doing a deployment we want as little manual work as possible and above we have 2 issues, manual configuration equals downtime and sample messagas is one of the best things when onboarding new API consumers we can’t ignore this.&lt;/p&gt;

&lt;p&gt;Let’s look at an example, this is how an operation is looking (note the sample):
&lt;a href=&quot;/assets/uploads/2017/09/apim-arm-template-creator-currency-convererter-operation-gui.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-arm-template-creator-currency-convererter-operation-gui.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And when this api is exported via the &lt;strong&gt;Automation Script&lt;/strong&gt; the sample is not part of the object returned:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; {
    &quot;comments&quot;: &quot;Generalized from resource: &apos;/subscriptions/c107df29-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/PreDemoTest/providers/Microsoft.ApiManagement/service/ibizmalo/apis/58a3138ca9f54041296baffd/operations/58a313e40647c00eecf8d408&apos;.&quot;,
    &quot;type&quot;: &quot;Microsoft.ApiManagement/service/apis/operations&quot;,
    &quot;name&quot;: &quot;[concat(parameters(&apos;service_ibizmalo_name&apos;), &apos;/&apos;, parameters(&apos;apis_58a3138ca9f54041296baffd_name&apos;), &apos;/&apos;, parameters(&apos;operations_58a313e40647c00eecf8d408_name&apos;))]&quot;,
    &quot;apiVersion&quot;: &quot;2017-03-01&quot;,
    &quot;scale&quot;: null,
    &quot;properties&quot;: {
        &quot;displayName&quot;: &quot;Conversion Rate&quot;,
        &quot;method&quot;: &quot;POST&quot;,
        &quot;urlTemplate&quot;: &quot;/conversionrate&quot;,
        &quot;description&quot;: &quot;&amp;lt;br&amp;gt;&amp;lt;b&amp;gt;Get conversion rate from one currency to another currency &amp;lt;b&amp;gt;&amp;lt;br&amp;gt;&amp;lt;p&amp;gt;&amp;lt;b&amp;gt;&amp;lt;font color=&apos;#000080&apos; size=&apos;1&apos; face=&apos;Verdana&apos;&amp;gt;&amp;lt;u&amp;gt;Differenct currency Code and Names around the world&amp;lt;/u&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;&amp;lt;font face=&apos;Verdana&apos; size=&apos;1&apos;&amp;gt;AFA-Afghanistan Afghani&amp;lt;br&amp;gt;ALL-Albanian Lek&amp;lt;br&amp;gt;DZD-Algerian Dinar&amp;lt;br&amp;gt;ARS-Argentine Peso&amp;lt;br&amp;gt;AWG-Aruba Florin&amp;lt;br&amp;gt;AUD-Australian Dollar&amp;lt;br&amp;gt;BSD-Bahamian Dollar&amp;lt;br&amp;gt;BHD-Bahraini Dinar&amp;lt;br&amp;gt;BDT-Bangladesh Taka&amp;lt;br&amp;gt;BBD-Barbados Dollar&amp;lt;br&amp;gt;BZD-Belize Dollar&amp;lt;br&amp;gt;BMD-Bermuda Dollar&amp;lt;br&amp;gt;BTN-Bhutan Ngultrum&amp;lt;br&amp;gt;BOB-Bolivian Boliviano&amp;lt;br&amp;gt;BWP-Botswana Pula&amp;lt;br&amp;gt;BRL-Brazilian Real&amp;lt;br&amp;gt;GBP-British Pound&amp;lt;br&amp;gt;BND-Brunei Dollar&amp;lt;br&amp;gt;BIF-Burundi Franc&amp;lt;br&amp;gt;XOF-CFA Franc (BCEAO)&amp;lt;br&amp;gt;XAF-CFA Franc (BEAC)&amp;lt;br&amp;gt;KHR-Cambodia Riel&amp;lt;br&amp;gt;CAD-Canadian Dollar&amp;lt;br&amp;gt;CVE-Cape Verde Escudo&amp;lt;br&amp;gt;KYD-Cayman Islands Dollar&amp;lt;br&amp;gt;CLP-Chilean Peso&amp;lt;br&amp;gt;CNY-Chinese Yuan&amp;lt;br&amp;gt;COP-Colombian Peso&amp;lt;br&amp;gt;KMF-Comoros Franc&amp;lt;br&amp;gt;CRC-Costa Rica Colon&amp;lt;br&amp;gt;HRK-Croatian Kuna&amp;lt;br&amp;gt;CUP-Cuban Peso&amp;lt;br&amp;gt;CYP-Cyprus Pound&amp;lt;br&amp;gt;CZK-Czech Koruna&amp;lt;br&amp;gt;DKK-Danish Krone&amp;lt;br&amp;gt;DJF-Dijibouti Franc&amp;lt;br&amp;gt;DOP-Dominican Peso&amp;lt;br&amp;gt;XCD-East Caribbean Dollar&amp;lt;br&amp;gt;EGP-Egyptian Pound&amp;lt;br&amp;gt;SVC-El Salvador Colon&amp;lt;br&amp;gt;EEK-Estonian Kroon&amp;lt;br&amp;gt;ETB-Ethiopian Birr&amp;lt;br&amp;gt;EUR-Euro&amp;lt;br&amp;gt;FKP-Falkland Islands Pound&amp;lt;br&amp;gt;GMD-Gambian Dalasi&amp;lt;br&amp;gt;GHC-Ghanian Cedi&amp;lt;br&amp;gt;GIP-Gibraltar Pound&amp;lt;br&amp;gt;XAU-Gold Ounces&amp;lt;br&amp;gt;GTQ-Guatemala Quetzal&amp;lt;br&amp;gt;GNF-Guinea Franc&amp;lt;br&amp;gt;GYD-Guyana Dollar&amp;lt;br&amp;gt;HTG-Haiti Gourde&amp;lt;br&amp;gt;HNL-Honduras Lempira&amp;lt;br&amp;gt;HKD-Hong Kong Dollar&amp;lt;br&amp;gt;HUF-Hungarian Forint&amp;lt;br&amp;gt;ISK-Iceland Krona&amp;lt;br&amp;gt;INR-Indian Rupee&amp;lt;br&amp;gt;IDR-Indonesian Rupiah&amp;lt;br&amp;gt;IQD-Iraqi Dinar&amp;lt;br&amp;gt;ILS-Israeli Shekel&amp;lt;br&amp;gt;JMD-Jamaican Dollar&amp;lt;br&amp;gt;JPY-Japanese Yen&amp;lt;br&amp;gt;JOD-Jordanian Dinar&amp;lt;br&amp;gt;KZT-Kazakhstan Tenge&amp;lt;br&amp;gt;KES-Kenyan Shilling&amp;lt;br&amp;gt;KRW-Korean Won&amp;lt;br&amp;gt;KWD-Kuwaiti Dinar&amp;lt;br&amp;gt;LAK-Lao Kip&amp;lt;br&amp;gt;LVL-Latvian Lat&amp;lt;br&amp;gt;LBP-Lebanese Pound&amp;lt;br&amp;gt;LSL-Lesotho Loti&amp;lt;br&amp;gt;LRD-Liberian Dollar&amp;lt;br&amp;gt;LYD-Libyan Dinar&amp;lt;br&amp;gt;LTL-Lithuanian Lita&amp;lt;br&amp;gt;MOP-Macau Pataca&amp;lt;br&amp;gt;MKD-Macedonian Denar&amp;lt;br&amp;gt;MGF-Malagasy Franc&amp;lt;br&amp;gt;MWK-Malawi Kwacha&amp;lt;br&amp;gt;MYR-Malaysian Ringgit&amp;lt;br&amp;gt;MVR-Maldives Rufiyaa&amp;lt;br&amp;gt;MTL-Maltese Lira&amp;lt;br&amp;gt;MRO-Mauritania Ougulya&amp;lt;br&amp;gt;MUR-Mauritius Rupee&amp;lt;br&amp;gt;MXN-Mexican Peso&amp;lt;br&amp;gt;MDL-Moldovan Leu&amp;lt;br&amp;gt;MNT-Mongolian Tugrik&amp;lt;br&amp;gt;MAD-Moroccan Dirham&amp;lt;br&amp;gt;MZM-Mozambique Metical&amp;lt;br&amp;gt;MMK-Myanmar Kyat&amp;lt;br&amp;gt;NAD-Namibian Dollar&amp;lt;br&amp;gt;NPR-Nepalese Rupee&amp;lt;br&amp;gt;ANG-Neth Antilles Guilder&amp;lt;br&amp;gt;NZD-New Zealand Dollar&amp;lt;br&amp;gt;NIO-Nicaragua Cordoba&amp;lt;br&amp;gt;NGN-Nigerian Naira&amp;lt;br&amp;gt;KPW-North Korean Won&amp;lt;br&amp;gt;NOK-Norwegian Krone&amp;lt;br&amp;gt;OMR-Omani Rial&amp;lt;br&amp;gt;XPF-Pacific Franc&amp;lt;br&amp;gt;PKR-Pakistani Rupee&amp;lt;br&amp;gt;XPD-Palladium Ounces&amp;lt;br&amp;gt;PAB-Panama Balboa&amp;lt;br&amp;gt;PGK-Papua New Guinea Kina&amp;lt;br&amp;gt;PYG-Paraguayan Guarani&amp;lt;br&amp;gt;PEN-Peruvian Nuevo Sol&amp;lt;br&amp;gt;PHP-Philippine Peso&amp;lt;br&amp;gt;XPT-Platinum Ounces&amp;lt;br&amp;gt;PLN-Polish Zloty&amp;lt;br&amp;gt;QAR-Qatar Rial&amp;lt;br&amp;gt;ROL-Romanian Leu&amp;lt;br&amp;gt;RUB-Russian Rouble&amp;lt;br&amp;gt;WST-Samoa Tala&amp;lt;br&amp;gt;STD-Sao Tome Dobra&amp;lt;br&amp;gt;SAR-Saudi Arabian Riyal&amp;lt;br&amp;gt;SCR-Seychelles Rupee&amp;lt;br&amp;gt;SLL-Sierra Leone Leone&amp;lt;br&amp;gt;XAG-Silver Ounces&amp;lt;br&amp;gt;SGD-Singapore Dollar&amp;lt;br&amp;gt;SKK-Slovak Koruna&amp;lt;br&amp;gt;SIT-Slovenian Tolar&amp;lt;br&amp;gt;SBD-Solomon Islands Dollar&amp;lt;br&amp;gt;SOS-Somali Shilling&amp;lt;br&amp;gt;ZAR-South African Rand&amp;lt;br&amp;gt;LKR-Sri Lanka Rupee&amp;lt;br&amp;gt;SHP-St Helena Pound&amp;lt;br&amp;gt;SDD-Sudanese Dinar&amp;lt;br&amp;gt;SRG-Surinam Guilder&amp;lt;br&amp;gt;SZL-Swaziland Lilageni&amp;lt;br&amp;gt;SEK-Swedish Krona&amp;lt;br&amp;gt;TRY-Turkey Lira&amp;lt;br&amp;gt;CHF-Swiss Franc&amp;lt;br&amp;gt;SYP-Syrian Pound&amp;lt;br&amp;gt;TWD-Taiwan Dollar&amp;lt;br&amp;gt;TZS-Tanzanian Shilling&amp;lt;br&amp;gt;THB-Thai Baht&amp;lt;br&amp;gt;TOP-Tonga Pa&apos;anga&amp;lt;br&amp;gt;TTD-Trinidad&amp;amp;amp;amp;Tobago Dollar&amp;lt;br&amp;gt;TND-Tunisian Dinar&amp;lt;br&amp;gt;TRL-Turkish Lira&amp;lt;br&amp;gt;USD-U.S. Dollar&amp;lt;br&amp;gt;AED-UAE Dirham&amp;lt;br&amp;gt;UGX-Ugandan Shilling&amp;lt;br&amp;gt;UAH-Ukraine Hryvnia&amp;lt;br&amp;gt;UYU-Uruguayan New Peso&amp;lt;br&amp;gt;VUV-Vanuatu Vatu&amp;lt;br&amp;gt;VEB-Venezuelan Bolivar&amp;lt;br&amp;gt;VND-Vietnam Dong&amp;lt;br&amp;gt;YER-Yemen Riyal&amp;lt;br&amp;gt;YUM-Yugoslav Dinar&amp;lt;br&amp;gt;ZMK-Zambian Kwacha&amp;lt;br&amp;gt;ZWD-Zimbabwe Dollar&amp;lt;/font&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&quot;,
        &quot;policies&quot;: null
    },
    &quot;dependsOn&quot;: [
        &quot;[resourceId(&apos;Microsoft.ApiManagement/service&apos;, parameters(&apos;service_ibizmalo_name&apos;))]&quot;,
        &quot;[resourceId(&apos;Microsoft.ApiManagement/service/apis&apos;, parameters(&apos;service_ibizmalo_name&apos;), parameters(&apos;apis_58a3138ca9f54041296baffd_name&apos;))]&quot;
    ]
},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To be compared with the representation recieved when extracting the API using the REST interface:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  {
    &quot;id&quot;: &quot;/subscriptions/c107df29-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/PreDemoTest/providers/Microsoft.ApiManagement/service/ibizmalo/apis/58a3138ca9f54041296baffd/operations/58a313e40647c00eecf8d408&quot;,
    &quot;type&quot;: &quot;Microsoft.ApiManagement/service/apis/operations&quot;,
    &quot;name&quot;: &quot;58a313e40647c00eecf8d408&quot;,
    &quot;properties&quot;: {
      &quot;displayName&quot;: &quot;Conversion Rate&quot;,
      &quot;method&quot;: &quot;POST&quot;,
      &quot;urlTemplate&quot;: &quot;/conversionrate&quot;,
      &quot;templateParameters&quot;: [],
      &quot;description&quot;: &quot;&amp;lt;br&amp;gt;&amp;lt;b&amp;gt;Get conversion rate from one currency to another currency &amp;lt;b&amp;gt;&amp;lt;br&amp;gt;&amp;lt;p&amp;gt;&amp;lt;b&amp;gt;&amp;lt;font color=&apos;#000080&apos; size=&apos;1&apos; face=&apos;Verdana&apos;&amp;gt;&amp;lt;u&amp;gt;Differenct currency Code and Names around the world&amp;lt;/u&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;&amp;lt;font face=&apos;Verdana&apos; size=&apos;1&apos;&amp;gt;AFA-Afghanistan Afghani&amp;lt;br&amp;gt;ALL-Albanian Lek&amp;lt;br&amp;gt;DZD-Algerian Dinar&amp;lt;br&amp;gt;ARS-Argentine Peso&amp;lt;br&amp;gt;AWG-Aruba Florin&amp;lt;br&amp;gt;AUD-Australian Dollar&amp;lt;br&amp;gt;BSD-Bahamian Dollar&amp;lt;br&amp;gt;BHD-Bahraini Dinar&amp;lt;br&amp;gt;BDT-Bangladesh Taka&amp;lt;br&amp;gt;BBD-Barbados Dollar&amp;lt;br&amp;gt;BZD-Belize Dollar&amp;lt;br&amp;gt;BMD-Bermuda Dollar&amp;lt;br&amp;gt;BTN-Bhutan Ngultrum&amp;lt;br&amp;gt;BOB-Bolivian Boliviano&amp;lt;br&amp;gt;BWP-Botswana Pula&amp;lt;br&amp;gt;BRL-Brazilian Real&amp;lt;br&amp;gt;GBP-British Pound&amp;lt;br&amp;gt;BND-Brunei Dollar&amp;lt;br&amp;gt;BIF-Burundi Franc&amp;lt;br&amp;gt;XOF-CFA Franc (BCEAO)&amp;lt;br&amp;gt;XAF-CFA Franc (BEAC)&amp;lt;br&amp;gt;KHR-Cambodia Riel&amp;lt;br&amp;gt;CAD-Canadian Dollar&amp;lt;br&amp;gt;CVE-Cape Verde Escudo&amp;lt;br&amp;gt;KYD-Cayman Islands Dollar&amp;lt;br&amp;gt;CLP-Chilean Peso&amp;lt;br&amp;gt;CNY-Chinese Yuan&amp;lt;br&amp;gt;COP-Colombian Peso&amp;lt;br&amp;gt;KMF-Comoros Franc&amp;lt;br&amp;gt;CRC-Costa Rica Colon&amp;lt;br&amp;gt;HRK-Croatian Kuna&amp;lt;br&amp;gt;CUP-Cuban Peso&amp;lt;br&amp;gt;CYP-Cyprus Pound&amp;lt;br&amp;gt;CZK-Czech Koruna&amp;lt;br&amp;gt;DKK-Danish Krone&amp;lt;br&amp;gt;DJF-Dijibouti Franc&amp;lt;br&amp;gt;DOP-Dominican Peso&amp;lt;br&amp;gt;XCD-East Caribbean Dollar&amp;lt;br&amp;gt;EGP-Egyptian Pound&amp;lt;br&amp;gt;SVC-El Salvador Colon&amp;lt;br&amp;gt;EEK-Estonian Kroon&amp;lt;br&amp;gt;ETB-Ethiopian Birr&amp;lt;br&amp;gt;EUR-Euro&amp;lt;br&amp;gt;FKP-Falkland Islands Pound&amp;lt;br&amp;gt;GMD-Gambian Dalasi&amp;lt;br&amp;gt;GHC-Ghanian Cedi&amp;lt;br&amp;gt;GIP-Gibraltar Pound&amp;lt;br&amp;gt;XAU-Gold Ounces&amp;lt;br&amp;gt;GTQ-Guatemala Quetzal&amp;lt;br&amp;gt;GNF-Guinea Franc&amp;lt;br&amp;gt;GYD-Guyana Dollar&amp;lt;br&amp;gt;HTG-Haiti Gourde&amp;lt;br&amp;gt;HNL-Honduras Lempira&amp;lt;br&amp;gt;HKD-Hong Kong Dollar&amp;lt;br&amp;gt;HUF-Hungarian Forint&amp;lt;br&amp;gt;ISK-Iceland Krona&amp;lt;br&amp;gt;INR-Indian Rupee&amp;lt;br&amp;gt;IDR-Indonesian Rupiah&amp;lt;br&amp;gt;IQD-Iraqi Dinar&amp;lt;br&amp;gt;ILS-Israeli Shekel&amp;lt;br&amp;gt;JMD-Jamaican Dollar&amp;lt;br&amp;gt;JPY-Japanese Yen&amp;lt;br&amp;gt;JOD-Jordanian Dinar&amp;lt;br&amp;gt;KZT-Kazakhstan Tenge&amp;lt;br&amp;gt;KES-Kenyan Shilling&amp;lt;br&amp;gt;KRW-Korean Won&amp;lt;br&amp;gt;KWD-Kuwaiti Dinar&amp;lt;br&amp;gt;LAK-Lao Kip&amp;lt;br&amp;gt;LVL-Latvian Lat&amp;lt;br&amp;gt;LBP-Lebanese Pound&amp;lt;br&amp;gt;LSL-Lesotho Loti&amp;lt;br&amp;gt;LRD-Liberian Dollar&amp;lt;br&amp;gt;LYD-Libyan Dinar&amp;lt;br&amp;gt;LTL-Lithuanian Lita&amp;lt;br&amp;gt;MOP-Macau Pataca&amp;lt;br&amp;gt;MKD-Macedonian Denar&amp;lt;br&amp;gt;MGF-Malagasy Franc&amp;lt;br&amp;gt;MWK-Malawi Kwacha&amp;lt;br&amp;gt;MYR-Malaysian Ringgit&amp;lt;br&amp;gt;MVR-Maldives Rufiyaa&amp;lt;br&amp;gt;MTL-Maltese Lira&amp;lt;br&amp;gt;MRO-Mauritania Ougulya&amp;lt;br&amp;gt;MUR-Mauritius Rupee&amp;lt;br&amp;gt;MXN-Mexican Peso&amp;lt;br&amp;gt;MDL-Moldovan Leu&amp;lt;br&amp;gt;MNT-Mongolian Tugrik&amp;lt;br&amp;gt;MAD-Moroccan Dirham&amp;lt;br&amp;gt;MZM-Mozambique Metical&amp;lt;br&amp;gt;MMK-Myanmar Kyat&amp;lt;br&amp;gt;NAD-Namibian Dollar&amp;lt;br&amp;gt;NPR-Nepalese Rupee&amp;lt;br&amp;gt;ANG-Neth Antilles Guilder&amp;lt;br&amp;gt;NZD-New Zealand Dollar&amp;lt;br&amp;gt;NIO-Nicaragua Cordoba&amp;lt;br&amp;gt;NGN-Nigerian Naira&amp;lt;br&amp;gt;KPW-North Korean Won&amp;lt;br&amp;gt;NOK-Norwegian Krone&amp;lt;br&amp;gt;OMR-Omani Rial&amp;lt;br&amp;gt;XPF-Pacific Franc&amp;lt;br&amp;gt;PKR-Pakistani Rupee&amp;lt;br&amp;gt;XPD-Palladium Ounces&amp;lt;br&amp;gt;PAB-Panama Balboa&amp;lt;br&amp;gt;PGK-Papua New Guinea Kina&amp;lt;br&amp;gt;PYG-Paraguayan Guarani&amp;lt;br&amp;gt;PEN-Peruvian Nuevo Sol&amp;lt;br&amp;gt;PHP-Philippine Peso&amp;lt;br&amp;gt;XPT-Platinum Ounces&amp;lt;br&amp;gt;PLN-Polish Zloty&amp;lt;br&amp;gt;QAR-Qatar Rial&amp;lt;br&amp;gt;ROL-Romanian Leu&amp;lt;br&amp;gt;RUB-Russian Rouble&amp;lt;br&amp;gt;WST-Samoa Tala&amp;lt;br&amp;gt;STD-Sao Tome Dobra&amp;lt;br&amp;gt;SAR-Saudi Arabian Riyal&amp;lt;br&amp;gt;SCR-Seychelles Rupee&amp;lt;br&amp;gt;SLL-Sierra Leone Leone&amp;lt;br&amp;gt;XAG-Silver Ounces&amp;lt;br&amp;gt;SGD-Singapore Dollar&amp;lt;br&amp;gt;SKK-Slovak Koruna&amp;lt;br&amp;gt;SIT-Slovenian Tolar&amp;lt;br&amp;gt;SBD-Solomon Islands Dollar&amp;lt;br&amp;gt;SOS-Somali Shilling&amp;lt;br&amp;gt;ZAR-South African Rand&amp;lt;br&amp;gt;LKR-Sri Lanka Rupee&amp;lt;br&amp;gt;SHP-St Helena Pound&amp;lt;br&amp;gt;SDD-Sudanese Dinar&amp;lt;br&amp;gt;SRG-Surinam Guilder&amp;lt;br&amp;gt;SZL-Swaziland Lilageni&amp;lt;br&amp;gt;SEK-Swedish Krona&amp;lt;br&amp;gt;TRY-Turkey Lira&amp;lt;br&amp;gt;CHF-Swiss Franc&amp;lt;br&amp;gt;SYP-Syrian Pound&amp;lt;br&amp;gt;TWD-Taiwan Dollar&amp;lt;br&amp;gt;TZS-Tanzanian Shilling&amp;lt;br&amp;gt;THB-Thai Baht&amp;lt;br&amp;gt;TOP-Tonga Pa&apos;anga&amp;lt;br&amp;gt;TTD-Trinidad&amp;amp;amp;amp;Tobago Dollar&amp;lt;br&amp;gt;TND-Tunisian Dinar&amp;lt;br&amp;gt;TRL-Turkish Lira&amp;lt;br&amp;gt;USD-U.S. Dollar&amp;lt;br&amp;gt;AED-UAE Dirham&amp;lt;br&amp;gt;UGX-Ugandan Shilling&amp;lt;br&amp;gt;UAH-Ukraine Hryvnia&amp;lt;br&amp;gt;UYU-Uruguayan New Peso&amp;lt;br&amp;gt;VUV-Vanuatu Vatu&amp;lt;br&amp;gt;VEB-Venezuelan Bolivar&amp;lt;br&amp;gt;VND-Vietnam Dong&amp;lt;br&amp;gt;YER-Yemen Riyal&amp;lt;br&amp;gt;YUM-Yugoslav Dinar&amp;lt;br&amp;gt;ZMK-Zambian Kwacha&amp;lt;br&amp;gt;ZWD-Zimbabwe Dollar&amp;lt;/font&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&quot;,
      &quot;request&quot;: {
        &quot;description&quot;: &quot;ConversionRequest&quot;,
        &quot;queryParameters&quot;: [],
        &quot;headers&quot;: [],
        &quot;representations&quot;: [
          {
            &quot;contentType&quot;: &quot;application/json&quot;,
            &quot;sample&quot;: &quot;{     \&quot;fromCurrency\&quot;: \&quot;SEK\&quot;,     \&quot;toCurrency\&quot;: \&quot;USD\&quot; }&quot;,
            &quot;schemaId&quot;: &quot;322649e9-bfd5-4c93-8ad1-3fc1780e8045&quot;,
            &quot;typeName&quot;: &quot;ConversionRate&quot;
          }
        ]
      },
      &quot;responses&quot;: [
        {
          &quot;statusCode&quot;: 200,
          &quot;description&quot;: &quot;ConversionResult&quot;,
          &quot;representations&quot;: [
            {
              &quot;contentType&quot;: &quot;application/json&quot;,
              &quot;sample&quot;: &quot;{\r\n    \&quot;rate\&quot;: 1.0\r\n}&quot;,
              &quot;schemaId&quot;: &quot;322649e9-bfd5-4c93-8ad1-3fc1780e8045&quot;,
              &quot;typeName&quot;: &quot;ConversionRateResponse&quot;
            }
          ],
          &quot;headers&quot;: []
        }
      ],
      &quot;policies&quot;: null
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can clearly see that the REST object contains far more inforamtion and since we are working withe environment setups with DEV/TEST/PROD it would be dissapointing to not be able to provide samples in DEV but not in TEST and PRODUCTION (where it makes most sense):&lt;/p&gt;

&lt;p&gt;So this was the start of my new project &lt;strong&gt;API Management ARM Template Creator&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As some of you know I’ve been contributing alot to the Logic App Template Creator: &lt;a href=&quot;https://github.com/jeffhollan/LogicAppTemplateCreator&quot;&gt;https://github.com/jeffhollan/LogicAppTemplateCreator&lt;/a&gt; so I thought I’ll do something similar for API Management.&lt;/p&gt;

&lt;p&gt;While starting this I added a few more requirements&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Possible to only extract one specific api, but get all required linked attributes such as Named Values.&lt;/li&gt;
  &lt;li&gt;Parameterized URL’s (both API and backend)&lt;/li&gt;
  &lt;li&gt;Parameterized Named Values value&lt;/li&gt;
  &lt;li&gt;Automated url/Named values handling for Logic Apps&lt;/li&gt;
  &lt;li&gt;Parameterized values on all changeable values that is needed for groups, products, authorization servers etc&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first release is made today and the project can be found at my GIT site: &lt;a href=&quot;https://github.com/MLogdberg/APIManagementARMTemplateCreator&quot;&gt;https://github.com/MLogdberg/APIManagementARMTemplateCreator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How does it work?&lt;/p&gt;

&lt;p&gt;Well it’s no magic, I’ve just combined the result from the REST API’s to ARM Templates and along the way added some ARM functionality to improve the development experience.&lt;/p&gt;

&lt;p&gt;Let’s show with a sample with one of my API’s:
I have a “simple” rest API, that has two GET operations, with a policy for api and one for each operation, each operation need’s an authentication key that is stored in Named Values.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/09/apim-arm-template-creator-traffic-api-overview.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-arm-template-creator-traffic-api-overview.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key components that need’s to be changed are the URL and the authentication key used in the request to the backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The URL&lt;/strong&gt;
&lt;a href=&quot;/assets/uploads/2017/09/apim-arm-template-creator-traffic-api-webserviceurl.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-arm-template-creator-traffic-api-webserviceurl.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The authenticationkey in the policy ()&lt;/strong&gt;
&lt;a href=&quot;/assets/uploads/2017/09/apim-arm-template-creator-traffic-api-policy.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-arm-template-creator-traffic-api-policy.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The authenticationkey in Named Values ()&lt;/strong&gt;
&lt;a href=&quot;/assets/uploads/2017/09/apim-arm-template-creator-traffic-api-namedvalues.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-arm-template-creator-traffic-api-namedvalues.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even for a rather simple API there are som places that need’s to be changed and in order to prevent downtime on your API this is needed to be changed before/during deployment.
So using the PowerShell module I can extract a ARM template that will represent this API.&lt;/p&gt;

&lt;p&gt;Let’s look at some samples:&lt;/p&gt;

&lt;h3 id=&quot;manually-created-rest-api&quot;&gt;Manually created REST API&lt;/h3&gt;

&lt;p&gt;Parameterization of URL, the API looks like this and as you can see the URL is parameterized with &lt;strong&gt;[parameters(‘order_serviceUrl’)]&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
      &quot;comments&quot;: &quot;Generated for resource /subscriptions/c107df29-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/PreDemoTest/providers/Microsoft.ApiManagement/service/ibizmalo/apis/order&quot;,
      &quot;type&quot;: &quot;Microsoft.ApiManagement/service/apis&quot;,
      &quot;name&quot;: &quot;[concat(parameters(&apos;service_ibizmalo_name&apos;), &apos;/&apos; ,parameters(&apos;api_order_name&apos;))]&quot;,
      &quot;apiVersion&quot;: &quot;2017-03-01&quot;,
      &quot;properties&quot;: {
        &quot;displayName&quot;: &quot;Order&quot;,
        &quot;apiRevision&quot;: &quot;[parameters(&apos;order_apiRevision&apos;)]&quot;,
        &quot;description&quot;: &quot;Azure Logic App.&quot;,
        &quot;serviceUrl&quot;: &quot;[parameters(&apos;order_serviceUrl&apos;)]&quot;,
        &quot;path&quot;: &quot;api/v1/order&quot;,
        &quot;protocols&quot;: [
          &quot;https&quot;
        ],
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Parameterization of authentication key, the Named Value (Properties it’s called in ARM) also has it’s value parameterized with &lt;strong&gt;[parameters(‘trafficauthkey_value’)]&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
      &quot;comments&quot;: &quot;Generated for resource /subscriptions/c107df29-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/PreDemoTest/providers/Microsoft.ApiManagement/service/ibizmalo/properties/trafficauthkey&quot;,
      &quot;type&quot;: &quot;Microsoft.ApiManagement/service/properties&quot;,
      &quot;name&quot;: &quot;[concat(parameters(&apos;service_ibizmalo_name&apos;), &apos;/&apos; ,parameters(&apos;property_trafficauthkey_name&apos;))]&quot;,
      &quot;apiVersion&quot;: &quot;2017-03-01&quot;,
      &quot;properties&quot;: {
        &quot;displayName&quot;: &quot;trafficauthkey&quot;,
        &quot;value&quot;: &quot;[parameters(&apos;trafficauthkey_value&apos;)]&quot;,
        &quot;tags&quot;: null,
        &quot;secret&quot;: true
      },
      &quot;resources&quot;: [],
      &quot;dependsOn&quot;: []
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And due to these parameters it’s easy to change the values between environments and deliver robust and quality deployments.&lt;/p&gt;

&lt;h3 id=&quot;logic-app&quot;&gt;Logic App&lt;/h3&gt;
&lt;p&gt;When generating the API from a Logic App the needed changes between enviroments are to change the following things: the resource group, the name of the logic app and the trigger name.
The rest will be automated according the standard generation in API Management for Logic Apps.&lt;/p&gt;

&lt;p&gt;Description of the standard generation of policy for Logic App instances, first there is a rewrite URL that will change the URL to match the Logic App and also add the sv and sig values (authentication) in a Named Value (Property) in to the URL.
Second step is to set the Base URL of the Call to match the Logic App URL.&lt;/p&gt;

&lt;p&gt;Lastly there is a comment section added with the path to the original Azure Resource (our Logic App) used when generating the policy. This is something we are using to automate the URL and authentication values.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/09/apim-arm-template-creator-logicapp-policy.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-arm-template-creator-logicapp-policy.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The policy will be updated so that the &lt;em&gt;policyContent&lt;/em&gt; will use the &lt;em&gt;listCallbackUrl&lt;/em&gt; ARM function to retrieve the Logic App’s base url.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; {
  &quot;comments&quot;: &quot;Generated for resource /subscriptions/c107df29-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/PreDemoTest/providers/Microsoft.ApiManagement/service/ibizmalo/apis/order/operations/59a6b4730d691205f068a8be/policies/policy&quot;,
  &quot;type&quot;: &quot;Microsoft.ApiManagement/service/apis/operations/policies&quot;,
  &quot;name&quot;: &quot;[concat(parameters(&apos;service_ibizmalo_name&apos;), &apos;/&apos; ,parameters(&apos;api_order_name&apos;), &apos;/&apos; ,parameters(&apos;operations_59a6b4730d691205f068a8be_name&apos;), &apos;/&apos; ,parameters(&apos;policy_policy_name&apos;))]&quot;,
  &quot;apiVersion&quot;: &quot;2017-03-01&quot;,
  &quot;properties&quot;: {
    &quot;policyContent&quot;: &quot;[Concat(&apos;&amp;lt;policies&amp;gt;\r\n  &amp;lt;inbound&amp;gt;\r\n    &amp;lt;rewrite-uri id=\&quot;apim-generated-policy\&quot; template=\&quot;?api-version=2016-06-01&amp;amp;amp;sp=/triggers/request/run&amp;amp;amp;\&quot; /&amp;gt;\r\n    &amp;lt;set-backend-service id=\&quot;apim-generated-policy\&quot; base-url=\&quot;&apos;,listCallbackUrl(resourceId(parameters(&apos;logicApp_INT001-GetOrderInfo_resourcegroup&apos;),&apos;Microsoft.Logic/workflows/triggers&apos;, parameters(&apos;logicApp_INT001-GetOrderInfo_name&apos;),parameters(&apos;logicApp_INT001-GetOrderInfo_trigger&apos;)), providers(&apos;Microsoft.Logic&apos;, &apos;workflows&apos;).apiVersions[0]).basePath,&apos;\&quot; /&amp;gt;\r\n    &amp;lt;base /&amp;gt;\r\n    &amp;lt;set-header name=\&quot;Ocp-Apim-Subscription-Key\&quot; exists-action=\&quot;delete\&quot; /&amp;gt;\r\n  &amp;lt;/inbound&amp;gt;\r\n  &amp;lt;outbound&amp;gt;\r\n    &amp;lt;base /&amp;gt;\r\n  &amp;lt;/outbound&amp;gt;\r\n  &amp;lt;backend&amp;gt;\r\n    &amp;lt;base /&amp;gt;\r\n    &amp;lt;!-- { \&quot;azureResource\&quot;: { \&quot;type\&quot;: \&quot;logicapp\&quot;, \&quot;id\&quot;: \&quot;/subscriptions/c107df29-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/PreDemoTest/providers/Microsoft.Logic/workflows/INT001-GetOrderInfo/triggers/request\&quot; } } --&amp;gt;\r\n  &amp;lt;/backend&amp;gt;\r\n&amp;lt;/policies&amp;gt;&apos;)]&quot;
  },
  &quot;resources&quot;: [],
  &quot;dependsOn&quot;: [
    &quot;[resourceId(&apos;Microsoft.ApiManagement/service/apis&apos;, parameters(&apos;service_ibizmalo_name&apos;) ,parameters(&apos;api_order_name&apos;))]&quot;,
    &quot;[resourceId(&apos;Microsoft.ApiManagement/service/apis/operations&apos;, parameters(&apos;service_ibizmalo_name&apos;), parameters(&apos;api_order_name&apos;), parameters(&apos;operations_59a6b4730d691205f068a8be_name&apos;))]&quot;
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The Named Value (Property) will be automated the same way, using the &lt;em&gt;listCallbackUrl&lt;/em&gt; ARM function.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;comments&quot;: &quot;Generated for resource /subscriptions/c107df29-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/PreDemoTest/providers/Microsoft.ApiManagement/service/ibizmalo/properties/59a6b478285385ab3dfbb752&quot;,
  &quot;type&quot;: &quot;Microsoft.ApiManagement/service/properties&quot;,
  &quot;name&quot;: &quot;[concat(parameters(&apos;service_ibizmalo_name&apos;), &apos;/&apos; ,parameters(&apos;property_59a6b478285385ab3dfbb752_name&apos;))]&quot;,
  &quot;apiVersion&quot;: &quot;2017-03-01&quot;,
  &quot;properties&quot;: {
    &quot;displayName&quot;: &quot;orderrequest59a6b4783fb21a7984df42ae&quot;,
    &quot;value&quot;: &quot;[concat(&apos;sv=&apos;,listCallbackUrl(resourceId(parameters(&apos;logicApp_INT001-GetOrderInfo_resourcegroup&apos;),&apos;Microsoft.Logic/workflows/triggers&apos;, parameters(&apos;logicApp_INT001-GetOrderInfo_name&apos;),parameters(&apos;logicApp_INT001-GetOrderInfo_trigger&apos;)), providers(&apos;Microsoft.Logic&apos;, &apos;workflows&apos;).apiVersions[0]).queries.sv,&apos;&amp;amp;sig=&apos;,listCallbackUrl(resourceId(parameters(&apos;logicApp_INT001-GetOrderInfo_resourcegroup&apos;),&apos;Microsoft.Logic/workflows/triggers&apos;, parameters(&apos;logicApp_INT001-GetOrderInfo_name&apos;),parameters(&apos;logicApp_INT001-GetOrderInfo_trigger&apos;)), providers(&apos;Microsoft.Logic&apos;, &apos;workflows&apos;).apiVersions[0]).queries.sig)]&quot;,
    &quot;tags&quot;: [],
    &quot;secret&quot;: true
  },
  &quot;resources&quot;: [],
  &quot;dependsOn&quot;: []
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By using the &lt;strong&gt;listCallbackUrl&lt;/strong&gt; function we can retrieve the values from the specific Logic App at deployment time, removing all manual handling of URL’s and authentication values when working with API’s exposing Logic Apps.&lt;/p&gt;

&lt;h3 id=&quot;soap&quot;&gt;SOAP&lt;/h3&gt;
&lt;p&gt;So when SOAP was introduced to API Management a new resource was added, &lt;strong&gt;Backend&lt;/strong&gt; this is unfortunally not editable in the GUI yet but we can do changes on with ARM deployments, the REST and PS API’s.
So in order to create a full ARM template for SOAP we need that extra resource and all other allready described information.&lt;/p&gt;

&lt;p&gt;In my sample API Manegement instance my SOAP Currency Converter API is generated with a backend that has a parameter &lt;em&gt;[parameters(‘f9211da9-8ce1-48c7-8e13-e38bc5dbcbcd_url’)]&lt;/em&gt; to be used to change the URL.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;comments&quot;: &quot;Generated for resource /subscriptions/c107df29-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/PreDemoTest/providers/Microsoft.ApiManagement/service/ibizmalo/backends/f9211da9-8ce1-48c7-8e13-e38bc5dbcbcd&quot;,
  &quot;type&quot;: &quot;Microsoft.ApiManagement/service/backends&quot;,
  &quot;name&quot;: &quot;[concat(parameters(&apos;service_ibizmalo_name&apos;), &apos;/&apos; ,parameters(&apos;backend_f9211da9-8ce1-48c7-8e13-e38bc5dbcbcd_name&apos;))]&quot;,
  &quot;apiVersion&quot;: &quot;2017-03-01&quot;,
  &quot;properties&quot;: {
    &quot;title&quot;: &quot;CurrencyConverter Soap Backend&quot;,
    &quot;description&quot;: &quot;CurrencyConverter Soap Backend&quot;,
    &quot;url&quot;: &quot;[parameters(&apos;f9211da9-8ce1-48c7-8e13-e38bc5dbcbcd_url&apos;)]&quot;,
    &quot;protocol&quot;: &quot;soap&quot;,
    &quot;properties&quot;: {},
    &quot;tls&quot;: {}
  },
  &quot;resources&quot;: []
},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;get-started&quot;&gt;Get Started&lt;/h3&gt;
&lt;p&gt;So how do you get started? First of download the repo &lt;a href=&quot;https://github.com/MLogdberg/APIManagementARMTemplateCreator&quot;&gt;https://github.com/MLogdberg/APIManagementARMTemplateCreator&lt;/a&gt;, compile it and use this PowerShell script (replace the values with appropiate ones from your subscription and API Management instance).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-PowerShell&quot;&gt;#if you have problem with execution policy execute this in a administrator runned powershell window.
#Set-ExecutionPolicy -ExecutionPolicy Unrestricted

Import-Module &quot;C:\temp\APIManagementARMTemplateCreator\APIManagementTemplate\bin\Debug\APIManagementTemplate.dll&quot;


#Set the name of the API Mangement instance
$apimanagementname = &apos;ibizmalo&apos;

#Set the resource group 
$resourcegroupname = &apos;PreDemoTest&apos; # &apos;app-tst-cs-int-Migrated&apos;
#Set the subscription id 
$subscriptionid = &apos;c107df29-a4af-4bc9-a733-f88f0eaa4296&apos;#&apos;d4baa1e9-15f5-4c85-bb3e-1e108dc79b00&apos;#
#Set the tenant to use when login ing, make sure it has the right tennant
$tenant = &apos;mattiaslogdbergibizsolution.onmicrosoft.com&apos;

#optional set filter for a specific api (using standard REST filter, with path we can select api based on the API path)
#$filter = &quot;path eq &apos;api/v1/order&apos;&quot;
#$filter = &quot;path eq &apos;api/v1/currencyconverter&apos;&quot;

 
#setting the output filename
$filenname = $apimanagementname + &apos;.json&apos;

Get-APIManagementTemplate -APIFilters $filter -APIManagement $apimanagementname -ResourceGroup $resourcegroupname -SubscriptionId $subscriptionid -TenantName $tenant -ExportPIManagementInstance $false  | Out-File $filenname

&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;upcoming&quot;&gt;Upcoming&lt;/h3&gt;
&lt;p&gt;More functions and better support for authentication is on the todo list, also smarter/simpler product handling, here are my bullet points:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Automated support for all Azure Resources.&lt;/li&gt;
  &lt;li&gt;Operations Schema support.&lt;/li&gt;
  &lt;li&gt;Retrieve authroization servers linked to API, and parameterize them as needed.&lt;/li&gt;
  &lt;li&gt;Better support for authorization servers.&lt;/li&gt;
  &lt;li&gt;Support for Products and linking API’s to products&lt;/li&gt;
&lt;/ul&gt;

</description>
                <link>/apimanagement/arm-template-creator</link>
                <guid>/apimanagement/APIManagement-arm-template-creator</guid>
                <pubDate>2017-09-11T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>API Management concurrency control</title>
                <description>&lt;p&gt;As I was mentioning in the last post with concurrency control for Logic App, it’s important in the distributed world today to make sure to not flood our backend services since there are more restrictions in the shared and distributed landscape than it has been in the &lt;em&gt;good old days&lt;/em&gt; OnPrem where we had full control over all our services. 
That means that we need to have control over our integration solutions so they don’t spin away like crazy and causes unwanted flooding to our backend systems.&lt;/p&gt;

&lt;p&gt;Historically we could control the request towards our backends system with &lt;em&gt;Rate-Call-Limit&lt;/em&gt; and &lt;em&gt;Qutoas&lt;/em&gt; to make sure that a maximum of request was made by a consumers during a time period, that could be minutes,hours,days,months.&lt;/p&gt;

&lt;p&gt;But in the &lt;a href=&quot;https://blogs.msdn.microsoft.com/apimanagement/2017/08/23/release-notes-august-23-2017/&quot;&gt;latest release the API Management&lt;/a&gt; the team added amongst other concurrency control.
This means that we now also can control/restrict the number of concurrent calls to our backend service.&lt;/p&gt;

&lt;p&gt;I.e. we have a SaaS service that allows 20 concurrent calls, all calls without that limit will be declined. This was hard to control from API Management and all the responsibility was left to the consumers.
We had a case where the consumer push 1000 calls in a few miliseconds, distributed world is lovely! But the backend service couldnt handle it and most of the failed and a new batch was fired and yes the story repeated itself.
It ended with the consumer needing to change their solution (yes I agree that was the best way) but we had no chance off protecting the backend from the flood except &lt;em&gt;Rate-Limit&lt;/em&gt; but that was not an optimal solution.&lt;/p&gt;

&lt;p&gt;Now whit &lt;em&gt;Concurrency control&lt;/em&gt; we can garantée that the backend system don’t have more than 20 concurrent calls and all calls after are queued up to a maximum limit, and processed right away as one of the 20 concurrent calls are finished. Making sure to not waste resoruces in retrys and idle time.
Using the Concurrency control is simple here is the policy: &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/api-management/api-management-advanced-policies#LimitConcurrency&quot;&gt;read more here&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;limit-concurrency key=&quot;expression&quot; max-count=&quot;number&quot; timeout=&quot;in seconds&quot; max-queue-length=&quot;number&quot;&amp;gt;
        &amp;lt;!— nested policy statements --&amp;gt;  
&amp;lt;/limit-concurrency&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So let’s show a sample, I’ve created a Logic App to act as a backend service, it hasen’t mutch logic but a delay to simulate really heavy work (20 seconds)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-backend.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-backend.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Part 1: A simple flow will be a simple Logic app to Logic App with no restrictions:
&lt;a href=&quot;/assets/uploads/2017/09/demoFlow-logictologicapp.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/demoFlow-logictologicapp.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now let’s see how this looks like when consumed by another Logic App in a foreach loop (without any concurrency restrictions).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-nocontrol-logicapp.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-nocontrol-logicapp.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As assumed the execution takes abit longer than 20 seconds:
&lt;a href=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-nocontrol-logicapp-run.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-nocontrol-logicapp-run.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Part 2: Adding concurrency control by exposing the Backend Logic App via API Management 
&lt;a href=&quot;/assets/uploads/2017/09/demoFlow-logictoapimtologicapp.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/demoFlow-logictoapimtologicapp.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Logic App is imported to API Management and the policy &lt;em&gt;Concurrency Control&lt;/em&gt; is added:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/09/apim-concurrency-control-apim-api.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-concurrency-control-apim-api.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the policy looks like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;policies&amp;gt;
	&amp;lt;inbound&amp;gt;
		&amp;lt;base /&amp;gt;
		&amp;lt;rewrite-uri id=&quot;apim-generated-policy&quot; template=&quot;?api-version=2016-06-01&amp;amp;amp;sp=/triggers/request/run&amp;amp;amp;&quot; /&amp;gt;
		&amp;lt;set-backend-service id=&quot;apim-generated-policy&quot; base-url=&quot;https://prod-40.westeurope.logic.azure.com/workflows/24b778e6805344e686536a203ee47bce/triggers/request/paths/invoke&quot; /&amp;gt;
		&amp;lt;set-header name=&quot;Ocp-Apim-Subscription-Key&quot; exists-action=&quot;delete&quot; /&amp;gt;
	&amp;lt;/inbound&amp;gt;
	&amp;lt;backend&amp;gt;
		&amp;lt;limit-concurrency key=&quot;constantstring&quot; max-count=&quot;2&quot; timeout=&quot;120&quot; max-queue-length=&quot;100&quot;&amp;gt;
			&amp;lt;forward-request timeout=&quot;120&quot; /&amp;gt;
		&amp;lt;/limit-concurrency&amp;gt;
		&amp;lt;!--{ &quot;azureResource&quot;: { &quot;type&quot;: &quot;logicapp&quot;, &quot;id&quot;: &quot;/subscriptions/c107df29-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/Concurrency/providers/Microsoft.Logic/workflows/INT0002-SingelInstance/triggers/request&quot; } }--&amp;gt;
	&amp;lt;/backend&amp;gt;
	&amp;lt;outbound&amp;gt;
		&amp;lt;base /&amp;gt;
	&amp;lt;/outbound&amp;gt;
	&amp;lt;on-error&amp;gt;
		&amp;lt;base /&amp;gt;
	&amp;lt;/on-error&amp;gt;
&amp;lt;/policies&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To demonstrat the functionallity a new Logic App is now used , same logic as before but using the API Management to access the backend Logic App.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-backend.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-backend.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Executing the Logic App will now take 4 minutes! since the concurrency is set to 2.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-backend-run.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-backend-run.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So that is great now we have prevented to many concurrent calls to our backend system, but is it all good? Let’s look in to the log of our “backend system”&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-backend-cotrolled-runs.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-backend-cotrolled-runs.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that there are 2 failed runs and 22 in total runs, but as you remember the list had 20 records so we only wanted 20 request to our “backend system”.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-backend-cotrolled-failed-run.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/09/apim-concurrency-control-logic-app-backend-cotrolled-failed-run.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The failed ones has failed due to timeout and that will also make the Logic App executing a retry, ending with a total of 22 calls to the backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt;
This is truly a nice feature that we will use alot but we also need to understand the nature of the API and how to configure it correctly to prevent unwanted behavior. In a flow where
resending the information is not allowed, the queue lenght should be set as low as possible to prevent the retry behavior of clients resending the information even if it’s not wanted.
Or we might want to use other techniques for that kind of flows.&lt;/p&gt;

&lt;p&gt;All in all a &lt;strong&gt;great feature&lt;/strong&gt; and &lt;strong&gt;wery usefull&lt;/strong&gt; one, but as allways make sure to understand the feature and the requirements of the protected API when configuring it.&lt;/p&gt;

</description>
                <link>/apimanagement/concurrency-control</link>
                <guid>/apimanagement/APIManagement-concurrency-control</guid>
                <pubDate>2017-09-07T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>Logic Apps concurrency control</title>
                <description>&lt;p&gt;In a distributed world with increasing amount of moving parts we need to make sure to not flood our services since there are more restrictions in the shared and distributed landscape than it has been in the &lt;em&gt;good old days&lt;/em&gt; where we had full control over all our services. 
That means that we need to have control over our solutions so they don’t spin away like crazy.&lt;/p&gt;

&lt;p&gt;On this topic Logic Apps has earlier had problem, when looping over an array in a foreach loop and calling a connector we could choose between 20 concurrent actions or sequentially call it one by one. This mean that if 20 parallel actions was flooding the destination we had to make it to sequantial call the destination and therefore also taking alot longer. 
When working with batches this is not always possible since it might take to long time, so sometimes we had to create two or more parallel flows in Logic Apps to make suer that we could keep the time limit.&lt;/p&gt;

&lt;p&gt;Making the flow complex and look &lt;em&gt;“uggly”&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/08/Logic-App-concurrency-multiple-foreach.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/08/Logic-App-concurrency-multiple-foreach.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;newly-released-concurrency-control&quot;&gt;Newly released concurrency control!&lt;/h1&gt;
&lt;p&gt;But fortunately there is now a newly released object property on the for each action that will help us, only available in &lt;strong&gt;CodeView&lt;/strong&gt; for now but that will work just fine.&lt;/p&gt;

&lt;p&gt;The new property looks like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;runtimeConfiguration&quot;: {
    &quot;concurrency&quot;: {
        &quot;repetitions&quot;: 2
    }
},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And setting the &lt;em&gt;repetitions&lt;/em&gt; to 2 will be the more or less the same as above solution in execution but it will be mutch easier to maintain and work with the Logic App now.&lt;/p&gt;

&lt;p&gt;The foreach now looks like: (removed the body to the function for clarity reasons)&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;For_each&quot;: {
    &quot;actions&quot;: {
        &quot;INT0020-Update-Fuse-Users&quot;: {
            &quot;inputs&quot;: {
                &quot;body&quot;: {
                   ...
                },
                &quot;function&quot;: {
                    &quot;id&quot;: &quot;/subscriptions/fakeee-15f5-4c85-bb3e-1e108dc79b00/resourceGroups/rgroup/providers/Microsoft.Web/sites/appname/functions/INT0020-Update-Fuse-Users-Compare&quot;
                }
            },
            &quot;runAfter&quot;: {},
            &quot;type&quot;: &quot;Function&quot;
        }
    },
    &quot;foreach&quot;: &quot;@body(&apos;INT0020-Split-Array&apos;)&quot;,
    &quot;runAfter&quot;: {
        &quot;GET_FUSE_TOKEN&quot;: [
            &quot;Succeeded&quot;
        ]
    },
    &quot;runtimeConfiguration&quot;: {
        &quot;concurrency&quot;: {
            &quot;repetitions&quot;: 2
        }
    },
    &quot;type&quot;: &quot;Foreach&quot;
},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Logic App in the designer will now look like:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/08/Logic-App-concurrency-one-foreach.PNG&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/08/Logic-App-concurrency-one-foreach.PNG&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;triggers-also-have-concurent-control&quot;&gt;Triggers also have concurent control&lt;/h1&gt;
&lt;p&gt;We can also set this on triggers, sample bellow is on a recurrent trigger (or polling trigger withou spliton) will look like;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;trigger&quot;: {
&quot;type&quot;:&quot;http&quot;,
&quot;recurrence&quot;: {},
&quot;runtimeConfiguration&quot;: {
    &quot;concurrency&quot; : {
    &quot;runs&quot;: 10
	}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For more detailed explanation on Trigger handling I suggest you read &lt;a href=&quot;https://toonvanhoutte.wordpress.com/2017/08/29/logic-apps-concurrency-control/&quot;&gt;this great post from Toon Vanhoutte&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m really happy that the product group finally has released this since it’s such an important part in our &lt;em&gt;new&lt;/em&gt; world of ditributed landscapes and our “new” responsibility and interest in making sure our solutions are not flooding the destionations.
We got the power and now we got the possibility to restrain them to the appropiate amount.&lt;/p&gt;

</description>
                <link>/logicapps/concurrency-control</link>
                <guid>/logicapps/Logic-Apps-looping-concurrency-control</guid>
                <pubDate>2017-08-29T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>OMS and Non Events</title>
                <description>&lt;p&gt;When it comes to monitoring a integration flows, there are several types of monitoring that we need to cover, just the other day I got the requirement to make sure that a Logic App has been run atleast one time during a 24 hour period.&lt;/p&gt;

&lt;p&gt;To solve this I started to look at possible solutions and turning my head to the Alert section of Logic Apps Diagnostics since it has the possibility to create a alarm based on input as number of runs, number of failed runs etc. unfortunally for me the max time limit was 6 hours. 
In this solution we are using &lt;em&gt;Log Analytics&lt;/em&gt; and &lt;strong&gt;OMS&lt;/strong&gt; as monitor tool, using the new Logic Apps Gallery it’s super nice (guess I need another post on this later on). Anyway there is alarm functionality inside the OMS Portal so I started to look in to that.&lt;/p&gt;

&lt;p&gt;Alarms in OMS is easily created based on a Search so first of we need to create a search, this is done in the search area and easiest way is to click your way to a start of the search and then change the last parts manually, I needed to check that a workflow was executed and ended sucessfully.
So my query ended up like this: (easy to reuse, just change the &lt;em&gt;resource_workflowName_s&lt;/em&gt; to the name of your Logic App.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;search * | where ( Type == &quot;AzureDiagnostics&quot; ) | where OperationName == &quot;Microsoft.Logic/workflows/workflowRunCompleted&quot; | where status_s == &quot;Succeeded&quot;   | where ( resource_workflowName_s == &quot;INT002_Update_Work_Order2&quot; )  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This query will return the results of succesfully runs, and we will be able to use it in our alarm.&lt;/p&gt;

&lt;p&gt;Setting up the alarm is rather simple, just &lt;em&gt;Add Alert Rule&lt;/em&gt; and fill in some information about the alarm, the important parts are the &lt;strong&gt;Search Query&lt;/strong&gt; here you shall choose the saved query above, &lt;strong&gt;Time Window&lt;/strong&gt; this is how far back we will look, so for our case we look 24 hours back.
&lt;strong&gt;Alert Frequency&lt;/strong&gt; is another time slot and it’s how often to check this rule, based on our case we wanted to check every hour. But in order for us to not get a new alert every hour (seems unnessisary to get 7 alarm emails during th night we can also specify &lt;strong&gt;Spuress alerts&lt;/strong&gt; this will make sure that an alarm will not be sent out more often than every 6 hours.&lt;/p&gt;

&lt;p&gt;So in reality we can now be sure that at most we will be alerted within 25 hours from the last run that there has not been any more runs and we will be alerted again every 6 hours until we have sucessfully completed a run.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/08/OMS-non-event-alarm.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/08/OMS-non-event-alarm.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is possibility to invoke webhooks, Runbook or ITSM actions but in our case an email is good enough so we will use that.
The email sent out is not containing that mutch information but it’s enought for us, we now that the flow has not been working and most likely the sending system has failed to send their file.&lt;/p&gt;

&lt;p&gt;The email:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/uploads/2017/08/OMS-non-event-alarm-email.png&quot;&gt;&lt;img src=&quot;/assets/uploads/2017/08/OMS-non-event-alarm-email.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Monitoring for events that should happen but are not happening is always tricky and has historically always been hard to solve, so often collegues or other people in your organisation creates tasks for them to do daily checks of some sort. It can be small things like checking that a folder is empty or a log for a row with todays date on it.
Even if the task itself is easy it burdens the people doing it and as more of these “small” tasks are added the more time it consumes, time these peoople should have spent working on more important tasks.
So to be able to handle monitoring of predicted events and get an alarm we can give services of great value to these people, now we notify them if anything is stopped or so and they can focus on their work. When they can rely on the things we build, we are not only building robust integrations we are then also building trust and a service of great value.&lt;/p&gt;

&lt;p&gt;It’s often the small things that makes the most.&lt;/p&gt;
</description>
                <link>/oms/oms-non-events</link>
                <guid>/oms/OMS-Non-event</guid>
                <pubDate>2017-08-27T00:00:00+00:00</pubDate>
        </item>

        <item>
                <title>New blog</title>
                <description>&lt;p&gt;Now I thought it was time to create my own blog.&lt;/p&gt;

&lt;p&gt;As you might now I’ve been blogging alot on my work blog, &lt;a href=&quot;http://blog.ibiz-solutions.se/&quot;&gt;http://blog.ibiz-solutions.se/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So now I’ve felt that I’m ready for my own blog. I’ll keep with the same line, bloggin about Integration and most part will most surely be about Integration in Azure.&lt;/p&gt;

&lt;p&gt;I’ll cover updates on the source projects I contriubute to here i.e Logic App Template Creator and some other new fun projects, so stay tuned and poke me if I’m keeping a to low pase on my blog.&lt;/p&gt;

&lt;p&gt;Hope to see you around!&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;
</description>
                <link>/thinking/new-blog</link>
                <guid>/thinking/New-blog</guid>
                <pubDate>2017-08-26T00:00:00+00:00</pubDate>
        </item>


</channel>
</rss>
