<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>AI Apps and Agents - Microsoft Azure Blog</title>
        <link>https://azure.github.io/Cloud-Native/blog</link>
        <description>AI Apps and Agents - Microsoft Azure Blog</description>
        <lastBuildDate>Thu, 06 Oct 2022 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Oct | `awesome-azd` Templates]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/29-awesome-azd</link>
            <guid>https://azure.github.io/Cloud-Native/blog/29-awesome-azd</guid>
            <pubDate>Thu, 06 Oct 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[What's new in Azure Developer CLI October 2022 release?]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Beyond #30DaysOfServerless!</code> in October!</p>
<p>Yes, it's October!! And since we ended #ServerlessSeptember with a focus on <strong>End-to-End Development</strong> for Serverless on Azure, we thought it would be good to share updates in October that can help you skill up even further.</p>
<p>Today, we're following up on the <strong><a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli">Code to Cloud with <code>azd</code></a></strong> blog post (Day #29) where we introduced the Azure Developer CLI (<code>azd</code>), an open-source tool for streamlining your end-to-end developer experience going from local development environment to Azure cloud. In today's post, we celebrate the <em>October 2022</em> release of the tool, with three cool new features.</p>
<p>And if it's October, it must be <strong>#Hacktoberfest</strong>!! Read on to learn about how you can take advantage of one of the new features, to contribute to the <code>azd</code> open-source community and ecosystem!</p>
<p>Ready? Let's go!</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/29-awesome-azd#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li><strong>Azure Friday</strong>: Introducing the Azure Developer CLI (Video)</li>
<li><strong>October 2022 Release</strong>: What's New in the Azure Developer CLI?<!-- -->
<ul>
<li><strong>Azure Pipelines for CI/CD</strong>: <a href="https://learn.microsoft.com/azure/developer/azure-developer-cli/configure-devops-pipeline?tabs=azdo" target="_blank" rel="noopener noreferrer">Learn more</a></li>
<li><strong>Improved Infrastructure as Code structure via Bicep modules:</strong> <a href="https://devblogs.microsoft.com/azure-sdk/azure-developer-cli-azd-october-2022-release/#improved-infrastructure-as-code-structure-via-bicep-modules" target="_blank" rel="noopener noreferrer">Learn more</a></li>
<li><strong>A new <code>azd</code> template gallery</strong>: The new <code>azd-templates</code> gallery for community use! <a href="https://devblogs.microsoft.com/azure-sdk/azure-developer-cli-azd-october-2022-release/#new-template-gallery-awesome-azd" target="_blank" rel="noopener noreferrer">Learn more</a></li>
</ul>
</li>
<li><strong>Awesome-Azd</strong>: The new <code>azd-templates</code> gallery for Community use<!-- -->
<ul>
<li>Features: discover, create, contribute, request - templates</li>
<li>Hacktoberfest: opportunities to contribute in October - and beyond!</li>
</ul>
</li>
</ul>
<p><img loading="lazy" alt="Serverless September slide promoting Savannah Ostrowski&amp;#39;s session on azd-template Gallery, titled E2E Dev – From Cloud to Community." src="https://azure.github.io/Cloud-Native/assets/images/banner-17bfa50821263d1d81d1e0ac8b509032.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="azure-friday">Azure Friday<a href="https://azure.github.io/Cloud-Native/blog/29-awesome-azd#azure-friday" class="hash-link" aria-label="Direct link to Azure Friday" title="Direct link to Azure Friday">​</a></h2>
<p>This post is a follow-up to our #ServerlessSeptember post on <strong><a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli">Code to Cloud with Azure Developer CLI</a></strong> where we introduced <code>azd</code>, a new open-source tool that makes it quick and simple for you to move your application from a <em>local development environment</em> to Azure, streamlining your <em>end-to-end developer workflow</em> in the process.</p>
<p>Prefer to watch a video overview? I have you covered! Check out my recent conversation with Scott Hanselman on <a href="https://learn.microsoft.com/Shows/Azure-Friday/" target="_blank" rel="noopener noreferrer">Azure Friday</a> where we:</p>
<ul>
<li>talked about the code-to-cloud developer journey</li>
<li>walkthrough the ins and outs of an <code>azd</code> template</li>
<li>explored Azure Developer CLI commands in the terminal and VS Code, and</li>
<li>(probably most importantly) got a web app up and running on Azure with a database, Key Vault and monitoring all in a couple of minutes</li>
</ul>
<iframe width="500" height="300" src="https://www.youtube.com/embed/VTk-FhJyo7s" title="Introducing the Azure Developer CLI (azd) | Azure Friday"></iframe>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="october-release">October Release<a href="https://azure.github.io/Cloud-Native/blog/29-awesome-azd#october-release" class="hash-link" aria-label="Direct link to October Release" title="Direct link to October Release">​</a></h2>
<p>We're pleased to announce the October 2022 release of the Azure Developer CLI (currently <code>0.3.0-beta.2</code>). Read <a href="https://devblogs.microsoft.com/azure-sdk/azure-developer-cli-azd-october-2022-release/#new-template-gallery-awesome-azd" target="_blank" rel="noopener noreferrer">the release announcement</a> for more details. Here are the highlights:</p>
<ul>
<li><strong>Azure Pipelines for CI/CD</strong>: This addresses <a href="https://github.com/Azure/azure-dev/issues/101" target="_blank" rel="noopener noreferrer">azure-dev#101</a>, adding support for Azure Pipelines (alongside GitHub Actions) as a CI/CD provider. <a href="https://learn.microsoft.com/azure/developer/azure-developer-cli/configure-devops-pipeline?tabs=azdo" target="_blank" rel="noopener noreferrer">Learn more</a> about usage and related documentation.</li>
<li><strong>Improved Infrastructure as Code structure via Bicep modules</strong>: This addresses <a href="https://github.com/Azure/azure-dev/issues/543" target="_blank" rel="noopener noreferrer">azure-dev#543</a>, which recognized the complexity of using a single <code>resources.bicep</code> file for all resources. With this release, <code>azd</code> templates now come with Bicep modules organized by purpose making it easier to edit and understand. <a href="https://devblogs.microsoft.com/azure-sdk/azure-developer-cli-azd-october-2022-release/#improved-infrastructure-as-code-structure-via-bicep-modules" target="_blank" rel="noopener noreferrer">Learn more</a> about this structure, and how to use it.</li>
<li><strong>New Templates Gallery - awesome-azd</strong>: This addresses <a href="https://github.com/Azure/azure-dev/issues/398" target="_blank" rel="noopener noreferrer">azure-dev#398</a>, which aimed to make templates more discoverable and easier to contribute. <a href="https://devblogs.microsoft.com/azure-sdk/azure-developer-cli-azd-october-2022-release/#new-template-gallery-awesome-azd" target="_blank" rel="noopener noreferrer">Learn more</a> about how the new gallery improves the template discovery experience.</li>
</ul>
<p>In the next section, we'll dive briefly into the last feature, introducing the new <a href="https://aka.ms/awesome-azd" target="_blank" rel="noopener noreferrer"><code>awesome-azd</code></a> site and resource for templates discovery and contribution. And, since it's #Hacktoberfest season, we'll talk about the <strong>Contributor Guide</strong> and the many ways you can contribute to this project - with, or without, code.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="its-awesome-azd">It's <code>awesome-azd</code><a href="https://azure.github.io/Cloud-Native/blog/29-awesome-azd#its-awesome-azd" class="hash-link" aria-label="Direct link to its-awesome-azd" title="Direct link to its-awesome-azd">​</a></h2>
<p>Welcome to <code>awesome-azd</code> a new template gallery hosted on GitHub Pages, and meant to be a destination site for discovering, requesting, and contributing <code>azd-templates</code> for community use!</p>
<p>In addition, it's <strong>README</strong> reflects the <a href="https://github.com/topics/awesome-list" target="_blank" rel="noopener noreferrer">awesome-list</a> resource format, providing a location for the community to share "best of" resources for Azure Developer CLI - from blog posts and videos, to full-scale tutorials and templates.</p>
<ul>
<li>Visit the <a href="https://azure.github.io/awesome-azd/" target="_blank" rel="noopener noreferrer">awesome-azd Gallery</a></li>
<li>Browse the <a href="https://github.com/Azure/awesome-azd/blob/main/README.md" target="_blank" rel="noopener noreferrer">awesome-azd README</a></li>
</ul>
<p><img loading="lazy" alt="Animated showcase of Awesome AZD Templates" src="https://azure.github.io/Cloud-Native/assets/images/gallery-6c6684d3eb7048353a6641b17b689046.gif" width="1894" height="942" class="img_ev3q"></p>
<p>The Gallery is organized into three main areas:</p>
<ul>
<li><a href="https://azure.github.io/awesome-azd/" target="_blank" rel="noopener noreferrer">Gallery</a> page hosting templates.</li>
<li><a href="https://azure.github.io/awesome-azd/docs/intro" target="_blank" rel="noopener noreferrer">Contributor Guide</a> with an FAQ for contributors.</li>
<li><a href="https://github.com/Azure/awesome-azd/issues/new/choose" target="_blank" rel="noopener noreferrer">Custom Issues</a> for the types of contributions you can make</li>
</ul>
<p>Take a minute to explore the Gallery and note the features:</p>
<ul>
<li><strong>Search</strong> for templates by name</li>
<li><strong>Requested</strong> Templates - indicating asks from the community</li>
<li><strong>Featured</strong> Templates - highlighting high-quality templates</li>
<li><strong>Filters</strong> - to discover templates by and/or query combinations</li>
</ul>
<p>Check back often to see the latest contributed templates and requests!</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="hacktoberfest">Hacktoberfest<a href="https://azure.github.io/Cloud-Native/blog/29-awesome-azd#hacktoberfest" class="hash-link" aria-label="Direct link to Hacktoberfest" title="Direct link to Hacktoberfest">​</a></h2>
<p>So, why is this a good time to talk about the Gallery? Because October means it's time for <a href="https://hacktoberfest.com/" target="_blank" rel="noopener noreferrer">#Hacktoberfest</a> - a month-long celebration of open-source projects and their maintainers, and an opportunity for <strong>first-time contributors</strong> to get support and guidance making their first pull-requests! Check out the <a href="https://github.com/topics/hacktoberfest" target="_blank" rel="noopener noreferrer">#Hacktoberfest</a> topic on GitHub for projects you can contribute to.</p>
<p>And we hope you think of <code>awesome-azd</code> as another possible project to contribute to.</p>
<ul>
<li>Explore <a href="https://azure.github.io/awesome-azd/docs/intro#our-custom-issues" target="_blank" rel="noopener noreferrer">Custom Issues</a> for actionable ways to contribute code.</li>
<li>Explore <a href="https://azure.github.io/awesome-azd/docs/intro#other-ways-to-help" target="_blank" rel="noopener noreferrer">Other Ways To Help</a> for equally important non-code contributions.</li>
</ul>
<p>Check out the FAQ section to learn how to <a href="https://azure.github.io/awesome-azd/docs/faq/create-template" target="_blank" rel="noopener noreferrer">create</a>, <a href="https://azure.github.io/awesome-azd/docs/faq/discover-azd" target="_blank" rel="noopener noreferrer">discover</a>, and <a href="https://azure.github.io/awesome-azd/docs/faq/contribute-template" target="_blank" rel="noopener noreferrer">contribute</a> templates. Or take a couple of minutes to watch this video walkthrough from <a href="https://twitter.com/jongallant" target="_blank" rel="noopener noreferrer">Jon Gallant</a>:</p>
<iframe width="350" height="500" src="https://www.youtube.com/embed/vJa0K0TDvdM" title="Awesome-azd"></iframe>
<p>And don't hesitate to reach out to us - either via Issues on the repo, or in the <a href="https://github.com/Azure/Cloud-Native/discussions" target="_blank" rel="noopener noreferrer">Discussions</a> section of this site, to give us feedback!</p>
<p>Happy Hacking! 🎃</p>
<hr>]]></content:encoded>
            <category>cloud-native</category>
            <category>devtools</category>
            <category>hacktoberfest</category>
            <category>azure-developer-cli</category>
        </item>
        <item>
            <title><![CDATA[Serverless September - In a Nutshell]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/serverless-status-post</link>
            <guid>https://azure.github.io/Cloud-Native/blog/serverless-status-post</guid>
            <pubDate>Tue, 04 Oct 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[A wrap-up post from Serverless September, referencing the many initiatives and resources]]></description>
            <content:encoded><![CDATA[
<hr>
<p>It's <code>Serverless September</code> in a Nutshell! Join us as we unpack our month-long learning journey exploring the core technology pillars for Serverless architectures on Azure. Then end with a look at next steps to build your Cloud-native applications on Azure.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/serverless-status-post#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>Functions-as-a-Service (FaaS)</li>
<li>Microservices and Containers</li>
<li>Serverless Integrations</li>
<li>End-to-End Solutions</li>
<li>Developer Tools &amp; #Hacktoberfest</li>
</ul>
<p><img loading="lazy" alt="Banner for Serverless September" src="https://azure.github.io/Cloud-Native/assets/images/banner-a09093dd5ad62259887d4b7b430f2365.png" width="1920" height="1080" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="building-cloud-native-apps">Building Cloud-native Apps<a href="https://azure.github.io/Cloud-Native/blog/serverless-status-post#building-cloud-native-apps" class="hash-link" aria-label="Direct link to Building Cloud-native Apps" title="Direct link to Building Cloud-native Apps">​</a></h2>
<p>By definition, <em>cloud-native technologies empower organizations to <strong>build and run scalable applications</strong> in modern, dynamic environments such as public, private, and hybrid clouds.</em> You can learn more about cloud-native in Kendall Roden's #ServerlessSeptember post on <a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-01">Going Cloud-native with Azure Container Apps</a>.</p>
<p>Serveless technologies accelerate productivity and minimize costs for deploying applications at cloud scale. So, what can we build with serverless technologies in cloud-native on Azure? <em>Anything that is event-driven</em> - examples include:</p>
<ul>
<li><strong>Microservices</strong> - scaled by KEDA-compliant triggers</li>
<li><strong>Public API Endpoints</strong> - scaled by #concurrent HTTP requests</li>
<li><strong>Event-Driven Applications</strong> - scaled by length of message queue</li>
<li><strong>Web Applications</strong> - scaled by #concurrent HTTP requests</li>
<li><strong>Background Process</strong> - scaled by CPU and Memory usage</li>
</ul>
<p><img loading="lazy" alt="Infographic explaining serverless cloud-native uses, including microservices, public APIs, web apps, event-driven, and background processing." src="https://azure.github.io/Cloud-Native/assets/images/cloud-native-f4c230814d34747c8920a9f01729ccca.png" width="1280" height="720" class="img_ev3q"></p>
<p>Great - but as developers, we really want to know <strong><em>how</em> we can get started building and deploying serverless solutions on Azure</strong>. That was the focus of our #ServerlessSeptember journey. Let's take a quick look at the four key themes.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="functions-as-a-service-faas">Functions-as-a-Service (FaaS)<a href="https://azure.github.io/Cloud-Native/blog/serverless-status-post#functions-as-a-service-faas" class="hash-link" aria-label="Direct link to Functions-as-a-Service (FaaS)" title="Direct link to Functions-as-a-Service (FaaS)">​</a></h2>
<p><em>Functions-as-a-Service</em> (FaaS) is the epitome of developer productivity for full-stack modern apps. As developers, you don't manage infrastructure and focus only on business logic and application code. And, with <strong>Serverless Compute</strong> you <em>only pay for when your code runs</em> - making this the simplest first step to begin migrating your application to cloud-native.</p>
<p>In Azure, FaaS is provided by Azure Functions. Check out our <a href="https://azure.github.io/Cloud-Native/blog/08-functions-azure">Functions + Serverless on Azure</a> to go from learning core concepts, to building your first Functions app in your programming language of choice. Azure functions support multiple programming languages including C#, F#, Java, JavaScript, Python, Typescript, and PowerShell.</p>
<p>Want to get extended language support for languages like Go, and Rust? You can <a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-03">Use Custom Handlers</a> to make this happen! But what if you want to have long-running functions, or create complex workflows involving more than one function? Read our <a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-02">post on Durable Entities</a> to learn how you can <em>orchestrate</em> this with Azure Functions.</p>
<p>Check out this recent <a href="https://aka.ms/ATEonDemand" target="_blank" rel="noopener noreferrer">AskTheExpert</a> Q&amp;A session with the Azure Functions team to get answers to popular community questions on Azure Functions features and usage.</p>
<iframe src="https://learn-video.azurefd.net/vod/player?show=ask-the-expert&amp;ep=serverless-september-azure-functions" width="600" height="400" title="Ask the Expert: Serverless September Azure Functions"></iframe>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="microservices-and-containers">Microservices and Containers<a href="https://azure.github.io/Cloud-Native/blog/serverless-status-post#microservices-and-containers" class="hash-link" aria-label="Direct link to Microservices and Containers" title="Direct link to Microservices and Containers">​</a></h2>
<p>Functions-as-a-Service is an ideal first step towards serverless development. But Functions are just <em>one of the 5 pillars</em> of <a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-01" target="_blank" rel="noopener noreferrer">cloud-native</a>. This week we'll look at two of the other pillars: <strong>microservices</strong> and <strong>containers</strong> - with specific focus on two core technologies: Azure Container Apps and Dapr (Distributed Application Runtime).</p>
<p>In this 6-part series of posts, we walk through each technology independently, before looking at the value of building Azure Container Apps <strong>with Dapr</strong>.</p>
<ul>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/09-aca-fundamentals" target="_blank" rel="noopener noreferrer">Hello Container Apps</a> we learned core concepts &amp; deployed our first ACA.</li>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/microservices-10" target="_blank" rel="noopener noreferrer">Microservices Communication</a> we learned about ACA environments and virtual networks, and how microservices communicate in ACA with a hands-on tutorial.</li>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps" target="_blank" rel="noopener noreferrer">Scaling Your Container Apps</a> we learned about KEDA (Kubernetes Event-Driven Autoscaler) and configuring ACA for autoscaling with KEDA-compliant triggers.</li>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/12-build-with-dapr" target="_blank" rel="noopener noreferrer">Build with Dapr</a> we introduced the Distributed Application Runtime (Dapr), exploring its Building Block APIs and sidecar architecture for working with ACA.</li>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id" target="_blank" rel="noopener noreferrer">Secure ACA Access</a> we learned how to secure ACA access to external services with - and without - Dapr, covering Secret Stores and Managed Identity.</li>
<li>Finally, <a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart" target="_blank" rel="noopener noreferrer">Build ACA with Dapr</a> tied it all together with a enterprise app scenario where an orders processor (ACA) uses Dapr APIs (PubSub, State Management) to receive and store order messages from Azure Service Bus.</li>
</ul>
<p><img loading="lazy" src="https://github.com/Azure/Cloud-Native/blob/41cc0890acd204a9069836dfcc5727c48d5fca97/website/blog/2022-09-14/img/ACA-Tutorial-AsyncComm-0922.jpg" alt="Build ACA with Dapr" class="img_ev3q"></p>
<p>Check out this recent <a href="https://aka.ms/ATEonDemand" target="_blank" rel="noopener noreferrer">AskTheExpert</a> Q&amp;A session with the Azure Container Apps team for answers to popular community questions on core features and usage.</p>
<iframe src="https://learn-video.azurefd.net/vod/player?show=ask-the-expert&amp;ep=serverless-september-azure-container-apps" width="640" height="360" title="Ask the Expert: Serverless September Azure Container Apps"></iframe>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="serverless-integrations">Serverless Integrations<a href="https://azure.github.io/Cloud-Native/blog/serverless-status-post#serverless-integrations" class="hash-link" aria-label="Direct link to Serverless Integrations" title="Direct link to Serverless Integrations">​</a></h2>
<p>In the first half of the month we looked at <em>compute</em> resources for building and deploying serverless applications. In the second half, we look at <em>integration</em> tools and resources that automate developer workflows to streamline the end-to-end developer experience.</p>
<p>In Azure, this is enabled by services like <a href="https://learn.microsoft.com/azure/logic-apps/logic-apps-overview" target="_blank" rel="noopener noreferrer">Azure Logic Apps</a> and <a href="https://learn.microsoft.com/azure/event-grid/overview" target="_blank" rel="noopener noreferrer">Azure Event Grid</a>. Azure Logic Apps provides a visual designer to <em>create and automate workflows</em> with little or no code involved. Azure Event Grid provides a <em>highly-scable event broker</em> with support for pub/sub communications to drive async event-driven architectures.</p>
<ul>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/17-integrate-cosmosdb" target="_blank" rel="noopener noreferrer">Tracking Weather Data Changes With Logic Apps</a> we look at how you can use Logic Apps to  integrate the MSN weather service with Azure CosmosDB, allowing automated collection of weather data on changes.</li>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/18-cloudmail" target="_blank" rel="noopener noreferrer">Teach the Cloud to Read &amp; Categorize Mail</a> we take it a step further, using Logic Apps to automate a workflow that includes a Computer Vision service to "read" images and store the results to CosmosDB.</li>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/20-events-graph" target="_blank" rel="noopener noreferrer">Integrate with Microsoft Graph</a> we explore a multi-cloud scenario (Azure + M365) where change notifications from Microsoft Graph can be integrated using Logic Apps and Event Hubs to power an onboarding workflow.</li>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid" target="_blank" rel="noopener noreferrer">Cloud Events with Event Grid</a> we learn about the CloudEvents specification (for consistently describing event data) - and learn how Event Grid brokers events in this format. Azure Logic Apps can be an Event handler (subscriber) that uses the event to trigger an automated workflow on receipt.</li>
</ul>
<p><img loading="lazy" src="https://azure.github.io/Cloud-Native/assets/images/21-cloudevents-via-event-grid-01-694e11ff4422f7f4f28ae03f08580170.png" alt="Azure Event Grid And Logic Apps" class="img_ev3q"></p>
<p>Want to explore other such integrations? Browse <a href="https://learn.microsoft.com/azure/architecture/browse/?filter-products=Logic%20A&amp;products=azure-event-grid%2Cazure-logic-apps" target="_blank" rel="noopener noreferrer">Azure Architectures</a> and filter by selected Azure services for more real-world scenarios.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="end-to-end-solutions">End-to-End Solutions<a href="https://azure.github.io/Cloud-Native/blog/serverless-status-post#end-to-end-solutions" class="hash-link" aria-label="Direct link to End-to-End Solutions" title="Direct link to End-to-End Solutions">​</a></h2>
<p>We've covered serverless <em>compute</em> solutions (for building your serverless applications) and serverless <em>integration</em> services to automate end-to-end workflows in synchronous or asynchronous event-driven architectures. In this final week, we want to leave you with a sense of <em>end-to-end</em> development tools and use cases that can be enabled by Serverless on Azure. Here are some  key examples:</p>
<table><thead><tr><th style="text-align:left">Article</th><th style="text-align:left">Description</th></tr></thead><tbody><tr><td style="text-align:left"><img loading="lazy" src="https://azure.github.io/Cloud-Native/assets/images/architecture-a2d16c0719ab5f90fe9e4b66a40198bc.png" alt="" class="img_ev3q"></td><td style="text-align:left">In <a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet" target="_blank" rel="noopener noreferrer"><strong>this tutorial</strong></a>, you'll learn to deploy a containerized ASP.NET Core 6.0 application to Azure Container Apps - with a Blazor front-end and two Web API projects</td></tr><tr><td style="text-align:left"><img loading="lazy" src="https://azure.github.io/Cloud-Native/assets/images/acr-portal-01-56ad80e74d4597e32bb2bb534148d10d.png" alt="Deploy Java containers to cloud" class="img_ev3q"></td><td style="text-align:left">In <a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet" target="_blank" rel="noopener noreferrer"><strong>this tutorial</strong></a> you learn to build and deploy a Java application running on Spring Boot, by publishing it in a container to Azure Container Registry, then deploying to Azure Container Apps,, from ACR, via the Azure Portal.</td></tr><tr><td style="text-align:left"><img loading="lazy" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-01-d6fac44727880dd526e03e2010938f0a.png" alt="Where am I? My GPS Location with Serverless Power Platform Custom Connector" class="img_ev3q"></td><td style="text-align:left">In <a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i" target="_blank" rel="noopener noreferrer"><strong>this step-by-step tutorial</strong></a> you learn to integrate a serverless application (built on Azure Functions and OpenAPI) with Power Platforms custom connectors via Azure API Management (API-M).This pattern can empower a new ecosystem of <em>fusion apps</em> for cases like inventory management.</td></tr><tr><td style="text-align:left"><img loading="lazy" src="https://microsoft.github.io/WhatTheHack/015-Serverless/images/preferred-solution.png" alt="" class="img_ev3q"></td><td style="text-align:left">And in our <a href="https://microsoft.github.io/WhatTheHack/015-Serverless/images/preferred-solution.png" target="_blank" rel="noopener noreferrer"><strong>Serverless Hacks</strong></a> initiative, we walked through an 8-step hack to build a serverless tollbooth. Check out <a href="https://aka.ms/serverless-september/videos" target="_blank" rel="noopener noreferrer"><strong>this 12-part video walkthrough</strong></a> of a reference solution using .NET.</td></tr></tbody></table>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="developer-tools">Developer Tools<a href="https://azure.github.io/Cloud-Native/blog/serverless-status-post#developer-tools" class="hash-link" aria-label="Direct link to Developer Tools" title="Direct link to Developer Tools">​</a></h2>
<p>But wait - there's more. Those are a sample of the end-to-end application scenarios that are built on serverless on Azure. But what about the <strong>developer experience</strong>? In <a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli" target="_blank" rel="noopener noreferrer"><strong>this article</strong></a>, we say hello to the <em>Azure Developer CLI</em> - an open-source tool that streamlines your develop-deploy workflow, with simple commands that map to core stages of your development journey. <strong>Go from code to cloud with one CLI</strong></p>
<p><img loading="lazy" src="https://azure.github.io/Cloud-Native/assets/images/azd-workflow-163d61cf5c6aa44a23dd4dda9858a296.png" alt="" class="img_ev3q"></p>
<p>And <strong>watch this space for more such tutorials and content through October</strong>, including a special #Hacktoberfest focused initiative to encourage and support first-time contributors to open-source. Here's a sneak peek at the project we plan to share - the new <a href="https://aka.ms/awesome-azd" target="_blank" rel="noopener noreferrer">awesome-azd templates</a> gallery.</p>
<p><img loading="lazy" alt="Animated showcase of Awesome AZD Templates" src="https://azure.github.io/Cloud-Native/assets/images/gallery-6c6684d3eb7048353a6641b17b689046.gif" width="1894" height="942" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="join-us-at-microsoft-ignite">Join us at Microsoft Ignite!<a href="https://azure.github.io/Cloud-Native/blog/serverless-status-post#join-us-at-microsoft-ignite" class="hash-link" aria-label="Direct link to Join us at Microsoft Ignite!" title="Direct link to Join us at Microsoft Ignite!">​</a></h2>
<p>Want to continue your learning journey, and learn about what's next for Serverless on Azure?
<strong>Microsoft Ignite</strong> happens Oct 12-14 this year and has multiple sessions on relevant technologies and tools. Check out the <a href="https://ignite.microsoft.com/sessions?q=cloud%2520native%2520architectures&amp;f=%255B%257B%2522name%2522%253A%2522Breakout%2522%252C%2522facetName%2522%253A%2522sessionType%2522%257D%255D&amp;s=%257B%2522name%2522%253A%2522translate.refine.label.sort.relevance%2522%252C%2522type%2522%253A0%257D&amp;t=%257B%2522from%2522%253A%25222022-10-12T00%253A00%253A00-07%253A00%2522%252C%2522to%2522%253A%25222022-10-13T23%253A59%253A59-07%253A00%2522%257D&amp;g=%255B%257B%2522name%2522%253A%2522live-now-and-upcoming%2522%252C%2522enabled%2522%253Afalse%257D%255Dl" target="_blank" rel="noopener noreferrer">Session Catalog</a> and <a href="https://ignite.microsoft.com/sessions/8950b2b1-62eb-48f9-90ef-5ad779ce8e22?source=sessions" target="_blank" rel="noopener noreferrer">register here</a> to attend online.</p>]]></content:encoded>
            <category>serverless-september</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
            <category>azure-event-grid</category>
            <category>azure-logic-apps</category>
            <category>azure-functions</category>
        </item>
        <item>
            <title><![CDATA[29. Code to Cloud with `azd`]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli</link>
            <guid>https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli</guid>
            <pubDate>Thu, 29 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[<FIXME>]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 29</code> of #30DaysOfServerless!</p>
<p>We are in the final days of the 30-day journey so it seemed appropriate to end the <em>End-to-End</em> Developer Journey with a discussion on <em>tooling</em> that can simplify and enhance the developer experience from development to deployment and beyond. Say hello to the <strong>Azure Developer CLI</strong>.</p>
<p>Ready? Let's go!</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Updated: October 6, 2022</div><div class="admonitionContent_BuS1"><p>Today marked the <a href="https://devblogs.microsoft.com/azure-sdk/azure-developer-cli-azd-october-2022-release/" target="_blank" rel="noopener noreferrer">October 22 release</a> of the Azure Developer CLI - bringing with it a few new features and community-targeted resources. Look out for a follow-up post to this one that dives into more details, just in time for <strong>#Hacktoberfest!</strong> 🌟</p></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li><strong>A new tool has entered the chat:</strong> Azure Developer CLI (<code>azd</code>)</li>
<li><strong>(Template) Anatomy 101</strong>: What makes an <code>azd</code> template?</li>
<li><strong>End-to-end support:</strong> Move code to cloud in a single step!</li>
<li><strong>Best practices:</strong> Monitor your application and run CI/CD on every commit</li>
<li><strong>Exercise:</strong> Try this yourself or create your own <code>azd</code> template</li>
<li><strong>Resources:</strong> For self-study!</li>
</ul>
<p><img loading="lazy" alt="Serverless September slide featuring Savannah Ostrowski presenting Azure Developer CLI: E2E Dev – From Code to Cloud." src="https://azure.github.io/Cloud-Native/assets/images/banner-ae42f77f55dd26f67623a51594c4d1e7.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="a-new-tool-has-entered-the-chat-what-is-the-azure-developer-cli-azd"><strong>A new tool has entered the chat:</strong> What is the Azure Developer CLI (<code>azd</code>)?<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#a-new-tool-has-entered-the-chat-what-is-the-azure-developer-cli-azd" class="hash-link" aria-label="Direct link to a-new-tool-has-entered-the-chat-what-is-the-azure-developer-cli-azd" title="Direct link to a-new-tool-has-entered-the-chat-what-is-the-azure-developer-cli-azd">​</a></h2>
<p>The Azure Developer CLI (<code>azd</code>) is a new, open source tool that makes it quick and simple for you to move your application from your local development environment to Azure while considering your end-to-end developer workflow. You might be familiar with other CLIs that focus on Infrastructure as Code or scaffolding your application but the Azure Developer CLI does all that and more!</p>
<p>The Azure Developer CLI commands are simple, high-level and map to core stages in your developer workflow. Think project initialization/creation, build, deploy, repeat!</p>
<p><img loading="lazy" alt="Code to Cloud guide with Azure Developer CLI, highlighting commands for initializing, deploying, and monitoring cloud-native applications." src="https://azure.github.io/Cloud-Native/assets/images/azd-workflow-163d61cf5c6aa44a23dd4dda9858a296.png" width="1920" height="1080" class="img_ev3q"></p>
<p>By using <a href="https://aka.ms/azure-dev/templates?source=serverless-september" target="_blank" rel="noopener noreferrer">idiomatic and flexible application templates</a>, the Azure Developer CLI uses recipes for common application architectures that you can customize for your use case. These templates include:</p>
<ul>
<li>best practices</li>
<li>sample application code that goes beyond "Hello World!"</li>
<li>infrastructure as code assets so you can move your code to the cloud and set up monitoring for your application, and</li>
<li>all the bits to set up CI/CD to run on every commit to your repo against resources on Azure</li>
</ul>
<p>...all in the language(s) you're most comfortable in. You can use an <a href="https://aka.ms/azure-dev/templates?source=serverless-september" target="_blank" rel="noopener noreferrer">existing template</a> or even create your own (more on that later!).</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="template-anatomy-101-what-makes-an-azd-template"><strong>(Template) Anatomy 101</strong>: What makes an <code>azd</code> template?<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#template-anatomy-101-what-makes-an-azd-template" class="hash-link" aria-label="Direct link to template-anatomy-101-what-makes-an-azd-template" title="Direct link to template-anatomy-101-what-makes-an-azd-template">​</a></h2>
<p>So now that you've been introduced to the Azure Developer CLI, let's take a look at an <code>azd</code>-enabled codebase, which we call a template. You can think of a template as a recipe - it provides a solid foundation that you can customize depending on your preference/use case/requirements.</p>
<p>To make this concrete and because it's #ServerlessSeptember, we're going to walk through this <a href="https://github.com/Azure-Samples/todo-python-mongo-swa-func" target="_blank" rel="noopener noreferrer">ToDo application template</a> that uses Azure Static Web Apps and Azure Functions.</p>
<p><img loading="lazy" alt="Azure resource group diagram showing a ReactJS web app, Python FastAPI, Cosmos DB, Key Vault, Azure Storage, and Azure Monitor." src="https://azure.github.io/Cloud-Native/assets/images/arch-diagram-9fc83dea79bdc2778665a6129823c6cd.png" width="1475" height="1509" class="img_ev3q"></p>
<p>Let's talk about the files in terms of their purpose:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="azure-developer-cli-specific-files">Azure Developer CLI-specific files<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#azure-developer-cli-specific-files" class="hash-link" aria-label="Direct link to Azure Developer CLI-specific files" title="Direct link to Azure Developer CLI-specific files">​</a></h3>
<ul>
<li><code>azure.yaml</code> - contains metadata that describes the application (Azure hosts, languages, template name) and serves as an entrypoint for functionality in Visual Studio Code (oh yeah, you can also use <code>azd</code> using <a href="https://aka.ms/azure-dev/vscode-ext?source=serverless-september" target="_blank" rel="noopener noreferrer">a VS Code extension</a>!).</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="application-development-support-code-run-debug-test">Application development support (code, run, debug, test)<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#application-development-support-code-run-debug-test" class="hash-link" aria-label="Direct link to Application development support (code, run, debug, test)" title="Direct link to Application development support (code, run, debug, test)">​</a></h3>
<ul>
<li><code>.devcontainer/</code> - support for if you're <a href="https://code.visualstudio.com/docs/remote/containers" target="_blank" rel="noopener noreferrer">writing code in a container</a></li>
<li><code>.vscode/</code> - support for local development in Visual Studio Code via <a href="https://code.visualstudio.com/docs/editor/debugging" target="_blank" rel="noopener noreferrer">launch.json</a> (for debugging) and <a href="https://code.visualstudio.com/docs/editor/tasks" target="_blank" rel="noopener noreferrer">tasks.json</a> (for spinning up the web app for local development)</li>
<li><code>src/</code> - contains all the sample application code which you can modify or swap out for your own application</li>
<li><code>tests/</code> - test for the application, written using <a href="https://playwright.dev/" target="_blank" rel="noopener noreferrer">Playwright</a></li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="infrastructure-as-code-provisioning-and-deploying-infrastructure-on-azure-programmatically">Infrastructure as Code (provisioning and deploying infrastructure on Azure, programmatically)<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#infrastructure-as-code-provisioning-and-deploying-infrastructure-on-azure-programmatically" class="hash-link" aria-label="Direct link to Infrastructure as Code (provisioning and deploying infrastructure on Azure, programmatically)" title="Direct link to Infrastructure as Code (provisioning and deploying infrastructure on Azure, programmatically)">​</a></h3>
<ul>
<li><code>infra/</code> - contains all infrastructure as code (IaC) assets written in <a href="https://docs.microsoft.com/azure/azure-resource-manager/bicep/overview?tabs=bicep" target="_blank" rel="noopener noreferrer">Bicep</a> or <a href="https://aka.ms/azure-dev/terraform" target="_blank" rel="noopener noreferrer">Terraform</a>; includes logic to set up all components we need to set up the application on Azure, wire everything up securely, and monitor application health, performance and usage!</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="cicd">CI/CD<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#cicd" class="hash-link" aria-label="Direct link to CI/CD" title="Direct link to CI/CD">​</a></h3>
<ul>
<li><code>.github/</code> - contains a GitHub Actions workflow to set up a CI/CD pipeline that runs on every new commit to the repo</li>
<li><code>.azdo/</code> - contains a Azure Pipelines workflow to set up a CI/CD pipeline that runs on every new commit to the repo</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="end-to-end-support-move-code-to-cloud-in-a-single-step"><strong>End-to-end support:</strong> Move code to cloud in a single step!<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#end-to-end-support-move-code-to-cloud-in-a-single-step" class="hash-link" aria-label="Direct link to end-to-end-support-move-code-to-cloud-in-a-single-step" title="Direct link to end-to-end-support-move-code-to-cloud-in-a-single-step">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="if-you-want-to-follow-along-in-this-section-and-dont-already-have-the-azure-developer-cli-installed-check-out-these-instructions-to-install-it-on-windows-linux-or-macos-in-your-favorite-terminal">If you want to follow along in this section and don't already have the Azure Developer CLI installed, check out <a href="https://aka.ms/azure-dev/install-instructions?source=serverless-september" target="_blank" rel="noopener noreferrer">these instructions</a> to install it on Windows, Linux or MacOS in your favorite terminal!<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#if-you-want-to-follow-along-in-this-section-and-dont-already-have-the-azure-developer-cli-installed-check-out-these-instructions-to-install-it-on-windows-linux-or-macos-in-your-favorite-terminal" class="hash-link" aria-label="Direct link to if-you-want-to-follow-along-in-this-section-and-dont-already-have-the-azure-developer-cli-installed-check-out-these-instructions-to-install-it-on-windows-linux-or-macos-in-your-favorite-terminal" title="Direct link to if-you-want-to-follow-along-in-this-section-and-dont-already-have-the-azure-developer-cli-installed-check-out-these-instructions-to-install-it-on-windows-linux-or-macos-in-your-favorite-terminal">​</a></h3>
<p>So now that we've gone over what this template contains on GitHub, let's pull this template code down to our local machine, set it up for local development, provision the right infrastructure, and deploy the code on Azure in a <strong>single step</strong>.</p>
<p>When designing the CLI, we wanted the experience to be both flexible and non-magical (no side effects, easy to understand). So, we're going to run this all with <code>azd up</code> but you could alternatively run a series of three commands and the outcome would be the same - <code>azd init --t Azure-Samples/todo-python-mongo-swa-func</code> (to pull the code down to your machine), <code>azd provision</code> (to provision infrastructure) and then <code>azd deploy</code> (to deploy application code on Azure). Choose your own adventure!</p>
<p><img loading="lazy" alt="Azure CLI guide showing commands: azd init for setup, azd provision for resource creation, and azd deploy for app deployment." src="https://azure.github.io/Cloud-Native/assets/images/single-step-b78e3ff4650026486170cea1a4931152.png" width="1226" height="366" class="img_ev3q"></p>
<p>So let's walk through it. On running <code>azd up -t todo-python-mongo-swa-func</code>, I'm prompted for a couple pieces of information as part of the <code>azd init</code> process being run under the hood:</p>
<ul>
<li><strong>An environment name</strong> - the prefix for the resource group that will be created to hold all Azure resources</li>
<li><strong>An Azure region</strong> - the Azure location where your resources will be deployed</li>
<li><strong>An Azure subscription</strong> - the Azure subscription where your resources will be deployed
<img loading="lazy" alt="Terminal output showing azd up command initializing an Azure project with template setup, environment name, and subscription details." src="https://azure.github.io/Cloud-Native/assets/images/start-up-93fc105dd5d9305c5b28c5912481341d.png" width="1352" height="122" class="img_ev3q"></li>
</ul>
<p>Once that information is provided, <code>azd</code> will pull down the code from GitHub and create a <code>.azure/</code> directory in the project root that contains all Azure Developer CLI environment information that you just entered. This directory will be important when it comes time to provision and deploy infrastructure in the next step in the <code>up</code> process.</p>
<p>The next step here is provisioning. <code>azd</code> is running <code>azd provision</code> on your behalf and leveraging the IaC assets in the <code>.infra/</code> directory in the project. As the tool works to provision, you'll see an output of each resource (name alongside a unique identifier which you can use to reference back to the Azure Portal, if you want)
<img loading="lazy" alt="Terminal output showing Azure CLI provisioning resources, including a static web app, function app, storage, Cosmos DB, and Key Vault." src="https://azure.github.io/Cloud-Native/assets/images/provision-up-dd676acea00f3760ddd140713ce9169a.png" width="1878" height="265" class="img_ev3q"></p>
<p>Finally, the final step here in running <code>azd up</code> is deployment. <code>azd</code> is running <code>azd deploy</code> and deploying the application code to the resources that we're provisioned in the previous phase of the process. Once this has completed, you'll be able to click on two different endpoint URLs - one for the backend and one for the frontend.
<img loading="lazy" alt="Terminal output displaying successful deployment of API and web services, with endpoints and resource group details." src="https://azure.github.io/Cloud-Native/assets/images/deploy-up-6d2e9abe348976287738e4acde709a80.png" width="1234" height="201" class="img_ev3q"></p>
<p>The backend endpoint (<code>service api</code>) hosts the specification for the API via the <code>openapi.yaml</code> file that's also in the root of the project template. You can explore the endpoints that are available in the web app here.
<img loading="lazy" alt="OpenAPI documentation for Simple Todo API, showing endpoints for CRUD operations on lists and items with HTTP methods." src="https://azure.github.io/Cloud-Native/assets/images/backend-61ff7bb024093a01f81ff1b2efcc5630.png" width="1466" height="883" class="img_ev3q"></p>
<p>The frontend endpoint (<code>service web</code>) hosts a fully-fledged and functional ToDo web app with a UI, Cosmos DB for the database and Key Vault for application secrets. This isn't just application hosting. It's really everything you need to be successful and productive, all set up on your behalf by the Azure Developer CLI.
<img loading="lazy" alt="Task management app view with a to-do list item and a detailed edit panel for setting task description, status, and due date." src="https://azure.github.io/Cloud-Native/assets/images/frontend-2c29ef61f79ab80a1f5486d3d29b242d.png" width="1916" height="767" class="img_ev3q"></p>
<p>...and that's it! We've successfully deployed our application on Azure!</p>
<p>But there's more!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="best-practices-monitoring-and-cicd">Best practices: Monitoring and CI/CD!<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#best-practices-monitoring-and-cicd" class="hash-link" aria-label="Direct link to Best practices: Monitoring and CI/CD!" title="Direct link to Best practices: Monitoring and CI/CD!">​</a></h2>
<p>In my opinion, it's not enough to <em>just</em> set up the application on Azure! I want to know that my web app is performant and serving my users reliably! I also want to make sure that I'm not inadvertently breaking my application as I continue to make changes to it. Thankfully, the Azure Developer CLI also handles all of this via two additional commands - <code>azd monitor</code> and <code>azd pipeline config</code>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="application-monitoring">Application Monitoring<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#application-monitoring" class="hash-link" aria-label="Direct link to Application Monitoring" title="Direct link to Application Monitoring">​</a></h3>
<p>When we provisioned all of our infrastructure, we also set up application monitoring via a Bicep file in our <code>.infra/</code> directory that spec'd out an Application Insights dashboard. By running <code>azd monitor</code> we can see the dashboard with live metrics that was configured for the application.
<img loading="lazy" alt="Azure Monitor dashboard showing metrics for incoming requests, outgoing requests, overall health, and server telemetry details." src="https://azure.github.io/Cloud-Native/assets/images/metrics-a7988df3076a04e473ddb210c80c95cf.png" width="1653" height="764" class="img_ev3q"></p>
<p>We can also navigate to the Application Dashboard by clicking on the resource group name, where you can set a specific refresh rate for the dashboard, and see usage, reliability, and performance metrics over time.
<img loading="lazy" alt="Application Insights dashboard with charts for user sessions, server response time, availability, and page load performance." src="https://azure.github.io/Cloud-Native/assets/images/dashboard-97724f78d1fcc7c1e075e41498f62fa4.png" width="1553" height="865" class="img_ev3q"></p>
<p>I don't know about everyone else but I have spent a ton of time building out similar dashboards. It can be super time-consuming to write all the queries and create the visualizations so this feels like a real time saver.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="cicd-1">CI/CD<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#cicd-1" class="hash-link" aria-label="Direct link to CI/CD" title="Direct link to CI/CD">​</a></h3>
<p>Finally let's talk about setting up CI/CD! This might be my favorite <code>azd</code> feature. As I mentioned before, the Azure Developer CLI has a command, <code>azd pipeline config</code>, which uses the files in the <code>.github/</code> directory to set up a GitHub Action. More than that, if there is no upstream repo, the Developer CLI will actually help you create one. But what does this mean exactly? Because our GitHub Action is using the same commands you'd run in the CLI under the hood, we're actually going to have CI/CD set up to run on every commit into the repo, against real Azure resources. What a sweet collaboration feature!</p>
<p><img loading="lazy" alt="Terminal log showing azd pipeline config command creating a GitHub repository and configuring CI pipeline with Azure secrets." src="https://azure.github.io/Cloud-Native/assets/images/pipeline-config-40319f9d957eb87325aa11427e1801eb.png" width="1798" height="960" class="img_ev3q"></p>
<p>That's it! We've gone end-to-end with the Azure Developer CLI - initialized a project, provisioned the resources on Azure, deployed our code on Azure, set up monitoring logs and dashboards, and set up a CI/CD pipeline with GitHub Actions to run on every commit into the repo (on real Azure resources!).</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-try-it-yourself-or-create-your-own-template"><strong>Exercise:</strong> Try it yourself or create your own template!<a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#exercise-try-it-yourself-or-create-your-own-template" class="hash-link" aria-label="Direct link to exercise-try-it-yourself-or-create-your-own-template" title="Direct link to exercise-try-it-yourself-or-create-your-own-template">​</a></h2>
<p>As an exercise, try out the workflow above with <a href="https://aka.ms/azure-dev/templates" target="_blank" rel="noopener noreferrer">any template on GitHub</a>!</p>
<p>Or, try turning your own project into an Azure Developer CLI-enabled template by following <a href="https://aka.ms/azure-dev/enabletemplate" target="_blank" rel="noopener noreferrer">this guidance</a>. If you create your own template, don't forget to tag the repo with the <a href="https://aka.ms/azure-dev/templates" target="_blank" rel="noopener noreferrer"><code>azd-templates</code> topic</a> on GitHub to help others find it (unfamiliar with GitHub topics? <a href="https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics#adding-topics-to-your-repository" target="_blank" rel="noopener noreferrer">Learn how to add topics to your repo</a>)! We'd also love to chat with you about your experience creating an <code>azd</code> template - if you're open to providing feedback around this, please fill out <a href="https://aka.ms/azd-user-research-signup?source=serverless-september" target="_blank" rel="noopener noreferrer">this form</a>!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources"><strong>Resources</strong><a href="https://azure.github.io/Cloud-Native/blog/29-azure-developer-cli#resources" class="hash-link" aria-label="Direct link to resources" title="Direct link to resources">​</a></h2>
<ul>
<li><a href="https://aka.ms/announcing-azure-dev-cli?source=serverless-september" target="_blank" rel="noopener noreferrer">Read more about the Azure Developer CLI preview release</a></li>
<li><a href="https://aka.ms/azure-dev/install-instructions?source=serverless-september" target="_blank" rel="noopener noreferrer">Install the Azure Developer CLI</a></li>
<li><a href="https://aka.ms/azd?source=serverless-september" target="_blank" rel="noopener noreferrer">Familiarize yourself with our Developer Hub</a></li>
<li><a href="https://aka.ms/azure-dev/templates?source=serverless-september" target="_blank" rel="noopener noreferrer">Take a look at some foundational templates on GitHub</a></li>
<li><a href="https://aka.ms/azure-dev/vscode-ext?source=serverless-september" target="_blank" rel="noopener noreferrer">Download the Azure Developer CLI VS Code extension</a></li>
</ul>]]></content:encoded>
            <category>serverless-september</category>
            <category>30-days-of-serverless</category>
            <category>microservices</category>
            <category>azd</category>
            <category>azure-developer-cli</category>
        </item>
        <item>
            <title><![CDATA[28. Serverless + Power Platforms]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/28-where-am-i</link>
            <guid>https://azure.github.io/Cloud-Native/blog/28-where-am-i</guid>
            <pubDate>Wed, 28 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Build a Power Platform custom connector with Azure Functions and OpenAPI to read my current GPS location and display it on Google Maps and Naver Map.]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 28</code> of #30DaysOfServerless!</p>
<p>Since it's the serverless end-to-end week, I'm going to discuss how to use a serverless application – <a href="https://docs.microsoft.com/azure/azure-functions/functions-overview?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure Functions</a> with <a href="https://aka.ms/azfunc-openapi" target="_blank" rel="noopener noreferrer">OpenAPI extension</a> – to be seamlessly integrated with <a href="https://docs.microsoft.com/connectors/custom-connectors/?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Power Platform custom connector</a> through <a href="https://docs.microsoft.com/azure/api-management/api-management-key-concepts?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure API Management</a> - in a post I call <em>"Where am I? My GPS Location with Serverless Power Platform Custom Connector"</em></p>
<p>OK. Are you ready? Let's get started!</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>What is Power Platform custom connector?</li>
<li>Proxy app to Google Maps and Naver Map API</li>
<li>API Management integration</li>
<li>Two ways of building custom connector</li>
<li>Where am I? – Power Apps app</li>
<li>Exercise: Try this yourself!</li>
<li>Resources: For self-study!</li>
</ul>
<p><img loading="lazy" alt="Event slide by Justin Yoo (@justinchronicle) on combining Serverless architecture with Microsoft Power Platform tools." src="https://azure.github.io/Cloud-Native/assets/images/banner-3e7c6e6693ff558354358bf059a7c853.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>SAMPLE REPO</div><div class="admonitionContent_BuS1"><p>Want to follow along? Check out the <a href="https://github.com/justinyoo/google-naver-maps-custom-connector-sample" target="_blank" rel="noopener noreferrer">sample app on GitHub repository</a> used in this post.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-power-platform-custom-connector">What is Power Platform custom connector?<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#what-is-power-platform-custom-connector" class="hash-link" aria-label="Direct link to What is Power Platform custom connector?" title="Direct link to What is Power Platform custom connector?">​</a></h2>
<p><a href="https://docs.microsoft.com/power-platform/?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Power Platform</a> is a low-code/no-code application development tool for <a href="https://www.gartner.com/en/articles/why-fusion-teams-matter" target="_blank" rel="noopener noreferrer">fusion teams</a> that consist of a group of people. Those people come from various disciplines, including field experts (domain experts), IT professionals and professional developers, to draw business values successfully. Within the fusion team, the domain experts become citizen developers or low-code developers by Power Platform. In addition, Making Power Platform more powerful is that it offers hundreds of connectors to other Microsoft 365 and third-party services like SAP, ServiceNow, Salesforce, Google, etc.</p>
<p>However, what if you want to use your internal APIs or APIs not yet offering their official connectors? Here's an example. If your company has an inventory management system, and you want to use it within your <a href="https://docs.microsoft.com/power-apps/powerapps-overview?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Power Apps</a> or <a href="https://docs.microsoft.com/power-automate/getting-started?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Power Automate</a>. That point is exactly where <a href="https://docs.microsoft.com/connectors/custom-connectors/?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Power Platform custom connectors</a> is necessary.</p>
<p><img loading="lazy" alt="Inventory Management System for Power Apps" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-01-d6fac44727880dd526e03e2010938f0a.png" width="1980" height="1720" class="img_ev3q"></p>
<p>Therefore, Power Platform custom connectors enrich those citizen developers' capabilities because those connectors can connect any API applications for the citizen developers to use.</p>
<p>In this post, let's build a custom connector that provides a static map image generated by <a href="https://developers.google.com/maps" target="_blank" rel="noopener noreferrer">Google Maps API</a> and <a href="https://www.ncloud.com/product/applicationService/maps" target="_blank" rel="noopener noreferrer">Naver Map API</a> using your GPS location.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="proxy-app-to-google-maps-and-naver-map-api">Proxy app to Google Maps and Naver Map API<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#proxy-app-to-google-maps-and-naver-map-api" class="hash-link" aria-label="Direct link to Proxy app to Google Maps and Naver Map API" title="Direct link to Proxy app to Google Maps and Naver Map API">​</a></h2>
<p>First, let's build an Azure Functions app that connects to Google Maps and Naver Map. Suppose that you've already got the API keys for both services. If you haven't yet, get the keys first by visiting <a href="https://developers.google.com/maps" target="_blank" rel="noopener noreferrer">here for Google</a> and <a href="https://www.ncloud.com/product/applicationService/maps" target="_blank" rel="noopener noreferrer">here for Naver</a>. Then, store them to <code>local.settings.json</code> within your Azure Functions app.</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "Values": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "Maps__Google__ApiKey": "&lt;GOOGLE_MAPS_API_KEY&gt;",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "Maps__Naver__ClientId": "&lt;NAVER_MAP_API_CLIENT_ID&gt;",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "Maps__Naver__ClientSecret": "&lt;NAVER_MAP_API_CLIENT_SECRET&gt;"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Here's the sample logic to get the static image from Google Maps API. It takes the latitude and longitude of your current location and image zoom level, then returns the static map image. There are a few hard-coded assumptions, though:</p>
<ul>
<li>The image size should be 400x400.</li>
<li>The image should be in <code>.png</code> format.</li>
<li>The marker should show be red and show my location.</li>
</ul>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">public class GoogleMapService : IMapService</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public async Task&lt;byte[]&gt; GetMapAsync(HttpRequest req)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var latitude = req.Query["lat"];</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var longitude = req.Query["long"];</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var zoom = (string)req.Query["zoom"] ?? "14";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var sb = new StringBuilder();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        sb.Append("https://maps.googleapis.com/maps/api/staticmap")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append($"?center={latitude},{longitude}")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append("&amp;size=400x400")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append($"&amp;zoom={zoom}")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append($"&amp;markers=color:red|{latitude},{longitude}")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append("&amp;format=png32")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append($"&amp;key={this._settings.Google.ApiKey}");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var requestUri = new Uri(sb.ToString());</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var bytes = await this._http.GetByteArrayAsync(requestUri).ConfigureAwait(false);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        return bytes;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The <code>NaverMapService</code> class has a similar logic with the same input and assumptions. Here's the code:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">public class NaverMapService : IMapService</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public async Task&lt;byte[]&gt; GetMapAsync(HttpRequest req)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var latitude = req.Query["lat"];</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var longitude = req.Query["long"];</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var zoom = (string)req.Query["zoom"] ?? "13";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var sb = new StringBuilder();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        sb.Append("https://naveropenapi.apigw.ntruss.com/map-static/v2/raster")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append($"?center={longitude},{latitude}")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append("&amp;w=400")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append("&amp;h=400")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append($"&amp;level={zoom}")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append($"&amp;markers=color:blue|pos:{longitude}%20{latitude}")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append("&amp;format=png")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          .Append("&amp;lang=en");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var requestUri = new Uri(sb.ToString());</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        this._http.DefaultRequestHeaders.Clear();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        this._http.DefaultRequestHeaders.Add("X-NCP-APIGW-API-KEY-ID", this._settings.Naver.ClientId);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        this._http.DefaultRequestHeaders.Add("X-NCP-APIGW-API-KEY", this._settings.Naver.ClientSecret);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var bytes = await this._http.GetByteArrayAsync(requestUri).ConfigureAwait(false);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        return bytes;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Let's take a look at the function endpoints. Here's for the Google Maps and Naver Map. As the <code>GetMapAsync(req)</code> method returns a byte array value, you need to transform it as <code>FileContentResult</code>, with the content type of <code>image/png</code>.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">// Google Maps</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">public class GoogleMapsTrigger</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [FunctionName(nameof(GoogleMapsTrigger.GetGoogleMapImage))]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public async Task&lt;IActionResult&gt; GetGoogleMapImage(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "google/image")] HttpRequest req)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        this._logger.LogInformation("C# HTTP trigger function processed a request.");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var bytes = await this._service.GetMapAsync(req).ConfigureAwait(false);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        return new FileContentResult(bytes, "image/png");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Naver Map</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">public class NaverMapsTrigger</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [FunctionName(nameof(NaverMapsTrigger.GetNaverMapImage))]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public async Task&lt;IActionResult&gt; GetNaverMapImage(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "naver/image")] HttpRequest req)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        this._logger.LogInformation("C# HTTP trigger function processed a request.");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var bytes = await this._service.GetMapAsync(req).ConfigureAwait(false);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        return new FileContentResult(bytes, "image/png");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Then, add the OpenAPI capability to each function endpoint. Here's the example:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">// Google Maps</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">public class GoogleMapsTrigger</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [FunctionName(nameof(GoogleMapsTrigger.GetGoogleMapImage))]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    // ⬇️⬇️⬇️ Add decorators provided by the OpenAPI extension ⬇️⬇️⬇️</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [OpenApiOperation(operationId: nameof(GoogleMapsTrigger.GetGoogleMapImage), tags: new[] { "google" })]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [OpenApiParameter(name: "lat", In = ParameterLocation.Query, Required = true, Type = typeof(string), Description = "The **latitude** parameter")]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [OpenApiParameter(name: "long", In = ParameterLocation.Query, Required = true, Type = typeof(string), Description = "The **longitude** parameter")]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [OpenApiParameter(name: "zoom", In = ParameterLocation.Query, Required = false, Type = typeof(string), Description = "The **zoom level** parameter &amp;ndash; Default value is `14`")]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "image/png", bodyType: typeof(byte[]), Description = "The map image as an OK response")]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    // ⬆️⬆️⬆️ Add decorators provided by the OpenAPI extension ⬆️⬆️⬆️</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public async Task&lt;IActionResult&gt; GetGoogleMapImage(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "google/image")] HttpRequest req)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Naver Map</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">public class NaverMapsTrigger</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [FunctionName(nameof(NaverMapsTrigger.GetNaverMapImage))]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    // ⬇️⬇️⬇️ Add decorators provided by the OpenAPI extension ⬇️⬇️⬇️</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [OpenApiOperation(operationId: nameof(NaverMapsTrigger.GetNaverMapImage), tags: new[] { "naver" })]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [OpenApiParameter(name: "lat", In = ParameterLocation.Query, Required = true, Type = typeof(string), Description = "The **latitude** parameter")]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [OpenApiParameter(name: "long", In = ParameterLocation.Query, Required = true, Type = typeof(string), Description = "The **longitude** parameter")]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [OpenApiParameter(name: "zoom", In = ParameterLocation.Query, Required = false, Type = typeof(string), Description = "The **zoom level** parameter &amp;ndash; Default value is `13`")]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "image/png", bodyType: typeof(byte[]), Description = "The map image as an OK response")]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    // ⬆️⬆️⬆️ Add decorators provided by the OpenAPI extension ⬆️⬆️⬆️</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public async Task&lt;IActionResult&gt; GetNaverMapImage(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "naver/image")] HttpRequest req)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Run the function app in the local. Here are the latitude and longitude values for Seoul, Korea.</p>
<ul>
<li>latitude: 37.574703</li>
<li>longitude: 126.978519</li>
</ul>
<p><img loading="lazy" alt="Google Map for Seoul" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-02-a3fc7d2cecbbf67069ec8aa4bf8ce52b.png" width="1820" height="2004" class="img_ev3q"></p>
<p>It seems to be working! Let's deploy it to Azure.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="api-management-integration">API Management integration<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#api-management-integration" class="hash-link" aria-label="Direct link to API Management integration" title="Direct link to API Management integration">​</a></h2>
<p><a href="https://visualstudio.microsoft.com/vs/?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Visual Studio 2022</a> provides a built-in deployment tool for <a href="https://docs.microsoft.com/azure/azure-functions/functions-overview?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure Functions</a> app onto Azure. In addition, the deployment tool supports seamless integration with <a href="https://docs.microsoft.com/azure/api-management/api-management-key-concepts?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure API Management</a> as long as your Azure Functions app enables the OpenAPI capability. In this post, I'm going to use this feature. Right-mouse click on the Azure Functions project and select the "Publish" menu.</p>
<p><img loading="lazy" alt="Visual Studio context menu for publish" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-03-2d9e1dbe2c83d6466021c293a5e8f7e3.png" width="914" height="902" class="img_ev3q"></p>
<p>Then, you will see the publish screen. Click the "➕ New" button to create a new publish profile.</p>
<p><img loading="lazy" alt="Create a new publish profile" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-04-b977bba0a3ab4c93a96507846fffe3fa.png" width="1127" height="741" class="img_ev3q"></p>
<p>Choose "Azure" and click the "Next" button.</p>
<p><img loading="lazy" alt="Choose the target platform for publish" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-05-e57ab49d94cd5f85818fcc52f0bcae39.png" width="1608" height="1128" class="img_ev3q"></p>
<p>Select the app instance. This time simply pick up the "Azure Function App (Windows)" option, then click "Next".</p>
<p><img loading="lazy" alt="Choose the target OS for publish" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-06-13b63e8c2cc950ddf632df116f502294.png" width="1608" height="1128" class="img_ev3q"></p>
<p>If you already provision an Azure Function app instance, you will see it on the screen. Otherwise, create a new one. Then, click "Next".</p>
<p><img loading="lazy" alt="Choose the target instance for publish" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-07-6af9c72f6f8902fbe457543f3ecda5c7.png" width="1608" height="1128" class="img_ev3q"></p>
<p>In the next step, you are asked to choose the Azure API Management instance for integration. Choose one, or create a new one. Then, click "Next".</p>
<p><img loading="lazy" alt="Choose the APIM instance for integration" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-08-b2d34b5ea9ddd5e4a0fe435d595ab766.png" width="1608" height="1128" class="img_ev3q"></p>
<p>Finally, select the publish method – either local publish or GitHub Actions workflow. Let's pick up the local publish method for now. Then, click "Finish".</p>
<p><img loading="lazy" alt="Choose the deployment type" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-09-359f43a8f8652049f72319270287508b.png" width="1608" height="1128" class="img_ev3q"></p>
<p>The publish profile has been created. Click "Close" to move on.</p>
<p><img loading="lazy" alt="Publish profile created" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-10-33476d1a905985ba03417cbec48b7f3e.png" width="1608" height="1128" class="img_ev3q"></p>
<p>Now the function app is ready for deployment. Click the "Publish" button and see how it goes.</p>
<p><img loading="lazy" alt="Publish function app" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-11-9a095865489916d95a5bc9fe86e6c30b.png" width="2192" height="847" class="img_ev3q"></p>
<p>The Azure function app has been deployed and integrated with the Azure API Management instance.</p>
<p><img loading="lazy" alt="Function app published" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-12-6c9c271c4d7c0db17627ff8f3885f455.png" width="2171" height="674" class="img_ev3q"></p>
<p>Go to the published function app site, and everything looks OK.</p>
<p><img loading="lazy" alt="Function app on Azure" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-13-693ef72fc7f6872e0ee20b2e5df60f43.png" width="3744" height="1778" class="img_ev3q"></p>
<p>And API Management shows the function app integrated perfectly.</p>
<p><img loading="lazy" alt="Function app integrated with APIM" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-14-2d93caa7008a0e987e746da7c7d8394c.png" width="3740" height="2019" class="img_ev3q"></p>
<p>Now, you are ready to create a custom connector. Let's move on.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="two-ways-of-building-custom-connector">Two ways of building custom connector<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#two-ways-of-building-custom-connector" class="hash-link" aria-label="Direct link to Two ways of building custom connector" title="Direct link to Two ways of building custom connector">​</a></h2>
<p>There are two ways to create a custom connector.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="export-custom-connector-from-api-management">Export custom connector from API Management<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#export-custom-connector-from-api-management" class="hash-link" aria-label="Direct link to Export custom connector from API Management" title="Direct link to Export custom connector from API Management">​</a></h3>
<p>First, you can directly use the built-in API Management feature. Then, click the ellipsis icon and select the "Create Power Connector" menu.</p>
<p><img loading="lazy" alt="Create Power Connector menu" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-15-6a12725fa9910e64352f37db80df18d6.png" width="3740" height="2020" class="img_ev3q"></p>
<p>Then, you are redirected to this screen. While the "API" and "API display name" fields are pre-populated, you need to choose the Power Platform environment tied to your tenant. Choose an environment, click "Authenticate", and click "Create".</p>
<p><img loading="lazy" alt="Create custom connector screen" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-16-b38ad1d7c34f0ad7ff9dba7e2bb34ebb.png" width="3740" height="2020" class="img_ev3q"></p>
<p>Check your custom connector on Power Apps or Power Automate side.</p>
<p><img loading="lazy" alt="Custom connector created on Power Apps" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-17-97512785618cde5ced81d5c0e6c00255.png" width="3744" height="2018" class="img_ev3q"></p>
<p>However, there's a caveat to this approach. Because it's tied to your tenant, you should use the second approach if you want to use this custom connector on the other tenant.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="import-custom-connector-from-openapi-document-or-url">Import custom connector from OpenAPI document or URL<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#import-custom-connector-from-openapi-document-or-url" class="hash-link" aria-label="Direct link to Import custom connector from OpenAPI document or URL" title="Direct link to Import custom connector from OpenAPI document or URL">​</a></h3>
<p>Click the ellipsis icon again and select the "Export" menu.</p>
<p><img loading="lazy" alt="Export menu" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-18-64689301d9363b7e31c8344ccdaf5171.png" width="3740" height="2020" class="img_ev3q"></p>
<p>On the Export API screen, choose the "OpenAPI v2 (JSON)" panel because Power Platform custom connector currently accepts version 2 of the OpenAPI document.</p>
<p><img loading="lazy" alt="Select OpenAPI v2" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-19-ef3102ea7e974ebe09f9b3da08137b30.png" width="3740" height="2020" class="img_ev3q"></p>
<p>Download the OpenAPI document to your local computer and move to your Power Apps or Power Automate page under your desired environment. I'm going to use the Power Automate page. First, go to the "Data" ➡️ "Custom connectors" page. Then, click the "➕ New custom connector" ➡️ "Import an OpenAPI file" at the top right corner.</p>
<p><img loading="lazy" alt="New custom connector" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-20-4b2014da86c8fcbd3f7f9340772dbc6e.png" width="3744" height="2018" class="img_ev3q"></p>
<p>When a modal pops up, give the custom connector name and import the OpenAPI document exported above. Then, click "Continue".</p>
<p><img loading="lazy" alt="Import custom connector" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-21-192c69f9c600c326b0ee2a38e5717df8.png" width="1520" height="851" class="img_ev3q"></p>
<p>Actually, that's it! Next, click the "✔️ Create connector" button to create the connector.</p>
<p><img loading="lazy" alt="Create custom connector" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-22-db21d8177d6141e9b72638958b85706d.png" width="3744" height="2018" class="img_ev3q"></p>
<p>Go back to the custom connector page, and you will see the "Maps API" custom connector you just created.</p>
<p><img loading="lazy" alt="Custom connector imported" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-23-d62a15c41d3c92c3eef96d315f9af563.png" width="3744" height="2018" class="img_ev3q"></p>
<p>So, you are ready to create a Power Apps app to display your location on Google Maps or Naver Map! Let's move on.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="where-am-i--power-apps-app">Where am I? – Power Apps app<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#where-am-i--power-apps-app" class="hash-link" aria-label="Direct link to Where am I? – Power Apps app" title="Direct link to Where am I? – Power Apps app">​</a></h2>
<p>Open the Power Apps Studio, and create an empty canvas app, named <code>Who am I</code> with a phone layout.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="custom-connector-integration">Custom connector integration<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#custom-connector-integration" class="hash-link" aria-label="Direct link to Custom connector integration" title="Direct link to Custom connector integration">​</a></h3>
<p>To use the custom connector created above, you need to add it to the Power App. Click the cylinder icon on the left and click the "Add data" button.</p>
<p><img loading="lazy" alt="Add custom connector to data pane" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-24-9e9c3740c0e94aca0337ad157e237ad8.png" width="669" height="1044" class="img_ev3q"></p>
<p>Search the custom connector name, "Maps API", and click the custom connector to add.</p>
<p><img loading="lazy" alt="Search custom connector" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-25-1c6f92ab001f1cfb580d1c764b3606cd.png" width="1300" height="2020" class="img_ev3q"></p>
<p>To use the custom connector, you also need to create a connection to it. Click the "Connect" button and move on.</p>
<p><img loading="lazy" alt="Create connection to custom connector" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-26-4f5ef854079d81869697e89f64ac274b.png" width="681" height="942" class="img_ev3q"></p>
<p>Now, you've got the connection to the custom connector.</p>
<p><img loading="lazy" alt="Connection to custom connector ready" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-27-1cd9a596a451fe339b1d9a1eb186f451.png" width="661" height="992" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="controls">Controls<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#controls" class="hash-link" aria-label="Direct link to Controls" title="Direct link to Controls">​</a></h3>
<p>Let's build the Power Apps app. First of all, put three controls – <a href="https://docs.microsoft.com/power-apps/maker/canvas-apps/controls/control-image?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Image</a>, <a href="https://docs.microsoft.com/power-apps/maker/canvas-apps/controls/control-slider?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Slider</a> and <a href="https://docs.microsoft.com/power-apps/maker/canvas-apps/controls/control-button?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Button</a> onto the canvas.</p>
<p><img loading="lazy" alt="Power Apps control added" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-28-ef73bc2f1dce3e4a76c0965c201a12de.png" width="3744" height="1922" class="img_ev3q"></p>
<p>Click the "Screen1" control and change the value on the property "OnVisible" to the formula below. The formula stores the current slider value in the <code>zoomlevel</code> collection.</p>
<div class="language-powerappsfl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powerappsfl codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ClearCollect(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    zoomlevel,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Slider1.Value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Click the "Botton1" control and change the value on the property "OnSelected" to the formula below. It passes the current latitude, longitude and zoom level to the custom connector and receives the image data. The received image data is stored in the <code>result</code> collection.</p>
<div class="language-powerappsfl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powerappsfl codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ClearCollect(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    result,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    MAPS.GetGoogleMapImage(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Location.Latitude,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Location.Longitude,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { zoom: First(zoomlevel).Value }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    )</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Click the "Image1" control and change the value on the property "Image" to the formula below. It gets the image data from the <code>result</code> collection.</p>
<div class="language-powerappsfl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powerappsfl codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">First(result).Url</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Click the "Slider1" control and change the value on the property "OnChange" to the formula below. It stores the current slider value to the <code>zoomlevel</code> collection, followed by calling the custom connector to get the image data against the current location.</p>
<div class="language-powerappsfl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powerappsfl codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ClearCollect(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    zoomlevel,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Slider1.Value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ClearCollect(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    result,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    MAPS.GetGoogleMapImage(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Location.Latitude,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Location.Longitude,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { zoom: First(zoomlevel).Value }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    )</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>That seems to be OK. Let's click the "Where am I?" button. But it doesn't show the image. The <code>First(result).Url</code> value is actually similar to this:</p>
<div class="language-powerappsfl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powerappsfl codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">appres://blobmanager/1090a86393a843adbfcf428f0b90e91b/1</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>It's the image reference value somewhere you can't get there.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="workaround--power-automate-workflow">Workaround – Power Automate workflow<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#workaround--power-automate-workflow" class="hash-link" aria-label="Direct link to Workaround – Power Automate workflow" title="Direct link to Workaround – Power Automate workflow">​</a></h3>
<p>Therefore, you need a workaround using a Power Automate workflow to sort out this issue. Open the Power Automate Studio, create an instant cloud flow with the Power App trigger, and give it the "Where am I" name. Then add input parameters of <code>lat</code>, <code>long</code> and <code>zoom</code>.</p>
<p><img loading="lazy" alt="Power Apps trigger on Power Automate workflow" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-29-55e6af8fe5ffea6563cea64747cd6cd0.png" width="1250" height="700" class="img_ev3q"></p>
<p>Add custom connector action to get the map image.</p>
<p><img loading="lazy" alt="Select action to get the Google Maps image" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-30-41539cecc71a570428cf215084d13872.png" width="1220" height="880" class="img_ev3q"></p>
<p>In the action, pass the appropriate parameters to the action.</p>
<p><img loading="lazy" alt="Pass parameters to the custom connector action" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-31-eea07023aa2901c6cf44b681fcfb43e4.png" width="1220" height="385" class="img_ev3q"></p>
<p>Add a "Response" action and put the following values into each field.</p>
<ul>
<li>
<p>"Body" field:</p>
<div class="language-bicep codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bicep codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "base64Image": &lt;power_automate_expression&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<blockquote>
<p>The <code>&lt;power_automate_expression&gt;</code> should be <code>concat('data:', body('GetGoogleMapImage')?['$content-type'], ';base64,', body('GetGoogleMapImage')?['$content'])</code>.</p>
</blockquote>
</li>
<li>
<p>"Response Body JSON Schema" field:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "type": "object",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "properties": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "base64Image": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "type": "string"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
</ul>
<p><img loading="lazy" alt="Format the Response action" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-32-7a518a829f43dc6adb07e3e0e2560b16.png" width="1220" height="1070" class="img_ev3q"></p>
<p>Let's return to the Power Apps Studio and add the Power Automate workflow you created.</p>
<p><img loading="lazy" alt="Add Power Automate workflow" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-33-d95c7bf0ed2ada4fb7ab84a85a935726.png" width="1300" height="944" class="img_ev3q"></p>
<p>Select "Button1" and change the value on the property "OnSelect" below. It replaces the direct call to the custom connector with the Power Automate workflow.</p>
<div class="language-powerappsfl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powerappsfl codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ClearCollect(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    result,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    WhereamI.Run(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Location.Latitude,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Location.Longitude,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        First(zoomlevel).Value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    )</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Also, change the value on the property "OnChange" of the "Slider1" control below, replacing the custom connector call with the Power Automate workflow call.</p>
<div class="language-powerappsfl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powerappsfl codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ClearCollect(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    zoomlevel,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Slider1.Value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ClearCollect(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    result,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    WhereamI.Run(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Location.Latitude,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Location.Longitude,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        First(zoomlevel).Value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    )</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>And finally, change the "Image1" control's "Image" property value below.</p>
<div class="language-powerappsfl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powerappsfl codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">First(result).base64Image</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The workaround has been applied. Click the "Where am I?" button to see your current location from Google Maps.</p>
<p><img loading="lazy" alt="Run Power Apps app #1" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-34-817219ce9f1534d0b79affc1b4027df6.png" width="3744" height="2018" class="img_ev3q"></p>
<p>If you change the slider left or right, you will see either the zoomed-in image or the zoomed-out image.</p>
<p><img loading="lazy" alt="Run Power Apps app #2" src="https://azure.github.io/Cloud-Native/assets/images/28-serverless-power-platform-custom-connector-35-5c8cb9cb4f5eda28d037e8d9dd35b158.png" width="3744" height="2018" class="img_ev3q"></p>
<p>Now, you've created a Power Apps app to show your current location using:</p>
<ul>
<li>Google Maps API through the custom connector, and</li>
<li>Custom connector written in Azure Functions with OpenAPI extension!</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-try-this-yourself">Exercise: Try this yourself!<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#exercise-try-this-yourself" class="hash-link" aria-label="Direct link to Exercise: Try this yourself!" title="Direct link to Exercise: Try this yourself!">​</a></h2>
<p>You can fork this <a href="https://github.com/justinyoo/google-naver-maps-custom-connector-sample" target="_blank" rel="noopener noreferrer">GitHub repository</a> to your account and play around with it to see how the custom connector works. After forking the repository, make sure that you create all the necessary secrets to your repository documented in the README file.</p>
<p>Then, click the "Deploy to Azure" button, and it will provision all necessary Azure resources and deploy an Azure Functions app for a custom connector.</p>
<p><img loading="lazy" src="https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/deploytoazure.svg?sanitize=true" alt="Deploy To Azure" class="img_ev3q"></p>
<p>Once everything is deployed successfully, try to create a <a href="https://docs.microsoft.com/power-apps/powerapps-overview?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Power Apps app</a> and <a href="https://docs.microsoft.com/power-automate/getting-started?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Power Automate workflow</a> to see your current location in real-time!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources-for-self-study">Resources: For self-study!<a href="https://azure.github.io/Cloud-Native/blog/28-where-am-i#resources-for-self-study" class="hash-link" aria-label="Direct link to Resources: For self-study!" title="Direct link to Resources: For self-study!">​</a></h2>
<p>Want to know more about Power Platform custom connector and Azure Functions OpenAPI extension? Here are several resources you can take a look at:</p>
<ul>
<li><a href="https://docs.microsoft.com/training/paths/transform-business-applications-with-fusion-development/?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer"><strong>Microsoft Learn</strong>: Transform your business applications with fusion development</a></li>
<li><a href="https://aka.ms/azfunc-openapi" target="_blank" rel="noopener noreferrer"><strong>GitHub repository</strong>: Azure Functions OpenAPI Extension</a></li>
</ul>]]></content:encoded>
            <category>serverless-september</category>
            <category>30-days-of-serverless</category>
            <category>azure-functions</category>
            <category>openapi</category>
            <category>power-platform</category>
            <category>custom-connector</category>
        </item>
        <item>
            <title><![CDATA[🚀 | Monitor + Troubleshoot Apps]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/zero2hero-func-07</link>
            <guid>https://azure.github.io/Cloud-Native/blog/zero2hero-func-07</guid>
            <pubDate>Mon, 26 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[When you’re running a function app, you want to be prepared for any issues that may arise, from 4xx errors to trigger failures. Azure Functions offers built-in integration with Azure Application Insights to monitor function executions. Let's learn more.]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 26</code> of #30DaysOfServerless!</p>
<p>Today, we have a special set of posts from our <a href="https://azure.github.io/Cloud-Native/serverless-september/ZeroToHero">Zero To Hero 🚀</a> initiative, featuring blog posts authored by our Product Engineering teams for #ServerlessSeptember. <em>Posts were originally published on the <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/monitoring-and-troubleshooting-apps-in-azure-functions/ba-p/3638230?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Apps on Azure</a> blog on Microsoft Tech Community.</em></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-07#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>Monitoring your Azure Functions</li>
<li>Built-in log streaming</li>
<li>Live Metrics stream</li>
<li>Troubleshooting Azure Functions</li>
</ul>
<p><img loading="lazy" alt="Serverless September slide featuring Madhura Bharadwaj presenting Monitoring &amp;amp; Troubleshooting Apps in Azure Functions." src="https://azure.github.io/Cloud-Native/assets/images/zero-to-hero-madhura-9186d0cba8bf8974d76dfdeb73cd5f50.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="monitoring-your-azure-functions">Monitoring your Azure Functions:<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-07#monitoring-your-azure-functions" class="hash-link" aria-label="Direct link to Monitoring your Azure Functions:" title="Direct link to Monitoring your Azure Functions:">​</a></h2>
<p>Azure Functions uses <strong>Application Insights</strong> to collect and analyze log data from individual function executions in your function app.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="using-application-insights">Using Application Insights<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-07#using-application-insights" class="hash-link" aria-label="Direct link to Using Application Insights" title="Direct link to Using Application Insights">​</a></h3>
<p>Application Insights collects <em>log, performance, and error data</em>. By automatically detecting performance anomalies and featuring powerful analytics tools, you can more easily diagnose issues and better understand how your functions are used. These tools are designed to help you continuously improve performance and usability of your functions. You can even use Application Insights during local function app project development.</p>
<p>Typically, you create an Application Insights instance when you create your function app. In this case, the instrumentation key required for the integration is already set as an application setting named <code>APPINSIGHTS_INSTRUMENTATIONKEY</code>. With Application Insights integration enabled, telemetry data is sent to your connected Application Insights instance. This data includes logs generated by the Functions host, traces written from your functions code, and performance data. In addition to data from your functions and the Functions host, you can also collect data from the <a href="https://learn.microsoft.com/azure/azure-functions/functions-monitoring#scale-controller-logs?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Functions scale controller</a>.</p>
<p>By default, the data collected from your function app is stored in Application Insights. In the <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">Azure portal</a>, Application Insights provides an extensive set of visualizations of your telemetry data. You can drill into error logs and query events and metrics. To learn more, including basic examples of how to view and query your collected data, see <a href="https://learn.microsoft.com/azure/azure-functions/analyze-telemetry-data?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Analyze Azure Functions telemetry in Application Insights</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="using-log-streaming">Using Log Streaming<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-07#using-log-streaming" class="hash-link" aria-label="Direct link to Using Log Streaming" title="Direct link to Using Log Streaming">​</a></h3>
<p>In addition to this, you can have a smoother debugging experience through log streaming. There are two ways to view a stream of log files being generated by your function executions.</p>
<ul>
<li><strong>Built-in log streaming</strong>: the App Service platform lets you view a stream of your application log files. This is equivalent to the output seen when you debug your functions during <a href="https://learn.microsoft.com/azure/azure-functions/functions-develop-local?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">local development</a> and when you use the Test tab in the portal. All log-based information is displayed. For more information, see <a href="https://learn.microsoft.com/azure/app-service/troubleshoot-diagnostic-logs#stream-logs?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Stream logs</a>. This streaming method supports only a single instance and can't be used with an app running on Linux in a Consumption plan.</li>
<li><strong>Live Metrics Stream</strong>: when your function app is <a href="https://learn.microsoft.com/azure/azure-functions/configure-monitoring#enable-application-insights-integration?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">connected to Application Insights</a>, you can view log data and other metrics in near real-time in the Azure portal using <a href="https://learn.microsoft.com/azure/azure-monitor/app/live-stream?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Live Metrics Stream</a>. Use this method when monitoring functions running on multiple-instances or on Linux in a Consumption plan. This method uses <a href="https://learn.microsoft.com/azure/azure-functions/configure-monitoring#configure-sampling?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">sampled data</a>.
Log streams can be viewed both in the portal and in most local development environments.</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Monitoring Azure Functions</div><div class="admonitionContent_BuS1"><p>Learn how to <a href="https://learn.microsoft.com/azure/azure-functions/configure-monitoring?source=recommendations&amp;tabs=v2&amp;WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">configure monitoring for your Azure Functions</a>. See <a href="https://learn.microsoft.com/azure/azure-functions/monitor-functions-reference?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Monitoring Azure Functions data reference</a> for detailed information on the metrics and logs metrics created by Azure Functions.</p></div></div>
<p>In addition to this, Azure Functions uses <a href="https://learn.microsoft.com/azure/azure-monitor/overview" target="_blank" rel="noopener noreferrer">Azure Monitor</a> to <a href="https://learn.microsoft.com/azure/azure-functions/monitor-functions?tabs=portal" target="_blank" rel="noopener noreferrer">monitor the health of your function apps</a>. Azure Functions collects the same kinds of monitoring data as other Azure resources that are described in <a href="https://learn.microsoft.com/azure/azure-monitor/essentials/monitor-azure-resource#monitoring-data-from-azure-resources" target="_blank" rel="noopener noreferrer">Azure Monitor data collection</a>. See <a href="https://learn.microsoft.com/azure/azure-functions/monitor-functions-reference" target="_blank" rel="noopener noreferrer">Monitoring Azure Functions data reference</a> for detailed information on the metrics and logs metrics created by Azure Functions.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="troubleshooting-your-azure-functions">Troubleshooting your Azure Functions:<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-07#troubleshooting-your-azure-functions" class="hash-link" aria-label="Direct link to Troubleshooting your Azure Functions:" title="Direct link to Troubleshooting your Azure Functions:">​</a></h2>
<p>When you do run into issues with your function app, Azure Functions diagnostics points out what’s wrong. It guides you to the right information to troubleshoot and resolve the issue more easily and quickly.</p>
<p>Let’s explore how to use Azure Functions diagnostics to diagnose and solve common function app issues.</p>
<ol>
<li>Navigate to your function app <a href="https://portal.azure.com/?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">in the Azure portal</a>.</li>
<li>Select Diagnose and solve problems to open Azure Functions diagnostics.</li>
<li>Once you’re here, there are multiple ways to retrieve the information you’re looking for. Choose a category that best describes the issue of your function app by using the keywords in the homepage tile. You can also type a keyword that best describes your issue in the search bar. There’s also a section at the bottom of the page that will directly take you to some of the more popular troubleshooting tools. For example, you could type execution to see a list of diagnostic reports related to your function app execution and open them directly from the homepage.</li>
</ol>
<p><img loading="lazy" alt="Monitoring and troubleshooting apps in Azure Functions" src="https://azure.github.io/Cloud-Native/assets/images/madhura-functions-1-cf245312022dd74d8e0c0325d6cddc20.png" width="777" height="361" class="img_ev3q"></p>
<ol start="4">
<li>For example, click on the Function App Down or Reporting Errors link under Popular troubleshooting tools section. You will find detailed analysis, insights and next steps for the issues that were detected. On the left you’ll see a list of detectors. Click on them to explore more, or if there’s a particular keyword you want to look for, type it Into the search bar on the top.</li>
</ol>
<p><img loading="lazy" alt="Monitoring and troubleshooting apps in Azure Functions" src="https://azure.github.io/Cloud-Native/assets/images/madhura-functions-2-9e52c0d12e76850ce3bb4c1d9c8d970a.png" width="788" height="390" class="img_ev3q"></p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>TROUBLESHOOTING TIP</div><div class="admonitionContent_BuS1"><p>Here are some general troubleshooting tips that you can follow if you find your Function App throwing <a href="https://learn.microsoft.com/azure/azure-functions/functions-recover-storage-account?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Azure Functions Runtime unreachable</a> error.</p><p>Also be sure to check out the recommended best practices to ensure your Azure Functions are highly reliable. <a href="https://learn.microsoft.com/azure/azure-functions/functions-best-practices?source=recommendations&amp;tabs=csharp&amp;WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">This article</a> details some best practices for designing and deploying efficient function apps that remain healthy and perform well in a cloud-based environment.</p></div></div>
<p>Bonus tip:</p>]]></content:encoded>
            <category>serverless-september</category>
            <category>zero-to-hero</category>
            <category>azure-functions</category>
        </item>
        <item>
            <title><![CDATA[25. Deploy Spring Boot App to ACA]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/25-aca-java</link>
            <guid>https://azure.github.io/Cloud-Native/blog/25-aca-java</guid>
            <pubDate>Sun, 25 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to deploy containerized Spring boot apps to Azure Container apps (ACA) using Azure Container Registry (ACR)]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 25</code> of #30DaysOfServerless!</p>
<p><a href="https://docs.microsoft.com/azure/container-apps/overview" target="_blank" rel="noopener noreferrer">Azure Container Apps</a> enable application code packaged in containers to run and scale without the overhead of managing cloud infrastructure and container orchestration.  In this post I'll show you how to <strong>deploy a Java application running on Spring Boot in a container to Azure Container Registry and Azure Container Apps.</strong></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>Introduction to Deploying Java containers in the cloud</li>
<li>Step-by-step: Deploying to Azure Container Registry</li>
<li>Step-by-step: Deploying and running on Azure Container Apps</li>
<li>Resources: For self-study!</li>
</ul>
<p><img loading="lazy" alt="Slide on &amp;quot;E2E – Container Apps&amp;quot; by Brian Benz (@bbenz), focusing on deploying Spring Boot with Azure Container Registry." src="https://azure.github.io/Cloud-Native/assets/images/banner-a80dd142b324c50ca8d68b0c69a4206b.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="deploy-java-containers-to-cloud">Deploy Java containers to cloud<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#deploy-java-containers-to-cloud" class="hash-link" aria-label="Direct link to Deploy Java containers to cloud" title="Direct link to Deploy Java containers to cloud">​</a></h2>
<p>We'll deploy a Java application running on Spring Boot in a container to Azure Container Registry and Azure Container Apps. Here are the main steps:</p>
<ul>
<li>Create Azure Container Registry (ACR) on Azure portal</li>
<li>Create Azure Container App (ACA) on Azure portal.</li>
<li>Deploy code to Azure Container Registry from the Azure CLI.</li>
<li>Deploy container from ACR to ACA using the Azure portal.</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>PRE-REQUISITES</div><div class="admonitionContent_BuS1"><ul>
<li><strong>Active Azure subscription</strong> with Contributor or Owner permissions. <a href="https://azure.microsoft.com/free/" target="_blank" rel="noopener noreferrer">Create an account for free</a> if you don't have one.</li>
<li><strong>GitHub account</strong>. Sign up for <a href="https://github.com/join" target="_blank" rel="noopener noreferrer">free</a> if you don't have one.</li>
<li>Install <strong><a href="https://github.com/git-guides/install-git" target="_blank" rel="noopener noreferrer">Git</a></strong>.</li>
<li>Install the <strong><a href="https://learn.microsoft.com/cli/azure/install-azure-cli" target="_blank" rel="noopener noreferrer">Azure CLI</a></strong>.</li>
</ul></div></div>
<p>Sign in to Azure from the CLI using the <code>az login</code> command, and follow the prompts in your browser to complete the authentication process.  Also, ensure you're running the latest version of the CLI by using the <code>az upgrade</code>  command.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="1-get-sample-code">1. Get Sample Code<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#1-get-sample-code" class="hash-link" aria-label="Direct link to 1. Get Sample Code" title="Direct link to 1. Get Sample Code">​</a></h2>
<p>Fork and clone the <a href="https://github.com/bbenz/spring-boot-docker-aca" target="_blank" rel="noopener noreferrer">sample GitHub repo</a> to your local machine.  Navigate to the  and click <strong>Fork</strong> in the top-right corner of the page.</p>
<blockquote>
<p>The <a href="https://github.com/bbenz/spring-boot-docker-aca" target="_blank" rel="noopener noreferrer">example code</a> that we're using is a very basic containerized Spring Boot example.  There are a lot more details to learn about Spring boot apps in docker, for a deep dive check out this <a href="https://spring.io/guides/gs/spring-boot-docker/" target="_blank" rel="noopener noreferrer">Spring Boot Guide</a></p>
</blockquote>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="2-run-sample-locally-optional">2. Run Sample Locally (Optional)<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#2-run-sample-locally-optional" class="hash-link" aria-label="Direct link to 2. Run Sample Locally (Optional)" title="Direct link to 2. Run Sample Locally (Optional)">​</a></h2>
<p>If you have docker installed locally, you can optionally test the code on your local machine.  Navigate to the root directory of the forked repository and run the following commands:</p>
<div class="language-azurecli codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-azurecli codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">docker build -t spring-boot-docker-aca .</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">docker run -p 8080:8080 spring-boot-docker-aca</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Open a browser and go to <a href="https://localhost:8080/" target="_blank" rel="noopener noreferrer">https://localhost:8080</a>.  You should see this message:</p>
<div class="language-azurecli codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-azurecli codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Hello Docker World</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>That indicates the the Spring Boot app is successfully running locally in a docker container.</p>
<p>Next, let's set up an Azure Container Registry an an Azure Container App and deploy this container to the cloud!</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="3-step-by-step-deploy-to-acr">3. Step-by-step: Deploy to ACR<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#3-step-by-step-deploy-to-acr" class="hash-link" aria-label="Direct link to 3. Step-by-step: Deploy to ACR" title="Direct link to 3. Step-by-step: Deploy to ACR">​</a></h2>
<p>To create a container registry from the <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">portal dashboard</a>, Select <strong>Create a resource &gt; Containers &gt; Container Registry</strong>.</p>
<p><img loading="lazy" alt="Navigate to container registry in portal" src="https://azure.github.io/Cloud-Native/assets/images/acr-portal-01-56ad80e74d4597e32bb2bb534148d10d.png" width="760" height="516" class="img_ev3q"></p>
<p>In the Basics tab, enter values for Resource group and Registry name. The registry name must be unique within Azure, and contain 5-50 alphanumeric characters. Create a new resource group in the West US location named spring-boot-docker-aca.  Select the 'Basic' SKU.</p>
<p>Keep the default values for the remaining settings. Then select <strong>Review + create</strong>, then  <strong>Create</strong>.  When the Deployment succeeded message appears, select the container registry in the portal.</p>
<p>Note the registry server name ending with azurecr.io. You will use this in the following steps when you push and pull images with Docker.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="31-log-into-registry-using-the-azure-cli">3.1 Log into registry using the Azure CLI<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#31-log-into-registry-using-the-azure-cli" class="hash-link" aria-label="Direct link to 3.1 Log into registry using the Azure CLI" title="Direct link to 3.1 Log into registry using the Azure CLI">​</a></h3>
<p>Before pushing and pulling container images, you must log in to the registry instance. Sign into the Azure CLI on your local machine, then run the <code>az acr login</code> command. For this step, use the registry name, not the server name ending with azurecr.io.</p>
<p>From the command line, type:</p>
<div class="language-azurecli codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-azurecli codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az acr login --name myregistryname</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The command returns <strong>Login Succeeded</strong> once completed.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="32-build--deploy-with-az-acr-build">3.2 Build &amp; deploy with <code>az acr build</code><a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#32-build--deploy-with-az-acr-build" class="hash-link" aria-label="Direct link to 32-build--deploy-with-az-acr-build" title="Direct link to 32-build--deploy-with-az-acr-build">​</a></h3>
<p>Next, we're going to deploy the docker container we created earlier using the AZ ACR Build command.  <a href="https://docs.microsoft.com/cli/azure/acr?view=azure-cli-latest#az-acr-build" target="_blank" rel="noopener noreferrer">AZ ACR Build</a> creates a docker build from local code and pushes the container to Azure Container Registry if the build is successful.</p>
<p>Go to your local clone of the <strong>spring-boot-docker-aca</strong> repo in the command line, type:</p>
<div class="language-azurecli codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-azurecli codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az acr build --registry myregistryname --image spring-boot-docker-aca:v1 .</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="33-list-container-images">3.3 List container images<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#33-list-container-images" class="hash-link" aria-label="Direct link to 3.3 List container images" title="Direct link to 3.3 List container images">​</a></h3>
<p>Once the AZ ACR Build command is complete, you should be able to view the container as a repository in the registry.  In the portal, open your registry and select <strong>Repositories</strong>, then select the <strong>spring-boot-docker-aca</strong> repository you created with docker push.  You should also see the <strong>v1</strong> image under Tags.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="4-deploy-on-aca">4. Deploy on ACA<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#4-deploy-on-aca" class="hash-link" aria-label="Direct link to 4. Deploy on ACA" title="Direct link to 4. Deploy on ACA">​</a></h2>
<p>Now that we have an image in the Azure Container Registry, we can deploy it to Azure Container Apps. For the first deployment, we'll pull the container from our ACR as part of the ACA setup.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="41-create-a-container-app">4.1 Create a container app<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#41-create-a-container-app" class="hash-link" aria-label="Direct link to 4.1 Create a container app" title="Direct link to 4.1 Create a container app">​</a></h3>
<p>We'll create the container app at the same place that we created the container registry in the Azure portal.  From the portal, select <strong>Create a resource &gt; Containers &gt; Container App</strong>.  In the <em>Basics</em> tab, set these values:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="42-enter-project-details">4.2 Enter project details<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#42-enter-project-details" class="hash-link" aria-label="Direct link to 4.2 Enter project details" title="Direct link to 4.2 Enter project details">​</a></h3>
<table><thead><tr><th>Setting</th><th>Action</th></tr></thead><tbody><tr><td>Subscription</td><td>Your Azure subscription.</td></tr><tr><td>Resource group</td><td>Use the <strong>spring-boot-docker-aca</strong> resource group</td></tr><tr><td>Container app name</td><td>Enter <strong>spring-boot-docker-aca</strong>.</td></tr></tbody></table>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="43-create-an-environment">4.3 Create an environment<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#43-create-an-environment" class="hash-link" aria-label="Direct link to 4.3 Create an environment" title="Direct link to 4.3 Create an environment">​</a></h3>
<ol>
<li>
<p>In the <em>Create Container App environment</em> field, select <strong>Create new</strong>.</p>
</li>
<li>
<p>In the <em>Create Container App Environment</em> page on the <em>Basics</em> tab, enter the following values:</p>
<table><thead><tr><th>Setting</th><th>Value</th></tr></thead><tbody><tr><td>Environment name</td><td>Enter <strong>my-environment</strong>.</td></tr><tr><td>Region</td><td>Select <strong>westus3</strong>.</td></tr></tbody></table>
</li>
<li>
<p>Select <strong>OK</strong>.</p>
</li>
<li>
<p>Select the <strong>Create</strong> button at the bottom of the <em>Create Container App Environment</em> page.</p>
</li>
<li>
<p>Select the <strong>Next: App settings</strong> button at the bottom of the page.</p>
</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="5-app-settings-tab">5. App settings tab<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#5-app-settings-tab" class="hash-link" aria-label="Direct link to 5. App settings tab" title="Direct link to 5. App settings tab">​</a></h2>
<p>The <em>App settings</em> tab is where you connect to the ACR and pull the repository image:</p>
<table><thead><tr><th>Setting</th><th>Action</th></tr></thead><tbody><tr><td>Use quickstart image</td><td><strong>Uncheck</strong> the checkbox.</td></tr><tr><td>Name</td><td>Enter <strong>spring-boot-docker-aca</strong>.</td></tr><tr><td>Image source</td><td>Select <strong>Azure Container Registry</strong></td></tr><tr><td>Registry</td><td>Select your ACR from the list.</td></tr><tr><td>Image</td><td>Select <strong>spring-boot-docker-aca</strong> from the list.</td></tr><tr><td>Image Tag</td><td>Select <strong>v1</strong> from the list.</td></tr></tbody></table>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="51-application-ingress-settings">5.1 Application ingress settings<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#51-application-ingress-settings" class="hash-link" aria-label="Direct link to 5.1 Application ingress settings" title="Direct link to 5.1 Application ingress settings">​</a></h3>
<table><thead><tr><th>Setting</th><th>Action</th></tr></thead><tbody><tr><td>Ingress</td><td>Select <strong>Enabled</strong>.</td></tr><tr><td>Ingress visibility</td><td>Select <strong>External</strong> to publicly expose your container app.</td></tr><tr><td>Target port</td><td>Enter <strong>8080</strong>.</td></tr></tbody></table>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="52-deploy-the-container-app">5.2 Deploy the container app<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#52-deploy-the-container-app" class="hash-link" aria-label="Direct link to 5.2 Deploy the container app" title="Direct link to 5.2 Deploy the container app">​</a></h3>
<ol>
<li>Select the <strong>Review and create</strong> button at the bottom of the page.</li>
<li>Select <strong>Create</strong>.</li>
</ol>
<p>Once the deployment is successfully completed, you'll see the message: <em>Your deployment is complete</em>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="53-verify-deployment">5.3 Verify deployment<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#53-verify-deployment" class="hash-link" aria-label="Direct link to 5.3 Verify deployment" title="Direct link to 5.3 Verify deployment">​</a></h3>
<p>In the portal, go to the Overview of your <strong>spring-boot-docker-aca</strong> Azure Container App, and click on the Application Url.   You should see this message in the browser:</p>
<div class="language-azurecli codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-azurecli codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Hello Docker World</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>That indicates the the Spring Boot app is running in a docker container in your <strong>spring-boot-docker-aca</strong> Azure Container App.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources-for-self-study">Resources: For self-study!<a href="https://azure.github.io/Cloud-Native/blog/25-aca-java#resources-for-self-study" class="hash-link" aria-label="Direct link to Resources: For self-study!" title="Direct link to Resources: For self-study!">​</a></h2>
<p>Once you have an understanding of the basics in ths post, there is so much more to learn!</p>
<ul>
<li>Check out the other <a href="https://azure.github.io/Cloud-Native/blog" target="_blank" rel="noopener noreferrer">Serverless September posts</a>.</li>
<li>For DevOps and Java on Azure, see the tutorials and workshops at <a href="https://aka.ms/devopsforjavashops" target="_blank" rel="noopener noreferrer">https://aka.ms/devopsforjavashops</a></li>
<li>Also see <a href="https://developer.microsoft.com/java" target="_blank" rel="noopener noreferrer">https://developer.microsoft.com/java</a> for everything Java on Azure!</li>
</ul>
<p>Thanks for stopping by!</p>]]></content:encoded>
            <category>serverless-september</category>
            <category>30-days-of-serverless</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
            <category>microservices</category>
        </item>
        <item>
            <title><![CDATA[24. Deploy ASP.NET app to ACA]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/24-aca-dotnet</link>
            <guid>https://azure.github.io/Cloud-Native/blog/24-aca-dotnet</guid>
            <pubDate>Sat, 24 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Deploy your containerized, multi-project .NET applications to Azure Container Apps]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 24</code> of #30DaysOfServerless!</p>
<p>We continue exploring E2E scenarios with this tutorial where you'll deploy a containerized ASP.NET Core 6.0 application to Azure Container Apps.</p>
<p>The application consists of a front-end web app built using Blazor Server, as well as two Web API projects to manage data. These projects will exist as three separate containers inside of a shared container apps environment.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>Deploy ASP.NET Core 6.0 app to Azure Container Apps</li>
<li>Automate deployment workflows using GitHub Actions</li>
<li>Provision and deploy resources using Azure Bicep</li>
<li>Exercise: Try this yourself!</li>
<li>Resources: For self-study!</li>
</ul>
<p><img loading="lazy" alt="Slide on &amp;quot;E2E – Container Apps&amp;quot; by Alex Wolf (@alexwolfmsft), covering ASP.NET, GitHub Actions, and Bicep in serverless deployments." src="https://azure.github.io/Cloud-Native/assets/images/banner-7fdb7fe187e430c2baabec8b2ae4b648.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<h1>Introduction</h1>
<p>Azure Container Apps enables you to run microservices and containerized applications on a serverless platform. With Container Apps, you enjoy the benefits of running containers while leaving behind the concerns of manually configuring cloud infrastructure and complex container orchestrators.</p>
<p>In this tutorial, you'll deploy a containerized ASP.NET Core 6.0 application to Azure Container Apps. The application consists of a front-end web app built using Blazor Server, as well as two Web API projects to manage data. These projects will exist as three separate containers inside of a shared container apps environment.</p>
<p>You will use GitHub Actions in combination with Bicep to deploy the application. These tools provide an approachable and sustainable solution for building CI/CD pipelines and working with Container Apps.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>PRE-REQUISITES</div><div class="admonitionContent_BuS1"><ul>
<li>An Azure subscription. <a href="https://azure.microsoft.com/" target="_blank" rel="noopener noreferrer">Sign up for free</a>.</li>
<li>A <a href="https://github.com/join" target="_blank" rel="noopener noreferrer">GitHub account</a>, with access to GitHub Actions.</li>
<li>The <a href="https://docs.microsoft.com/azure/install-azure-cli" target="_blank" rel="noopener noreferrer">Azure CLI</a> installed locally.</li>
<li><a href="https://visualstudio.microsoft.com/vs/" target="_blank" rel="noopener noreferrer">Microsoft Visual Studio 2022</a></li>
</ul></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="architecture">Architecture<a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#architecture" class="hash-link" aria-label="Direct link to Architecture" title="Direct link to Architecture">​</a></h2>
<p>In this tutorial, we'll setup a container app environment with a separate container for each project in the sample store app. The major components of the sample project include:</p>
<ul>
<li>A Blazor Server front-end web app to display product information</li>
<li>A products API to list available products</li>
<li>An inventory API to determine how many products are in stock</li>
<li>GitHub Actions and Bicep templates to provision Azure resources and then build and deploy the sample app.</li>
</ul>
<p>You will explore these templates later in the tutorial.</p>
<p>Public internet traffic should be proxied to the Blazor app. The back-end APIs should only be reachable via requests from the Blazor app inside the container apps environment. This setup can be achieved using container apps environment ingress configurations during deployment.</p>
<p><img loading="lazy" alt="An architecture diagram of the shopping app" src="https://azure.github.io/Cloud-Native/assets/images/architecture-a2d16c0719ab5f90fe9e4b66a40198bc.png" width="1051" height="586" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="project-sources">Project Sources<a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#project-sources" class="hash-link" aria-label="Direct link to Project Sources" title="Direct link to Project Sources">​</a></h2>
<p>Want to follow along? Fork the sample below. The tutorial can be completed with or without Dapr integration. Pick the path you feel comfortable in. Dapr provides various benefits that make working with Microservices easier - you can learn more in the docs. For this tutorial you will need GitHub and Azure CLI.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>PICK YOUR PATH</div><div class="admonitionContent_BuS1"><p>To follow along with this tutorial, fork the relevant sample project below.</p><ul>
<li><a href="https://github.com/Azure-Samples/dotNET-FrontEnd-to-BackEnd-on-Azure-Container-Apps" target="_blank" rel="noopener noreferrer"><strong>Project Repo: Without Dapr</strong></a></li>
<li><a href="https://github.com/Azure-Samples/dotNET-FrontEnd-to-BackEnd-with-DAPR-on-Azure-Container-Apps" target="_blank" rel="noopener noreferrer"><strong>Project Repo: With Dapr</strong></a></li>
</ul></div></div>
<p>You can run the app locally from Visual Studio:</p>
<ul>
<li>Right click on the Blazor <strong>Store</strong> project and select <strong>Set as Startup Project</strong>.</li>
<li>Press the start button at the top of Visual Studio to run the app.</li>
<li>(Once running) start each API in the background by</li>
</ul>
<ul>
<li>right-clicking on the project node</li>
<li>selecting <strong>Debug --&gt; Start without debugging</strong>.</li>
</ul>
<p>Once the Blazor app is running, you should see something like this:</p>
<p><img loading="lazy" alt="An architecture diagram of the shopping app" src="https://azure.github.io/Cloud-Native/assets/images/store-ui-78a5d31238363380a388f368b62cdbfc.png" width="871" height="593" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="configuring-azure-credentials">Configuring Azure credentials<a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#configuring-azure-credentials" class="hash-link" aria-label="Direct link to Configuring Azure credentials" title="Direct link to Configuring Azure credentials">​</a></h2>
<p>In order to deploy the application to Azure through GitHub Actions, you first need to create a service principal. The service principal will allow the GitHub Actions process to authenticate to your Azure subscription to create resources and deploy code. You can <a href="https://docs.microsoft.com/azure/create-an-azure-service-principal-azure-cli" target="_blank" rel="noopener noreferrer">learn more about Service Principals</a> in the Azure CLI documentation. For this step you'll need to be logged into the Azure CLI.</p>
<ol>
<li>
<p>If you have not done so already, make sure to <a href="https://github.com/Azure-Samples/dotNET-FrontEnd-to-BackEnd-on-Azure-Container-Apps" target="_blank" rel="noopener noreferrer">fork the sample project</a> to your own GitHub account or organization.</p>
</li>
<li>
<p>Once you have completed this step, create a service principal using the Azure CLI command below:</p>
<div class="language-azurecli codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-azurecli codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$subscriptionId=$(az account show --query id --output tsv)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">az ad sp create-for-rbac --sdk-auth --name WebAndApiSample --role Contributor --scopes /subscriptions/$subscriptionId</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>Copy the JSON output of the CLI command to your clipboard</p>
</li>
<li>
<p>Under the settings tab of your forked GitHub repo, create a new secret named <strong>AzureSPN</strong>. The name is important to match the Bicep templates included in the project, which we'll review later. Paste the copied service principal values on your clipboard into the secret and save your changes. This new secret will be used by the GitHub Actions workflow to authenticate to Azure.</p>
<p>:::image type="content" source="./img/dotnet/github-secrets.png" alt-text="A screenshot of adding GitHub secrets.":::</p>
</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="deploy-using-github-actions">Deploy using Github Actions<a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#deploy-using-github-actions" class="hash-link" aria-label="Direct link to Deploy using Github Actions" title="Direct link to Deploy using Github Actions">​</a></h2>
<p>You are now ready to deploy the application to Azure Container Apps using GitHub Actions. The sample application includes a GitHub Actions template that is configured to build and deploy any changes to a branch named <strong>deploy</strong>.  The deploy branch does not exist in your forked repository by default, but you can easily create it through the GitHub user interface.</p>
<ol>
<li>Switch to the <strong>Actions</strong> tab along the top navigation of your GitHub repository. If you have not done so already, ensure that workflows are enabled by clicking the button in the center of the page.</li>
</ol>
<p><img loading="lazy" alt="A screenshot showing how to enable GitHub actions" src="https://azure.github.io/Cloud-Native/assets/images/enable-actions-6cdb57033746b72e51ed61517c896578.png" width="800" height="352" class="img_ev3q"></p>
<ol>
<li>Navigate to the main <strong>Code</strong> tab of your repository and select the <strong>main</strong> dropdown. Enter <em>deploy</em> into the branch input box, and then select <strong>Create branch: deploy from 'main'</strong>.</li>
</ol>
<p><img loading="lazy" alt="A screenshot showing how to create the deploy branch" src="https://azure.github.io/Cloud-Native/assets/images/create-branch-07796a21bc3c6ad935f349c2e88c8486.png" width="935" height="303" class="img_ev3q"></p>
<ol>
<li>
<p>On the new <strong>deploy</strong> branch, navigate down into the <strong>.github/workflows</strong> folder. You should see a file called <strong>deploy.yml</strong>, which contains the main GitHub Actions workflow script. Click on the file to view its content. You'll learn more about this file later in the tutorial.</p>
</li>
<li>
<p>Click the pencil icon in the upper right to edit the document.</p>
</li>
<li>
<p>Change the <strong>RESOURCE_GROUP_NAME:</strong> value to <em>msdocswebappapis</em> or another valid resource group name of your choosing.</p>
</li>
<li>
<p>In the upper right of the screen, select <strong>Start commit</strong> and then <strong>Commit changes</strong> to commit your edit. This will persist the change to the file and trigger the GitHub Actions workflow to build and deploy the app.</p>
</li>
</ol>
<p><img loading="lazy" alt="A screenshot showing how to commit changes" src="https://azure.github.io/Cloud-Native/assets/images/commit-changes-0ad6c269b0d29b68df48a08978134a64.png" width="1015" height="433" class="img_ev3q"></p>
<ol>
<li>Switch to the <strong>Actions</strong> tab along the top navigation again. You should see the workflow running to create the necessary resources and deploy the app. The workflow may take several minutes to run. When it completes successfully, all of the jobs should have a green checkmark icon next to them.</li>
</ol>
<p><img loading="lazy" alt="The completed GitHub workflow." src="https://azure.github.io/Cloud-Native/assets/images/github-actions-success-8d42fb6cb84d9818e2198d23b712a610.png" width="1343" height="452" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="explore-the-azure-resources">Explore the Azure resources<a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#explore-the-azure-resources" class="hash-link" aria-label="Direct link to Explore the Azure resources" title="Direct link to Explore the Azure resources">​</a></h2>
<p>Once the GitHub Actions workflow has completed successfully you can browse the created resources in the Azure portal.</p>
<ol>
<li>
<p>On the left navigation, select <strong>Resource Groups</strong>. Next,choose the <strong>msdocswebappapis</strong> resource group that was created by the GitHub Actions workflow.</p>
</li>
<li>
<p>You should see seven resources available that match the screenshot and table descriptions below.</p>
</li>
</ol>
<p><img loading="lazy" alt="The resources created in Azure." src="https://azure.github.io/Cloud-Native/assets/images/azure-resources-10875582a2a87a5283aa93138831819e.png" width="818" height="426" class="img_ev3q"></p>
<table><thead><tr><th>Resource name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>inventory</td><td>Container app</td><td>The containerized inventory API.</td></tr><tr><td>msdocswebappapisacr</td><td>Container registry</td><td>A registry that stores the built Container images for your apps.</td></tr><tr><td>msdocswebappapisai</td><td>Application insights</td><td>Application insights provides advanced monitoring, logging and metrics for your apps.</td></tr><tr><td>msdocswebappapisenv</td><td>Container apps environment</td><td>A container environment that manages networking, security and resource concerns. All of your containers live in this environment.</td></tr><tr><td>msdocswebappapislogs</td><td>Log Analytics workspace</td><td>A workspace environment for managing logging and analytics for the container apps environment</td></tr><tr><td>products</td><td>Container app</td><td>The containerized products API.</td></tr><tr><td>store</td><td>Container app</td><td>The Blazor front-end web app.</td></tr></tbody></table>
<ol start="3">
<li>
<p>You can view your running app in the browser by clicking on the <strong>store</strong> container app. On the overview page, click the <strong>Application Url</strong> link on the upper right of the screen.</p>
<p>:::image type="content" source="./img/dotnet/application-url.png" alt-text="The link to browse the app.":::</p>
</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="understanding-the-github-actions-workflow">Understanding the GitHub Actions workflow<a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#understanding-the-github-actions-workflow" class="hash-link" aria-label="Direct link to Understanding the GitHub Actions workflow" title="Direct link to Understanding the GitHub Actions workflow">​</a></h2>
<p>The GitHub Actions workflow created and deployed resources to Azure using the <strong>deploy.yml</strong> file in the <strong>.github</strong> folder at the root of the project. The primary purpose of this file is to respond to events - such as commits to a branch - and run jobs to accomplish tasks. The <strong>deploy.yml</strong> file in the sample project has three main jobs:</p>
<ul>
<li><strong>Provision</strong>: Create the necessary resources in Azure, such as the container apps environment. This step leverages Bicep templates to create the Azure resources, which you'll explore in a moment.</li>
<li><strong>Build</strong>: Create the container images for the three apps in the project and store them in the container registry.</li>
<li><strong>Deploy</strong>: Deploy the container images to the different container apps created during the provisioning job.</li>
</ul>
<p>The <strong>deploy.yml</strong> file also accepts parameters to make the workflow more dynamic, such as setting the resource group name or the Azure region resources will be provisioned to.</p>
<p>Below is a commented version of the <strong>deploy.yml</strong> file that highlights the essential steps.</p>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Build and deploy .NET application to Container Apps</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Trigger the workflow on pushes to the deploy branch</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">on</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">push</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">branches</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> deploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">env</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># Set workflow variables</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">RESOURCE_GROUP_NAME</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> msdocswebappapis</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">REGION</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> eastus</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">STORE_DOCKER</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Store/Dockerfile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">STORE_IMAGE</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> store</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">INVENTORY_DOCKER</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Store.InventoryApi/Dockerfile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">INVENTORY_IMAGE</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> inventory</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">PRODUCTS_DOCKER</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Store.ProductApi/Dockerfile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">PRODUCTS_IMAGE</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> products</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">jobs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># Create the required Azure resources</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">provision</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">runs-on</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">steps</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Checkout to the branch</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> actions/checkout@v2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Azure Login</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> azure/login@v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">with</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">creds</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> secrets.AzureSPN </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Create resource group</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> azure/CLI@v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">with</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">inlineScript</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token scalar string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">          echo "Creating resource group in Azure"</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">          echo "Executing 'az group create -l ${{ env.REGION }} -n ${{ env.RESOURCE_GROUP_NAME }}'"</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">          az group create -l ${{ env.REGION }} -n ${{ env.RESOURCE_GROUP_NAME }}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Use Bicep templates to create the resources in Azure</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Creating resources</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> azure/CLI@v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">with</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">inlineScript</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token scalar string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">          echo "Creating resources"</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">          az deployment group create --resource-group ${{ env.RESOURCE_GROUP_NAME }} --template-file '/github/workspace/Azure/main.bicep' --debug</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># Build the three app container images</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">build</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">runs-on</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">needs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> provision</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">steps</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Checkout to the branch</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> actions/checkout@v2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Azure Login</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> azure/login@v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">with</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">creds</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> secrets.AzureSPN </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Set up Docker Buildx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> docker/setup</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">buildx</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">action@v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Login to ACR</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">run</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token scalar string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        set -euo pipefail</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        access_token=$(az account get-access-token --query accessToken -o tsv)</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        refresh_token=$(curl https://${{ env.RESOURCE_GROUP_NAME }}acr.azurecr.io/oauth2/exchange -v -d "grant_type=access_token&amp;service=${{ env.RESOURCE_GROUP_NAME }}acr.azurecr.io&amp;access_token=$access_token" | jq -r .refresh_token)</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        docker login -u 00000000-0000-0000-0000-000000000000 --password-stdin ${{ env.RESOURCE_GROUP_NAME }}acr.azurecr.io &lt;&lt;&lt; "$refresh_token"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Build the products api image and push it to ACR</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> docker/build</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">push</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">action@v2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">with</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">push</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">tags</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">acr.azurecr.io/$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.PRODUCTS_IMAGE </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> github.sha </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">file</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.PRODUCTS_DOCKER </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Build the inventory api image and push it to ACR</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> docker/build</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">push</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">action@v2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">with</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">push</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">tags</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">acr.azurecr.io/$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.INVENTORY_IMAGE </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> github.sha </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">file</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.INVENTORY_DOCKER </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Build the frontend image and push it to ACR</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> docker/build</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">push</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">action@v2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">with</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">push</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">tags</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">acr.azurecr.io/$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.STORE_IMAGE </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> github.sha </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">file</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.STORE_DOCKER </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># Deploy the three container images</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">deploy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">runs-on</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">needs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> build</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">steps</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Checkout to the branch</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> actions/checkout@v2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Azure Login</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> azure/login@v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">with</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">creds</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> secrets.AzureSPN </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Installing Container Apps extension</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> azure/CLI@v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">with</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">inlineScript</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token scalar string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">          az config set extension.use_dynamic_install=yes_without_prompt</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          az extension add </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">name containerapp </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">yes</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Login to ACR</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">run</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token scalar string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        set -euo pipefail</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        access_token=$(az account get-access-token --query accessToken -o tsv)</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        refresh_token=$(curl https://${{ env.RESOURCE_GROUP_NAME }}acr.azurecr.io/oauth2/exchange -v -d "grant_type=access_token&amp;service=${{ env.RESOURCE_GROUP_NAME }}acr.azurecr.io&amp;access_token=$access_token" | jq -r .refresh_token)</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        docker login -u 00000000-0000-0000-0000-000000000000 --password-stdin ${{ env.RESOURCE_GROUP_NAME }}acr.azurecr.io &lt;&lt;&lt; "$refresh_token"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Deploy Container Apps</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">uses</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> azure/CLI@v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">with</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">inlineScript</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token scalar string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">          az containerapp registry set -n products -g ${{ env.RESOURCE_GROUP_NAME }} --server ${{ env.RESOURCE_GROUP_NAME }}acr.azurecr.io</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          az containerapp update </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">n products </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">g $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">i $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">acr.azurecr.io/$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.PRODUCTS_IMAGE </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> github.sha </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          az containerapp registry set </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">n inventory </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">g $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">server $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">acr.azurecr.io</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          az containerapp update </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">n inventory </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">g $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">i $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">acr.azurecr.io/$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.INVENTORY_IMAGE </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> github.sha </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          az containerapp registry set </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">n store </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">g $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">server $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">acr.azurecr.io</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          az containerapp update </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">n store </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">g $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">i $</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.RESOURCE_GROUP_NAME </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">acr.azurecr.io/$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> env.STORE_IMAGE </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> github.sha </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> logout</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">run</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token scalar string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        az logout</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="understanding-the-bicep-templates">Understanding the Bicep templates<a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#understanding-the-bicep-templates" class="hash-link" aria-label="Direct link to Understanding the Bicep templates" title="Direct link to Understanding the Bicep templates">​</a></h2>
<p>During the provisioning stage of the GitHub Actions workflow, the <strong>main.bicep</strong> file is processed. Bicep files provide a declarative way of generating resources in Azure and are ideal for managing infrastructure as code. You can <a href="https://docs.microsoft.com/azure/azure-resource-manager/bicep/overview?tabs=bicep" target="_blank" rel="noopener noreferrer">learn more about Bicep</a> in the related documentation.  The <em>main.bicep</em> file in the sample project creates the following resources:</p>
<ul>
<li>The container registry to store images of the containerized apps.</li>
<li>The container apps environment, which handles networking and resource management for the container apps.</li>
<li>Three container apps - one for the Blazor front-end and two for the back-end product and inventory APIs.</li>
<li>Configuration values to connect these services together</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="mainbicep-without-dapr"><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#tab/exclude-dapper"><em>main.bicep</em> without Dapr</a><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#mainbicep-without-dapr" class="hash-link" aria-label="Direct link to mainbicep-without-dapr" title="Direct link to mainbicep-without-dapr">​</a></h3>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">param location string = resourceGroup().location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the azure container registry</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">resource acr 'Microsoft.ContainerRegistry/registries@2021</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">09</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> toLower('$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">resourceGroup().name</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">acr')</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">sku</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Basic'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">properties</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">adminUserEnabled</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the aca environment</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module env 'environment.bicep' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'containerAppEnvironment'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">params</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the various configuration pairs</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var shared_config = </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'ASPNETCORE_ENVIRONMENT'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Development'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'APPINSIGHTS_INSTRUMENTATIONKEY'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> env.outputs.appInsightsInstrumentationKey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'APPLICATIONINSIGHTS_CONNECTION_STRING'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> env.outputs.appInsightsConnectionString</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the products api container app</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module products 'container_app.bicep' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'products'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">params</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'products'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryPassword</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().passwords</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">.value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryUsername</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().username</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">containerAppEnvironmentId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> env.outputs.id</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registry</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">envVars</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> shared_config</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">externalIngress</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the inventory api container app</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module inventory 'container_app.bicep' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'inventory'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">params</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'inventory'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryPassword</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().passwords</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">.value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryUsername</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().username</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">containerAppEnvironmentId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> env.outputs.id</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registry</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">envVars</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> shared_config</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">externalIngress</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the store api container app</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var frontend_config = </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'ProductsApi'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'http://${products.outputs.fqdn}'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'InventoryApi'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'http://${inventory.outputs.fqdn}'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module store 'container_app.bicep' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'store'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">params</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'store'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryPassword</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().passwords</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">.value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryUsername</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().username</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">containerAppEnvironmentId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> env.outputs.id</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registry</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">envVars</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> union(shared_config</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> frontend_config)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">externalIngress</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="mainbicep-with-dapr"><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#tab/include-dapper"><em>main.bicep</em> with Dapr</a><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#mainbicep-with-dapr" class="hash-link" aria-label="Direct link to mainbicep-with-dapr" title="Direct link to mainbicep-with-dapr">​</a></h3>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param location string = resourceGroup().location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the azure container registry</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">resource acr 'Microsoft.ContainerRegistry/registries@2021</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">09</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> toLower('$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">resourceGroup().name</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">acr')</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">sku</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Basic'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">properties</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">adminUserEnabled</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the aca environment</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module env 'environment.bicep' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'containerAppEnvironment'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">params</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the various config pairs</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var shared_config = </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'ASPNETCORE_ENVIRONMENT'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Development'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'APPINSIGHTS_INSTRUMENTATIONKEY'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> env.outputs.appInsightsInstrumentationKey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'APPLICATIONINSIGHTS_CONNECTION_STRING'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> env.outputs.appInsightsConnectionString</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the products api container app</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module products 'container_app.bicep' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'products'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">params</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'products'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryPassword</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().passwords</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">.value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryUsername</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().username</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">containerAppEnvironmentId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> env.outputs.id</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registry</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">envVars</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> shared_config</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">externalIngress</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the inventory api container app</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module inventory 'container_app.bicep' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'inventory'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">params</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'inventory'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryPassword</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().passwords</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">.value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryUsername</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().username</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">containerAppEnvironmentId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> env.outputs.id</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registry</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">envVars</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> shared_config</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">externalIngress</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the store api container app</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module store 'container_app.bicep' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'store'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">params</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'store'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryPassword</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().passwords</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">.value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryUsername</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().username</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">containerAppEnvironmentId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> env.outputs.id</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registry</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">envVars</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> shared_config</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">externalIngress</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<hr>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="bicep-modules">Bicep Modules<a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#bicep-modules" class="hash-link" aria-label="Direct link to Bicep Modules" title="Direct link to Bicep Modules">​</a></h3>
<p>The <em>main.bicep</em> file references modules to create resources, such as <code>module products</code>. Modules are a feature of Bicep templates that enable you to abstract resource declarations into their own files or sub-templates. As the <em>main.bicep</em> file is processed, the defined modules are also evaluated. Modules allow you to create resources in a more organized and reusable way. They can also define input and output parameters that are passed to and from the parent template, such as the name of a resource.</p>
<p>For example, the <em>environment.bicep</em> module extracts the details of creating a container apps environment into a reusable template. The module defines necessary resource dependencies such as Log Analytics Workspaces and an Application Insights instance.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="environmentbicep-without-dapr"><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#tab/exclude-dapper"><em>environment.bicep</em> without Dapr</a><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#environmentbicep-without-dapr" class="hash-link" aria-label="Direct link to environmentbicep-without-dapr" title="Direct link to environmentbicep-without-dapr">​</a></h3>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">param baseName string = resourceGroup().name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param location string = resourceGroup().location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">resource logs 'Microsoft.OperationalInsights/workspaces@2021</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">06</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'${baseName}logs'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">properties</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> any(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">retentionInDays</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">30</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">features</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">searchVersion</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">sku</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'PerGB2018'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">resource appInsights 'Microsoft.Insights/components@2020</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">02</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">02' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'${baseName}ai'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">kind</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'web'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">properties</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">Application_Type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'web'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">WorkspaceResourceId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> logs.id</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">resource env 'Microsoft.App/managedEnvironments@2022</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">preview' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'${baseName}env'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">properties</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">appLogsConfiguration</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">destination</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'log-analytics'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">logAnalyticsConfiguration</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">customerId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> logs.properties.customerId</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">sharedKey</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> logs.listKeys().primarySharedKey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">output id string = env.id</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">output appInsightsInstrumentationKey string = appInsights.properties.InstrumentationKey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">output appInsightsConnectionString string = appInsights.properties.ConnectionString</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="environmentbicep-with-dapr"><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#tab/include-dapper"><em>environment.bicep</em> with Dapr</a><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#environmentbicep-with-dapr" class="hash-link" aria-label="Direct link to environmentbicep-with-dapr" title="Direct link to environmentbicep-with-dapr">​</a></h3>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param baseName string = resourceGroup().name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param location string = resourceGroup().location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">resource logs 'Microsoft.OperationalInsights/workspaces@2021</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">06</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'${baseName}logs'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">properties</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> any(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">retentionInDays</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">30</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">features</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">searchVersion</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">sku</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'PerGB2018'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">resource appInsights 'Microsoft.Insights/components@2020</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">02</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">02' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'${baseName}ai'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">kind</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'web'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">properties</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">Application_Type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'web'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">WorkspaceResourceId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> logs.id</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">resource env 'Microsoft.App/managedEnvironments@2022</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">preview' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'${baseName}env'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">properties</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">appLogsConfiguration</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">destination</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'log-analytics'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">logAnalyticsConfiguration</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">customerId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> logs.properties.customerId</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">sharedKey</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> logs.listKeys().primarySharedKey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">output id string = env.id</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">output appInsightsInstrumentationKey string = appInsights.properties.InstrumentationKey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">output appInsightsConnectionString string = appInsights.properties.ConnectionString</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<hr>
<p>The <em>container_apps.bicep</em> template defines numerous parameters to provide a reusable template for creating container apps. This allows the module to be used in other CI/CD pipelines as well.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="container_appbicep-without-dapr"><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#tab/exclude-dapper"><em>container_app.bicep</em> without Dapr</a><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#container_appbicep-without-dapr" class="hash-link" aria-label="Direct link to container_appbicep-without-dapr" title="Direct link to container_appbicep-without-dapr">​</a></h3>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">param name string</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param location string = resourceGroup().location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param containerAppEnvironmentId string</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param repositoryImage string = 'mcr.microsoft.com/azuredocs/containerapps</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">helloworld</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">latest'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param envVars array = </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param registry string</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param minReplicas int = 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param maxReplicas int = 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param port int = 80</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param externalIngress bool = false</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param allowInsecure bool = true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param transport string = 'http'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param registryUsername string</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@secure()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param registryPassword string</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">resource containerApp 'Microsoft.App/containerApps@2022</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">preview' =</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  properties</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">managedEnvironmentId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> containerAppEnvironmentId</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">configuration</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">activeRevisionsMode</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'single'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">secrets</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'container-registry-password'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> registryPassword</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">      </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">registries</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">server</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> registry</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">username</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> registryUsername</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">passwordSecretRef</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'container-registry-password'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">ingress</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">external</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> externalIngress</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">targetPort</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> port</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">transport</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> transport</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">allowInsecure</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> allowInsecure</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">template</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">containers</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> repositoryImage</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">env</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> envVars</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">scale</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">minReplicas</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> minReplicas</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">maxReplicas</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> maxReplicas</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">output fqdn string = containerApp.properties.configuration.ingress.fqdn</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="container_appbicep-with-dapr"><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#tab/include-dapper"><em>container_app.bicep</em> with Dapr</a><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#container_appbicep-with-dapr" class="hash-link" aria-label="Direct link to container_appbicep-with-dapr" title="Direct link to container_appbicep-with-dapr">​</a></h3>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param name string</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param location string = resourceGroup().location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param containerAppEnvironmentId string</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param repositoryImage string = 'mcr.microsoft.com/azuredocs/containerapps</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">helloworld</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">latest'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param envVars array = </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param registry string</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param minReplicas int = 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param maxReplicas int = 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param port int = 80</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param externalIngress bool = false</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param allowInsecure bool = true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param transport string = 'http'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param appProtocol string = 'http'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param registryUsername string</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@secure()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">param registryPassword string</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">resource containerApp 'Microsoft.App/containerApps@2022</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">preview' =</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  properties</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">managedEnvironmentId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> containerAppEnvironmentId</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">configuration</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">dapr</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">enabled</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">appId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">appPort</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> port</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">appProtocol</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> appProtocol</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">activeRevisionsMode</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'single'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">secrets</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'container-registry-password'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> registryPassword</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">      </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">registries</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">server</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> registry</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">username</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> registryUsername</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">passwordSecretRef</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'container-registry-password'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">ingress</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">external</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> externalIngress</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">targetPort</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> port</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">transport</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> transport</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">allowInsecure</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> allowInsecure</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">template</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">containers</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> repositoryImage</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">env</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> envVars</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">scale</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">minReplicas</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> minReplicas</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">maxReplicas</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> maxReplicas</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">output fqdn string = containerApp.properties.configuration.ingress.fqdn</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="understanding-configuration-differences-with-dapr">Understanding configuration differences with Dapr<a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#understanding-configuration-differences-with-dapr" class="hash-link" aria-label="Direct link to Understanding configuration differences with Dapr" title="Direct link to Understanding configuration differences with Dapr">​</a></h2>
<p>The code for this specific sample application is largely the same whether or not Dapr is integrated. However, even with this simple app, there are a few benefits and configuration differences when using Dapr that are worth exploring.</p>
<p>In this scenario most of the changes are related to communication between the container apps. However, you can explore the full range of Dapr benefits by reading the <a href="https://docs.microsoft.com/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml" target="_blank" rel="noopener noreferrer">Dapr integration with Azure Container Apps</a> article in the conceptual documentation.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="without-dapr"><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#tab/exclude-dapper">Without Dapr</a><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#without-dapr" class="hash-link" aria-label="Direct link to without-dapr" title="Direct link to without-dapr">​</a></h3>
<p>Without Dapr the <em>main.bicep</em> template handles wiring up the front-end store app to communicate with the back-end apis by manually managing environment variables. The bicep template retrieves the fully qualified domains (fqdn) of the API apps as output parameters when they are created. Those configurations are then set as environment variables on the store container app.</p>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Retrieve environment variables from API container creation </span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var frontend_config = </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'ProductsApi'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'http://${products.outputs.fqdn}'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'InventoryApi'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'http://${inventory.outputs.fqdn}'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># create the store api container app, passing in config</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module store 'container_app.bicep' = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'store'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">params</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'store'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryPassword</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().passwords</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">.value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registryUsername</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.listCredentials().username</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">containerAppEnvironmentId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> env.outputs.id</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">registry</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> acr.name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">envVars</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> union(shared_config</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> frontend_config)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">externalIngress</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The environment variables are then retrieved inside of the <code>program</code> class and used to configure the base URLs of the corresponding HTTP clients.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">builder.Services.AddHttpClient("Products", (httpClient) =&gt; httpClient.BaseAddress = new Uri(builder.Configuration.GetValue&lt;string&gt;("ProductsApi")));</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">builder.Services.AddHttpClient("Inventory", (httpClient) =&gt; httpClient.BaseAddress = new Uri(builder.Configuration.GetValue&lt;string&gt;("InventoryApi")));</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="with-dapr"><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#tab/include-dapper">With Dapr</a><a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#with-dapr" class="hash-link" aria-label="Direct link to with-dapr" title="Direct link to with-dapr">​</a></h3>
<p>Dapr can be enabled on a container app when it is created, as seen below. This configuration adds a Dapr sidecar to the app to streamline discovery and communication features between the different container apps in your environment.</p>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Create the container app with Dapr enabled</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">resource containerApp 'Microsoft.App/containerApps@2022</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">01</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">preview' =</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  properties</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">managedEnvironmentId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> containerAppEnvironmentId</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">configuration</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">dapr</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">enabled</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">appId</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">appPort</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> port</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">appProtocol</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> appProtocol</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">activeRevisionsMode</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'single'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">secrets</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'container-registry-password'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> registryPassword</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">      </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Rest of template omitted for brevity...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Some of these Dapr features can be surfaced through the <code>program</code> file. You can configure your HttpClient to leverage Dapr configurations when communicating with other apps in your environment.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// reconfigure code to make requests to Dapr sidecar</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var baseURL = (Environment.GetEnvironmentVariable("BASE_URL") ?? "http://localhost") + ":" + (Environment.GetEnvironmentVariable("DAPR_HTTP_PORT") ?? "3500");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">builder.Services.AddHttpClient("Products", (httpClient) =&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    httpClient.BaseAddress = new Uri(baseURL);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    httpClient.DefaultRequestHeaders.Add("dapr-app-id", "Products");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">builder.Services.AddHttpClient("Inventory", (httpClient) =&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    httpClient.BaseAddress = new Uri(baseURL);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    httpClient.DefaultRequestHeaders.Add("dapr-app-id", "Inventory");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="clean-up-resources">Clean up resources<a href="https://azure.github.io/Cloud-Native/blog/24-aca-dotnet#clean-up-resources" class="hash-link" aria-label="Direct link to Clean up resources" title="Direct link to Clean up resources">​</a></h2>
<p>If you're not going to continue to use this application, you can delete the Azure Container Apps and all the associated services by removing the resource group.</p>
<p>Follow these steps in the Azure portal to remove the resources you created:</p>
<ol>
<li>In the Azure portal, navigate to the <strong>msdocswebappsapi</strong> resource group using the left navigation or search bar.</li>
<li>Select the <strong>Delete resource group</strong> button at the top of the resource group <em>Overview</em>.</li>
<li>Enter the resource group name <strong>msdocswebappsapi</strong> in the <em>Are you sure you want to delete "msdocswebappsapi"</em> confirmation dialog.</li>
<li>Select <strong>Delete</strong>.<br>
<!-- -->The process to delete the resource group may take a few minutes to complete.</li>
</ol>]]></content:encoded>
            <category>serverless-september</category>
            <category>30-days-of-serverless</category>
            <category>dotnet</category>
            <category>asp.net</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
            <category>microservices</category>
        </item>
        <item>
            <title><![CDATA[21. CloudEvents with Event Grid]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid</link>
            <guid>https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid</guid>
            <pubDate>Wed, 21 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Introducing CloudEvents, the CNCF's standard event spec, and how to consume it through Azure Event Grid, Logic Apps and Azure Functions]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 21</code> of #30DaysOfServerless!</p>
<p>We've so far walked through what <a href="https://docs.microsoft.com/azure/event-grid/overview?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure Event Grid</a> is and how it generally works. Today, let's discuss how Azure Event Grid deals with <a href="https://cloudevents.io/" target="_blank" rel="noopener noreferrer">CloudEvents</a>.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li><a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#what-well-cover">What We'll Cover</a></li>
<li><a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#what-is-cloudevents">What is CloudEvents?</a></li>
<li><a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#how-azure-event-grid-brokers-cloudevents">How Azure Event Grid brokers CloudEvents</a>
<ul>
<li><a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#azure-event-grid-for-azure">Azure Event Grid for Azure</a></li>
<li><a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#azure-event-grid-for-systems-outside-azure">Azure Event Grid for Systems outside Azure</a></li>
</ul>
</li>
<li><a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#how-azure-logic-apps-consumes-cloudevents">How Azure Logic Apps consumes CloudEvents</a></li>
<li><a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#exercise-try-this-yourself">Exercise: Try this yourself!</a></li>
<li><a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#resources-for-self-study">Resources: For self-study!</a></li>
</ul>
<p><img loading="lazy" alt="Slide for &amp;quot;Brokering Cloud Events,&amp;quot; presented by Justin Yoo (@justinchronicle), discussing Event Grid for integrating cloud services." src="https://azure.github.io/Cloud-Native/assets/images/banner-44903533e9d0b0bdac7d242027cc0694.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<p>OK. Let's get started!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-cloudevents">What is CloudEvents?<a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#what-is-cloudevents" class="hash-link" aria-label="Direct link to What is CloudEvents?" title="Direct link to What is CloudEvents?">​</a></h2>
<p>Needless to say, events are everywhere. Events come not only from event-driven systems but also from many different systems and devices, including IoT ones like Raspberry PI.</p>
<p>But the problem is that every event publisher (system/device that creates events) describes their events differently, meaning there is no standard way of describing events. It has caused many issues between systems, mainly from the interoperability perspective.</p>
<ol>
<li>Consistency: No standard way of describing events resulted in developers having to write their own event handling logic for each event source.</li>
<li>Accessibility: There were no common libraries, tooling and infrastructure to deliver events across systems.</li>
<li>Productivity: The overall productivity decreases because of the lack of the standard format of events.</li>
</ol>
<p><img loading="lazy" alt="Cloud Events Logo" src="https://azure.github.io/Cloud-Native/assets/images/cloudevents-icon-color-eb63959a4ce7e47461aba884b786ae9b.png" width="200" height="200" class="img_ev3q"></p>
<p>Therefore, <a href="https://cncf.io/" target="_blank" rel="noopener noreferrer">CNCF (Cloud-Native Computing Foundation)</a> has brought up the concept, called <a href="https://cloudevents.io/" target="_blank" rel="noopener noreferrer">CloudEvents</a>. CloudEvents is a specification that commonly describes event data. Conforming any event data to this spec will simplify the event declaration and delivery across systems and platforms and more, resulting in a huge productivity increase.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-azure-event-grid-brokers-cloudevents">How Azure Event Grid brokers CloudEvents<a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#how-azure-event-grid-brokers-cloudevents" class="hash-link" aria-label="Direct link to How Azure Event Grid brokers CloudEvents" title="Direct link to How Azure Event Grid brokers CloudEvents">​</a></h2>
<p>Before CloudEvents, <a href="https://docs.microsoft.com/azure/event-grid/overview?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure Event Grid</a> described events in their own way. Therefore, if you want to use Azure Event Grid, you should follow the event format/schema that Azure Event Grid declares. However, not every system/service/application follows the Azure Event Grid schema. Therefore, Azure Event Grid now supports <a href="https://docs.microsoft.com/azure/event-grid/cloudevents-schema?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">CloudEvents spec</a> as input and output formats.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="azure-event-grid-for-azure">Azure Event Grid for Azure<a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#azure-event-grid-for-azure" class="hash-link" aria-label="Direct link to Azure Event Grid for Azure" title="Direct link to Azure Event Grid for Azure">​</a></h3>
<p>Take a look at the simple diagram below, which describes how Azure Event Grid captures events raised from various Azure services. In this diagram, Azure Key Vault takes the role of the event source or event publisher, and <a href="https://docs.microsoft.com/azure/logic-apps/logic-apps-overview?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure Logic Apps</a> takes the role of the event handler (I'll discuss Azure Logic Apps as the event handler later in this post). We use <a href="https://docs.microsoft.com/azure/event-grid/system-topics?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure Event Grid System Topic</a> for Azure.</p>
<p><img loading="lazy" alt="Azure Event Grid for Azure" src="https://azure.github.io/Cloud-Native/assets/images/21-cloudevents-via-event-grid-01-694e11ff4422f7f4f28ae03f08580170.png" width="3840" height="840" class="img_ev3q"></p>
<p>Therefore, let's create an <a href="https://docs.microsoft.com/azure/event-grid/system-topics?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure Event Grid System Topic</a> that captures events raised from <a href="https://docs.microsoft.com/azure/key-vault/general/basic-concepts?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure Key Vault</a> when a new version of a secret is added.</p>
<p><img loading="lazy" alt="Azure Event Grid System Topic for Key Vault" src="https://azure.github.io/Cloud-Native/assets/images/21-cloudevents-via-event-grid-02-534038bbd75d4593fb17b225b4ed3d0a.png" width="3744" height="1430" class="img_ev3q"></p>
<p>As Azure Event Grid makes use of the <a href="https://www.enterpriseintegrationpatterns.com/PublishSubscribeChannel.html" target="_blank" rel="noopener noreferrer">pub/sub pattern</a>, you need to create the <a href="https://docs.microsoft.com/azure/event-grid/concepts?WT.mc_id=dotnet-75362-juyoo#event-subscriptions" target="_blank" rel="noopener noreferrer">Azure Event Grid Subscription</a> to consume the events. Here's the subscription that uses the Event Grid data format:</p>
<p>![Azure Event Grid System Subscription for Key Vault in Event Grid Format][./img/21-cloudevents-via-event-grid-03.png]</p>
<p>Once you create the subscription, create a new version of the secret on Azure Key Vault. Then, Azure Key Vault raises an event, which is captured in the Event Grid format:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "id": "6f44b9c0-d37e-40e7-89be-f70a6da291cc",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "topic": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rg-aegce-krc/providers/Microsoft.KeyVault/vaults/kv-xxxxxxxx",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "subject": "hello",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "eventType": "Microsoft.KeyVault.SecretNewVersionCreated",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "data": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "Id": "https://kv-xxxxxxxx.vault.azure.net/secrets/hello/064dfc082fec463f8d4610ed6118811d",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "VaultName": "kv-xxxxxxxx",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "ObjectType": "Secret",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "ObjectName": "hello",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "Version": "064dfc082fec463f8d4610ed6118811d",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "NBF": null,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "EXP": null</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "dataVersion": "1",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "metadataVersion": "1",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "eventTime": "2022-09-21T07:08:09.1234567Z"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>So, how is it different from the CloudEvents format? Let's take a look. According to the <a href="https://github.com/cloudevents/spec/blob/v1.0/json-format.md#23-examples" target="_blank" rel="noopener noreferrer">spec</a>, the JSON data in CloudEvents might look like this:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "id" : "C234-1234-1234",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "source" : "/mycontext",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "specversion" : "1.0",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "type" : "com.example.someevent",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "comexampleextension1" : "value",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "time" : "2018-04-05T17:31:00Z",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "datacontenttype" : "application/cloudevents+json",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "data" : {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "appinfoA" : "abc",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "appinfoB" : 123,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "appinfoC" : true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This time, let's create another subscription using the CloudEvents schema. Here's how to create the subscription against the system topic:</p>
<p><img loading="lazy" alt="Azure Event Grid System Subscription for Key Vault in CloudEvents Format" src="https://azure.github.io/Cloud-Native/assets/images/21-cloudevents-via-event-grid-04-b80d8235ced38e84b57edcf3897aa6a3.png" width="3744" height="2017" class="img_ev3q"></p>
<p>Therefore, Azure Key Vault emits the event data in the CloudEvents format:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "id": "6f44b9c0-d37e-40e7-89be-f70a6da291cc",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "source": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rg-aegce-krc/providers/Microsoft.KeyVault/vaults/kv-xxxxxxxx",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "specversion": "1.0",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "type": "Microsoft.KeyVault.SecretNewVersionCreated",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "subject": "hello",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "time": "2022-09-21T07:08:09.1234567Z",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "data": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "Id": "https://kv-xxxxxxxx.vault.azure.net/secrets/hello/064dfc082fec463f8d4610ed6118811d",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "VaultName": "kv-xxxxxxxx",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "ObjectType": "Secret",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "ObjectName": "hello",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "Version": "064dfc082fec463f8d4610ed6118811d",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "NBF": null,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "EXP": null</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Can you identify some differences between the Event Grid format and the CloudEvents format? Fortunately, both Event Grid schema and CloudEvents schema look similar to each other. But they might be significantly different if you use a different event source outside Azure.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="azure-event-grid-for-systems-outside-azure">Azure Event Grid for Systems outside Azure<a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#azure-event-grid-for-systems-outside-azure" class="hash-link" aria-label="Direct link to Azure Event Grid for Systems outside Azure" title="Direct link to Azure Event Grid for Systems outside Azure">​</a></h3>
<p>As mentioned above, the event data described outside Azure or your own applications within Azure might not be understandable by Azure Event Grid. In this case, we need to use <a href="https://docs.microsoft.com/azure/event-grid/custom-topics?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure Event Grid Custom Topic</a>. Here's the diagram for it:</p>
<p><img loading="lazy" alt="Azure Event Grid for Applications outside Azure" src="https://azure.github.io/Cloud-Native/assets/images/21-cloudevents-via-event-grid-05-3302c0aa7803104c5fcd4efd83b7f112.png" width="3840" height="840" class="img_ev3q"></p>
<p>Let's create the Azure Event Grid Custom Topic. When you create the topic, make sure that you use the CloudEvent schema during the provisioning process:</p>
<p><img loading="lazy" alt="Azure Event Grid Custom Topic" src="https://azure.github.io/Cloud-Native/assets/images/21-cloudevents-via-event-grid-06-240c34d97c26b9175b4d6f05c88bbddb.png" width="3744" height="2018" class="img_ev3q"></p>
<p>If your application needs to publish events to Azure Event Grid Custom Topic, your application should build the event data in the CloudEvents format. If you use a .NET application, add the <a href="https://www.nuget.org/packages/Azure.Messaging.EventGrid" target="_blank" rel="noopener noreferrer">NuGet package</a> first.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">dotnet add package Azure.Messaging.EventGrid</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Then, create the publisher instance. You've already got the topic endpoint URL and the access key.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">var topicEndpoint = new Uri("&lt;Azure Event Grid Custom Topic Endpoint URL&gt;");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var credential = new AzureKeyCredential("&lt;Azure Event Grid Custom Topic Access Key&gt;");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var publisher = new EventGridPublisherClient(topicEndpoint, credential);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now, build the event data like below. Make sure that you follow the CloudEvents schema that requires additional metadata like event source, event type and content type.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">var source = "/your/event/source";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var type = "com.source.event.your/OnEventOccurs";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var data = new MyEventData() { Hello = "World" };</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var @event = new CloudEvent(source, type, data);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>And finally, send the event to Azure Event Grid Custom Topic.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">await publisher.SendEventAsync(@event);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The captured event data looks like the following:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "id": "cc2b2775-52b8-43b8-a7cc-c1c33c2b2e59",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "source": "/your/event/source",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "type": "com.source.event.my/OnEventOccurs",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "data": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "Hello": "World"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "time": "2022-09-21T07:08:09.1234567+00:00",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "specversion": "1.0"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>However, due to limitations, someone might insist that their existing application doesn't or can't emit the event data in the CloudEvents format. In this case, what should we do? There's no standard way of sending the event data in the CloudEvents format to Azure Event Grid Custom Topic. One of the approaches we may be able to apply is to put a converter between the existing application and Azure Event Grid Custom Topic like below:</p>
<p><img loading="lazy" alt="Azure Event Grid for Applications outside Azure with Converter" src="https://azure.github.io/Cloud-Native/assets/images/21-cloudevents-via-event-grid-07-f7192ae5bffc82738d60b79649a643bd.png" width="3840" height="840" class="img_ev3q"></p>
<p>Once the Function app (or any converter app) receives legacy event data, it internally converts the CloudEvents format and publishes it to Azure Event Grid.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">var data = default(MyRequestData);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">using (var reader = new StreamReader(req.Body))</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    var serialised = await reader.ReadToEndAsync();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    data = JsonConvert.DeserializeObject&lt;MyRequestData&gt;(serialised);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var converted = new MyEventData() { Hello = data.Lorem };</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var @event = new CloudEvent(source, type, converted);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The converted event data is captured like this:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "id": "df296da3-77cd-4da2-8122-91f631941610",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "source": "/your/event/source",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "type": "com.source.event.my/OnEventOccurs",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "data": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "Hello": "ipsum"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "time": "2022-09-21T07:08:09.1234567+00:00",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "specversion": "1.0"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This approach is beneficial in many integration scenarios to make all the event data canonicalised.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-azure-logic-apps-consumes-cloudevents">How Azure Logic Apps consumes CloudEvents<a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#how-azure-logic-apps-consumes-cloudevents" class="hash-link" aria-label="Direct link to How Azure Logic Apps consumes CloudEvents" title="Direct link to How Azure Logic Apps consumes CloudEvents">​</a></h2>
<p>I put <a href="https://docs.microsoft.com/azure/logic-apps/logic-apps-overview?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure Logic Apps</a> as the event handler in the previous diagrams. According to the <a href="https://github.com/cloudevents/spec/blob/v1.0/http-webhook.md#4-abuse-protection" target="_blank" rel="noopener noreferrer">CloudEvents spec</a>, each event handler must implement request validation to avoid abuse. One good thing about using Azure Logic Apps is that it has already implemented this request validation feature. It implies that we just subscribe to the topic and consume the event data.</p>
<p>Create a new Logic Apps instance and add the HTTP Request trigger. Once it saves, you will get the endpoint URL.</p>
<p><img loading="lazy" alt="Azure Logic Apps with HTTP Request Trigger" src="https://azure.github.io/Cloud-Native/assets/images/21-cloudevents-via-event-grid-08-8eb13d8f2eb780c1ac54987644c832cd.png" width="3744" height="2018" class="img_ev3q"></p>
<p>Then, create the Azure Event Grid Subscription with:</p>
<ul>
<li>Endpoint type: Webhook</li>
<li>Endpoint URL: The Logic Apps URL from above.</li>
</ul>
<p><img loading="lazy" alt="Azure Logic Apps with HTTP Request Trigger" src="https://azure.github.io/Cloud-Native/assets/images/21-cloudevents-via-event-grid-09-f4132c208e6f6a4ce229c6d907cdd061.png" width="3744" height="2018" class="img_ev3q"></p>
<p>Once the subscription is ready, this Logic Apps works well as the event handler. Here's how it receives the CloudEvents data from the subscription.</p>
<p><img loading="lazy" alt="Azure Logic Apps that Received CloudEvents data" src="https://azure.github.io/Cloud-Native/assets/images/21-cloudevents-via-event-grid-10-0d9e5e1baa7b398319a99d651d91cf61.png" width="3744" height="2018" class="img_ev3q"></p>
<p>Now you've got the CloudEvents data. It's entirely up to you to handle that event data however you want!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-try-this-yourself">Exercise: Try this yourself!<a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#exercise-try-this-yourself" class="hash-link" aria-label="Direct link to Exercise: Try this yourself!" title="Direct link to Exercise: Try this yourself!">​</a></h2>
<p>You can fork this <a href="https://github.com/justinyoo/azure-event-grid-cloudevents-sample" target="_blank" rel="noopener noreferrer">GitHub repository</a> to your account and play around with it to see how Azure Event Grid with CloudEvents works. Alternatively, the "Deploy to Azure" button below will provision all necessary Azure resources and deploy an Azure Functions app to mimic the event publisher.</p>
<p><a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fjustinyoo%2Fazure-event-grid-cloudevents-sample%2Fmain%2FResources%2Fazuredeploy.json" target="_blank" rel="noopener noreferrer"><img loading="lazy" src="https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/deploytoazure.svg?sanitize=true" alt="Deploy To Azure" class="img_ev3q"></a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources-for-self-study">Resources: For self-study!<a href="https://azure.github.io/Cloud-Native/blog/21-cloudevents-via-event-grid#resources-for-self-study" class="hash-link" aria-label="Direct link to Resources: For self-study!" title="Direct link to Resources: For self-study!">​</a></h2>
<p>Want to know more about CloudEvents in real-life examples? Here are several resources you can take a look at:</p>
<ul>
<li><a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/azure-cli-for-eventgrid-subscription-to-custom-topic/ba-p/2038834?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Azure CLI for EventGrid Subscription to Custom Topic</a></li>
<li><a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/cloudevents-for-azure-eventgrid-via-azure-functions/ba-p/2048140?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">CloudEvents for Azure EventGrid via Azure Functions</a></li>
<li><a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/websub-to-eventgrid-via-cloudevents-and-beyond/ba-p/2092709?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">WebSub to EventGrid via CloudEvents, and Beyond</a></li>
<li><a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/event-driven-keyvault-secrets-rotation-management/ba-p/2187249?WT.mc_id=dotnet-75362-juyoo" target="_blank" rel="noopener noreferrer">Event-Driven KeyVault Secrets Rotation Management</a></li>
</ul>]]></content:encoded>
            <category>serverless-september</category>
            <category>cloudevents</category>
            <category>azure-event-grid</category>
            <category>azure-logic-apps</category>
            <category>azure-functions</category>
        </item>
        <item>
            <title><![CDATA[20. Integrate with Microsoft Graph]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/20-events-graph</link>
            <guid>https://azure.github.io/Cloud-Native/blog/20-events-graph</guid>
            <pubDate>Tue, 20 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[build a seamsless onboarding experience to new employees joining a company with the power of Microsoft Graph.]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 20</code> of #30DaysOfServerless!</p>
<p>Every day millions of people spend their precious time in productivity tools. What if you use data and intelligence behind the Microsoft applications (Microsoft Teams, Outlook, and many other Office apps) to build seamless automations and custom apps to boost productivity?</p>
<p>In this post, we'll learn how to build a seamless onboarding experience for new employees joining a company with the power of Microsoft Graph, integrated with Event Hubs and Logic Apps!</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/20-events-graph#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>✨ The power of Microsoft Graph</li>
<li>🖇️ How do Microsoft Graph and Event Hubs work together?</li>
<li>🛠 Let's Build an Onboarding Workflow!<!-- -->
<ul>
<li>1️⃣ Setup Azure Event Hubs + Key Vault</li>
<li>2️⃣ Subscribe to <code>users</code>, receive change notifications from Logic Apps</li>
<li>3️⃣ Create Onboarding workflow in the Logic Apps</li>
</ul>
</li>
<li>🚀 Debug: Your onboarding experience</li>
<li>✋ Exercise: Try this tutorial out yourself!</li>
<li>📚 Resources: For Self-Study</li>
</ul>
<p><img loading="lazy" alt="Slide featuring &amp;quot;Integrate Microsoft Graph: Automation With Logic Apps and Event Hubs&amp;quot; by Ayça Baş, contact @aycabs, part of Serverless September." src="https://azure.github.io/Cloud-Native/assets/images/banner-a18bdc5dea8b6ae90be31453092132fc.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>PRE-REQUISITES (Recommended)</div><div class="admonitionContent_BuS1"><ul>
<li><a href="https://aka.ms/m365developers" target="_blank" rel="noopener noreferrer">Microsoft 365 Developer Program account</a></li>
<li><a href="https://azure.microsoft.com/free/" target="_blank" rel="noopener noreferrer">Microsoft Azure Subscription</a></li>
</ul></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="-the-power-of-microsoft-graph">✨ The Power of Microsoft Graph<a href="https://azure.github.io/Cloud-Native/blog/20-events-graph#-the-power-of-microsoft-graph" class="hash-link" aria-label="Direct link to ✨ The Power of Microsoft Graph" title="Direct link to ✨ The Power of Microsoft Graph">​</a></h2>
<p>Microsoft Graph is the gateway to data and intelligence in Microsoft 365 platform. Microsoft Graph exploses Rest APIs and client libraries to access data across Microsoft 365 core services such as Calendar, Teams, To Do, Outlook, People, Planner, OneDrive, OneNote and more.</p>
<p><img loading="lazy" alt="Overview of Microsoft Graph" src="https://azure.github.io/Cloud-Native/assets/images/graph-0a406d21c2ade5253dea8ef245ba38b2.png" width="1280" height="720" class="img_ev3q"></p>
<p>You can build custom experiences by using Microsoft Graph such as automating the onboarding process for new employees. When new employees are created in the Azure Active Directory, they will be automatically added in the Onboarding team on Microsoft Teams.</p>
<p><img loading="lazy" alt="Solution architecture" src="https://azure.github.io/Cloud-Native/assets/images/architecture-328af443a035a73e3d6eab0d4edb782e.png" width="1280" height="720" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="️-microsoft-graph-with-event-hubs">🖇️ Microsoft Graph with Event Hubs<a href="https://azure.github.io/Cloud-Native/blog/20-events-graph#%EF%B8%8F-microsoft-graph-with-event-hubs" class="hash-link" aria-label="Direct link to 🖇️ Microsoft Graph with Event Hubs" title="Direct link to 🖇️ Microsoft Graph with Event Hubs">​</a></h2>
<p>Microsoft Graph uses a webhook mechanism to track changes in resources and deliver change notifications to the clients. For example, with Microsoft Graph Change Notifications, you can receive change notifications when:</p>
<ul>
<li>a new task is added in the to-do list</li>
<li>a user changes the presence status from busy to available</li>
<li>an event is deleted/cancelled from the calendar</li>
</ul>
<p>If you'd like to track a large set of resources at a high frequency, use Azure Events Hubs instead of traditional webhooks to receive change notifications. Azure Event Hubs is a popular real-time events ingestion and distribution service built for scale.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>EVENT GRID - PARTNER EVENTS</div><div class="admonitionContent_BuS1"><blockquote>
<p>Microsoft Graph Change Notifications can be also received by using <strong>Azure Event Grid</strong> -- currently available for Microsoft Partners! Read the <a href="https://docs.microsoft.com/azure/event-grid/partner-events-overview" target="_blank" rel="noopener noreferrer">Partner Events Overview</a> documentation for details.</p>
</blockquote></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="setup-azure-event-hubs--key-vault">Setup Azure Event Hubs + Key Vault.<a href="https://azure.github.io/Cloud-Native/blog/20-events-graph#setup-azure-event-hubs--key-vault" class="hash-link" aria-label="Direct link to Setup Azure Event Hubs + Key Vault." title="Direct link to Setup Azure Event Hubs + Key Vault.">​</a></h2>
<p>To get Microsoft Graph Change Notifications delivered to Azure Event Hubs, we'll have to setup Azure Event Hubs and Azure Key Vault. We'll use Azure Key Vault to access to Event Hubs connection string.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1️⃣-create-azure-event-hubs">1️⃣ Create Azure Event Hubs<a href="https://azure.github.io/Cloud-Native/blog/20-events-graph#1%EF%B8%8F%E2%83%A3-create-azure-event-hubs" class="hash-link" aria-label="Direct link to 1️⃣ Create Azure Event Hubs" title="Direct link to 1️⃣ Create Azure Event Hubs">​</a></h3>
<ol>
<li>Go to <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">Azure Portal</a> and select <strong>Create a resource</strong>, type <strong>Event Hubs</strong> and select click <strong>Create</strong>.</li>
<li>Fill in the Event Hubs namespace creation details, and then click <strong>Create</strong>.</li>
<li>Go to the newly created Event Hubs namespace page, select <strong>Event Hubs</strong> tab from the left pane and <strong>+ Event Hub</strong>:<!-- -->
<ul>
<li>Name your Event Hub as <em>Event Hub</em></li>
<li>Click <strong>Create</strong>.</li>
</ul>
</li>
<li>Click the name of the Event Hub, and then select <strong>Shared access policies</strong> and <strong>+ Add</strong> to add a new policy:<!-- -->
<ul>
<li>Give a name to the policy</li>
<li>Check <strong>Send</strong> and <strong>Listen</strong></li>
<li>Click <strong>Create</strong>.</li>
</ul>
</li>
<li>After the policy has been created, click the name of the policy to open the details panel, and then copy the <strong>Connection string-primary key</strong> value. Write it down; you'll need it for the next step.</li>
<li>Go to <strong>Consumer groups</strong> tab in the left pane and select <strong>+ Consumer group</strong>, give a name for your consumer group as <em>onboarding</em> and select <strong>Create</strong>.</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2️⃣-create-azure-key-vault">2️⃣ Create Azure Key Vault<a href="https://azure.github.io/Cloud-Native/blog/20-events-graph#2%EF%B8%8F%E2%83%A3-create-azure-key-vault" class="hash-link" aria-label="Direct link to 2️⃣ Create Azure Key Vault" title="Direct link to 2️⃣ Create Azure Key Vault">​</a></h3>
<ol>
<li>Go to <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">Azure Portal</a> and select <strong>Create a resource</strong>, type <strong>Key Vault</strong> and select <strong>Create</strong>.</li>
<li>Fill in the Key Vault creation details, and then click <strong>Review + Create</strong>.</li>
<li>Go to newly created Key Vault and select <strong>Secrets</strong> tab from the left pane and click <strong>+ Generate/Import</strong>:<!-- -->
<ul>
<li>Give a name to the secret</li>
<li>For the value, paste in the connection string you generated at the Event Hubs step</li>
<li>Click <strong>Create</strong></li>
<li>Copy the <strong>name of the secret</strong>.</li>
</ul>
</li>
<li>Select <strong>Access Policies</strong> from the left pane and <strong>+ Add Access Policy</strong>:<!-- -->
<ul>
<li>For <strong>Secret permissions</strong>, select <strong>Get</strong></li>
<li>For Principal, select <strong>Microsoft Graph Change Tracking</strong></li>
<li>Click <strong>Add</strong>.</li>
</ul>
</li>
<li>Select <strong>Overview</strong> tab from the left pane and copy the <strong>Vault URI</strong>.</li>
</ol>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="subscribe-for-logic-apps-change-notifications">Subscribe for Logic Apps change notifications<a href="https://azure.github.io/Cloud-Native/blog/20-events-graph#subscribe-for-logic-apps-change-notifications" class="hash-link" aria-label="Direct link to Subscribe for Logic Apps change notifications" title="Direct link to Subscribe for Logic Apps change notifications">​</a></h2>
<p>To start receiving Microsoft Graph Change Notifications, we'll need to create subscription to the resource that we'd like to track - here, 'users'. We'll use Azure Logic Apps to create subscription.</p>
<p>To create subscription for Microsoft Graph Change Notifications, we'll need to make a http post request to <code>https://graph.microsoft.com/v1.0/subscriptions</code>. Microsoft Graph requires Azure Active Directory authentication make API calls. First, we'll need to register an app to Azure Active Directory, and then we will make the Microsoft Graph Subscription API call with Azure Logic Apps.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1️⃣-create-an-app-in-azure-active-directory">1️⃣ Create an app in Azure Active Directory<a href="https://azure.github.io/Cloud-Native/blog/20-events-graph#1%EF%B8%8F%E2%83%A3-create-an-app-in-azure-active-directory" class="hash-link" aria-label="Direct link to 1️⃣ Create an app in Azure Active Directory" title="Direct link to 1️⃣ Create an app in Azure Active Directory">​</a></h3>
<ol>
<li>In the <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">Azure Portal</a>, go to <strong>Azure Active Directory</strong> and select <strong>App registrations</strong> from the left pane and select <strong>+ New registration</strong>. Fill in the details for the new App registration form as below:<!-- -->
<ul>
<li>Name: Graph Subscription Flow Auth</li>
<li>Supported account types: <em>Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)</em></li>
<li>Select <strong>Register</strong>.</li>
</ul>
</li>
<li>Go to newly registered app in Azure Active Directory, select <strong>API permissions</strong>:<!-- -->
<ul>
<li>Select <strong>+ Add a permission</strong> and <strong>Microsoft Graph</strong></li>
<li>Select <strong>Application permissions</strong> and add <code>User.Read.All</code> and <code>Directory.Read.All</code>.</li>
<li>Select <strong>Grant admin consent for <em>the organization</em></strong></li>
</ul>
</li>
<li>Select <strong>Certificates &amp; secrets</strong> tab from the left pane, select <strong>+ New client secret</strong>:<!-- -->
<ul>
<li>Choose desired expiry duration</li>
<li>Select <strong>Add</strong></li>
<li>Copy the <em>value of the secret</em>.</li>
</ul>
</li>
<li>Go to <strong>Overview</strong> from the left pane, copy <em>Application (client) ID</em> and <em>Directory (tenant) ID</em>.</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2️⃣-create-subscription-with-azure-logic-apps">2️⃣ Create subscription with Azure Logic Apps<a href="https://azure.github.io/Cloud-Native/blog/20-events-graph#2%EF%B8%8F%E2%83%A3-create-subscription-with-azure-logic-apps" class="hash-link" aria-label="Direct link to 2️⃣ Create subscription with Azure Logic Apps" title="Direct link to 2️⃣ Create subscription with Azure Logic Apps">​</a></h3>
<ol>
<li>
<p>Go to <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">Azure Portal</a> and select <strong>Create a resource</strong>, type <strong>Logic apps</strong> and select click <strong>Create</strong>.</p>
</li>
<li>
<p>Fill in the Logic Apps creation details, and then click <strong>Create</strong>.</p>
</li>
<li>
<p>Go to the newly created Logic Apps page, select <strong>Workflows</strong> tab from the left pane and select <strong>+ Add</strong>:</p>
<ul>
<li>Give a name to the new workflow as <em>graph-subscription-flow</em></li>
<li>Select <strong>Stateful</strong> as a state type</li>
<li>Click <strong>Create</strong>.</li>
</ul>
</li>
<li>
<p>Go to <em>graph-subscription-flow</em>, and then select <strong>Designer</strong> tab.</p>
</li>
<li>
<p>In the Choose an operation section, search for <strong>Schedule</strong> and select <strong>Recurrence</strong> as a trigger. Fill in the parameters as below:</p>
<ul>
<li>Interval: <code>61</code></li>
<li>Frequency: <code>Minute</code></li>
<li>Time zone: <em>Select your own time zone</em></li>
<li>Start time: <em>Set a start time</em></li>
</ul>
</li>
<li>
<p>Select <strong>+</strong> button in the flow and select <strong>add an action</strong>. Search for <strong>HTTP</strong> and select <strong>HTTP</strong> as an action. Fill in the parameters as below:</p>
<ul>
<li>Method: <code>POST</code></li>
<li>URI: <code>https://graph.microsoft.com/v1.0/subscriptions</code></li>
<li>Headers:<!-- -->
<ul>
<li>Key: <code>Content-type</code></li>
<li>Value: <code>application/json</code></li>
</ul>
</li>
<li>Body:</li>
</ul>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">"changeType": "created, updated",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">"clientState": "secretClientValue",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">"expirationDateTime": "@{addHours(utcNow(), 1)}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">"notificationUrl": "EventHub:https://&lt;YOUR-VAULT-URI&gt;/secrets/&lt;YOUR-KEY-VAULT-SECRET-NAME&gt;?tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">"resource": "users"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<blockquote>
<p>In <code>notificationUrl</code>, make sure to replace <code>&lt;YOUR-VAULT-URI&gt;</code> with the vault uri and <code>&lt;YOUR-KEY-VAULT-SECRET-NAME&gt;</code> with the secret name that you copied from the Key Vault.</p>
</blockquote>
<blockquote>
<p>In <code>resource</code>, define the resource type you'd like to track changes. For our example, we will track changes for <code>users</code> resource.</p>
</blockquote>
<ul>
<li>Authentication:<!-- -->
<ul>
<li>Authentication type: <code>Active Directory OAuth</code></li>
<li>Authority: <code>https://login.microsoft.com</code></li>
<li>Tenant: <em>Directory (tenant) ID</em> copied from AAD app</li>
<li>Audience: <code>https://graph.microsoft.com</code></li>
<li>Client ID: <em>Application (client) ID</em> copied from AAD app</li>
<li>Credential Type: <code>Secret</code></li>
<li>Secret: <em>value of the secret</em> copied from AAD app</li>
</ul>
</li>
</ul>
</li>
<li>
<p>Select <strong>Save</strong> and run your workflow from the <strong>Overview</strong> tab.</p>
</li>
</ol>
<blockquote>
<p><strong>Check your subscription in Graph Explorer:</strong> If you'd like to make sure that your subscription is created successfully by Logic Apps, you can go to <a href="https://aka.ms/ge" target="_blank" rel="noopener noreferrer">Graph Explorer</a>, login with your Microsoft 365 account and make <code>GET</code> request to <code>https://graph.microsoft.com/v1.0/subscriptions</code>. Your subscription should appear in the response after it's created successfully.</p>
</blockquote>
<p><img loading="lazy" alt="Subscription workflow success" src="https://azure.github.io/Cloud-Native/assets/images/subscription-succes-d4124fab8a924b63e56e2265803a93ca.png" width="2256" height="1202" class="img_ev3q"></p>
<p>After subscription is created successfully by Logic Apps, Azure Event Hubs will receive notifications whenever there is a new user created in Azure Active Directory.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="create-onboarding-workflow-in-logic-apps">Create Onboarding workflow in Logic Apps<a href="https://azure.github.io/Cloud-Native/blog/20-events-graph#create-onboarding-workflow-in-logic-apps" class="hash-link" aria-label="Direct link to Create Onboarding workflow in Logic Apps" title="Direct link to Create Onboarding workflow in Logic Apps">​</a></h2>
<p>We'll create a second workflow in the Logic Apps to receive change notifications from Event Hubs when there is a new user created in the Azure Active Directory and add new user in Onboarding team on Microsoft Teams.</p>
<ol>
<li>Go to the Logic Apps you created in the previous steps, select <strong>Workflows</strong> tab and create a new workflow by selecting <strong>+ Add</strong>:<!-- -->
<ul>
<li>Give a name to the new workflow as <em>teams-onboarding-flow</em></li>
<li>Select <strong>Stateful</strong> as a state type</li>
<li>Click <strong>Create</strong>.</li>
</ul>
</li>
<li>Go to <em>teams-onboarding-flow</em>, and then select <strong>Designer</strong> tab.</li>
<li>In the Choose an operation section, search for <strong>Event Hub</strong>, select <strong>When events are available in Event Hub</strong> as a trigger. Setup Event Hub connection as below:<!-- -->
<ul>
<li>Create Connection:<!-- -->
<ul>
<li>Connection name: <code>Connection</code></li>
<li>Authentication Type: <code>Connection String</code></li>
<li>Connection String: Go to <strong>Event Hubs &gt; Shared Access Policies &gt; RootManageSharedAccessKey</strong> and copy <em>Connection string–primary key</em></li>
<li>Select <strong>Create</strong>.</li>
</ul>
</li>
<li>Parameters:<!-- -->
<ul>
<li>Event Hub Name: <code>Event Hub</code></li>
<li>Consumer Group Name: <code>onboarding</code></li>
</ul>
</li>
</ul>
</li>
<li>Select <strong>+</strong> in the flow and <strong>add an action</strong>, search for <strong>Control</strong> and add <strong>For each</strong> as an action. Fill in For each action as below:<!-- -->
<ul>
<li>Select output from previous steps: <code>Events</code></li>
</ul>
</li>
<li>Inside For each, select <strong>+</strong> in the flow and <strong>add an action</strong>, search for <strong>Data operations</strong> and select <strong>Parse JSON</strong>. Fill in Parse JSON action as below:<!-- -->
<ul>
<li>Content: <code>Events Content</code></li>
<li>Schema: Copy the json content from <a target="_blank" href="https://azure.github.io/Cloud-Native/assets/files/schema-parse-b0acc741357540c9dfdb8fa9612a8bfb.json">schema-parse.json</a> and paste as a schema</li>
</ul>
</li>
<li>Select <strong>+</strong> in the flow and <strong>add an action</strong>, search for <strong>Control</strong> and add <strong>For each</strong> as an action. Fill in For each action as below:<!-- -->
<ul>
<li>Select output from previous steps: <code>value</code></li>
</ul>
</li>
<li>
<ol>
<li>Inside For each, select <strong>+</strong> in the flow and <strong>add an action</strong>, search for <strong>Microsoft Teams</strong> and select <strong>Add a member to a team</strong>. Login with your Microsoft 365 account to create a connection and fill in Add a member to a team action as below:</li>
</ol>
<ul>
<li>Team: <em>Create an Onboarding team on Microsoft Teams and select</em></li>
<li>A user AAD ID for the user to add to a team: <code>id</code></li>
</ul>
</li>
<li>Select <strong>Save</strong>.</li>
</ol>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="-debug-your-onboarding-experience">🚀 Debug your onboarding experience<a href="https://azure.github.io/Cloud-Native/blog/20-events-graph#-debug-your-onboarding-experience" class="hash-link" aria-label="Direct link to 🚀 Debug your onboarding experience" title="Direct link to 🚀 Debug your onboarding experience">​</a></h2>
<p>To debug our onboarding experience, we'll need to create a new user in Azure Active Directory and see if it's added in Microsoft Teams Onboarding team automatically.</p>
<ol>
<li>
<p>Go to <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">Azure Portal</a> and select Azure Active Directory from the left pane and go to <strong>Users</strong>. Select <strong>+ New user</strong> and <strong>Create new user</strong>. Fill in the details as below:</p>
<ul>
<li>User name: <code>JaneDoe</code></li>
<li>Name: <code>Jane Doe</code></li>
</ul>
<p><img loading="lazy" alt="new user in Azure Active Directory" src="https://azure.github.io/Cloud-Native/assets/images/new-user-3d42a176e307e5a85cbfd5aa89f7ddb5.png" width="1519" height="1467" class="img_ev3q"></p>
</li>
<li>
<p>When you added <code>Jane Doe</code> as a new user, it should trigger the <em>teams-onboarding-flow</em> to run.
<img loading="lazy" alt="teams onboarding flow success" src="https://azure.github.io/Cloud-Native/assets/images/teams-onboarding-success-22562106caa80996b5536846f00ee48e.png" width="2250" height="1186" class="img_ev3q"></p>
</li>
<li>
<p>Once the <em>teams-onboarding-flow</em> runs successfully, you should be able to see <code>Jane Doe</code> as a member of the Onboarding team on Microsoft Teams! 🥳
<img loading="lazy" alt="new member in Onboarding team on Microsoft Teams" src="https://azure.github.io/Cloud-Native/assets/images/new-member-onboarding-8130b3390a8e6a66074c9940f8e7c91c.png" width="1519" height="1468" class="img_ev3q"></p>
</li>
</ol>
<div class="theme-admonition theme-admonition-success admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Congratulations! 🎉</div><div class="admonitionContent_BuS1"><p>You just built an onboarding experience using Azure Logic Apps, Azure Event Hubs and Azure Key Vault.</p></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="-resources">📚 Resources<a href="https://azure.github.io/Cloud-Native/blog/20-events-graph#-resources" class="hash-link" aria-label="Direct link to 📚 Resources" title="Direct link to 📚 Resources">​</a></h2>
<ul>
<li><a href="https://aka.ms/learn-graph" target="_blank" rel="noopener noreferrer">Microsoft Graph Fundamentals</a></li>
<li><a href="https://docs.microsoft.com/graph/change-notifications-delivery" target="_blank" rel="noopener noreferrer">Get change notifications delivered in different ways</a></li>
<li><a href="https://docs.microsoft.com/azure/architecture/solution-ideas/articles/presence-microsoft-365-power-platform" target="_blank" rel="noopener noreferrer">Real-time presence with Microsoft 365, Azure, and Power Platform</a></li>
<li><a href="https://docs.microsoft.com/azure/event-grid/partner-events-overview" target="_blank" rel="noopener noreferrer">Partner Events overview for customers - Azure Event Grid</a></li>
</ul>]]></content:encoded>
            <category>serverless-september</category>
            <category>30-days-of-serverless</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
            <category>microservices</category>
            <category>microsoft-graph</category>
            <category>logic-apps</category>
            <category>microsoft-365</category>
            <category>event-hubs</category>
        </item>
        <item>
            <title><![CDATA[🚀 | Error Handling w/ Apache Kafka]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/zero2hero-func-05</link>
            <guid>https://azure.github.io/Cloud-Native/blog/zero2hero-func-05</guid>
            <pubDate>Mon, 19 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Recently we have launched the Apache Kafka extension for Azure functions in GA with some cool new features like deserialization of Avro Generic records and Kafka headers support. Let's learn more about it.]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 19</code> of #30DaysOfServerless!</p>
<p>Today, we have a special set of posts from our <a href="https://azure.github.io/Cloud-Native/serverless-september/ZeroToHero">Zero To Hero 🚀</a> initiative, featuring blog posts authored by our Product Engineering teams for #ServerlessSeptember. <em>Posts were originally published on the <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/error-handling-with-apache-kafka-extension-for-azure-functions/ba-p/3628936?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Apps on Azure</a> blog on Microsoft Tech Community.</em></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-05#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>Retry Policy Support - in Apache Kafka Extension</li>
<li>AutoOffsetReset property - in Apache Kafka Extension</li>
<li>Key support for Kafka messages - in Apache Kafka Extension</li>
<li>References: Apache Kafka Extension for Azure Functions</li>
</ul>
<p><img loading="lazy" alt="Error handling strategies in Azure Functions using Kafka Extension by Ramya Oruganti." src="https://azure.github.io/Cloud-Native/assets/images/ramya-functions-kafka-5a847320c1814350e946ac762907c8e3.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<p><em>Recently we launched the <a href="https://github.com/Azure/azure-functions-kafka-extension" target="_blank" rel="noopener noreferrer">Apache Kafka extension for Azure functions</a> in GA with some cool new features like deserialization of Avro Generic records and Kafka headers support. We received great responses - so we're back with more updates!</em></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="retry-policy-support">Retry Policy support<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-05#retry-policy-support" class="hash-link" aria-label="Direct link to Retry Policy support" title="Direct link to Retry Policy support">​</a></h2>
<p>Handling errors in Azure Functions is important to avoid data loss or miss events or monitor the health of an application. Apache Kafka Extension for Azure Functions supports retry policy which tells the runtime to rerun a failed execution until either successful completion occurs or the maximum number of retries is reached.</p>
<p>A retry policy is evaluated when a trigger function raises an uncaught exception. As a best practice, you should catch all exceptions in your code and rethrow any errors that you want to result in a retry.</p>
<p>There are two retry strategies supported by policy that you can configure :- fixed delay and exponential backoff</p>
<ol>
<li><strong>Fixed Delay</strong> -  A specified amount of time is allowed to elapse between each retry.</li>
<li><strong>Exponential Backoff</strong> - The first retry waits for the minimum delay. On subsequent retries, time is added exponentially to the initial duration for each retry, until the maximum delay is reached. Exponential back-off adds some small randomization to delays to stagger retries in high-throughput scenarios.</li>
</ol>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Please Note</div><div class="admonitionContent_BuS1"><p>Retry Policy for Kafka extension <strong>is NOT supported</strong> for C# (in proc and out proc) trigger and output binding. This is supported for languages like Java, Node (JS , TypeScript), PowerShell and Python trigger and output bindings.</p></div></div>
<p>Here is the sample code view of exponential backoff retry strategy</p>
<p><img loading="lazy" alt="Error Handling with Apache Kafka extension for Azure Functions" src="https://azure.github.io/Cloud-Native/assets/images/ramya-kafka-1-f619e8e934a373383a58a0b2c69dd146.png" width="400" height="239" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="autooffsetreset-property">AutoOffsetReset property<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-05#autooffsetreset-property" class="hash-link" aria-label="Direct link to AutoOffsetReset property" title="Direct link to AutoOffsetReset property">​</a></h2>
<p>AutoOffsetReset property enables customers to configure the behaviour in the absence of an initial offset. Imagine a scenario when there is a need to change consumer group name. The consumer connected using a new consumer group had to reprocess all events starting from the oldest (earliest) one,  as this was the default one and this setting wasn’t exposed as configurable option in the Apache Kafka extension for Azure Functions(previously). With the help of this kafka setting you can configure on how to start processing events for newly created consumer groups.</p>
<p>Due to lack of the ability to configure this setting, offset commit errors were causing topics to restart from earliest offset· Users were looking to be able to set  offset setting  to either latest or earliest  based on their requirements.</p>
<p>We are happy to share that we have enabled the AutoOffsetReset setting as a configurable one to either - Earliest(Default) and Latest. Setting the value to Earliest configures the consumption of the messages from the the earliest/smallest offset or beginning of the topic partition. Setting the property to Latest configures the consumption of the messages from the latest/largest offset or from the end of the topic partition. This is supported for all the Azure Functions supported languages (C# (in &amp; out), Java, Node (JS and TypeScript), PowerShell and python) and can be used for both triggers and output binding</p>
<p><img loading="lazy" alt="Error Handling with Apache Kafka extension for Azure Functions" src="https://azure.github.io/Cloud-Native/assets/images/ramya-kafka-2-55db6b33ea9564e6af55bd6dfca64f89.png" width="400" height="175" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="key-support-for-kafka-messages">Key support for Kafka messages<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-05#key-support-for-kafka-messages" class="hash-link" aria-label="Direct link to Key support for Kafka messages" title="Direct link to Key support for Kafka messages">​</a></h2>
<p>With keys the producer/output binding can be mapped to broker and partition to write based on the message. So alongside the message value, we can choose to send a message key and that key can be whatever you want it could be a string, it could be a number . In case  you don’t send the key, the key is set to null then the data will be sent in a <a href="https://www.geeksforgeeks.org/round-robin-scheduling-with-different-arrival-times/" target="_blank" rel="noopener noreferrer">Round Robin</a> fashion to make it very simple. <strong>But in case you send a key with your message</strong>, all the messages that share the same key will always go to the same partition and thus you can enable grouping of similar messages into partitions</p>
<p>Previously while consuming a Kafka event message using the Azure Function kafka extension, the event key was always none although the key was present in the event message.</p>
<p>Key support was implemented in the extension which enables customers to set/view key in the Kafka event messages coming in to the kafka trigger and set keys to the messages going in to kafka topics (with keys set) through output binding. Therefore key support was enabled in the extension to support both trigger and output binding for all Azure Functions supported languages ( (C# (in &amp; out), Java, Node (JS and TypeScript), PowerShell and python)</p>
<p>Here is the view of an output binding producer code where Kafka messages are being set with key</p>
<p><img loading="lazy" alt="Error Handling with Apache Kafka extension for Azure Functions" src="https://azure.github.io/Cloud-Native/assets/images/ramya-kafka-3-3e5a8fd156c09ad453e579efcbab521b.png" width="400" height="284" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion:<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-05#conclusion" class="hash-link" aria-label="Direct link to Conclusion:" title="Direct link to Conclusion:">​</a></h2>
<p>In this article you have learnt about the latest additions to the Apache Kafka extension for Azure Functions. Incase you have been waiting for these features to get released or need them you are all set and please go head and try them out!! They are available in the latest extension bundles</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Want to learn more?</div><div class="admonitionContent_BuS1"><p>Please refer to <a href="https://docs.microsoft.com/azure/azure-functions/functions-bindings-kafka?tabs=in-process%2Cportal&amp;pivots=programming-language-csharp" target="_blank" rel="noopener noreferrer">Apache Kafka bindings for Azure Functions</a> | Microsoft Docs for detail documentation, samples on the Azure function supported languages and more!</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="references">References<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-05#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References">​</a></h2>
<ul>
<li><a href="https://docs.microsoft.com/azure/azure-functions/functions-bindings-kafka?tabs=in-process%2Cportal&amp;pivots=programming-language-csharp" target="_blank" rel="noopener noreferrer">Apache Kafka bindings for Azure Functions | Microsoft Docs</a></li>
</ul>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>FEEDBACK WELCOME</div><div class="admonitionContent_BuS1"><ul>
<li>If you would like to provide feedback on Kafka trigger extension, please post them to our GitHub repository- Issues · <a href="https://github.com/Azure/azure-functions-kafka-extension/issues" target="_blank" rel="noopener noreferrer">Azure/azure-functions-kafka-extension (github.com)</a></li>
<li>This extension is being developed in the open-source community. Please contribute, try out and post any issues on the <a href="https://github.com/Azure/azure-functions-kafka-extension" target="_blank" rel="noopener noreferrer">Azure Functions Kafka extension GitHub repo</a></li>
</ul></div></div>
<p>Keep in touch with us on Twitter via <a href="https://twitter.com/AzureFunctions" target="_blank" rel="noopener noreferrer">@AzureFunctions</a>.</p>]]></content:encoded>
            <category>serverless-september</category>
            <category>zero-to-hero</category>
            <category>azure-functions</category>
        </item>
        <item>
            <title><![CDATA[🚀 | Observability with ACA]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/zero2hero-aca-06</link>
            <guid>https://azure.github.io/Cloud-Native/blog/zero2hero-aca-06</guid>
            <pubDate>Mon, 19 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Azure Container Apps provides several observability features to help you debug and diagnose your apps. There are both Azure portal and CLI options you can use to help understand the health of your apps and help identify when issues arise. Let's explore the options.]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 19</code> of #30DaysOfServerless!</p>
<p>Today, we have a special set of posts from our <a href="https://azure.github.io/Cloud-Native/serverless-september/ZeroToHero">Zero To Hero 🚀</a> initiative, featuring blog posts authored by our Product Engineering teams for #ServerlessSeptember. <em>Posts were originally published on the <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/observability-with-azure-container-apps/ba-p/3627909?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Apps on Azure</a> blog on Microsoft Tech Community.</em></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-06#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>Log Streaming - in Azure Portal</li>
<li>Console Connect - in Azure Portal</li>
<li>Metrics - using Azure Monitor</li>
<li>Log Analytics - using Azure Monitor</li>
<li>Metric Alerts and Log Alerts - using Azure Monitor</li>
</ul>
<p><img loading="lazy" alt="Learn how to monitor and manage Azure Container Apps effectively with Mike Morton’s observability tips." src="https://azure.github.io/Cloud-Native/assets/images/mike-aca-observability-fdc8af07553b1411298f719b22ceca15.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<p>In past weeks, <a href="https://techcommunity.microsoft.com/t5/user/viewprofilepage/user-id/296868" target="_blank" rel="noopener noreferrer">@kendallroden</a> wrote about <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/go-cloud-native-with-azure-container-apps/ba-p/3616407" target="_blank" rel="noopener noreferrer">what it means to be Cloud-Native</a> and <a href="https://techcommunity.microsoft.com/t5/user/viewprofilepage/user-id/236816" target="_blank" rel="noopener noreferrer">@Anthony Chu</a> the various ways to <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/journey-to-the-cloud-with-azure-container-apps/ba-p/3622609" target="_blank" rel="noopener noreferrer">get your apps running on Azure Container Apps</a>. Today, we will talk about the <strong>observability tools</strong> you can use to observe, debug, and diagnose your Azure Container Apps.</p>
<p><strong>Azure Container Apps</strong> provides several observability features to help you debug and diagnose your apps. There are both Azure portal and CLI options you can use to help understand the health of your apps and help identify when issues arise.</p>
<p>While these features are helpful throughout your container app’s lifetime, there are two that are especially helpful.  Log streaming and console connect can be a huge help in the initial stages when issues often rear their ugly head. Let's dig into both of these a little.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="log-streaming">Log Streaming<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-06#log-streaming" class="hash-link" aria-label="Direct link to Log Streaming" title="Direct link to Log Streaming">​</a></h2>
<p>Log streaming allows you to use the Azure portal to view the streaming logs from your app. You’ll see the logs written from the app to the container’s console (stderr and stdout). If your app is running multiple revisions, you can choose from which revision to view logs. You can also select a specific replica if your app is configured to scale. Lastly, you can choose from which container to view the log output. This is useful when you are running a custom or Dapr sidecar container.
<img loading="lazy" alt="view streaming logs" src="https://azure.github.io/Cloud-Native/assets/images/mike-observability-1-f28ac55d716d668659b11621cee6119c.png" width="549" height="334" class="img_ev3q"></p>
<p>Here’s an example CLI command to view the logs of a container app.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp logs show -n MyContainerapp -g MyResourceGroup</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You can find more information about the different options in our <a href="https://aka.ms/container-apps/logs-cli" target="_blank" rel="noopener noreferrer">CLI docs</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="console-connect">Console Connect<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-06#console-connect" class="hash-link" aria-label="Direct link to Console Connect" title="Direct link to Console Connect">​</a></h2>
<p>In the Azure portal, you can connect to the console of a container in your app. Like log streaming, you can select the revision, replica, and container if applicable. After connecting to the console of the container, you can execute shell commands and utilities that you have installed in your container.  You can view files and their contents, monitor processes, and perform other debugging tasks.</p>
<p>This can be great for checking configuration files or even modifying a setting or library your container is using. Of course, updating a container in this fashion is not something you should do to a production app, but tweaking and re-testing an app in a non-production environment can speed up development.</p>
<p><img loading="lazy" alt="Azure portal view of an active container instance revision displaying console logs and files." src="https://azure.github.io/Cloud-Native/assets/images/mike-observability-2-2e21617739406a5d9b090b9580b95dd3.png" width="550" height="336" class="img_ev3q"></p>
<p>Here’s an example CLI command to connect to the console of a container app.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp exec -n MyContainerapp -g MyResourceGroup</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You can find more information about the different options in our <a href="https://aka.ms/container-apps/exec-cli" target="_blank" rel="noopener noreferrer">CLI docs</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="metrics">Metrics<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-06#metrics" class="hash-link" aria-label="Direct link to Metrics" title="Direct link to Metrics">​</a></h2>
<p>Azure Monitor collects metric data from your container app at regular intervals to help you gain insights into the performance and health of your container app. Container apps provide these metrics:</p>
<ul>
<li>CPU usage</li>
<li>Memory working set bytes</li>
<li>Network in bytes</li>
<li>Network out bytes</li>
<li>Requests</li>
<li>Replica count</li>
<li>Replica restart count</li>
</ul>
<p>Here you can see the metrics explorer showing the replica count for an app as it scaled from one replica to fifteen, and then back down to one.</p>
<p><img loading="lazy" alt="Azure Monitor chart showing replica count spike for &amp;#39;album-api&amp;#39; over the past 30 minutes." src="https://azure.github.io/Cloud-Native/assets/images/mike-observability-3-fcd3dd1c9bc4cc4ab8df18c1321502a8.png" width="550" height="319" class="img_ev3q"></p>
<p>You can also retrieve metric data through <a href="https://aka.ms/container-apps/azure-monitor-metrics-cli" target="_blank" rel="noopener noreferrer">the Azure CLI</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="log-analytics">Log Analytics<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-06#log-analytics" class="hash-link" aria-label="Direct link to Log Analytics" title="Direct link to Log Analytics">​</a></h2>
<p>Azure Monitor Log Analytics is great for viewing your historical logs emitted from your container apps. There are two custom tables of interest, the ContainerAppConsoleLogs_CL which contains all the log messages written by your app (stdout and stderr), and the ContainerAppSystemLogs_CL which contain the system messages from the Azure Container Apps service.</p>
<p><img loading="lazy" alt="Azure Log Analytics query output for &amp;#39;album-api&amp;#39; revision with shutdown messages listed." src="https://azure.github.io/Cloud-Native/assets/images/mike-observability-4-d284a4303e3c243917edb8eb2685f1ac.png" width="550" height="345" class="img_ev3q"></p>
<p>You can also query Log Analytics through the <a href="https://aka.ms/container-apps/azure-monitor-logs-cli" target="_blank" rel="noopener noreferrer">Azure CLI</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="alerts">Alerts<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-06#alerts" class="hash-link" aria-label="Direct link to Alerts" title="Direct link to Alerts">​</a></h2>
<p>Azure Monitor alerts notify you so that you can respond quickly to critical issues. There are two types of alerts that you can define:</p>
<ul>
<li><a href="https://docs.microsoft.com/azure/azure-monitor/alerts/alerts-types#metric-alerts" target="_blank" rel="noopener noreferrer">Metric alerts</a> based on Azure Monitor metric data</li>
<li><a href="https://docs.microsoft.com/azure/azure-monitor/alerts/alerts-types#log-alerts" target="_blank" rel="noopener noreferrer">Log alerts</a> based on Azure Monitor Log Analytics data</li>
</ul>
<p>You can create alert rules from metric charts in the metric explorer and from queries in Log Analytics. You can also define and manage alerts from the <strong>Monitor|Alerts</strong> page.</p>
<p>Here is what creating an alert looks like in the Azure portal. In this case we are setting an alert rule from the metric explorer to trigger an alert if the replica restart count for a specific container app is greater than two within the last fifteen minutes.</p>
<p><img loading="lazy" alt="Setting up an alert rule in Azure for container replica restart thresholds." src="https://azure.github.io/Cloud-Native/assets/images/mike-observability-5-b64a5cdcac00d2090c8efdd42861e339.png" width="550" height="302" class="img_ev3q"></p>
<p>To learn more about alerts, refer to <a href="https://docs.microsoft.com/azure/azure-monitor/alerts/alerts-overview" target="_blank" rel="noopener noreferrer">Overview of alerts in Microsoft Azure</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-06#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>In this article, we looked at the several ways to observe, debug, and diagnose your Azure Container Apps. As you can see there are rich portal tools and a complete set of CLI commands to use. All the tools are helpful throughout the lifecycle of your app, be sure to take advantage of them when having an issue and/or to prevent issues.</p>
<p>To learn more, visit <a href="https://aka.ms/containerapps" target="_blank" rel="noopener noreferrer">Azure Container Apps | Microsoft Azure</a> today!</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>ASK THE EXPERT: LIVE Q&amp;A</div><div class="admonitionContent_BuS1"><p>The Azure Container Apps team will answer questions live on <strong>September 29</strong>.</p><ul>
<li><a href="https://reactor.microsoft.com/reactor/events/17004/?WT.mc_id=javascript-99907-ninarasi" target="_blank" rel="noopener noreferrer">Sign up to attend</a> for live Q&amp;A with the team</li>
<li><a href="https://github.com/Azure/Cloud-Native/issues/new?assignees=&amp;labels=ask+the+expert&amp;template=---ask-the-expert-.md&amp;title=%5BAsk+The+Expert%5D++" target="_blank" rel="noopener noreferrer">submit your questions</a> ahead of time, for prioritization.</li>
</ul></div></div>]]></content:encoded>
            <category>serverless-september</category>
            <category>zero-to-hero</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
        </item>
        <item>
            <title><![CDATA[18. Logic Apps + Computer Vision]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/18-cloudmail</link>
            <guid>https://azure.github.io/Cloud-Native/blog/18-cloudmail</guid>
            <pubDate>Sun, 18 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[<FIXME>]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 18</code> of #30DaysOfServerless!</p>
<p>Yesterday my Serverless September post introduced you to making Azure Logic Apps and Azure Cosmos DB work together with a sample application that collects weather data.  Today I'm sharing a more robust solution that actually reads my mail.  Let's learn about <strong>Teaching the cloud to read your mail!</strong></p>
<p>Ready? Let's go!</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/18-cloudmail#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>Introduction to the ReadMail solution</li>
<li>Setting up Azure storage, Cosmos DB and Computer Vision</li>
<li>Connecting it all together with a Logic App</li>
<li>Resources: For self-study!</li>
</ul>
<p><img loading="lazy" alt="Slide promoting &amp;quot;Integrate Computer Vision: Teach the Cloud to Read &amp;amp; Categorize Your Mail&amp;quot; by Brian Benz, with contact handle @bbenz." src="https://azure.github.io/Cloud-Native/assets/images/banner-e7cc7a75c1dd0c42170942a9186aeee3.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="introducing-the-readmail-solution">Introducing the ReadMail solution<a href="https://azure.github.io/Cloud-Native/blog/18-cloudmail#introducing-the-readmail-solution" class="hash-link" aria-label="Direct link to Introducing the ReadMail solution" title="Direct link to Introducing the ReadMail solution">​</a></h2>
<p>The US Postal system offers <a href="https://informeddelivery.usps.com/" target="_blank" rel="noopener noreferrer">a subscription service</a> that sends you images of mail it will be delivering to your home.  I decided it would be cool to try getting Azure to collect data based on these images, so that I could categorize my mail and track the types of mail that I received.</p>
<p>To do this, I used Azure storage, Cosmos DB, Logic Apps, and computer vision.  When a new email comes in from the US Postal service (USPS), it triggers a logic app that:</p>
<ul>
<li>Posts attachments to Azure storage</li>
<li>Triggers Azure Computer vision to perform an OCR function on attachments</li>
<li>Extracts any results into a JSON document</li>
<li>Writes the JSON document to Cosmos DB</li>
</ul>
<p><img loading="lazy" alt="workflow for the readmail solution" src="https://azure.github.io/Cloud-Native/assets/images/readmailworkflow-e456d7ecabffc87c26955a45333118e5.png" width="2573" height="744" class="img_ev3q"></p>
<p>In this post I'll walk you through setting up the solution for yourself.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Prerequisites</div><div class="admonitionContent_BuS1"><ul>
<li>Contributor or Owner permissions on an active Azure subscription.<!-- -->
<ul>
<li>Don't have one? <a href="https://azure.microsoft.com/free/" target="_blank" rel="noopener noreferrer">Create an account for free</a>.</li>
</ul>
</li>
<li>A <a href="https://informeddelivery.usps.com/" target="_blank" rel="noopener noreferrer">USPS Informed Delivery account</a>.<!-- -->
<ul>
<li>Alternatively, any service that sends attached images via email</li>
</ul>
</li>
</ul></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="setup-azure-services">Setup Azure Services<a href="https://azure.github.io/Cloud-Native/blog/18-cloudmail#setup-azure-services" class="hash-link" aria-label="Direct link to Setup Azure Services" title="Direct link to Setup Azure Services">​</a></h2>
<p>First, we'll create all of the target environments we need to be used by our Logic App, then we;ll create the Logic App.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-azure-storage">1. Azure Storage<a href="https://azure.github.io/Cloud-Native/blog/18-cloudmail#1-azure-storage" class="hash-link" aria-label="Direct link to 1. Azure Storage" title="Direct link to 1. Azure Storage">​</a></h3>
<p>We'll be using Azure storage to collect attached images from emails as they arrive.  Adding images to Azure storage will also trigger a workflow that performs OCR on new attached images and stores the OCR data in Cosmos DB.</p>
<p>To create a new Azure storage account from the <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">portal dashboard</a>, Select <strong>Create a resource &gt; Storage account &gt; Create</strong>.</p>
<p>The <strong>Basics</strong> tab covers all of the features and information that we will need for this solution:</p>
<table><thead><tr><th>Section</th><th>Field</th><th>Required or optional</th><th>Description</th></tr></thead><tbody><tr><td>Project details</td><td>Subscription</td><td>Required</td><td>Select the subscription for the new storage account.</td></tr><tr><td>Project details</td><td>Resource group</td><td>Required</td><td>Create a new resource group that you will use for storage, Cosmos DB, Computer Vision and the Logic App.</td></tr><tr><td>Instance details</td><td>Storage account name</td><td>Required</td><td>Choose a unique name for your storage account. Storage account names must be between 3 and 24 characters in length and may contain numbers and lowercase letters only.</td></tr><tr><td>Instance details</td><td>Region</td><td>Required</td><td>Select the appropriate region for your storage account.</td></tr><tr><td>Instance details</td><td>Performance</td><td>Required</td><td>Select <strong>Standard</strong> performance for general-purpose v2 storage accounts (default).</td></tr><tr><td>Instance details</td><td>Redundancy</td><td>Required</td><td>Select <strong>locally-redundant Storage (LRS)</strong> for this example.</td></tr></tbody></table>
<p>Select <strong>Review + create</strong> to accept the remaining default options, then validate and create the account.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-azure-cosmosdb">2. Azure CosmosDB<a href="https://azure.github.io/Cloud-Native/blog/18-cloudmail#2-azure-cosmosdb" class="hash-link" aria-label="Direct link to 2. Azure CosmosDB" title="Direct link to 2. Azure CosmosDB">​</a></h3>
<p>CosmosDB will be used to store the JSON documents returned by the COmputer Vision OCR process.</p>
<blockquote>
<p>See more details and screen shots for setting up CosmosDB in yesterday's Serverless September post - <strong>Using Logic Apps with Cosmos DB</strong></p>
</blockquote>
<p>To get started with Cosmos DB, you create an account, then a database, then a container to store JSON documents. To create a new Cosmos DB account from the <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">portal dashboard</a>, Select <strong>Create a resource &gt; Azure Cosmos DB &gt; Create</strong>.  Choose <strong>core SQL</strong> for the API.</p>
<p>Select your subscription, then for simplicity use the same resource group you created when you set up storage.  Enter an account name and choose a location, select provisioned throughput capacity mode and apply the free tier discount. From here you can select <strong>Review and Create</strong>, then <strong>Create</strong></p>
<p>Next, create a new database and container. Go to the <strong>Data Explorer</strong> in your new Cosmos DB account, and choose <strong>New Container</strong>.  Name the database, and keep all the other defaults except:</p>
<table><thead><tr><th>Setting</th><th>Action</th></tr></thead><tbody><tr><td>Container ID</td><td>id</td></tr><tr><td>Container partition</td><td>/id</td></tr></tbody></table>
<p>Press <strong>OK</strong> to create a database and container</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-azure-computer-vision">3. Azure Computer Vision<a href="https://azure.github.io/Cloud-Native/blog/18-cloudmail#3-azure-computer-vision" class="hash-link" aria-label="Direct link to 3. Azure Computer Vision" title="Direct link to 3. Azure Computer Vision">​</a></h3>
<p>Azure Cognitive Services' <a href="https://azure.microsoft.com/products/cognitive-services/computer-vision/" target="_blank" rel="noopener noreferrer">Computer Vision</a> will perform an OCR process on each image attachment that is stored in Azure storage.</p>
<p>From the <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">portal dashboard</a>, Select <strong>Create a resource &gt; AI + Machine Learning &gt; Computer Vision &gt; Create</strong>.</p>
<p>The <strong>Basics</strong> and <strong>Identity</strong> tabs cover all of the features and information that we will need for this solution:</p>
<p><strong>Basics Tab</strong></p>
<table><thead><tr><th>Section</th><th>Field</th><th>Required or optional</th><th>Description</th></tr></thead><tbody><tr><td>Project details</td><td>Subscription</td><td>Required</td><td>Select the subscription for the new service.</td></tr><tr><td>Project details</td><td>Resource group</td><td>Required</td><td>Use the same resource group that you used for Azure storage and Cosmos DB.</td></tr><tr><td>Instance details</td><td>Region</td><td>Required</td><td>Select the appropriate region for your Computer Vision service.</td></tr><tr><td>Instance details</td><td>Name</td><td>Required</td><td>Choose a unique name for your Computer Vision service.</td></tr><tr><td>Instance details</td><td>Pricing</td><td>Required</td><td>Select the free tier for this example.</td></tr></tbody></table>
<p><strong>Identity Tab</strong></p>
<table><thead><tr><th>Section</th><th>Field</th><th>Required or optional</th><th>Description</th></tr></thead><tbody><tr><td>System assigned managed identity</td><td>Status</td><td>Required</td><td>Enable system assigned identity to grant the resource access to other existing resources.</td></tr></tbody></table>
<p>Select <strong>Review + create</strong> to accept the remaining default options, then validate and create the account.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="connect-it-all-with-a-logic-app">Connect it all with a Logic App<a href="https://azure.github.io/Cloud-Native/blog/18-cloudmail#connect-it-all-with-a-logic-app" class="hash-link" aria-label="Direct link to Connect it all with a Logic App" title="Direct link to Connect it all with a Logic App">​</a></h2>
<p>Now we're ready to put this all together in a Logic App workflow!</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>1. Create Logic App</div></div>
<p>From the <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">portal dashboard</a>, Select <strong>Create a resource &gt; Integration &gt; Logic App &gt; Create</strong>.  Name your Logic App and select a location, the rest of the settings can be left at their defaults.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>2. Create Workflow: Add Trigger</div></div>
<p>Once the Logic App is created, select <strong>Create a workflow from designer</strong>.</p>
<blockquote>
<p>A workflow is a series of steps that defines a task or process. Each workflow starts with a single trigger, after which you must add one or more actions.</p>
</blockquote>
<p>When in designer, search for <strong>outlook.com</strong> on the right under <strong>Add a trigger</strong>.  Choose <strong>outlook.com</strong>.  Choose
<strong>When a new email arrives</strong> as the trigger.</p>
<blockquote>
<p>A trigger is always the first step in any workflow and specifies the condition for running any further steps in that workflow.</p>
</blockquote>
<p>Set the following values:</p>
<table><thead><tr><th>Parameter</th><th>Value</th></tr></thead><tbody><tr><td>Folder</td><td>Inbox</td></tr><tr><td>Importance</td><td>Any</td></tr><tr><td>Only With Attachments</td><td>Yes</td></tr><tr><td>Include Attachments</td><td>Yes</td></tr></tbody></table>
<p>Then add a new parameter:</p>
<table><thead><tr><th>Parameter</th><th>Value</th></tr></thead><tbody><tr><td>From</td><td>Add the email address that sends you the email with attachments</td></tr></tbody></table>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>3. Create Workflow: Add Action (for Trigger)</div></div>
<p>Choose <strong>add an action</strong> and choose <strong>control &gt; for-each</strong>.</p>
<p><img loading="lazy" alt="logic app for each" src="https://azure.github.io/Cloud-Native/assets/images/logicappforeach-3b1e9d6ff4b39773b7d6b66aaf1a3445.png" width="1088" height="861" class="img_ev3q"></p>
<p>Inside the for-each action, in <strong>Select an output from previous steps</strong>, choose <strong>attachments</strong>.  Then, again inside the  for-each action, add the <strong>create blob</strong> action:</p>
<p>Set the following values:</p>
<table><thead><tr><th>Parameter</th><th>Value</th></tr></thead><tbody><tr><td>Folder Path</td><td>/mailreaderinbox</td></tr><tr><td>Blob Name</td><td>Attachments Name</td></tr><tr><td>Blob Content</td><td>Attachments Content</td></tr></tbody></table>
<p>This extracts attachments from the email and created a new blob for each attachment.</p>
<p>Next, inside the same for-each action, add the <strong>get blob content</strong> action.</p>
<p>Set the following values:</p>
<table><thead><tr><th>Parameter</th><th>Value</th></tr></thead><tbody><tr><td>Blob</td><td>id</td></tr><tr><td>Infer content type</td><td>Yes</td></tr></tbody></table>
<blockquote>
<p>We create and read from a blob for each attachment because Computer Vision needs a non-virtual source to read from when performing an OCR process. Because we enabled system assigned identity to grant Computer Vision to other existing resources, it can access the blob but not the outlook.com attachment.  Also, we pass the ID of the blob to use as a unique ID when writing to Cosmos DB.</p>
</blockquote>
<p><img loading="lazy" alt="create blob from attachments" src="https://azure.github.io/Cloud-Native/assets/images/createblobfromattachments-973aec90c10abe51b785a2353f4e1992.png" width="1225" height="1529" class="img_ev3q"></p>
<p>Next, inside the same for-each action, choose <strong>add an action</strong> and choose <strong>control &gt; condition</strong>. Set the value to <strong>Media Type &gt; is equal to &gt; image/JPEG</strong></p>
<blockquote>
<p>The USPS sends attachments of multiple types, but we only want to scan attachments that have images of our mail, which are always JPEG images. If the condition is true, we will process the image with Computer Vision OCR and write the results to a JSON document in CosmosDB.</p>
</blockquote>
<p>In the <strong>True</strong> section of the condition, add an action and choose <strong>Computer Vision API &gt; Optical Character Recognition (OCR) to JSON</strong>.</p>
<p>Set the following values:</p>
<table><thead><tr><th>Parameter</th><th>Value</th></tr></thead><tbody><tr><td>Image Source</td><td>Image Content</td></tr><tr><td>Image content</td><td>File Content</td></tr></tbody></table>
<p>In the same <strong>True</strong> section of the condition, choose <strong>add an action</strong> and choose Cosmos DB.  Choose <strong>Create or Update Document</strong> from the actions.  Select <strong>Access Key</strong>, and provide the primary read-write key (found under keys in Cosmos DB), and the Cosmos DB account ID (without 'documents.azure.com').</p>
<p>Next, fill in your Cosmos DB Database ID and Collection ID.  Create a JSON document by selecting dynamic content elements and wrapping JSON formatting around them.</p>
<blockquote>
<p>Be sure to use the ID passed from blob storage as your unique ID for CosmosDB.  That way you can troubleshoot and JSON or OCR issues by tracing back the JSON document in Cosmos Db to the blob in Azure storage.  Also, include the Computer Vision JSON response, as it contains the results of the Computer Vision OCR scan.  all other elements are optional.</p>
</blockquote>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>4. TEST WORKFLOW</div></div>
<p>When complete, you should have an action the Logic App designer that looks something like this:</p>
<p><img loading="lazy" alt="Logic App workflow create or update document in cosmosdb" src="https://azure.github.io/Cloud-Native/assets/images/cosmoscreateorupdatedocument-359018e398dfed9dd6f41991a6b600f2.png" width="2042" height="1401" class="img_ev3q"></p>
<p>Save the workflow and test the connections by clicking <strong>Run Trigger &gt; Run</strong>.  If connections are working, you should see documents flowing into Cosmos DB each time that an email arrives with image attachments.</p>
<p>Check the data in Cosmos Db by opening the Data explorer, then choosing the container you created and selecting <strong>items</strong>.  You should see documents similar to this:</p>
<p><img loading="lazy" alt="Logic App workflow with trigger and action" src="https://azure.github.io/Cloud-Native/assets/images/readmailfinalresults-cf50ccd6301f2feebab1e9e7df3d4d70.png" width="2357" height="1325" class="img_ev3q"></p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>1. Congratulations</div><div class="admonitionContent_BuS1"><p>You just built your personal ReadMail solution with Logic Apps! 🎉</p></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources-for-self-study">Resources: For self-study!<a href="https://azure.github.io/Cloud-Native/blog/18-cloudmail#resources-for-self-study" class="hash-link" aria-label="Direct link to Resources: For self-study!" title="Direct link to Resources: For self-study!">​</a></h2>
<p>Once you have an understanding of the basics in ths post, there is so much more to learn!</p>
<ul>
<li>Check out the other <a href="https://azure.github.io/Cloud-Native/blog" target="_blank" rel="noopener noreferrer">Serverless September posts</a>.</li>
<li>For more detail about Cosmos DB, see the docs at <a href="https://learn.microsoft.com/azure/cosmos-db/" target="_blank" rel="noopener noreferrer">https://learn.microsoft.com/azure/cosmos-db/</a></li>
<li>For more info on Logic Apps, see the docs at <a href="https://learn.microsoft.com/azure/logic-apps/" target="_blank" rel="noopener noreferrer">https://learn.microsoft.com/azure/logic-apps/</a></li>
<li>For details on Azure Cognitive Services and Computer Vision, see <a href="https://azure.microsoft.com/products/cognitive-services/computer-vision/" target="_blank" rel="noopener noreferrer">https://azure.microsoft.com/products/cognitive-services/computer-vision/</a>.</li>
</ul>
<p>Thanks for stopping by!</p>]]></content:encoded>
            <category>serverless-september</category>
            <category>30-days-of-serverless</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
            <category>microservices</category>
        </item>
        <item>
            <title><![CDATA[17. Logic Apps + Cosmos DB]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/17-integrate-cosmosdb</link>
            <guid>https://azure.github.io/Cloud-Native/blog/17-integrate-cosmosdb</guid>
            <pubDate>Sat, 17 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[<FIXME>]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 17</code> of #30DaysOfServerless!</p>
<p>In past weeks, we've covered serverless technologies that provide core capabilities (functions, containers, microservices) for building serverless solutions. This week we're looking at technologies that make <strong>service integrations</strong> more seamless, starting with <strong>Logic Apps</strong>. Let's look at one usage example today!</p>
<p>Ready? Let's Go!</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/17-integrate-cosmosdb#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>Introduction to Logic Apps</li>
<li>Settng up Cosmos DB for Logic Apps</li>
<li>Setting up a Logic App connection and event</li>
<li>Writing data to Cosmos DB from a Logic app</li>
<li>Resources: For self-study!</li>
</ul>
<p><img loading="lazy" alt="Serverless September session on using CosmosDB and Logic Apps for tracking weather data changes, hosted by Brian Benz." src="https://azure.github.io/Cloud-Native/assets/images/banner-285b55411e45272a99069fd37ec84557.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="introduction-to-logic-apps">Introduction to Logic Apps<a href="https://azure.github.io/Cloud-Native/blog/17-integrate-cosmosdb#introduction-to-logic-apps" class="hash-link" aria-label="Direct link to Introduction to Logic Apps" title="Direct link to Introduction to Logic Apps">​</a></h2>
<p>Previously in Serverless September, we've covered Azure Functions, where the event triggers code. In Logic Apps, the event triggers a workflow that you design. Logic Apps enable serverless applications to connect to external sources for data then automate business processes via workflows.</p>
<p>In this post I'll walk you through setting up a Logic App that works with Cosmos DB.  For this example, we'll connect to the MSN weather service, an design a logic app workflow that collects data when weather changes, and writes the data to Cosmos DB.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>PREREQUISITES</div><div class="admonitionContent_BuS1"><ul>
<li>An active Azure subscription (with Contributor or Owner permissions).</li>
<li>Don't have one? <a href="https://azure.microsoft.com/free/" target="_blank" rel="noopener noreferrer">Create an account for free</a>.</li>
</ul></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="setup-cosmos-db-for-logic-apps">Setup Cosmos DB for Logic Apps<a href="https://azure.github.io/Cloud-Native/blog/17-integrate-cosmosdb#setup-cosmos-db-for-logic-apps" class="hash-link" aria-label="Direct link to Setup Cosmos DB for Logic Apps" title="Direct link to Setup Cosmos DB for Logic Apps">​</a></h2>
<p>Cosmos DB has <a href="https://learn.microsoft.com/azure/cosmos-db/choose-api" target="_blank" rel="noopener noreferrer">many APIs to choose from</a>, but to use the <a href="https://docs.microsoft.com/connectors/documentdb/" target="_blank" rel="noopener noreferrer">default Logic App connection</a>, we need to choose the a Cosmos DB SQL API.  We'll set this up via the Azure Portal.</p>
<p>To get started with Cosmos DB, you create an account, then a database, then a container to store JSON documents. To create a new Cosmos DB account from the <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">portal dashboard</a>, Select <strong>Create a resource &gt; Azure Cosmos DB &gt; Create</strong>.  Choose <strong>core SQL</strong> for the API.</p>
<p><img loading="lazy" alt="Azure Cosmos DB API selection screen showing Core SQL, MongoDB, Cassandra, Azure Table, and Gremlin options with &amp;quot;Create&amp;quot; buttons." src="https://azure.github.io/Cloud-Native/assets/images/cosmosdbapiselection-573c0193332958da1c5090a29c6a7941.png" width="2976" height="1478" class="img_ev3q"></p>
<p>Select your subscription, then create a new resource group called <strong>CosmosWeather</strong>.  Enter an account name and choose a location, select provisioned throughput capacity mode and apply the free tier discount. From here you can select <strong>Review and Create</strong>, then <strong>Create</strong></p>
<blockquote>
<p>Azure Cosmos DB is available in two different capacity modes: provisioned throughput and <a href="https://docs.microsoft.com/azure/cosmos-db/throughput-serverless" target="_blank" rel="noopener noreferrer">serverless</a>. You can perform the same database operations in both modes, but the way you get billed for these operations is different. We wil be using provisioned throughput and the free tier for this example.</p>
</blockquote>
<p><img loading="lazy" alt="Setup the CosmosDB account" src="https://azure.github.io/Cloud-Native/assets/images/cosmosdbaccount-6ea06e0494167d6441438aca97437d71.png" width="2455" height="1705" class="img_ev3q"></p>
<p>Next, create a new database and container. Go to the <strong>Data Explorer</strong> in your new Cosmos DB account, and choose <strong>New Container</strong>.  Name the database, and keep all the orher defaults except:</p>
<table><thead><tr><th>Setting</th><th>Action</th></tr></thead><tbody><tr><td>Container ID</td><td>id</td></tr><tr><td>Container partition</td><td>/id</td></tr></tbody></table>
<p>Press <strong>OK</strong> to create a database and container</p>
<blockquote>
<p>A database is analogous to a traditional DBMS namespace. It's used to organize one or more containers.</p>
</blockquote>
<p><img loading="lazy" alt="Setup the CosmosDB Container" src="https://azure.github.io/Cloud-Native/assets/images/cosmosdbcontainer-c65af0651e4633b0a779c276b6eb3ae8.png" width="2424" height="1767" class="img_ev3q"></p>
<p>Now we're ready to set up our logic app an write to Cosmos DB!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="setup-logic-app-connection--event">Setup Logic App connection + event<a href="https://azure.github.io/Cloud-Native/blog/17-integrate-cosmosdb#setup-logic-app-connection--event" class="hash-link" aria-label="Direct link to Setup Logic App connection + event" title="Direct link to Setup Logic App connection + event">​</a></h2>
<p>Once the Cosmos DB SQL API account is created, we can set up our Logic App.  From the <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">portal dashboard</a>, Select <strong>Create a resource &gt; Integration &gt; Logic App &gt; Create</strong>.  Name your Logic App and select a location, the rest fo the settings can be left at their defaults.  Once you new Logic App is created, select <strong>Create a workflow from designer</strong> to get started.</p>
<blockquote>
<p>A workflow is a series of steps that defines a task or process. Each workflow starts with a single trigger, after which you must add one or more actions.</p>
</blockquote>
<p>When in designer, search for <strong>weather</strong> on the right under <strong>Add a trigger</strong>.  Choose <strong>MSN Weather</strong>.  Choose
<strong>When the current conditions change</strong> as the trigger.</p>
<blockquote>
<p>A trigger is always the first step in any workflow and specifies the condition for running any further steps in that workflow.</p>
</blockquote>
<p>Add a location.  Valid locations are City, Region, State, Country, Landmark, Postal Code, latitude and longitude.  This triggers a new workflow when the conditions change for a location.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="write-data-from-logic-app-to-cosmos-db">Write data from Logic App to Cosmos DB<a href="https://azure.github.io/Cloud-Native/blog/17-integrate-cosmosdb#write-data-from-logic-app-to-cosmos-db" class="hash-link" aria-label="Direct link to Write data from Logic App to Cosmos DB" title="Direct link to Write data from Logic App to Cosmos DB">​</a></h2>
<p>Now we are ready to set up the action to write data to Cosmos DB.  Choose <strong>add an action</strong> and choose Cosmos DB.</p>
<blockquote>
<p>An action is each step in a workflow after the trigger. Every action runs some operation in a workflow.</p>
</blockquote>
<p>In this case, we will be writing a JSON document to the Cosmos DB container we created earlier.  Choose <strong>Create or Update Document</strong> from the actions.  At this point you should have a workflow in designer that looks something like this:</p>
<p><img loading="lazy" alt="Logic App workflow with trigger" src="https://azure.github.io/Cloud-Native/assets/images/logicappworkflow1-f6bd9943b7239df52a2f6143b5cc5d46.png" width="1145" height="856" class="img_ev3q"></p>
<p>Start wth the connection for set up the Cosmos DB action.  Select <strong>Access Key</strong>, and provide the primary read-write key (found under keys in Cosmos DB), and the Cosmos DB account ID (without 'documents.azure.com').</p>
<p>Next, fill in your Cosmos DB Database ID and Collection ID.  Create a JSON document bt selecting dynamic content elements and wrapping JSON formatting around them.</p>
<p>You will need a unique ID for each document that you write to Cosmos DB, for that you can use an expression.  Because we declared <strong>id</strong> to be our unique ID in Cosmos DB, we will use use that for the name.  Under expressions, type <code>guid()</code> and press enter to add a unique ID to the JSON document.  When complete, you should have a workflow in designer that looks something like this:</p>
<p><img loading="lazy" alt="Logic App workflow with trigger and action" src="https://azure.github.io/Cloud-Native/assets/images/logicappworkflow2-f2d7cbaa73c21f5f7552db112dd7bb33.png" width="1906" height="1530" class="img_ev3q"></p>
<p>Save the workflow and test the connections by clicking <strong>Run Trigger &gt; Run</strong>.  If connections are working, you should see documents flowing into Cosmos DB over the next few minutes.</p>
<p>Check the data in Cosmos Db by opening the Data explorer, then choosing the container you created and selecting <strong>items</strong>.  You should see documents similar to this:</p>
<p><img loading="lazy" alt="Logic App workflow with trigger and action" src="https://azure.github.io/Cloud-Native/assets/images/cosmosdresults-cd7ecf449f4cf9aa49ec2d3343a774ac.png" width="2712" height="1761" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources-for-self-study">Resources: For self-study!<a href="https://azure.github.io/Cloud-Native/blog/17-integrate-cosmosdb#resources-for-self-study" class="hash-link" aria-label="Direct link to Resources: For self-study!" title="Direct link to Resources: For self-study!">​</a></h2>
<p>Once you've grasped the basics in ths post, there is so much more to learn!</p>
<ul>
<li>Check out the other <a href="https://azure.github.io/Cloud-Native/blog" target="_blank" rel="noopener noreferrer">Serverless September posts</a>.</li>
<li>For more detail about Cosmos DB, see the docs at <a href="https://learn.microsoft.com/azure/cosmos-db/" target="_blank" rel="noopener noreferrer">https://learn.microsoft.com/azure/cosmos-db/</a></li>
<li>For more info on Logic Apps, see the docs at <a href="https://learn.microsoft.com/azure/logic-apps/" target="_blank" rel="noopener noreferrer">https://learn.microsoft.com/azure/logic-apps/</a></li>
</ul>
<p>Thanks for stopping by!</p>]]></content:encoded>
            <category>serverless-september</category>
            <category>30-days-of-serverless</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
            <category>microservices</category>
        </item>
        <item>
            <title><![CDATA[15. ACA + Serverless On Azure]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/15-microservices-azure</link>
            <guid>https://azure.github.io/Cloud-Native/blog/15-microservices-azure</guid>
            <pubDate>Thu, 15 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Recap of Week 2: Microservices, Azure Container Apps and Dapr]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 15</code> of #30DaysOfServerless!</p>
<p>This post marks the midpoint of our Serverless on Azure journey! Our <a href="https://azure.github.io/Cloud-Native/serverless-september/30DaysOfServerless/" target="_blank" rel="noopener noreferrer">Week 2 Roadmap</a> showcased two key technologies - <a href="https://learn.microsoft.com/azure/container-apps/" target="_blank" rel="noopener noreferrer">Azure Container Apps (ACA)</a> and <a href="https://dapr.io/" target="_blank" rel="noopener noreferrer">Dapr</a> - for building serverless microservices. We'll also look at what happened elsewhere in #ServerlessSeptember, then set the stage for our next week's focus: Serverless Integrations.</p>
<p>Ready? Let's Go!</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/15-microservices-azure#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li><strong>ICYMI</strong>: This Week on #ServerlessSeptember</li>
<li><strong>Recap</strong>: Microservices, Azure Container Apps &amp; Dapr</li>
<li><strong>Coming Next:</strong> Serverless Integrations</li>
<li><strong>Exercise</strong>: <a href="https://docs.microsoft.com/learn/challenges?id=b950cd7a-d456-46ab-81ba-3bd1ad86dc1c&amp;WT.mc_id=javascript-99907-ninarasi" target="_blank" rel="noopener noreferrer">Take the Cloud Skills Challenge</a></li>
<li><strong>Resources</strong>: For self-study!</li>
</ul>
<p><img loading="lazy" alt="Day 15 recap of ACA and Dapr featuring E2E solutions and next steps by Nitya Narasimhan and Devanshi Joshi, highlighting integrations." src="https://azure.github.io/Cloud-Native/assets/images/banner-639be8df2be1df5b73125c263e8a21e1.png" width="1600" height="672" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="this-week-in-events">This Week In Events<a href="https://azure.github.io/Cloud-Native/blog/15-microservices-azure#this-week-in-events" class="hash-link" aria-label="Direct link to This Week In Events" title="Direct link to This Week In Events">​</a></h2>
<p>We had a number of activities happen this week - here's a quick summary:</p>
<ul>
<li>On <strong>Zero To Hero:</strong> <br>Anthony Chu took us on a <a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-04">Journey to the Cloud with Azure Container Apps</a> exploring tools to simplify develop-deploy workflows for ACA. And Melony Qin talked about <a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-03">Using Custom Handlers For Go</a>, explaining how this allows extended languages support in Azure Functions.</li>
<li>On <strong>Serverless Hacks:</strong>  <br>Gwyn was joined by Liam Hampton as they talked about <a href="https://www.youtube.com/watch?v=EcsAcm22GqI" target="_blank" rel="noopener noreferrer">How to DevOps and Serverless The Right Way</a>. And it's not too late to complete the hack and <a href="https://azure.github.io/Cloud-Native/serverless-september/ServerlessHacks/" target="_blank" rel="noopener noreferrer">submit your solution to our hall of fame</a>.</li>
<li>On <strong>Ask The Expert:</strong> <br>We had our first Live Q&amp;A Session featuring members of the Azure Functions team, hosted by Gwyn. Catch up on the <a href="https://www.youtube.com/watch?v=wB5Va1a-MeY" target="_blank" rel="noopener noreferrer">recording</a> for useful tips and guidance.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="this-week-in-30days">This Week in #30Days<a href="https://azure.github.io/Cloud-Native/blog/15-microservices-azure#this-week-in-30days" class="hash-link" aria-label="Direct link to This Week in #30Days" title="Direct link to This Week in #30Days">​</a></h2>
<p>In our #30Days series we focused on Azure Container Apps and Dapr.</p>
<ul>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/09-aca-fundamentals" target="_blank" rel="noopener noreferrer">Hello Container Apps</a> we learned how Azure Container Apps helps you run microservices and containerized apps on serverless platforms. And we build and deployed our first ACA.</li>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/microservices-10" target="_blank" rel="noopener noreferrer">Microservices Communication</a> we explored concepts like <em>environments</em> and <em>virtual networking</em>, with a hands-on example to show how two microservices communicate in a deployed ACA.</li>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps" target="_blank" rel="noopener noreferrer">Scaling Your Container Apps</a> we learned about KEDA (Kubernetes Event-Driven Autoscaler) and how to configure autoscaling for your ACA based on KEDA-supported triggers.</li>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/12-build-with-dapr" target="_blank" rel="noopener noreferrer">Build with Dapr</a> we introduced the Distributed Application Runtime (Dapr) and learned how its Building Block APIs and sidecar architecture make it easier to develop microservices with ACA.</li>
<li>In <a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id" target="_blank" rel="noopener noreferrer">Secure ACA Access</a> we learned how to secure ACA access to external services with - and without - Dapr, covering Secret Stores and Managed Identity.</li>
<li>Finally, <a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart" target="_blank" rel="noopener noreferrer">Build ACA with Dapr</a> tied it all together with a enterprise app scenario where an orders processor (ACA) uses Dapr APIs (PubSub, State Management) to receive and store order messages from Azure Service Bus.</li>
</ul>
<p>Here's a visual recap:</p>
<p><img loading="lazy" alt="Summary of microservices and container apps with Azure Container Apps, Dapr integration, scaling, and secure access concepts." src="https://azure.github.io/Cloud-Native/assets/images/roadmap-Week2-cdacf0e02c8a938d944f3c4d9a29721a.png" width="3840" height="2160" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="self-study-code-samples--tutorials">Self Study: Code Samples &amp; Tutorials<a href="https://azure.github.io/Cloud-Native/blog/15-microservices-azure#self-study-code-samples--tutorials" class="hash-link" aria-label="Direct link to Self Study: Code Samples &amp; Tutorials" title="Direct link to Self Study: Code Samples &amp; Tutorials">​</a></h2>
<p>There's no better way to get familiar with the concepts, than to dive in and play with code samples and hands-on tutorials. Here are 4 resources to bookmark and try out:</p>
<ol>
<li><a href="https://docs.dapr.io/getting-started/quickstarts/" target="_blank" rel="noopener noreferrer">Dapr Quickstarts</a> - these walk you through samples showcasing individual Building Block APIs - with multiple language options available.</li>
<li><a href="https://docs.dapr.io/getting-started/tutorials/" target="_blank" rel="noopener noreferrer">Dapr Tutorials</a> provides more complex examples of microservices applications and tools usage, including a <a href="https://github.com/dapr/quickstarts/tree/master/tutorials/distributed-calculator" target="_blank" rel="noopener noreferrer">Distributed Calculator</a> polyglot app.</li>
<li>Next, try to <a href="https://learn.microsoft.com/azure/container-apps/microservices-dapr?tabs=bash" target="_blank" rel="noopener noreferrer">Deploy a Dapr application to Azure Container Apps</a> to get familiar with the process of setting up the environment, then deploying the app.</li>
<li>Or, explore the many <a href="https://learn.microsoft.com/azure/container-apps/samples?source=recommendations" target="_blank" rel="noopener noreferrer">Azure Container Apps samples</a> showcasing various features and more complex architectures tied to real world scenarios.</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="whats-next-serverless-integrations">What's Next: Serverless Integrations!<a href="https://azure.github.io/Cloud-Native/blog/15-microservices-azure#whats-next-serverless-integrations" class="hash-link" aria-label="Direct link to What's Next: Serverless Integrations!" title="Direct link to What's Next: Serverless Integrations!">​</a></h2>
<p>So far we've talked about core technologies (Azure Functions, Azure Container Apps, Dapr) that provide foundational support for your serverless solution. Next, we'll look at <strong>Serverless Integrations</strong> - specifically at technologies like Azure Logic Apps and Azure Event Grid that <em>automate workflows</em> and create seamless end-to-end solutions that integrate <em>other</em> Azure services in serverless-friendly ways.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="take-the-challenge">Take the Challenge!<a href="https://azure.github.io/Cloud-Native/blog/15-microservices-azure#take-the-challenge" class="hash-link" aria-label="Direct link to Take the Challenge!" title="Direct link to Take the Challenge!">​</a></h2>
<p>The <a href="https://docs.microsoft.com/learn/challenges?id=b950cd7a-d456-46ab-81ba-3bd1ad86dc1c&amp;WT.mc_id=javascript-99907-ninarasi" target="_blank" rel="noopener noreferrer"><strong>Cloud Skills Challenge</strong></a> is still going on, and we've already had hundreds of participants join and complete the learning modules to skill up on Serverless.</p>
<p>There's still time to join and get yourself on the leaderboard. Get familiar with Azure Functions, SignalR, Logic Apps, Azure SQL and more - in serverless contexts!!</p>
<hr>]]></content:encoded>
            <category>serverless-september</category>
            <category>30-days-of-serverless</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
        </item>
        <item>
            <title><![CDATA[14. Build ACA with Dapr]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart</link>
            <guid>https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart</guid>
            <pubDate>Wed, 14 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Let's build our first Azure Container Apps solution with Dapr!]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 14</code> of #30DaysOfServerless!</p>
<p>In the past few days we focused our attention on Azure Container Apps, building microservices-based solutions and learning related concepts like environments, networking and auto-scaling - before introducing the sidecar capability of Dapr. Today, we look at how Dapr and ACA work seamlessly together to simplify microservices development in the cloud.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>Dapr refresher</li>
<li>Application scenario we are covering today</li>
<li>Quickstart: Build your first ACA with Dapr</li>
<li>Exercise: Try this yourself!</li>
<li>What's Next: Advanced scenario in 12-part series</li>
<li>Resources: For self-study!</li>
</ul>
<p><img loading="lazy" alt="Day 14 Serverless September graphic featuring &amp;quot;Build With Dapr&amp;quot; topic by Taiseer Joudeh, focusing on Dapr and Azure Container Apps." src="https://azure.github.io/Cloud-Native/assets/images/banner-7d7a40cad48fa26cd9b62cdf2a073fe5.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="introduction-to-dapr">Introduction To Dapr<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#introduction-to-dapr" class="hash-link" aria-label="Direct link to Introduction To Dapr" title="Direct link to Introduction To Dapr">​</a></h2>
<p>As developers, we are often tasked with create scalable resilient and distributed microservices, but face challenges such as recovering state after failures, establishing reliable communication between services, integrating with external resources and instrumenting distributed tracing for end-to-end solution observability. Dapr (Distributed Application Runtime) offers an approach for solving these common problems more easily.</p>
<p>Dapr provides its core capabilities as a set of <a href="https://docs.dapr.io/concepts/building-blocks-concept/" target="_blank" rel="noopener noreferrer">Building Blocks</a> as detailed in the introduction to dapr article released as a part of this series. Building Blocks provide consistent APIs that abstract away the implementation details to keep microservices code simple and portable.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="todays-app-scenario">Today's App Scenario<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#todays-app-scenario" class="hash-link" aria-label="Direct link to Today's App Scenario" title="Direct link to Today's App Scenario">​</a></h2>
<p>In this blog post we will create an Azure Container App which will act as an internal-only, background processor service. This service will not be accessible from the internet or from other services directly. We will also configure two Dapr building blocks (APIs): Pub/Sub and State Management. Let's take a look at the architecture diagram below to have better understanding of what we are building:</p>
<p><img loading="lazy" alt="Diagram showing architecture of sample project" src="https://azure.github.io/Cloud-Native/assets/images/ACA-Tutorial-AsyncComm-0922-909e943512d388e21a69516efb153bdf.jpg" width="1222" height="735" class="img_ev3q"></p>
<p>Our service, <code>orders-processor</code>, will be processing messages published to an Azure Service Bus Topic named <code>orderreceivedtopic</code>. The Dapr Pub/Sub building block will be configured by providing a configuration file named <code>pubsub-svcbus.yaml</code> which contains all the needed information to establish the connection between the container app and the service bus topic. Once a message is consumed by the <code>orders-processor</code> service, it will store a copy of it in Azure Cosmos DB. To wire up Cosmos DB, we will use the Dapr State Store building block and a <code>statestore-cosmosdb.yaml</code> component.</p>
<p>Because we are leveraging Dapr, we will not introduce any SDK for Azure Service Bus nor Azure Cosmos DB; everything will be configured using the component files, so let's jump into the code! :)</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Looking for Advanced scenarios?</div><div class="admonitionContent_BuS1"><p>This scenario is a simplified version of a detailed tutorial which covers more advanced scenarios, if you are interested you can check more <a href="https://bitoftech.net/2022/08/25/tutorial-building-microservice-applications-azure-container-apps-dapr/" target="_blank" rel="noopener noreferrer">Advanced scenarios on my blog.</a></p></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="build-aca-with-dapr">Build ACA with Dapr<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#build-aca-with-dapr" class="hash-link" aria-label="Direct link to Build ACA with Dapr" title="Direct link to Build ACA with Dapr">​</a></h2>
<p>In today's post, we'll be using VS Code to build the app using ASP.NET Core 6.0. In the process, we'll setup our development environment with the relevant command-line tools and VS Code extensions. In addition, we will use the Azure CLI to create the Azure resources which will be used in this solution.</p>
<p><em>Note: Completing this exercise may incur a a cost of a few USD based on your Azure subscription.</em></p>
<p>First, make sure you have your development environment setup and configured.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>PRE-REQUISITES</div><div class="admonitionContent_BuS1"><ol>
<li><strong>An Azure account with an active subscription</strong> - <a href="https://azure.microsoft.com/free/?ref=microsoft.com&amp;utm_source=microsoft.com&amp;utm_medium=docs&amp;utm_campaign=visualstudio" target="_blank" rel="noopener noreferrer">Create an account for free</a></li>
<li><strong>dotnet 6.0</strong> - <a href="https://dotnet.microsoft.com/download/dotnet/6.0" target="_blank" rel="noopener noreferrer">Install</a></li>
<li><strong>Docker Desktop</strong> - <a href="https://docs.docker.com/desktop/install/windows-install/" target="_blank" rel="noopener noreferrer">Install</a></li>
<li><strong>Visual Studio Code</strong> - <a href="https://code.visualstudio.com/" target="_blank" rel="noopener noreferrer">Install</a></li>
<li><strong>VS Code Docker extension</strong> - <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker" target="_blank" rel="noopener noreferrer">Install</a></li>
<li><strong>Dapr CLI. Details on installation on this post too</strong> - <a href="https://docs.dapr.io/getting-started/install-dapr-cli/" target="_blank" rel="noopener noreferrer">Install</a></li>
<li><strong>VS Code Dapr extension. Depends on Dapr CLI</strong> - <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-dapr" target="_blank" rel="noopener noreferrer">Install</a></li>
<li><strong>Azure CLI</strong> - <a href="https://docs.microsoft.com/cli/azure/install-azure-cli" target="_blank" rel="noopener noreferrer">Install</a></li>
</ol></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="create-the-service-project-web-api">Create the service project (Web API)<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#create-the-service-project-web-api" class="hash-link" aria-label="Direct link to Create the service project (Web API)" title="Direct link to Create the service project (Web API)">​</a></h3>
<ol>
<li>
<p>Open a command-line terminal and create a folder for your project. Use the <code>code</code> command to launch Visual Studio Code from that directory as shown:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">mkdir orders-service</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">cd orders-service</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">code .</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>From VS Code Terminal tab, open developer command prompt or PowerShell terminal in the project folder <code>orders-service</code> and initialize the project by typing: <code>dotnet new webapi -o Orders.Processor  --no-https</code> This will create and ASP.NET Web API project scaffolded with 1 single controller.</p>
</li>
<li>
<p>We need to containerize this application so we can push it to Azure Container Registry as a docker image and deploy it to Azure Container Apps. To do so, Open the VS Code Command Palette (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>p</kbd>) and select <code>Docker: Add Docker Files to Workspace...</code></p>
<ul>
<li>Use <code>.NET: ASP.NET Core</code> when prompted for application platform.</li>
<li>Choose <code>Linux</code> when prompted to choose the operating system.</li>
<li>You will be asked if you want to add Docker Compose files. Select <code>No</code>.</li>
<li>Take a not of the provided <strong>application port</strong> as we will be using later on.</li>
<li><code>Dockerfile</code> and <code>.dockerignore</code> files are added to the workspace.</li>
</ul>
</li>
<li>
<p>Now we will add the DTO which will be used to deserialize the consumed message from Azure Service Bus Topic, so add a new file named <code>OrderModel.cs</code> under a new folder named <code>Models</code> and use the code below</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">public class OrderModel</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public Guid OrderId { get; set; } = Guid.NewGuid();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public string Reference { get; set; } = string.Empty;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public int Quantity { get; set; }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public DateTime CreatedOn { get; set; }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>Install Dapr Client NuGet package, we will use this package to subscribe to the Azure Service Bus Topic in a programmatic way. From the developer command prompt or PowerShell terminal type <code>dotnet add package Dapr.AspNetCore</code></p>
</li>
<li>
<p>Create an API endpoint for the consumer/service to subscribe to the topic, this endpoint will start receiving the messages published to the topic <code>orderreceivedtopic</code>. Add a new controller named <code>ExternalOrdersController.cs</code> under the <code>Controllers</code> folder and use the code below:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[ApiController]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[Route("api/externalorders")]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">public class ExternalOrdersController : ControllerBase</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    private readonly ILogger&lt;ExternalOrdersController&gt; _logger;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    private readonly DaprClient _daprClient;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public ExternalOrdersController(ILogger&lt;ExternalOrdersController&gt; logger, DaprClient daprClient)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        _logger = logger;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        _daprClient = daprClient;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [Topic("pubsub-servicebus", "orderreceivedtopic")]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    [HttpPost("orderreceived")]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public async Task&lt;IActionResult&gt; OrderReceived([FromBody] OrderModel orderModel)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        _logger.LogInformation("Received new order at: '{0}' Order Id: '{1}' Order reference: '{2}', Order quantity: '{3}'",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                DateTime.UtcNow, orderModel.OrderId, orderModel.Reference, orderModel.Quantity);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        //Do your business logic with order received</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        orderModel.CreatedOn = DateTime.UtcNow;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ////ToDo: Your exercise :) Save the received message into CosmoDb using the SveStateAsync</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        //await _daprClient.SaveStateAsync&lt;OrderModel&gt;("statestore-cosmosdb", orderModel.OrderId.ToString(), orderModel);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        //Return 200 ok to acknowledge order is processed successfully          </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        return Ok($"Order Processing completed successfully");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        //Retunr 400 bad request to retry re-processing based on service broker configuration</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        //return BadRequest($"Failed to process order due to: failure reason");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
</ol>
<p>In summary, the above steps result in:</p>
<ul>
<li>
<p>An action method called <code>orderreceived</code> which can be reached on the route <code>api/externalorders/orderreceived</code> and receives an <code>OrderModel</code> object.</p>
</li>
<li>
<p>An attribute <code>Topic</code> on the action method including the name of the pub/sub component and the topic to subscribe to.</p>
</li>
<li>
<p>Business logic for processing the message which will result in an appropriate response which dictates if the message was process successfully, should be retried or should be dead-lettered.</p>
</li>
</ul>
<ol start="7">
<li>Register the Dapr client and Subscribe handler at service startup. Open the file <code>Program.cs</code> and replace with the content below:<!-- -->
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">    var builder = WebApplication.CreateBuilder(args);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    // Add services to the container.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    builder.Services.AddControllers().AddDapr();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    builder.Services.AddEndpointsApiExplorer();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    builder.Services.AddSwaggerGen();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    var app = builder.Build();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    // Configure the HTTP request pipeline.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    if (app.Environment.IsDevelopment())</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    app.UseSwagger();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    app.UseSwaggerUI();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    app.UseAuthorization();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    app.UseCloudEvents();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    app.MapControllers();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    app.MapSubscribeHandler();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    app.Run();</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<!-- -->:::note Want to know more?
Check this <a href="https://bitoftech.net/2022/09/02/azure-container-apps-async-communication-with-dapr-pub-sub-api-part-6/" target="_blank" rel="noopener noreferrer">blog post</a> which describes in detail how the consumer was able to discover available topic names, Pub/Sub names, and which routes/endpoints to push messages to.
:::</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="provision-azure-service-bus-topic-and-subscription">Provision Azure Service Bus, Topic and Subscription<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#provision-azure-service-bus-topic-and-subscription" class="hash-link" aria-label="Direct link to Provision Azure Service Bus, Topic and Subscription" title="Direct link to Provision Azure Service Bus, Topic and Subscription">​</a></h3>
<p>We need to create the Azure Service Bus so we can configure the Dapr Pub/Sub component and test locally</p>
<ol>
<li>
<p>Open your Powershell console and login to Azure by using the command <code>az login</code>. If you have multiple subscriptions, set the subscription you want to use in this tutorial before proceeding, you can do this by using <code>az account set --subscription &lt;name or id&gt;</code>. Calling <code>az upgrade</code> is a good practice to ensure you are running the latest Aure CLI version.</p>
</li>
<li>
<p>Create an Azure Resource Group by using the code below, feel free to change the name and location of the resource group</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$RESOURCE_GROUP="orders-services-rg"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$LOCATION="eastus"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">az group create `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --name $RESOURCE_GROUP `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --location "$LOCATION"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>Create the necessary Azure Service Bus resource and retrieve the primary connection string (for local dev testing).</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$NamespaceName="ordersservices"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$TopicName="orderreceivedtopic"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$TopicSubscription="orders-processor-subscription"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">##Create servicebus namespace</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">az servicebus namespace create --resource-group $RESOURCE_GROUP --name $NamespaceName --location $LOCATION</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">##Create a topic under namespace</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">az servicebus topic create --resource-group $RESOURCE_GROUP --namespace-name $NamespaceName --name $TopicName</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">##Create a topic subscription</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">az servicebus topic subscription create `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --resource-group $RESOURCE_GROUP `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --namespace-name $NamespaceName `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --topic-name $TopicName `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --name $TopicSubscription</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">##List connection string</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">az servicebus namespace authorization-rule keys list --resource-group $RESOURCE_GROUP --namespace-name $NamespaceName --name RootManageSharedAccessKey --query primaryConnectionString --output tsv</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
</ol>
<p>You can navigate to the Azure Portal and check that the resource group is created and the service bus namespace is created too.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="setup-dapr-for-local-dev">Setup Dapr for local dev<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#setup-dapr-for-local-dev" class="hash-link" aria-label="Direct link to Setup Dapr for local dev" title="Direct link to Setup Dapr for local dev">​</a></h3>
<p>In order to run Dapr locally on our development machine, we need to install Dapr CLI, you can follow the <a href="https://docs.dapr.io/getting-started/install-dapr-cli/" target="_blank" rel="noopener noreferrer">official documentation</a> or use the steps below.</p>
<ol>
<li>
<p>Install the Dapr CLI, run PowerShell console as an administrator and run the below command:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"> powershell -Command "iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1 | iex"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Note: You might need to execute the following  PowerShell command <code>Set-ExecutionPolicy RemoteSigned -scope CurrentUser</code> before installing the Dapr CLI, this command is to allow local PowerShell scripts to run regardless of signature, and requires trusted digital signatures only for remote scripts.</p>
</li>
<li>
<p>Initialize Dapr in your local development environment. By initializing Dapr, we will fetch and install the Dapr sidecar binaries locally, and we will create a development environment that streamlines application development with Dapr. To do so open the PowerShell console as an administrator and run the below command:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">dapr init</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>To verify the deployment; check Dapr version by running the following command: <code>dapr --version</code></p>
<p>:::note Want to know more?
Check this <a href="https://bitoftech.net/2022/08/29/dapr-integration-with-azure-container-apps/" target="_blank" rel="noopener noreferrer">blog post</a> which describes in detail what components added to your machine when we called <code>dapr init</code>
:::</p>
</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="create-a-local-dapr-component-file-for-pubsub">Create a local Dapr Component file for Pub/Sub<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#create-a-local-dapr-component-file-for-pubsub" class="hash-link" aria-label="Direct link to Create a local Dapr Component file for Pub/Sub" title="Direct link to Create a local Dapr Component file for Pub/Sub">​</a></h3>
<p>Dapr uses a modular design where functionality is delivered as a component. Each component has an interface definition. All of the components are pluggable so that you can swap out one component with the same interface for another.</p>
<p>Components are configured at design-time with a YAML file which is stored in either a components/local folder within your solution, or globally in the .dapr folder created when invoking dapr init <a href="https://bitoftech.net/2022/08/29/dapr-integration-with-azure-container-apps/" target="_blank" rel="noopener noreferrer">(read here for more details)</a>. These YAML files adhere to the generic <a href="https://docs.dapr.io/operations/components/component-schema/" target="_blank" rel="noopener noreferrer">Dapr component schema</a>, but each is specific to the component specification.</p>
<ol>
<li>
<p>Create 2 new folders under the project root directory <code>orders-service</code>, one called <code>dapr-component</code> and the second one <code>component</code> (will be used in next steps). Add a new yaml file called <code>pubsub-svcbus.yaml</code> under folder <code>dapr-component</code> using the content below:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">apiVersion</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> dapr.io/v1alpha1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">kind</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Component</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">metadata</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> pubsub</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">servicebus</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">spec</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> pubsub.azure.servicebus</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">version</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">metadata</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> connectionString </span><span class="token comment" style="color:#999988;font-style:italic"># Used for local dev testing.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;connection string from step 2.3&gt;"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> consumerID</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"orders-processor-subscription"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">scopes</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> orders</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">processor</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Note that we used the name <code>pubsub-servicebus</code> which should match the name of Pub/Sub component we've used earlier in the <code>ExternalOrdersController.cs</code> controller on the action method with the attribute <code>Topic</code>. As well we have set the metadata (key/value) to allow us to connect to Azure Service Bus topic. The metdata <code>consumerID</code> value should match the topic subscription name <code>orders-processor-subscription</code>. We have set the scopes section to include the <code>orders-processor</code> app id, as this will be the specific application that needs access to Azure Service Bus.</p>
<p>You need to replace the <code>connectionString</code> value with your Service Bus connection string. This is only needed for your local testing on your development machine, we'll be using a different approach (<strong>Managed Identities</strong>) when deploying Dapr component to Azure Container Apps Environment. For full metadata specs, you can <a href="https://docs.dapr.io/reference/components-reference/supported-pubsub/setup-azure-servicebus/" target="_blank" rel="noopener noreferrer">check this page</a>.</p>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>warning</div><div class="admonitionContent_BuS1"><p>The above sample uses secrets as plain strings for local dev testing. It is recommended to use Managed Identities approach when we deploy the app to Azure Container Apps. Your Dapr components directory should be added to your .gitignore to avoid checking in secrets.</p></div></div>
</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="preview-dapr-app-locally-for-e2e-testing">Preview Dapr app locally for e2e testing<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#preview-dapr-app-locally-for-e2e-testing" class="hash-link" aria-label="Direct link to Preview Dapr app locally for e2e testing" title="Direct link to Preview Dapr app locally for e2e testing">​</a></h3>
<ol>
<li>
<p>Within VS Code, open PowerShell terminal, change the directory in the terminal to folder <code>orders-service</code> and run the below command in PS terminal:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">dapr run --app-id orders-processor --app-port 5039 --dapr-http-port 3500 --components-path "../dapr-components" dotnet run</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>When using the <code>dapr run</code> command we are running a dapr process as a sidecar next to the Web API application. The following properties were configured:</p>
<ul>
<li>app-id: The unique identifier of the application. Used for service discovery, state encapsulation, and the pub/sub consumer identifier.</li>
<li>app-port: This parameter tells Dapr which port your application is listening on, you can get the app port from <code>dockerfile</code> in the Web API Project.</li>
<li>dapr-http-port: the HTTP port for Dapr to listen on.</li>
<li>components-path: path to the Dapr component(s) folder.</li>
</ul>
<p>If all is working as expected, you can open the VS Code Dapr extension to see the application <code>orders-processor</code> up and running as shown below:</p>
<p><img loading="lazy" alt="Image showing Dapr Application up and Running" src="https://azure.github.io/Cloud-Native/assets/images/DaprRunning-792ed943c5235ef05dede830b5e4d317.jpg" width="406" height="450" class="img_ev3q"></p>
</li>
<li>
<p>To publish a message to the topic <code>orderreceivedtopic</code> we can use Dapr extension:</p>
<ul>
<li>Right click on the Dapr application <code>orders-processor</code> and select <code>Publish Message to Application</code>.</li>
<li>Wizard will ask what is the Pub/sub component name you want to publish to, provide <code>pubsub-servicebus</code> and hit enter.</li>
<li>Wizard will ask what topic name to publish to, provide <code>orderreceivedtopic</code> and hit enter.</li>
<li>Wizard will ask to provide a JSON payload for the method, provide the JSON below and hit enter.<!-- -->
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "reference": "Order 1",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "quantity": 5,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "createdOn": "2022-08-19T12:45:22.0983978Z"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
</ul>
</li>
</ol>
<p>To check the results, go to the VS Code terminal and check the logs. In the action method, we are logging information when a message is consumed. You should see something similar to the below
<img loading="lazy" alt="Image showing logs in terminal" src="https://azure.github.io/Cloud-Native/assets/images/TerminalLogs-4813eaba2150ac7a867dafd58ba5dbfc.jpg" width="1444" height="161" class="img_ev3q"></p>
<p>:::info Want to debug Dapr application locally?
If you want to set breakpoints and debug your daper application locally, you can do this in VS code by following simple steps. This is very important when you are running multiple services together and want to test your microservice where multi-services are invoking each other. To learn more, you can continue reading on <a href="https://bitoftech.net/2022/08/29/dapr-integration-with-azure-container-apps/" target="_blank" rel="noopener noreferrer">my blog.</a>
:::</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="deploy-the-app-to-azure-container-apps">Deploy the app to Azure Container Apps<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#deploy-the-app-to-azure-container-apps" class="hash-link" aria-label="Direct link to Deploy the app to Azure Container Apps" title="Direct link to Deploy the app to Azure Container Apps">​</a></h3>
<p>We will follow few steps in order to deploy the service <code>Orders.Processor</code> to Azure Container Apps, but we need to do one addition before deploying, we have to create a component file for Azure Service Bus which meets the <a href="https://docs.microsoft.com/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml#configure-dapr-components" target="_blank" rel="noopener noreferrer">specs defined by Azure Container Apps</a>.</p>
<ol>
<li>Create a new yaml file named <code>pubsub-svcbus.yaml</code> and add it under folder <code>components</code> (folder created earlier), use the file content below:<!-- -->
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># pubsub.yaml for Azure Service Bus component</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">componentType</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> pubsub.azure.servicebus</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">version</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">metadata</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> namespaceName</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"ordersservices.servicebus.windows.net"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> consumerID</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"orders-processor-subscription"</span><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Application scopes  </span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">scopes</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> orders</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">processor</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
</ol>
<p>Things to notice here:</p>
<ul>
<li>We didn't specify the component name <code>pubsub-servicebus</code> when we created this component file, we are going to specify it once we add this dapr component to Azure Container Apps Environment via CLI.</li>
<li>We are not referencing any service bus connection strings as the authentication between Dapr and Azure Service Bus will be configured using Managed Identities.</li>
<li>The metadata <code>namespaceName</code> value is set to the address of the Service Bus namespace as a fully qualified domain name. The key is mandatory when using Managed Identities for authentication.</li>
<li>We are setting the metadata <code>consumerID</code> value to match the topic subscription name <code>orders-processor-subscription</code>. If you didn't set this metadata, dapr runtime will try to create a subscription using the dapr application ID.</li>
</ul>
<ol start="2">
<li>
<p>Createan  Azure Container Registry (ACR) instance in the resource group to build/push and store docker images of our service. Feel free to change the name of the ACR, to do so run the following command:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  ## Create Azure Container Registry</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  $ACR_NAME="ordersservicesacr"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  az acr create `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    --resource-group $RESOURCE_GROUP `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    --name $ACR_NAME `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    --sku Basic `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    --admin-enabled true</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>Build the Web API project on ACR and push the docker image to ACR. Use the below command to initiate the image build and push process using ACR:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">## Build and push image to ACR</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$BACKEND_SVC_NAME="orders-processor"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">cd {YourLocalPath}\orders-service</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">az acr build --registry $ACR_NAME --image $BACKEND_SVC_NAME --file 'Orders.Processor/Dockerfile' .      </span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>Provision an Azure Container Apps Env and Container App: the Azure Container Apps Environment acts as a secure boundary around a group of all container apps:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ## Upgrade az container app cli or install it</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  az extension add --name containerapp --upgrade</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ## Create ACA Env</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  $ENVIRONMENT="orders-services-aca-env"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  az containerapp env create `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    --name $ENVIRONMENT `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    --resource-group $RESOURCE_GROUP `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    --location $LOCATION</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>Deploy the Dapr Pub/Sub Component to the Azure Container Apps Environment using the following command:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">    az containerapp env dapr-component set `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    --name $ENVIRONMENT --resource-group $RESOURCE_GROUP `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    --dapr-component-name pubsub-servicebus `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    --yaml '.\components\pubsub-svcbus.yaml'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>Create a new Azure Container App with the below capabilities:</p>
<ul>
<li>Ingress should be disabled</li>
<li>Dapr needs to be enabled</li>
</ul>
<p>To achieve the above run the below PowerShell script:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">## Create Azure COntain App</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$BACKEND_SVC_NAME="orders-processor"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp create `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --name $BACKEND_SVC_NAME  `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --resource-group $RESOURCE_GROUP `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --environment $ENVIRONMENT `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --registry-server "$ACR_NAME.azurecr.io" `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --image "$ACR_NAME.azurecr.io/$BACKEND_SVC_NAME" `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --min-replicas 1 `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --max-replicas 1 `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --cpu 0.50 --memory 1.0Gi `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --enable-dapr `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --dapr-app-id  $BACKEND_SVC_NAME `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --dapr-app-port 5039</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="configure-managed-identities-in-azure-container-app">Configure Managed Identities in Azure Container App<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#configure-managed-identities-in-azure-container-app" class="hash-link" aria-label="Direct link to Configure Managed Identities in Azure Container App" title="Direct link to Configure Managed Identities in Azure Container App">​</a></h3>
<p>As you noticed so far, we are not using any connection strings to establish the relation between our Container App and Azure Service Bus, we will rely on <a href="https://learn.microsoft.com/azure/container-apps/managed-identity?tabs=portal%2Cdotnet" target="_blank" rel="noopener noreferrer">Managed Identities</a> to allow our container app to access Azure Service Bus.</p>
<p>We will be using a <code>system-assigned</code> identity with a role assignments to grant our container app the <code>Azure Service Bus Data Receiver</code> role which will allow it to receive messages from Service Bus queues and subscriptions.</p>
<ol>
<li>
<p>Run the command below to create <code>system-assigned</code> identity for our container app:</p>
<div class="language-PowerShell language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">##assigning the system assigned identity</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp identity assign `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --resource-group $RESOURCE_GROUP `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --name $BACKEND_SVC_NAME `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --system-assigned</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This command will create an Enterprise Application (so a Service Principal) within Azure AD, which is linked to our container app, the output of this command will be as the below, keep a note of the property <code>principalId</code> as we are going to use it in the next step.</p>
<div class="language-Json language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"> {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   "principalId": "456782b0-d5be-4dbd-afa0-5e2cff05d04d",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   "tenantId": "0a02a8b1-XXXX-XXXX-XXXX-67ceb9132d81",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   "type": "SystemAssigned"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Note: This can be done from Azure Portal as described <a href="https://learn.microsoft.com/azure/container-apps/managed-identity?tabs=portal%2Cdotnet#add-a-system-assigned-identity" target="_blank" rel="noopener noreferrer">here.</a></p>
</li>
<li>
<p>Next, we need to associate the container app system-identity with the target Azure Service Bus resouce. You can read more about <a href="https://learn.microsoft.com/azure/service-bus-messaging/service-bus-managed-service-identity#azure-built-in-roles-for-azure-service-bus" target="_blank" rel="noopener noreferrer">Azure built-in roles for Azure Service Bus.</a>. Run the command below to associate the <code>system-assigned</code> with access-control role <code>Azure Service Bus Data Receiver</code></p>
<div class="language-PowerShell language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  $subscription_id = "&lt;Your Azure Subscription ID&gt;"	## Your Azure Subscription</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  $principalId = "456782b0-d5be-4dbd-afa0-5e2cff05d04d" ## Principal Id after creating system identity for container app </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  $roleNameOrId =  "Azure Service Bus Data Receiver" ## Built in role name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  $resourceName = "ordersservices" ##Name of your Service Bus Namespace</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  az role assignment create `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --assignee $principalId `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --role $roleNameOrId `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --scope /subscriptions/$subscription_id/resourcegroups/$RESOURCE_GROUP/providers/Microsoft.ServiceBus/namespaces/$resourceName</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You can verify from Azure Portal that the association relation is created by going to your container app, select <code>identity</code> tab, then click on <code>Azure role assignments</code> button, you should see the role assignment below:
<img loading="lazy" alt="Image showing container apps role assignment" src="https://azure.github.io/Cloud-Native/assets/images/RoleAssignment-S-4d69197e34696dc635708ccffc9bbe66.jpg" width="855" height="338" class="img_ev3q"></p>
</li>
<li>
<p>Lastly, we need to restart the container app revision, to do so run the command below:</p>
<div class="language-PowerShell language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"> ##Get revision name and assign it to a variable</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> $REVISION_NAME = (az containerapp revision list `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         --name $BACKEND_SVC_NAME  `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         --resource-group $RESOURCE_GROUP `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         --query [0].name)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> ##Restart revision by name							   </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> az containerapp revision restart `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   --resource-group $RESOURCE_GROUP `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   --name $BACKEND_SVC_NAME  `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   --revision $REVISION_NAME</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="run-end-to-end-test-on-azure">Run end-to-end Test on Azure<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#run-end-to-end-test-on-azure" class="hash-link" aria-label="Direct link to Run end-to-end Test on Azure" title="Direct link to Run end-to-end Test on Azure">​</a></h3>
<p>From the Azure Portal, select the Azure Container App <code>orders-processor</code> and navigate to <code>Log stream</code> under <code>Monitoring</code> tab, leave the stream connected and opened. From the Azure Portal, select the Azure Service Bus Namespace <code>ordersservices</code>, select the topic <code>orderreceivedtopic</code>, select the subscription named <code>orders-processor-subscription</code>, then click on <code>Service Bus Explorer (preview)</code>. From there we need to publish/send a message. Use the JSON payload below</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "data": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "reference": "Order 150",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "quantity": 150,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "createdOn": "2022-05-10T12:45:22.0983978Z"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>If all is configured correctly, you should start seeing the information logs in Container Apps Log stream, similar to the images below
<img loading="lazy" alt="Image showing publishing messages from Azure Service" src="https://azure.github.io/Cloud-Native/assets/images/SvsBusPublishMessage-S-db3c800138a71f277bc45fcdab54e297.jpg" width="669" height="344" class="img_ev3q"></p>
<p>Information logs on the <code>Log stream</code> of the deployed Azure Container App
<img loading="lazy" alt="Image showing ACA Log Stream" src="https://azure.github.io/Cloud-Native/assets/images/ACA-Logstream-s-93516646409771be6bbdeac37155df15.jpg" width="686" height="394" class="img_ev3q"></p>
<div class="theme-admonition theme-admonition-success admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>🎉 CONGRATULATIONS</div><div class="admonitionContent_BuS1"><p>You have successfully deployed to the cloud an Azure Container App and configured Dapr Pub/Sub API with Azure Service Bus.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="9-clean-up">9. Clean up<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#9-clean-up" class="hash-link" aria-label="Direct link to 9. Clean up" title="Direct link to 9. Clean up">​</a></h3>
<p>If you are done with the tutorial, use the following command to delete the resource group and all its contained resources to avoid incurring further costs.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az group delete --name $RESOURCE_GROUP</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2>
<p>I left for you the configuration of the Dapr State Store API with Azure Cosmos DB :)</p>
<p>When you look at the action method <code>OrderReceived</code> in controller <code>ExternalOrdersController</code>, you will see that I left a line with <code>ToDo:</code> note, this line is responsible to save the received message (OrderModel) into Azure Cosmos DB.</p>
<p>There is no need to change anything on the code base (other than removing this commented line), that's the beauty of Dapr Building Blocks and how easy it allows us to plug components to our microservice application without any plumping and brining external SDKs.</p>
<p>For sure you need to work on the configuration part of Dapr State Store by creating a new component file like what we have done with the Pub/Sub API, things that you need to work on are:</p>
<ul>
<li>Provision Azure Cosmos DB Account and obtain its masterKey.</li>
<li>Create a Dapr Component file adhering to Dapr Specs.</li>
<li>Create an Azure Container Apps component file adhering to ACA component specs.</li>
<li>Test locally on your dev machine using Dapr Component file.</li>
<li>Register the new Dapr State Store component with Azure Container Apps Environment and set the Cosmos Db masterKey from the Azure Portal. <em>If you want to challenge yourself more, use the Managed Identity approach as done in this post! The right way to protect your keys and you will not worry about managing CosmosDb keys anymore!</em></li>
<li>Build a new image of the application and push it to Azure Container Registry.</li>
<li>Update Azure Container Apps and create a new revision which contains the updated code.</li>
<li>Verify the results by checking Azure Cosmos DB, you should see the Order Model stored in Cosmos DB.</li>
</ul>
<p>If you need help, you can always refer to my blog post <a href="https://bitoftech.net/2022/08/29/azure-container-apps-state-store-with-dapr-state-management-api/" target="_blank" rel="noopener noreferrer">Azure Container Apps State Store With Dapr State Management API</a> which contains exactly what you need to implement here, so I'm very confident you will be able to complete this exercise with no issues, happy coding :)</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="whats-next">What's Next?<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#whats-next" class="hash-link" aria-label="Direct link to What's Next?" title="Direct link to What's Next?">​</a></h2>
<p>If you enjoyed working with Dapr and Azure Container Apps, and you want to have a deep dive with more complex scenarios (Dapr bindings, service discovery, auto scaling with KEDA, sync services communication, distributed tracing, health probes, etc...) where multiple services deployed to a single Container App Environment; I have created a detailed tutorial which should walk you through step by step with through details to build the application.</p>
<p>So far, the published posts below, and I'm publishing more posts on weekly basis, so stay tuned :)</p>
<ul>
<li><a href="https://bitoftech.net/2022/08/25/tutorial-building-microservice-applications-azure-container-apps-dapr/" target="_blank" rel="noopener noreferrer">Tutorial for building Microservice Applications with Azure Container Apps and Dapr – Part 1</a></li>
<li><a href="https://bitoftech.net/2022/08/25/deploy-microservice-application-azure-container-apps/" target="_blank" rel="noopener noreferrer">Deploy backend API Microservice to Azure Container Apps – Part 2</a></li>
<li><a href="https://bitoftech.net/2022/08/25/communication-microservices-azure-container-apps/" target="_blank" rel="noopener noreferrer">Communication between Microservices in Azure Container Apps – Part 3</a></li>
<li><a href="https://bitoftech.net/2022/08/29/dapr-integration-with-azure-container-apps/" target="_blank" rel="noopener noreferrer">Dapr Integration with Azure Container Apps – Part 4</a></li>
<li><a href="https://bitoftech.net/2022/08/29/azure-container-apps-state-store-with-dapr-state-management-api/" target="_blank" rel="noopener noreferrer">Azure Container Apps State Store With Dapr State Management API – Part 5</a></li>
<li><a href="https://bitoftech.net/2022/09/02/azure-container-apps-async-communication-with-dapr-pub-sub-api-part-6/" target="_blank" rel="noopener noreferrer">Azure Container Apps Async Communication with Dapr Pub/Sub API – Part 6</a></li>
<li><a href="https://bitoftech.net/2022/09/05/azure-container-apps-with-dapr-bindings-building-block/" target="_blank" rel="noopener noreferrer">Azure Container Apps with Dapr Bindings Building Block – Part 7</a></li>
<li><a href="https://bitoftech.net/2022/09/09/azure-container-apps-monitoring-and-observability-with-application-insights-part-8/" target="_blank" rel="noopener noreferrer">Azure Container Apps Monitoring and Observability with Application Insights – Part 8</a></li>
<li><a href="https://bitoftech.net/2022/09/13/continuous-deployment-for-azure-container-apps-using-github-actions-part-9/" target="_blank" rel="noopener noreferrer">Continuous Deployment for Azure Container Apps using GitHub Actions – Part 9</a></li>
<li><a href="https://bitoftech.net/2022/09/16/use-bicep-to-deploy-dapr-microservices-apps-to-azure-container-apps-part-10/" target="_blank" rel="noopener noreferrer">Use Bicep to Deploy Dapr Microservices Apps to Azure Container Apps – Part 10</a></li>
<li><a href="https://bitoftech.net/2022/09/22/azure-container-apps-auto-scaling-with-keda-part-11/" target="_blank" rel="noopener noreferrer">Azure Container Apps Auto Scaling with KEDA – Part 11</a></li>
<li><em>Integrate Health probes in Azure Container Apps – Part 12</em></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="https://azure.github.io/Cloud-Native/blog/14-dapr-aca-quickstart#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2>
<ul>
<li><a href="https://docs.microsoft.com/azure/container-apps/" target="_blank" rel="noopener noreferrer">Azure Container Apps documentation</a></li>
<li><a href="https://docs.dapr.io/getting-started/" target="_blank" rel="noopener noreferrer">Getting started with Dapr</a></li>
<li><a href="https://docs.microsoft.com/dotnet/architecture/dapr-for-net-developers/" target="_blank" rel="noopener noreferrer">Dapr for .NET Developers</a></li>
<li><a href="https://docs.microsoft.com/cli/azure/containerapp?view=azure-cli-latest" target="_blank" rel="noopener noreferrer">az containerapp cli</a></li>
</ul>]]></content:encoded>
            <category>serverless-september</category>
            <category>30-days-of-serverless</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
            <category>microservices</category>
        </item>
        <item>
            <title><![CDATA[13. Secrets + Managed Identity]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/13-aca-managed-id</link>
            <guid>https://azure.github.io/Cloud-Native/blog/13-aca-managed-id</guid>
            <pubDate>Tue, 13 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn to make use of Container Apps (ACA) secrets and managed identities to securely access cloud-hosted resources that your ACA depends on! ]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 13</code> of #30DaysOfServerless!</p>
<p>In the previous post, we learned about all things Distributed Application Runtime (Dapr) and highlighted the capabilities you can unlock through managed Dapr in Azure Container Apps! Today, we'll dive into how we can make use of Container Apps secrets and managed identities to securely access cloud-hosted resources that your Container Apps depend on!</p>
<p>Ready? Let's go.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>Secure access to external services overview</li>
<li>Using Container Apps Secrets</li>
<li>Using Managed Identity for connecting to Azure resources</li>
<li>Using Dapr secret store component references (Dapr-only)</li>
<li>Conclusion</li>
<li>Resources: For self-study!</li>
</ul>
<p><img loading="lazy" alt="Session by Kendall Roden on securing ACA with container secrets, managed identity, and the Dapr secret store." src="https://azure.github.io/Cloud-Native/assets/images/banner-9d61f89816a8e8b5682eae3c4fcdb71c.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="securing-access-to-external-services">Securing access to external services<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#securing-access-to-external-services" class="hash-link" aria-label="Direct link to Securing access to external services" title="Direct link to Securing access to external services">​</a></h2>
<p>In most, if not all, microservice-based applications, one or more services in the system will rely on other cloud-hosted resources; Think external services like databases, secret stores, message brokers, event sources, etc. To interact with these services, an application must have the ability to establish a secure connection. Traditionally, an application will authenticate to these backing resources using some type of connection string or password.</p>
<p>I'm not sure if it was just me, but one of the first things I learned as a developer was to ensure credentials and other sensitive information were never checked into the codebase. The ability to inject these values at runtime is a non-negotiable.</p>
<p>In Azure Container Apps, applications can securely leverage connection information via <strong>Container Apps Secrets</strong>. If the resource is Azure-based, a more ideal solution that removes the dependence on secrets altogether is using Managed Identity.</p>
<p>Specifically for Dapr-enabled container apps, users can now tap into the power of the <strong>Dapr secrets API!</strong> With this new capability unlocked in Container Apps, users can call the Dapr secrets API from application code to securely access secrets from Key Vault or other backing secret stores. In addition, customers can also make use of a secret store component reference when wiring up Dapr state store components and more!</p>
<p>ALSO, I'm excited to share that <strong>support for  Dapr + Managed Identity is now available</strong>!!. What does this mean? It means that you can enable Managed Identity for your container app - and when establishing connections via Dapr, the Dapr sidecar can use this identity! This means simplified components without the need for secrets when connecting to Azure services!</p>
<p>Let's dive a bit deeper into the following three topics:</p>
<ol>
<li>Using Container Apps secrets in your container apps</li>
<li>Using Managed Identity to connect to Azure services</li>
<li>Connecting to services securely for Dapr-enabled apps</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="secure-access-to-external-services-without-dapr">Secure access to external services without Dapr<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#secure-access-to-external-services-without-dapr" class="hash-link" aria-label="Direct link to Secure access to external services without Dapr" title="Direct link to Secure access to external services without Dapr">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="leveraging-container-apps-secrets-at-runtime">Leveraging Container Apps secrets at runtime<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#leveraging-container-apps-secrets-at-runtime" class="hash-link" aria-label="Direct link to Leveraging Container Apps secrets at runtime" title="Direct link to Leveraging Container Apps secrets at runtime">​</a></h3>
<p>Users can leverage this approach for any values which need to be securely stored, however, it is recommended to use Managed Identity where possible when connecting to Azure-specific resources.</p>
<p>First, let's establish a few important points regarding secrets in container apps:</p>
<ul>
<li>Secrets are scoped at the container app level, meaning secrets cannot be shared across container apps today</li>
<li>When running in multiple-revision mode,<!-- -->
<ul>
<li>changes to secrets <strong>do not</strong> generate a new revision</li>
<li>running revisions will not be automatically restarted to reflect changes. If you want to force-update existing container app revisions to reflect the changed secrets values, you will need to perform revision restarts.</li>
</ul>
</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>STEP 1</div><div class="admonitionContent_BuS1"><p>Provide the secure value as a secret parameter when creating your container app using the syntax <strong>"SECRET_NAME=SECRET_VALUE"</strong></p></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp create \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --resource-group "my-resource-group" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --name queuereader \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --environment "my-environment-name" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --image demos/queuereader:v1 \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --secrets "queue-connection-string=$CONNECTION_STRING"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>STEP 2</div><div class="admonitionContent_BuS1"><p>Create an environment variable which references the value of the secret created in step 1 using the syntax <strong>"ENV_VARIABLE_NAME=secretref<!-- -->:SECRET_NAME<!-- -->"</strong></p></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp create \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --resource-group "my-resource-group" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --name myQueueApp \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --environment "my-environment-name" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --image demos/myQueueApp:v1 \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --secrets "queue-connection-string=$CONNECTIONSTRING" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --env-vars "QueueName=myqueue" "ConnectionString=secretref:queue-connection-string"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This <strong>ConnectionString</strong> environment variable can be used within your application code to securely access the connection string value at runtime.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="using-managed-identity-to-connect-to-azure-services">Using Managed Identity to connect to Azure services<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#using-managed-identity-to-connect-to-azure-services" class="hash-link" aria-label="Direct link to Using Managed Identity to connect to Azure services" title="Direct link to Using Managed Identity to connect to Azure services">​</a></h3>
<p>A managed identity from Azure Active Directory (Azure AD) allows your container app to access other Azure AD-protected resources. This approach is recommended where possible as it eliminates the need for managing secret credentials in your container apps and allows you to properly scope the permissions needed for a given container app using role-based access control. Both system-assigned and user-assigned identities are available in container apps. For more background on managed identities in Azure AD, see <a href="https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview" target="_blank" rel="noopener noreferrer">Managed identities for Azure resources</a>.</p>
<p>To configure your app with a system-assigned managed identity you will follow similar steps to the following:</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>STEP 1</div><div class="admonitionContent_BuS1"><p>Run the following command to create a system-assigned identity for your container app</p></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp identity assign \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --name "myQueueApp" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --resource-group "my-resource-group" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --system-assigned</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>STEP 2</div><div class="admonitionContent_BuS1"><p>Retrieve the identity details for your container app and store the Principal ID for the identity in a variable <strong>"PRINCIPAL_ID"</strong></p></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp identity show \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --name "myQueueApp" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --resource-group "my-resource-group"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>STEP 3</div><div class="admonitionContent_BuS1"><p>Assign the appropriate roles and permissions to your container app's managed identity using the Principal ID in step 2 based on the resources you need to access (example below)</p></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az role assignment create \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --role "Storage Queue Data Contributor" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --assignee $PRINCIPAL_ID \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --scope "/subscriptions/&lt;subscription&gt;/resourceGroups/&lt;resource-group&gt;/providers/Microsoft.Storage/storageAccounts/&lt;storage-account&gt;/queueServices/default/queues/&lt;queue&gt;"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>After running the above commands, your container app will be able to access your Azure Store Queue because it's managed identity has been assigned the "Store Queue Data Contributor" role. The role assignments you create will be contingent solely on the resources your container app needs to access. To instrument your code to use this managed identity, see more details <a href="https://learn.microsoft.com/azure/container-apps/managed-identity?tabs=portal%2Cdotnet#connect-to-azure-services-in-app-code" target="_blank" rel="noopener noreferrer">here</a>.</p>
<p>In addition to using managed identity to access services from your container app, you can also use managed identity to <a href="https://learn.microsoft.com/azure/container-apps/containers#container-registries" target="_blank" rel="noopener noreferrer">pull your container images from Azure Container Registry</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="secure-access-to-external-services-with-dapr">Secure access to external services with Dapr<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#secure-access-to-external-services-with-dapr" class="hash-link" aria-label="Direct link to Secure access to external services with Dapr" title="Direct link to Secure access to external services with Dapr">​</a></h2>
<p>For Dapr-enabled apps, there are a few ways to connect to the resources your solutions depend on. In this section, we will discuss when to use each approach.</p>
<ol>
<li>Using Container Apps secrets in your Dapr components</li>
<li>Using Managed Identity with Dapr Components</li>
<li>Using Dapr Secret Stores for runtime secrets and component references</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="using-container-apps-secrets-in-dapr-components">Using Container Apps secrets in Dapr components<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#using-container-apps-secrets-in-dapr-components" class="hash-link" aria-label="Direct link to Using Container Apps secrets in Dapr components" title="Direct link to Using Container Apps secrets in Dapr components">​</a></h3>
<p>Prior to providing support for the Dapr Secret's Management building block, this was the only approach available for securely storing sensitive values for use in Dapr components.</p>
<p>In Dapr OSS, when no secret store reference is provided in a Dapr component file, the default secret store is set to "Kubernetes secrets". In Container Apps, we do not expose the ability to use this default store. Rather, Container Apps secrets can be used in it's place.</p>
<p>With the introduction of the Secrets API and the ability to use Dapr + Managed Identity, this approach is useful for a limited number of scenarios:</p>
<ul>
<li>Quick demos and dev/test scenarios using the Container Apps CLI</li>
<li>Securing values when a secret store is not configured or available for use</li>
<li>Using service principal credentials to configure an Azure Key Vault secret store component (Using Managed Identity is recommend)</li>
<li>Securing access credentials which may be required when creating a non-Azure secret store component</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>STEP 1</div><div class="admonitionContent_BuS1"><p>Create a Dapr component which can be used by one or more services in the container apps environment. In the below example, you will create a secret to store the storage account key and reference this secret from the appropriate Dapr metadata property.</p></div></div>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token key atrule" style="color:#00a4db">componentType</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> state.azure.blobstorage</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token key atrule" style="color:#00a4db">version</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token key atrule" style="color:#00a4db">metadata</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> accountName</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> testStorage</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> accountKey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token key atrule" style="color:#00a4db">secretRef</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> account</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">key</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> containerName</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> myContainer</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token key atrule" style="color:#00a4db">secrets</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> account</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">key</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;STORAGE_ACCOUNT_KEY&gt;"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token key atrule" style="color:#00a4db">scopes</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> myApp</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>STEP 2</div><div class="admonitionContent_BuS1"><p>Deploy the Dapr component using the below command with the appropriate arguments.</p></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"> az containerapp env dapr-component set \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   --name "my-environment" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   --resource-group "my-resource-group" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   --dapr-component-name statestore \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   --yaml "./statestore.yaml"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="using-managed-identity-with-dapr-components">Using Managed Identity with Dapr Components<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#using-managed-identity-with-dapr-components" class="hash-link" aria-label="Direct link to Using Managed Identity with Dapr Components" title="Direct link to Using Managed Identity with Dapr Components">​</a></h3>
<p>Dapr-enabled container apps can now make use of managed identities within Dapr components. This is the most ideal path for connecting to Azure services securely, and allows for the removal of sensitive values in the component itself.</p>
<p>The Dapr sidecar makes use of the existing identities available within a given container app; Dapr itself does not have it's own identity. Therefore, the steps to enable Dapr + MI are similar to those in the section regarding managed identity for non-Dapr apps. See example steps below specifically for using a system-assigned identity:</p>
<ol>
<li>Create a system-assigned identity for your container app</li>
<li>Retrieve the identity details for your container app and store the Principal ID for the identity in a variable <strong>"PRINCIPAL_ID"</strong></li>
<li>Assign the appropriate roles and permissions (for accessing resources backing your Dapr components) to your ACA's managed identity using the Principal ID</li>
<li>Create a simplified Dapr component without any secrets required</li>
</ol>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">componentType</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> state.azure.blobstorage</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">version</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">metadata</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> accountName</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> testStorage</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> containerName</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> myContainer</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">scopes</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> myApp</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="5">
<li>Deploy the component to test the connection from your container app via Dapr!</li>
</ol>
<p>Keep in mind, all Dapr components will be loaded by each Dapr-enabled container app in an environment by default. In order to avoid apps without the appropriate permissions from loading a component unsuccessfully, use scopes. This will ensure that only applications with the appropriate identities to access the backing resource load the component.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="using-dapr-secret-stores-for-runtime-secrets-and-component-references">Using Dapr Secret Stores for runtime secrets and component references<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#using-dapr-secret-stores-for-runtime-secrets-and-component-references" class="hash-link" aria-label="Direct link to Using Dapr Secret Stores for runtime secrets and component references" title="Direct link to Using Dapr Secret Stores for runtime secrets and component references">​</a></h3>
<p>Dapr integrates with secret stores to provide apps and other components with secure storage and access to secrets such as access keys and passwords. The Dapr Secrets API is now available for use in Container Apps.</p>
<p>Using Dapr’s secret store building block typically involves the following:</p>
<ul>
<li>Setting up a component for a specific secret store solution.</li>
<li>Retrieving secrets using the Dapr secrets API in the application code.</li>
<li>Optionally, referencing secrets in Dapr component files.</li>
</ul>
<p><img loading="lazy" alt="Diagram showing Dapr fetching secrets from cloud secret stores like AWS Secrets Manager, Azure Key Vault, and passing them to Service A." src="https://azure.github.io/Cloud-Native/assets/images/secrets-overview-cloud-stores-f0c9f823ba6a3246dac070c4da40a80a.png" width="1739" height="1057" class="img_ev3q"></p>
<p>Let's walk through a couple sample workflows involving the use of Dapr's Secrets Management capabilities!</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="setting-up-a-component-for-a-specific-secret-store-solution">Setting up a component for a specific secret store solution<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#setting-up-a-component-for-a-specific-secret-store-solution" class="hash-link" aria-label="Direct link to Setting up a component for a specific secret store solution" title="Direct link to Setting up a component for a specific secret store solution">​</a></h4>
<ol>
<li>Create an Azure Key Vault instance for hosting the secrets required by your application.</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az keyvault create --name "&lt;your-unique-keyvault-name&gt;" --resource-group "my-resource-group" --location "&lt;your-location&gt;"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="2">
<li>Create an Azure Key Vault component in your environment without the secrets values, as the connection will be established to Azure Key Vault via Managed Identity.</li>
</ol>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">componentType</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> secretstores.azure.keyvault</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">version</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">metadata</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> vaultName</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"[your_keyvault_name]"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">scopes</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> myApp </span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp env dapr-component set \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --name "my-environment" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --resource-group "my-resource-group" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --dapr-component-name secretstore \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --yaml "./secretstore.yaml"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="3">
<li>Run the following command to create a system-assigned identity for your container app</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp identity assign \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --name "myApp" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --resource-group "my-resource-group" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --system-assigned</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="4">
<li>Retrieve the identity details for your container app and store the Principal ID for the identity in a variable <strong>"PRINCIPAL_ID"</strong></li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp identity show \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --name "myApp" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --resource-group "my-resource-group"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="5">
<li>Assign the appropriate roles and permissions to your container app's managed identity to access Azure Key Vault</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az role assignment create \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--role "Key Vault Secrets Officer" \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--assignee $PRINCIPAL_ID \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--scope /subscriptions/{subscriptionid}/resourcegroups/{resource-group-name}/providers/Microsoft.KeyVault/vaults/{key-vault-name}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="6">
<li>Begin using the Dapr Secrets API in your application code to retrieve secrets! See additional details <a href="https://docs.dapr.io/reference/api/secrets_api/" target="_blank" rel="noopener noreferrer">here</a>.</li>
</ol>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="referencing-secrets-in-dapr-component-files">Referencing secrets in Dapr component files<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#referencing-secrets-in-dapr-component-files" class="hash-link" aria-label="Direct link to Referencing secrets in Dapr component files" title="Direct link to Referencing secrets in Dapr component files">​</a></h4>
<p>Once a Dapr secret store component is available in the environment, it can be used to retrieve secrets for use in other components. For example, when creating a state store component, you can add a reference to the Dapr secret store from which you would like to source connection information. You will no longer use secrets directly in the component spec, but rather will instruct the Dapr sidecar to retrieve the secrets from the specified store.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">componentType</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> state.azure.blobstorage</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">version</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">metadata</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> accountName</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> testStorage</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> accountKey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">secretRef</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> account</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">key</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> containerName</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> myContainer</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">secretStoreComponent</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;SECRET_STORE_COMPONENT_NAME&gt;"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">scopes</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> myApp</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="summary">Summary<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary">​</a></h2>
<p>In this post, we have covered the high-level details on how to work with secret values in Azure Container Apps for both Dapr and Non-Dapr apps. In the next article, we will walk through a complex Dapr example from end-to-end which makes use of the new support for Dapr + Managed Identity. Stayed tuned for additional documentation around Dapr secrets as it will be release in the next two weeks!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="https://azure.github.io/Cloud-Native/blog/13-aca-managed-id#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2>
<p>Here are the main resources to explore for self-study:</p>
<ul>
<li><a href="https://learn.microsoft.com/azure/container-apps/manage-secrets?tabs=azure-cli" target="_blank" rel="noopener noreferrer">Azure Container Apps Secrets</a></li>
<li><a href="https://learn.microsoft.com/azure/container-apps/managed-identity?tabs=portal%2Cdotnet" target="_blank" rel="noopener noreferrer">Managed Identities in Azure Container Apps</a></li>
<li><a href="https://v1-9.docs.dapr.io/concepts/" target="_blank" rel="noopener noreferrer">Dapr Documentation: Core Concepts</a></li>
<li><a href="https://docs.dapr.io/getting-started/quickstarts/" target="_blank" rel="noopener noreferrer">Dapr Quickstarts</a></li>
<li><a href="https://docs.dapr.io/getting-started/tutorials/" target="_blank" rel="noopener noreferrer">Dapr Tutorials</a></li>
<li><a href="https://learn.microsoft.com/azure/container-apps/dapr-overview" target="_blank" rel="noopener noreferrer">Azure Container Apps: Dapr Integration</a></li>
<li><a href="https://learn.microsoft.com/azure/container-apps/microservices-dapr" target="_blank" rel="noopener noreferrer">Dapr-enabled Azure Container Apps: Using Azure CLI</a></li>
<li><a href="https://learn.microsoft.com/azure/container-apps/microservices-dapr-azure-resource-manager" target="_blank" rel="noopener noreferrer">Dapr-enabled Azure Container Apps: Using Bicep or ARM</a></li>
</ul>]]></content:encoded>
            <category>serverless-september</category>
            <category>30-days-of-serverless</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
            <category>microservices</category>
        </item>
        <item>
            <title><![CDATA[12. Build With Dapr!]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/12-build-with-dapr</link>
            <guid>https://azure.github.io/Cloud-Native/blog/12-build-with-dapr</guid>
            <pubDate>Mon, 12 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Today we'll shift gears and talk about Dapr - the Distributed Application Runtime - and how it makes microservices development with ACA _easier_]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 12</code> of #30DaysOfServerless!</p>
<p>So far we've looked at Azure Container Apps - what it is, how it enables microservices communication, and how it enables auto-scaling with KEDA compliant scalers. Today we'll shift gears and talk about Dapr - the Distributed Application Runtime - and how it makes microservices development with ACA <em>easier</em> with core building blocks and a sidecar architecture!</p>
<p>Ready? Let's go!</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/12-build-with-dapr#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>What is Dapr and why use it?</li>
<li>Building Block APIs</li>
<li>Dapr Quickstart and Tutorials</li>
<li>Dapr-enabled ACA: A Sidecar Approach</li>
<li>Exercise: Build &amp; Deploy a Dapr-enabled ACA.</li>
<li>Resources: For self-study!</li>
</ul>
<p><img loading="lazy" alt="Session slide by Nitya Narasimhan on Dapr, explaining microservices with sidecar patterns, API blocks, and practical examples." src="https://azure.github.io/Cloud-Native/assets/images/banner-cc3cfe656444b6f21e4bc8d2c541bc3e.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="hello-dapr">Hello, Dapr!<a href="https://azure.github.io/Cloud-Native/blog/12-build-with-dapr#hello-dapr" class="hash-link" aria-label="Direct link to Hello, Dapr!" title="Direct link to Hello, Dapr!">​</a></h2>
<p>Building distributed applications is hard. Building <strong>reliable and portable microservces</strong> means having middleware that deals with challenges like service discovery, sync and async communications, state management, secure information sharing and more. Integrating these support services into your application can be challenging from both development and maintenance perspectives, adding complexity that is independent of the core application logic you want to focus on.</p>
<p>This is where <a href="https://dapr.io/" target="_blank" rel="noopener noreferrer"><strong>Dapr (Distributed Application Runtime)</strong></a> shines - <a href="https://docs.dapr.io/" target="_blank" rel="noopener noreferrer">it's defined as:</a>:</p>
<blockquote>
<p>a portable, event-driven runtime that makes it easy for any developer to build resilient, stateless and stateful applications that run on the cloud and edge and embraces the diversity of languages and developer frameworks.</p>
</blockquote>
<p>But what does this actually mean to me as an app developer?</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="dapr--apps-a-sidecar-approach">Dapr + Apps: A Sidecar Approach<a href="https://azure.github.io/Cloud-Native/blog/12-build-with-dapr#dapr--apps-a-sidecar-approach" class="hash-link" aria-label="Direct link to Dapr + Apps: A Sidecar Approach" title="Direct link to Dapr + Apps: A Sidecar Approach">​</a></h2>
<p>The strength of Dapr lies in its ability to:</p>
<ul>
<li>abstract complexities of distributed systems middleware - with  <strong>Building Block APIs</strong> that implement components using best practices to tackle key challenges.</li>
<li>implement a <strong>Sidecar Pattern</strong> with interactions via APIs - allowing applications to keep their codebase clean and focus on app logic.</li>
<li>be <strong>Incrementally Adoptable</strong> - allowing developers to start by integrating one API, then evolving to use more as and when needed.</li>
<li>be <strong>Platform Agnostic</strong> - allowing applications to be developed in a preferred language or framework without impacting integration capabilities.</li>
</ul>
<p>The application-dapr sidecar interaction is illustrated below. The API abstraction allows applications to get the desired functionality without having to know <em>how</em> it was implemented, or without having to integrate Dapr-specific code into their codebase. Note how the sidecar process listens on port <code>3500</code> and the API provides clear routes for the specific building blocks supported by Dapr (e.g, <code>/secrets</code>, <code>/state</code> etc.)</p>
<p><img loading="lazy" src="https://docs.dapr.io/images/overview-sidecar-model.png" alt="" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="dapr-building-blocks-api-interactions">Dapr Building Blocks: API Interactions<a href="https://azure.github.io/Cloud-Native/blog/12-build-with-dapr#dapr-building-blocks-api-interactions" class="hash-link" aria-label="Direct link to Dapr Building Blocks: API Interactions" title="Direct link to Dapr Building Blocks: API Interactions">​</a></h2>
<p>Dapr Building Blocks refers to <strong>HTTP and gRPC endpoints exposed by Dapr</strong> API endpoints exposed by the Dapr sidecar, providing key capabilities like state management, observability, service-to-service invocation, pub/sub messaging and more to the associated application.</p>
<table><thead><tr><th style="text-align:left"></th><th style="text-align:left"><strong>Building Blocks: Under the Hood</strong></th></tr></thead><tbody><tr><td style="text-align:left"><img loading="lazy" src="https://docs.dapr.io/images/concepts-building-blocks.png" alt="" class="img_ev3q"></td><td style="text-align:left">The Dapr API is implemented by <a href="https://docs.dapr.io/concepts/building-blocks-concept/" target="_blank" rel="noopener noreferrer">modular components</a> that codify best practices for tackling the specific challenge that they represent. The API abstraction allows component implementations to evolve, or alternatives to be used , without requiring changes to the application codebase.</td></tr></tbody></table>
<p><img loading="lazy" src="https://docs.dapr.io/images/building_blocks.png" alt="" class="img_ev3q"></p>
<p>The <a href="https://docs.dapr.io/concepts/building-blocks-concept/" target="_blank" rel="noopener noreferrer">latest Dapr release</a> has the building blocks shown in the above figure. Not all capabilities are available to Azure Container Apps by default -  check the <a href="https://learn.microsoft.com/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml#unsupported-dapr-capabilities" target="_blank" rel="noopener noreferrer">documentation</a> for the latest updates on this. For now, Azure Container Apps + Dapr integration provides the following capabilities to the application:</p>
<ul>
<li><a href="https://docs.dapr.io/developing-applications/building-blocks/service-invocation/service-invocation-overview/" target="_blank" rel="noopener noreferrer">Service-to-Service Invocation</a> for synchronous communications</li>
<li><a href="https://docs.dapr.io/developing-applications/building-blocks/state-management/state-management-overview/" target="_blank" rel="noopener noreferrer">State management</a> for transactions and CRUD operations</li>
<li><a href="https://docs.dapr.io/developing-applications/building-blocks/pubsub/pubsub-overview" target="_blank" rel="noopener noreferrer">Pub/Sub messaging</a> for asynchronous (message-driven) communications</li>
<li><a href="https://docs.dapr.io/developing-applications/building-blocks/bindings/bindings-overview/" target="_blank" rel="noopener noreferrer">Bindings</a> for seamless workflow integrations using event triggers</li>
<li><a href="https://docs.dapr.io/developing-applications/building-blocks/actors/actors-overview/" target="_blank" rel="noopener noreferrer">Actors</a> for encapsulated &amp; reusable objects that enable reliable, scalable behaviors</li>
<li><a href="https://learn.microsoft.com/azure/container-apps/observability" target="_blank" rel="noopener noreferrer">Observability</a> to monitor application events for health and performance</li>
<li><a href="https://docs.dapr.io/developing-applications/building-blocks/secrets/" target="_blank" rel="noopener noreferrer">Secrets</a> for securely accessing sensitive values.</li>
</ul>
<p>In the next section, we'll dive into Dapr-enabled Azure Container Apps. Before we do that, here are a couple of resources to help you explore the Dapr platform by itself, and get more hands-on experience with the concepts and capabilities:</p>
<ul>
<li><a href="https://docs.dapr.io/getting-started/quickstarts/" target="_blank" rel="noopener noreferrer">Dapr Quickstarts</a> - build your first Dapr app, then explore quickstarts for a core APIs including service-to-service invocation, pub/sub, state mangement, bindings and secrets management.</li>
<li><a href="https://docs.dapr.io/getting-started/tutorials/" target="_blank" rel="noopener noreferrer">Dapr Tutorials</a> - go beyond the basic quickstart and explore more realistic service integrations and usage scenarios. Try the <a href="https://github.com/dapr/quickstarts/tree/master/tutorials/distributed-calculator" target="_blank" rel="noopener noreferrer">distributed calculator</a> example!</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="integrate-dapr--azure-container-apps">Integrate Dapr &amp; Azure Container Apps<a href="https://azure.github.io/Cloud-Native/blog/12-build-with-dapr#integrate-dapr--azure-container-apps" class="hash-link" aria-label="Direct link to Integrate Dapr &amp; Azure Container Apps" title="Direct link to Integrate Dapr &amp; Azure Container Apps">​</a></h2>
<p>Dapr currently has a <a href="https://v1-9.docs.dapr.io/" target="_blank" rel="noopener noreferrer">v1.9 (preview)</a> version, but Azure Container Apps supports <a href="https://learn.microsoft.com/azure/container-apps/dapr-overview#current-supported-dapr-version" target="_blank" rel="noopener noreferrer">Dapr v1.8</a>. In this section, we'll look at what it takes to enable, configure, and use, Dapr integration with Azure Container Apps. It involves 3 steps: <em>enabling</em> Dapr using settings, <em>configuring</em> Dapr components (API) for use, then invoking the APIs.</p>
<p>Here's a simple <a href="https://learn.microsoft.com/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml#dapr-settings" target="_blank" rel="noopener noreferrer">a publisher-subscriber scenario</a> from the documentation. We have two Container apps identified as <code>publisher-app</code> and <code>subscriber-app</code> deployed in a single environment. Each ACA has an activated <code>daprd</code> sidecar, allowing them to use the <em>Pub/Sub</em> API to communicate asynchronously with each other - without having to write the underlying pub/sub implementation themselves. Rather, we can see that the Dapr API uses a <code>pubsub,azure.servicebus</code> <strong>component</strong> to implement that capability.</p>
<p><img loading="lazy" src="https://learn.microsoft.com/azure/container-apps/media/dapr-overview/dapr-in-aca.png" alt="Pub/sub example" class="img_ev3q"></p>
<p>Let's look at how this is setup.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-enable-dapr-in-aca-settings">1. <a href="https://learn.microsoft.com/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml#enable-dapr" target="_blank" rel="noopener noreferrer">Enable Dapr in ACA: Settings</a><a href="https://azure.github.io/Cloud-Native/blog/12-build-with-dapr#1-enable-dapr-in-aca-settings" class="hash-link" aria-label="Direct link to 1-enable-dapr-in-aca-settings" title="Direct link to 1-enable-dapr-in-aca-settings">​</a></h3>
<p>We can enable Dapr integration in the Azure Container App during creation by <em>specifying settings</em> in one of two ways, based on your development preference:</p>
<ul>
<li><strong>Using Azure CLI</strong>: use custom commandline options for each setting</li>
<li><strong>Using Infrastructure-as-Code (IaC)</strong>: using properties for Bicep, ARM templates</li>
</ul>
<p>Once enabled, Dapr will run in the same <em>environment</em> as the Azure Container App, and listen on <strong>port 3500</strong> for API requests. The Dapr sidecar can be shared my multiple Container Apps <em>deployed in the same environment</em>.</p>
<p>There are four main settings we will focus on for this demo - the example below shows the ARM template properties, but you can <a href="https://learn.microsoft.com/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml#enable-dapr" target="_blank" rel="noopener noreferrer">find the equivalent CLI parameters here</a> for comparison.</p>
<ul>
<li><code>dapr.enabled</code> - enable Dapr for Azure Container App</li>
<li><code>dapr.appPort</code> - specify port on which app is listening</li>
<li><code>dapr.appProtocol</code> - specify if using <code>http</code> (default) or <code>gRPC</code> for API</li>
<li><code>dapr.appId</code> - specify unique application ID for service discovery, usage</li>
</ul>
<p>These are defined under the <code>properties.configuration</code> section for your resource. Changing Dapr settings does not update the revision but it <em>will</em> restart ACA revisions and replicas. Here is what the relevant section of the ARM template looks like for the <code>publisher-app</code> ACA in the scenario shown above.</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">"dapr": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   "enabled": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   "appId": "publisher-app",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   "appProcotol": "http",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   "appPort": 80</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-configure-dapr-in-aca--components">2. <a href="https://learn.microsoft.com/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml#configure-dapr-components" target="_blank" rel="noopener noreferrer">Configure Dapr in ACA:  Components</a><a href="https://azure.github.io/Cloud-Native/blog/12-build-with-dapr#2-configure-dapr-in-aca--components" class="hash-link" aria-label="Direct link to 2-configure-dapr-in-aca--components" title="Direct link to 2-configure-dapr-in-aca--components">​</a></h3>
<p>The next step after activating the Dapr sidecar, is to define the <em>APIs</em> that you want to use and potentially specify the <strong>Dapr components</strong> (specific implementations of that API) that you prefer. These components are created at environment-level and by default, Dapr-enabled containers apps in an environment will load the complete set of deployed components -- <strong>use the <code>scopes</code> property</strong> to ensure only components needed by a given app are loaded at runtime. Here's what the ARM template <code>resources</code> section looks like for the example above. This tells us that the environment has a <code>dapr-pubsub</code> component of type <code>pubsub.azure.servicebus</code> deployed - where that component is loaded by container apps with dapr ids (<code>publisher-app</code>, <code>subscriber-app</code>).</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>USING MANAGED IDENTITY + DAPR</div><div class="admonitionContent_BuS1"><p>The secrets approach used here is idea for demo purposes. However, we recommend using <em>Managed Identity with Dapr</em> in production. For more details on secrets, check out tomorrow's post on <em>Secrets and Managed Identity in Azure Container Apps</em></p></div></div>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "resources": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "type": "daprComponents",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "name": "dapr-pubsub",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "properties": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "componentType": "pubsub.azure.servicebus",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "version": "v1",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "secrets": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "name": "sb-root-connectionstring",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "value": "value"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "metadata": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "name": "connectionString",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "secretRef": "sb-root-connectionstring"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        // Application scopes</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "scopes": ["publisher-app", "subscriber-app"]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>With this configuration, the ACA is now set to use pub/sub capabilities from the Dapr sidecar, using standard HTTP requests to the exposed API endpoint for this service.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-deploy-dapr-enabled-aca">Exercise: Deploy Dapr-enabled ACA<a href="https://azure.github.io/Cloud-Native/blog/12-build-with-dapr#exercise-deploy-dapr-enabled-aca" class="hash-link" aria-label="Direct link to Exercise: Deploy Dapr-enabled ACA" title="Direct link to Exercise: Deploy Dapr-enabled ACA">​</a></h2>
<p>In the next couple posts in this series, we'll be discussing how you can use the Dapr secrets API and doing a walkthrough of a more complex example, to show how Dapr-enabled Azure Container Apps are created and deployed.</p>
<p>However, you can get hands-on experience with these concepts by walking through one of these two tutorials, each providing an alternative approach to configure and setup the application describe in the scenario below:</p>
<ul>
<li><strong>Tutorial 1</strong>: <a href="https://learn.microsoft.com/azure/container-apps/microservices-dapr" target="_blank" rel="noopener noreferrer">Deploy a Dapr-enabled ACA using <strong>Azure CLI</strong></a></li>
<li><strong>Tutorial 2</strong>: <a href="https://learn.microsoft.com/azure/container-apps/microservices-dapr" target="_blank" rel="noopener noreferrer">Deploy a Dapr-enabled ACA using <strong>Bicep or ARM templates</strong></a></li>
</ul>
<p><img loading="lazy" src="https://learn.microsoft.com/azure/container-apps/media/microservices-dapr/azure-container-apps-microservices-dapr.png" alt="" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="https://azure.github.io/Cloud-Native/blog/12-build-with-dapr#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2>
<p>Here are the main resources to explore for self-study:</p>
<ul>
<li><a href="https://v1-9.docs.dapr.io/concepts/" target="_blank" rel="noopener noreferrer">Dapr Documentation: Core Concepts</a></li>
<li><a href="https://docs.dapr.io/getting-started/quickstarts/" target="_blank" rel="noopener noreferrer">Dapr Quickstarts</a></li>
<li><a href="https://docs.dapr.io/getting-started/tutorials/" target="_blank" rel="noopener noreferrer">Dapr Tutorials</a></li>
<li><a href="https://learn.microsoft.com/azure/container-apps/dapr-overview" target="_blank" rel="noopener noreferrer">Azure Container Apps: Dapr Integration</a></li>
<li><a href="https://learn.microsoft.com/azure/container-apps/microservices-dapr" target="_blank" rel="noopener noreferrer">Dapr-enable Azure Container Apps: Using Azure CLI</a></li>
<li><a href="https://learn.microsoft.com/azure/container-apps/microservices-dapr-azure-resource-manager" target="_blank" rel="noopener noreferrer">Dapr-enabled Azure Container Apps: Using Bicep or ARM</a></li>
</ul>]]></content:encoded>
            <category>serverless-september</category>
            <category>30-days-of-serverless</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
            <category>microservices</category>
        </item>
        <item>
            <title><![CDATA[🚀 | Use Custom Handlers For Go]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/zero2hero-func-03</link>
            <guid>https://azure.github.io/Cloud-Native/blog/zero2hero-func-03</guid>
            <pubDate>Mon, 12 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Azure functions support multiple programming languages including C#, F#, Java, JavaScript, Python, typescript, and PowerShell. If you want to get extended language support with Azure functions for other languages such as Go, and Rust, that’s where custom handler comes in.]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 12</code> of #30DaysOfServerless!</p>
<p>Today, we have a special set of posts from our <a href="https://azure.github.io/Cloud-Native/serverless-september/ZeroToHero">Zero To Hero 🚀</a> initiative, featuring blog posts authored by our Product Engineering teams for #ServerlessSeptember. <em>Posts were originally published on the <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/building-serverless-go-applications-with-azure-functions-custom/ba-p/3623617?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Apps on Azure</a> blog on Microsoft Tech Community.</em></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-03#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>What are Custom Handlers, and why use them?</li>
<li>How Custom Handler Works</li>
<li>Message Processing With Azure Custom Handler</li>
<li>Azure Portal Monitoring</li>
</ul>
<p><img loading="lazy" alt="Custom Handlers for Serverless Go Apps by Melony Qin with an illustrated flowchart." src="https://azure.github.io/Cloud-Native/assets/images/zero-to-hero-melony-a4e4f337b95ea7199352808d42961764.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<p>If you have been working with <a href="https://docs.microsoft.com/azure/azure-functions/?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Azure Functions</a> for a while, you may know Azure Functions is a serverless FaaS (Function as a Service) offered provided by Microsoft Azure, which is built for your key scenarios, including building web APIs, processing file uploads, responding to database changes, processing IoT data streams, managing message queues, and more.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="custom-handlers-what-and-why">Custom Handlers: What and Why<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-03#custom-handlers-what-and-why" class="hash-link" aria-label="Direct link to Custom Handlers: What and Why" title="Direct link to Custom Handlers: What and Why">​</a></h2>
<p>Azure functions support multiple programming languages including C#, F#, Java, JavaScript, Python, typescript, and PowerShell. If you want to get <strong>extended language support with Azure functions for other languages</strong> such as Go, and Rust, that’s where custom handler comes in.</p>
<p>An Azure function custom handler allows the use of any language that supports HTTP primitives and author Azure functions. With custom handlers, you can use triggers and input and output bindings via extension bundles,  hence it supports all the triggers and bindings you're used to with Azure functions.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-a-custom-handler-works">How a Custom Handler Works<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-03#how-a-custom-handler-works" class="hash-link" aria-label="Direct link to How a Custom Handler Works" title="Direct link to How a Custom Handler Works">​</a></h2>
<p>Let’s take a look at custom handlers and how it works.</p>
<ul>
<li>A request is sent to the function host when an event is triggered.  It’s up to the function host to issue a request payload to the custom handler, which holds the trigger and inputs binding data as well as other metadata for the function.</li>
<li>The custom handler is a local HTTP web server. It executes the function code and returns a response payload to the Functions host.</li>
<li>The Functions host passes data from the response to the function's output bindings which will be passed to the downstream stream services for data processing.</li>
</ul>
<p>Check out <a href="https://docs.microsoft.com/azure/azure-functions/functions-custom-handlers?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">this article to know more about Azure functions custom handlers</a>.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="message-processing-with-custom-handlers">Message processing with Custom Handlers<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-03#message-processing-with-custom-handlers" class="hash-link" aria-label="Direct link to Message processing with Custom Handlers" title="Direct link to Message processing with Custom Handlers">​</a></h2>
<p><a href="https://docs.microsoft.com/azure/architecture/guide/technology-choices/messaging?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Message processing</a> is one of the key scenarios that Azure functions are trying to address. In the message-processing scenario, events are often collected in queues. These events can trigger Azure functions to execute a piece of business logic.</p>
<p>You can use the Service Bus trigger to respond to messages from an <a href="https://docs.microsoft.com/azure/service-bus-messaging/service-bus-messaging-overview?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Azure Service Bus queue</a> - it's then up to the Azure functions custom handlers to take further actions to process the messages. The process is described in the following diagram:</p>
<p><img loading="lazy" alt="Building Serverless Go Applications with Azure functions custom handlers" src="https://azure.github.io/Cloud-Native/assets/images/melony-processing-42772dfd2586d1ff1cf70e085d3702e6.png" width="999" height="188" class="img_ev3q"></p>
<p>In Azure function, the <code>function.json</code> defines the function's trigger, input and output bindings, and other configuration settings. Note that every function can have multiple bindings, but it can only have one trigger. The following is an example of setting up the Service Bus queue trigger in the function.json file :</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> "bindings": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     "name": "queueItem",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     "type": "serviceBusTrigger",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     "direction": "in",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     "queueName": "functionqueue",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     "connection": "ServiceBusConnection"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   ]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You can add a binding definition in the function.json to write the output to a database or other locations of your desire. <a href="https://docs.microsoft.com/azure/azure-functions/functions-triggers-bindings?tabs=csharp#add-bindings-to-a-function&amp;WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Supported bindings can be found here</a>.</p>
<p>As we’re programming in Go, so we need to set the value of <code>defaultExecutablePath</code> to handler in the <code>customHandler.description</code> section in the <code>host.json</code> file.</p>
<p>Assume we’re programming in Windows OS, and we have named our go application as <code>server.go</code>,  after we executed <code>go build server.go</code> command,  it produces an executable called <code>server.exe</code>. So here we set <code>server.exe</code> in the <code>host.json</code> as the following example :</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  "customHandler": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "description": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "defaultExecutablePath": "./server.exe",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "workingDirectory": "",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "arguments": []</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We’re showcasing a simple Go application here with Azure functions custom handlers where we print out the messages received from the function host. The following is the full code of <code>server.go</code> application :</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">package</span><span class="token plain"> main</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token string" style="color:#e3116c">"encoding/json"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token string" style="color:#e3116c">"fmt"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token string" style="color:#e3116c">"log"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token string" style="color:#e3116c">"net/http"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token string" style="color:#e3116c">"os"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> InvokeRequest </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	Data     </span><span class="token keyword" style="color:#00009f">map</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">json</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">RawMessage</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	Metadata </span><span class="token keyword" style="color:#00009f">map</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">]</span><span class="token keyword" style="color:#00009f">interface</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">queueHandler</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">w http</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ResponseWriter</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> r </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">http</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Request</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> invokeRequest InvokeRequest</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	d </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> json</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">NewDecoder</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">r</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Body</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	d</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Decode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">invokeRequest</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> parsedMessage </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	json</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Unmarshal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">invokeRequest</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Data</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"queueItem"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">parsedMessage</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parsedMessage</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	customHandlerPort</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> exists </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">LookupEnv</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"FUNCTIONS_CUSTOMHANDLER_PORT"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!</span><span class="token plain">exists </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		customHandlerPort </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"8080"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	mux </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> http</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">NewServeMux</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	mux</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">HandleFunc</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/MessageProcessorFunction"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> queueHandler</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Go server Listening on: "</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> customHandlerPort</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Fatal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">http</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">ListenAndServe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">":"</span><span class="token operator" style="color:#393A34">+</span><span class="token plain">customHandlerPort</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mux</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Ensure you have <a href="https://github.com/Azure/azure-functions-core-tools" target="_blank" rel="noopener noreferrer">Azure functions core tools</a> installed, then we can use func start command to start our function. Then we’ll have have a <a href="https://github.com/cloudmelon/cloud-native-serverless/tree/main/message-sender-servicebus/MessageSendToServiceBus" target="_blank" rel="noopener noreferrer">C#-based Message Sender application</a> on Github to send out 3000 messages to the Azure service bus queue. You’ll see Azure functions instantly start to process the messages and print out the message as the following:</p>
<p><img loading="lazy" alt="Monitoring Serverless Go Applications with Azure functions custom handlers" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAX4AAAFECAIAAACvWcJgAAAACXBIWXMAAAsTAAALEwEAmpwYAAAgAElEQVR4nO2dMXLbOPuHvyuk8Hg8zvgS6f6V2/SbJoUKV0nvmdV2nkwaVZlU32R1gS3UZU/gJtt8F/AF9hr/AUgC7wu8AClIChXxeSaza0MkQUrizwBIPPzPHQDAT+c/P79KAACiBwBmgOgBgBkgegBgBogeAJgBogcAZoDoAYAZIHoAYAaIHgCYAaIHAM49ej58/u/Al/W7vOg3a8n/fv5QW12udffujy9xkT/edat8/qh2wi2T1z6UHI/CIciKPn52r3wUCw4L52/Luz++iAN5t/7yZf3bu3U83HDIR+I3te1QtfkOJ++htavG6vFdMd+0fmvyGON2/OcqVv/4eTh28ZGGd0O+w2Gt39Zf5Bbk8R7xy/Dnj38VP77d3X37R/z+593d799fwu//fOvWc8sMP/e4xV6+/969+jL8oBf788fL3+vwW/Lq+u8XV92JcG9yfEPVBz28pfps/eC//fZ5nX3NDo8euWlfb9ybj5+HinVexEOKq7u9/mhHjw6aD5+/fFHfsO6r3G2nO/NPwvgh3KU7oF6Kx+VOCbdQ/XxO4vUIqDPTHU73DbDe4fRDKe1qmhd5jerPT/9hxW+eWODD58+fh+pk9IR9KJ0ScR/y6DnVl8GFwI+X7yESQnD0/P79pQ+I9fcXH0Z+mZcXl1OB9d8v/xrR8+PHP/0qWfR8+/Hvy8tLrOuk0fPh83+/fPlixkT4MhejR3yFCl+z40VP+KTF3vS7ElIp8O6P7pDC6vLbPBY9nz+oZdx3dN1tJ6/oWEw4hMnR4w529ugpJaDc7bhL9q7+5v5faU3YqZGsMrxjrtaP/S515f7tdVGlN2KWDPtzdtHj0qHLjm///PiW5MjL9+8xcV7iD3+6vOrXl6v4n8MGTxw9/mtgfsSxQToePeHzPWH0hHhTrZ7+W2V9BXUvpHAwqp3mN+JrjGd4dxrLs8Vu9x9I7RD2jZ7h9Js5ekQCpu9w9qGYuzqEb4nwRRRV5qsMX+7u/YkRH77fXb9JtXLSzfafTqXDdfxvRBI9oX/lE0S1emS4fPsxZEqXGipxfo8/uAZRtwURPf0yv7tNrk8dPTH6k3Zr6Q9qsdUTGs55Z/9IYz3DpxuLRMnoeRu+lBM6XOt3w2kzfNv0+e+/c8ccJTlO9KTv1PlET6nDFT6UsegZhm/UX8iW6Invg/jTOnxxuwX2iZ4ZWz0yicQyQ1isv/vOVyl67kJmxegJNcY4O130hNMw+ciS03N0rEcOKZ6sw5XujWsGmXtv91bSr2Bpj/tVui3EutLdyNP6IGqHIM+ESR0uc5tzdLiMxlfWiRbvdrqrycha2ji3PoJ8ME52uMJYmG/YFkIq3+z5drhi4yVpswyBUo6eu2RJPzAUCYUniR59RSL+Rck+FP0nOWv1iP71z4we+V0cH6Pds9UzjDfHn08bPeVDkOOmyTDESPSo4VI9CHLy6PHfLWsI2f5QCruajRnn4zgxad6tP3fBURpmVslrDHCG7f9Kw8yuLxaGmUO4hKHiWvTc+XGil25kJ7Z0+tp9x+1E0ZO1dMRYR7akuobVv+GjDedTR0+yN8aVzvq1eXfA2bVbdVTDwcSm0OgFvAMwD6Fw9XdK9Kgd1n2hE0WP/ENWvDpuH2ZhV+0r5ZF4FVyOsme99PT9CQlV2L64uK6DTOy5Ot6jh1BprMe3R0T0dJelvv+umzNJU6gQPXf+Alm/QVFdSDTZFJLX4A8j+7PtW6byxJRvqXU7i/zm93+Px27CcHBLIQDMANEDADNA9ADADBA9ADADRA8AzADRAwAzQPQAwAwQPQAwA0QPgMG/vwh3vyxEDwDMANEDADNA9ADADBA9ADADRA8AzADRAwAzQPQAwAwQPQAwA0QPAPwK0fP28WvPp4fT7BL8KsTvwuPb6oKr3au/nm/u716vn1/9tftp+3e+rHhDmqLn08MbVfTm4ZP1FTRKzSULq5tYi8owfDNh93Vo5rXH7X1NXslrF2uP7b99mFN3Xu7U3qsnexnfgfLq3SrdYvnq+jgfPu0fPffbq7/+d7V+371+u/nf+UaS39VX/t/1Ki3p/223w9JP1+rXoaT/Nxzjiug5RvQ8fBoK3De5/9n9KE7lrtRc0iwsVW1tM6wjXi+v/+BXqO/88JL63az9TVx/hMKxT975gAuCA1YXi1ZWd2ny6D5pa+30iMejx52r/qxb7frT0v3wfLV58i8/XW+f+wXOjvc3WxeaMi8SXG52B+IW2N2sn0X0vL/ZDoEll7zP3pDlcYxWj3rRfwvF6RFOFnvJ8cIBc5t6DVdYXP/to98Ha2fs2o36siMqR49vUNg7M1RU2/n66r7OPY59v9X7Y/ULJiubxzu1Zslq92qzvdn2p9/16um6P6vdudq3Efpg0oUxocYKk5ZI/FepqI7bTsgRUdht8Ona1+hadqrqmFbupal1XT6niR75re0b9cmXc//osbapCpNlCjRGT+GIDo2e4s6XVw+L7X/sKmJKq4eQzTdYiLfW6Hl6vX6+Xt3dbna3wyka2wU+GroemXnGFgp3w3keV9dtjT47zIoaoiffDR09oi8paocjR0/Xk4gL9WMEj2+zleKS5uqVivU2dV5k4zj7RE9eex49+RGpYZBp55+oaL+dD1XJVfY6dv3p2avHJbLoKUVMQ/T0Z+z99mqzu3anrose/1/R7Ro6I+bg9OiI9RAKMi9CytgV1XEhki6mGjWx3mQx1xELrS04dvT4k1B9k/VgbDKsnH5X08L8nC5tU15mefvYv16OBDN6zF1Ko6d8RGH50VMwrcjc+THiju25enrs+epJ425aq6o9euJQiBtSqQzf+raD+yebJ0ZhsoWhCtHq8ed/bZy4vMNm/GUrGq2eMLyl93/hHCd6/BklivXIiPzWpkuWC1PK25SLjA765tFTqr0y1lOqvX4K1g9z+oi1WdGE1Wv92W514+JeDP7i5tuiR5+ELiDi4GsR14TJzt5QqF4NXaGQUPHMH68o3VurzWIO/ejoCWHX4cehp9d72RwheswzqisLP4frQY25U96m2s7EwQ6xWKX2pIp67XZ7Jm3G1XJH7/yEoaLK6vLSeLGKsZf0H4zKJ3S06JEtFBtzXEZ2o/T1765PZ5ztoxWpXTX7SmaTx4oefYVrqdezThE92V9KcX7qe0bMJYurm2TbNO/0GVl3Yu15vtRqT5dNssOuqLzzafSYHcji6nn0WF3KkbdODTwnqBUaoud2kySI7HkljRRVIseGs8IuJvprXjdWq0d0efKKTJKrY0N2GGPGepfCkv1Az6Ru3aI47hUuWCItV7h+GkmrJ+kBwXwQPXDR0aOHV5jJcT4whwtOP4drVnSHi1Hec4GZ6wAwA0QPAMwA0QMAM0D0AMAMMMwMzaAKa2WFrwdVGKoweUOkKRVDFbaHKmx4Vd/QrFYnejyowlCFFad3WaWowtJ3Sfg3htuyN2EqfME0do8qDFVY+URbrCosXVKAKqysCosTuF7bFg57uuliQRUWQBWWTTc1poahCiurwsIsDaJnAqjCelCFZVPnpzqYUYWlc2Kt6GHaegKqMAeqsMQ0Zmg0UIXVVWEybrLoYe5YDqowVGH5IE4+vowqbEQVlqg55CWtkvFn4aAKQxVm6dOycR9UYRNVYUmrh9wpgSoMVZhu4eSdT1Rhk1RhZvQUTGOArwcu3NeDKuxcQRUGFx09qMLOFeZwQTOowqAdZq4DwAwQPQAwA0QPAMwA0QMAM8AwMzSDKqyVFaowVGGowtJnp07wh+lr6eMX1/Mzzd+SF5756WchnOtjag5ThckJFqjCJKjCUIWpSVtj/jBUYXupwu7sB5/eowpDFaZOqsWrwsb8YajCDlOFMYk0giosgCrsITVjJL+iCjtEFWbn0XJBFdaDKsynjMxfP+gjogdVWJYdU1RhrguWjvUAqrAOVGFRFVbyh6EKO0AVFjIojKwDqjBUYcVBHFGIKqxdFWb3zhYPqjBUYZYOVReiCmtWhQl4IoUCVRiqMHVhzyhEFdauCosDPYz1JODrgYv29aAKO1eIHrjo6EEVdq4whwuaQRUG7TBzHQBmgOgBgBkgegBgBogeAJgBhpmhGVRhraxQhaEKW4IqrLwBc5/SQlRhB6jC5ANI4wSuFdGDKmwZqjB5601Y1Dwis1CAKmwvVZicMiomUtyjCkMVtghVmMqLfknziAqHGUAVtp8qLL+hkemjA6jCFqEKi5sLfhDriEqH2YMqbF9VWDKPFFuYAFXYYlRhfZRoDYY+otJhhh0wD7FhIkV/xt5vrza7a3fquraD/+8uP1GjTD7ZQtUkP4SCnC8euj92RXWaVGGydj/og6jw6NGjbFvJH0z919L0cqWF+Tld2qaptipHQlEQke1SGj3lIwrLj56CaUUlL1eVuGOTV49512fUG/OIaoeJKqxNFeb6XN0w8+52taPDFUAVtgBVWL7zXx/tIyoeJqqw46jCsBQGUIUtQBWm9y20gMwjMgtRhR2uCqstv0hQhWm0BT2JitCLC+WiX5csm2RHdrNQOPntcaI0eswOZHH1JHqS+vUx5nufFqIKO4oqjGtbGnw9cNG+HlRh5wrRAxcdPajCzhXmcEEzqMKgHWauA8AMED0AMANEDwDMANEDADPAMDM0gyqslRW+HlRhqMKymxJRhSkOVYVZhSuiB1UYqrCh/YIqzOL9zXaYRTHkxT6qsELhPaowVGERVGGowuqo+aKTVGHlQkAVFkAVhirs2KqwUiGgCgugCkMVdgJVmF0IqMJ6UIWhCqvHQaMqrOQPA1RhFZMOqjBUYQeqwqb4wxYLqjBUYQ5UYadWhdHqSUAVhioMVZh4OF/KgaqwscIFg68HLtrXgyrsXCF64KKjB1XYucIcLmgGVRi0w8x1AJgBogcAZoDoAYAZIHoAYAYYZoZmUIW1ssLXgyoMVZjx/FKfKfq5yQp9LX384np+pvlb8sKNfH7CQTpD6pdThfmj0xMmSlKxFdGDKgxVmFaFde6Qh/QZ8AE3wT2Z7zYePbkZy/3wfNXrJp6ut8/9Ar+yKuz1+rl8V7Ra8g5VGKowAaqwB/cm+MR5U4ieNzGqD7ulcLV7tdnebPs8ul4F+4T5kHJRGBNqrDDOWkgmQ1QqOkgVNhY9yrABqMICqMJigNjR88YOmdboeXq9fr5e3d1udrfDaSlkoy4aujNZ6bgGCoW74dyOq+u2Rp8dZkUHqsLq0WPu8JI5ZvRE21a3UD9G8Pg2Wyn3cpUK04r1NnVe6BGKAqW/56jC5GdkvkuliGmInv48vN9ebXbX7oR00eP/K7pdQ++s6Mqp9tGGU13mRUgZu6IDVWFqrCdNGZo8J4seZdvqL30Mv+q/lqaXKy1UQ5u+vLRNeZnl7WP/er76Xe2kQhVmfEbJu+Q/ePMr0R49nS991Q+pVJ70EMQ3sllhFCZbGKoQrR6fFPVHSrSpwhSi0pEll8txoie1bXXf3DfGt9b0cpVkXdlC9jblImNbMU4qVGH5+5m9S5XGbmP06L6JO1fTWeYGrgmTdWpCoXo1dHCkr6t/dbyivVVhxioxempLLhZUYajCHDrX0+ipZ/rRoidrLGSY4zKyG6Wvf3d9OiNlRis6TBWmbT40eUxQhaEKU6qw9B6e/gk5tRt7GqInytJ7ZM8raaSoEjk2nA+siNGW3Y3V6hG9s7yiA1VhcoMiqupSsQWDrwcu2teDKuxcIXrgoqMHVdi5whwuaAZVGLTDzHUAmAGiBwBmgOgBgBkgegBgBhhmhmZQhbWywteDKgxVWHKTYP6GoAqbpgpLbkFEFXby+3pM25aYUR5LzSUrsq68amubYZ3UemGun0iwUIVN+Yyqnz+qMEPKYYIq7PS+Hj3V05osbsZENTvMbeo1Cj6ZYeNVCRaqsCmfEaqwiirsdlOfMIE3Q4EqLIAqLMmZLHpQhdVUYT5Z1rtMnJgvCceOHlRhE9/AoX2xn+csjMHIVfbQpPWDwqI/tafODVVYTRUW5srbXjGaPCmowhyowsZ1bqjC6qowY55q/BVvRg6qMFRhU3RuqMJGVWG6XaOiB1WYAaowVGGOMIZf0kiiCkvIGzJCNa9+psljgioMVVgyAoQqrE0VVnjADqqwAvh64KJ9PajCzhWiBy46elCFnSvM4YJmUIVBO8xcB4AZIHoAYAaIHgCYAaIHAGaAYWZoBlVYKytUYajCUIWhCqtziCpMP/s03oK4InpQhZXNWMljyE1RWX2GgaSgSZvsObO8RdNXl7fehEWn69wEqMLqArCysse9Kqe579wPq13xwe2XDqqwab6egvysHD2+M2KHwVBRzXNWX93XuZcmLdn5x7dtOjdUYajCjgWqsACqMFRhdQ5ShS25gWOCKqxmxoqtgoJYSxnTp80mQBUWz9j77dVmd+1OXXfe+v/u8nO16MrJT+9kgX7LIS/c9M6r9ftSRXVaVWFxTmlVn7o4UIU5UIWhCqufJweqwnTwwfGiJ5W87KehKsq6soXsbcpFRgd980GNUu2VsZ5S7fWGT/0wp49YmxXVVs93/uvjnp8RqrBDVGE96JklqMJQhTlQhZ1OFTaAq1CBKgxVGKqw06nCRAljPRp8PXDRvh5UYecK0QMXHT2ows4V5nBBM6jCoB1mrgPADBA9ADADRA8AzADRAwAzwDAzNIMqrJUVvh5UYajC9NxX+fjRvkzNkTUmyo5fXM/PNH9LXriRz/u0anNBfwlVmD868wZCf1+ivPV5RfSgCkMVVtKCJZO8elCFpdEU5ky8Xj8bd0X7G4tuklkX96jCUIWpkwpV2EjKoAqrqMKs6Hm6Dg0iZD0aVGEBVGG625TPzi/MzW+5m3m1e7V5er1+vl7d3W52t8MJLGZdRsWEOeG7ULgb5nnG1U2BqVnRYaqwQqsnLEb0aFCF9aAKC22cMLSTBEopYhqi5wJVYclYj45FoicHVZgDVZjZosk9jcY36JDo8Vngc+H9zfa58qSH8FwH2awwCpMtDFWIVo9PitojJVpVYQpR6ciSywVVGKqwKfIzVGGjqrBaf5DoyUEVhirMYV3NioNfdYNiW6tHD4u4ZkLeWMgwx2VkN0pf/+76dEa/bLSiFlVYJLP5ED05qMJQhUlVWBzoqd3Xo6OmIXpuN0mCyJ5X7Af5ZVSJqeCSA73hgRDuerYvlw/hE72zvKIDVWFygyGq9H5O6NktB3w9cNG+HlRh5wrRAxcdPajCzhXmcEEzqMKgHWauA8AMED0AMANEDwDMANEDADPAMDM0gyqslRW+HlRhqMLMqaLd29JNrUAVNkUVVpsXhirsNPf1mLYtYaCIpeaSFVlXXrW1zbBOar0w13/wK9R3fnhJ/W7WXp9hMPou7bHzlsFr+ury1puwqHlEcflHc74oqrD0HbEery4KUYX9VF+PFtx1v9lLjhcOmNvUaxR8MsPG/T5YO2PXbtSXHVE5enxnxN6ZoaLaztdX93XudezJzj++rXxG/SuFCaX58bb6erY3Wz+7arW7XgX7RP7Y8mQ6wm5qYdLoiP8qFdUx54sqb0ZWiCqsCKqwAKowHyAhklCF7akKqxQyfTQHVVgPqrCuZRQbSFn0oAqrq8IqhURPDqowB6qwrhum4iaJHlRh01Rh0wsXDqowVGExWeSTcLQgA1XYRFWY7Q8jenJQhaEKK6jCRDMHVdhEVVgpYoieHFRhqMKUKsyIHlRhk1Rho/4wVGEKfD1w0b4eVGHnCtEDFx09qMLOFeZwQTOowqAdZq4DwAwQPQAwA0QPAMwA0QMAM8AwMzSDKqyVFaowVGGowlCF1ZmoCssEHcO9hbEkPuN0RfSgCkMVNrRfUIVZvL/ZDrMohrwoWsEKdzMPiZM8En7Xb3Op00pRhQVQhaEKO0gVdrvJXs1vaJyqJbt8UIUFUIWhCjtEFeYzaL1T4sSkUbPgNk4OqrAeVGGowuqMqMK6AaChUTMsLNMqk8MvG1RhDlRhqMLq58m4KsyYpzo0fIZ20K0zUtPh6kEVhirMgyrsUFWY9qImSTRsJ17kWjyowlCFOVCF7Zk7hv1LPhUnf0IOtrAEVGGowlCFiTtuUvZRhRkP2Gl45M5SwNcDF+3rQRV2rhA9cNHRgyrsXGEOFzSDKgzaYeY6AMwA0QMAM0D0AMAMED0AMAMMM0MzqMJaWeHrQRWGKkyrwpJHjbri/Omj+lr6+MX1/Ezzt+SFG/ncvb/ZtINLUYVZhSuiB1UYqjCtCqs/Xr2f66VfH4+e3Izlfni+CrqJ7XM+4+kiVGGVwl2/zaXOZUcVFkAV9jAaPearLbcUujnc25ttf/pdr8LcS3PmgXxy+W5qodUS8f8qFR1bFVYoBFRhElRhfe+qGD1v7JBpjZ6n1+vn69Xd7WZ3O5zAYtZlVIuacr9C4W5olcTVzVaJWdHxVWF2IThQhfWgCut6UmpgZ9qYTkP09Gfs/fZqs7t2p647Rf1/xck5dEaKrpzqmTyEgsyLkDJ2RcdXhdn+MHCgCnOgCjNbNC6FQpmPJvOkaY8enwU+F9yQSmX41o9D64c6mIXJFoYqRKvHJ0VtnPioqrCSPwxQhQ25Y3QylMLGLSSWsc7DQndkvKLwanV8d6SisY6S3vmvj3sekTG6fGD06D6OC4gJZ6ZrwmSdo1CoXg1doZBQMaR+nips3B+2WFCFoQorqMJEU7Aei0eLHtlCsTHHZWQ3Sl//7vp0xtk+WtHRVGF1f9iSQRWGKkypwsRQz1CW39ejo6Yhem43SYLInlfSSFElhoJLDKb4mOgHdG+sVo/oneUVnUIVhi2sCL4euGhfD6qwc4XogYuOHlRh5wpzuKAZVGHQDjPXAWAGiB4AmAGiBwBmgOgBgBlgmBmaQRXWygpfD6owVGHGTYI6U1CFHaQKkzclDvdVr4geVGGowoas6W9eNqfSqlRCFTZdFRbu0s6X3PUZtNS57KjCAqjC3PTRt4+1+wNRhe2pClPTR03H0GI5TfTIadB94z35PqfneblQVZxsM51vXRY7BLoJ27WdH1AzKgtHVJ5X6ReyD8Z6l9KdL68eFtvn2OPmQqPGfD+70gfV34qgCttbFSa00/a0r+WCKqwHVdjj10/9sM4QOMl7gipsb1VYHNkJYlboQRXmQBXWtWjSdo38FVVYgypMZpAPoGkm1kVwnOhJJVhlDZWpy6o7tEa3uZdtK+9woQoT76f+eGP0oAprUoUFL6I1l3XhoApDFeYIuS5HvMLPqMIaVWF6fAc3swRVGKowpQpTtrDgKEQV1qwK6wd6JhmgFwW+HrhoXw+qsHOF6IGLjh5UYecKc7igGVRh0A4z1wFgBogeAJgBogcAiB4AWAYMM0MzqMJaWeHrQRWGKgxVWJ2JqrCCP0w++zTegrgielCFoQob2i+owize32yHWRRDXiSYT1I3CuV8rntUYajCIqjCUIXVSeaLhkJzZunEwuWCKiyAKgxV2N7RY4oHbRvhgl2oJqjCelCFoQqrY807n9K6iXNKURRKUIU5UIWhCrurMq4KqxaGDEIVFkAVhirMgyrsUFVYpVBsBy38AKowVGEOVGF75s6+TZ6RVFogqMJQhaEKq/SD9lGFFZ7DZdzXA/h64MJ9PajCzhVUYXDR0YMq7FxhDhc0gyoM2kGaAQAzQPQAwAwQPQAwA0QPAMwAw8zQDKqwVlb4elCFoQqrP2j004NRqK+lj19cz880f/dduJHP+7R+cVVYdgtit7A/5OyuwhXRgyoMVViiCqtoRPqydMHx6MnNWO6H56t+QtPT9fa5X+CXVoVZtzi/Xj8bt0rfowpDFRZBFfYwmjJvYlQfdkvhavdqs73Z9nl0vQqiCeux5Wo6wm5qodUS8f8qFR2kCrvdGFMl7OgBVGECVGEqQN7kiWIUHRI9T6/Xz9eru9vN7nY4gYVXNCompuu4Xq93Q6skrm62SsyKDlOF+UNY75I0JHpKoArrQRWm2zh7dKwaoqc/Y++3V5vdtTt13Xnr/yu6XUPvrOjKqfbRhlCQeRFSxq7oIFVYNwA0pGFYWI31YMwQoApzoApLWjRG/6sX+hw1enwW+FxwQyqV4dvwXAfZPDEKky0MVYhWj0+K2jhxqyrMmKeaLC/2BFCFDbmTj2BEhc2wkFjGOg8L3ZHxisKrxdcmVFRbPd/5r4/VI8rHl41G0IHRo/s47rS0TtcE14TJOkehUL0aukLycTT9q+MVNajCtBfVqgJVmARVGKowh8yhvMlTj8WjRc94u8Acl5HdKH39u+vTGSlzElWYfABO4WE4KHsiqMJQhWlVWN75zO/r0a83RM/tJkkQ2fNKGimqRI4N52MoYmBld2O1ekTvLK/oYFWYcdVM1sKTcBT4euBQztrXgyrsXCF64KKjB1XYucIcLmgGVRi0w8x1AJgBogcAZoDoAYAZIHoAYAYYZoZmUIW1ssLXgyoMVVh6k2AMlL4UVdgUVVhxXphl51gRPajCUIUNcdPd0Cxv0kEVtp8qzCoUr4opZveowlCF6e6DvDWuMn00zHIqT27ybQf7TruhIl2hnhRaX93XWVu9sIpc0j4ia0kBqrCKKswoDHPlC9O+lsxx72YWJ1WYf9i335PTwvqDaheqipNtpjPIy2KHu4oOolC7OjULR3Ro9BR3vrx6WGyfY4+bC1O0CkdkLBlAFVZThVmF0gTkGk1nrKD+6aAK60EVFv+m9EmEKmwfVZhZ6KPndT8MFGWMgCqsB1VYaNHECPYBZLf7NKjCJKpXlbR09vQEXTbHafWkEqyyhsrUZdUdWqPb3Mu2ZcpoUIX176clFfNdLlRho6owq1CP9Uw0sS4EVGGowhx95OjmX2gBoQqbogqzCv2VdXGVnadTBFCFoQrT4zrytp6ueYgqbKIqbMwfRu5I8PXARft6UIWdK0QPXHT0oAo7V5jDBc2gCoN2mLkOADNA9ADADBA9ADADRA8AzADDzNAMqrBWVvh6UIWhCiurwvr7DFGFHaQKk7PTu1QAAAGESURBVM8vHSZwrYgeVGGowjJVmJzAbolNps5oj+RmLPfD81VwaG2fL1QVFh7orJe8RxWGKiyCKuxhVD+GKmw/VZh+1ZT7LBZUYQFUYWPqNVRh+6rCupZO16CzZ3gtF1RhPajCHr9+0vnbC3tGO1btvp777dVmd+3OUtc68P8V3a6hd+YWzrpjZqFRhbJYhLnjdkXHV4WF7buBHiRhp4kepVtIpKj6r6Xp5UoL1dCmLy9tU15mefvYv56vLjdsiX7yXUoFqeUjCsuPnoJpRebOjxF3bPLqhgBsr/cTVVgp/sa8GTGwfAAxeT2AKgxV2BT1GqqwI6nCznQ0fQZQhaEKc2g7Ydo8RBXWqArT4ztWl225HB49/yfUUsIvZWio3lpLmoVFsm3GktHeiuyDTak9PxtrtafLJo+UsCsq73z6RAqzA1lcvetvJgPGhWMcfz9RhR2iCusHeuSdPuDA1wMX7etBFXauED1w0dGDKuxcYQ4XNIMqDNph5joAzADRAwB3P5//ByGmE+9/bVhzAAAAAElFTkSuQmCC" width="382" height="324" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="azure-portal-monitoring">Azure portal monitoring<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-03#azure-portal-monitoring" class="hash-link" aria-label="Direct link to Azure portal monitoring" title="Direct link to Azure portal monitoring">​</a></h2>
<p>Let’s go back to Azure portal portal the events see how those messages in Azure Service Bus queue were being processed. There was 3000 messages were queued in the Service Bus queue ( the Blue line stands for incoming Messages ). The outgoing messages (the red line in smaller wave shape ) showing there are progressively being read by Azure functions as the following :</p>
<p><img loading="lazy" alt="Monitoring Serverless Go Applications with Azure functions custom handlers" src="https://azure.github.io/Cloud-Native/assets/images/melony-monitoring-1430568906cea1cff64b9a49f40419e0.png" width="998" height="301" class="img_ev3q"></p>
<p>Check out <a href="https://docs.microsoft.com/azure/service-bus-messaging/monitor-service-bus?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">this article about monitoring Azure Service bus</a> for further information.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="next-steps">Next steps<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-func-03#next-steps" class="hash-link" aria-label="Direct link to Next steps" title="Direct link to Next steps">​</a></h2>
<p>Thanks for following along, we’re looking forward to hearing your feedback.  Also, if you discover potential issues, please record them on <a href="https://github.com/Azure/azure-functions-host/issues" target="_blank" rel="noopener noreferrer">Azure Functions host</a>  GitHub repository or tag us <a href="https://twitter.com/AzureFunctions" target="_blank" rel="noopener noreferrer">@AzureFunctions on Twitter</a>.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>RESOURCES</div><div class="admonitionContent_BuS1"><p>Start to build your serverless applications with custom handlers, check out the official documentation:</p><ul>
<li><a href="https://docs.microsoft.com/azure/azure-functions/functions-custom-handlers?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Getting started with Azure functions custom handlers</a></li>
<li><a href="https://docs.microsoft.com/azure/azure-functions/create-first-function-vs-code-other?tabs=go%2Cwindows&amp;WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Create a Go or Rust function in Azure using Visual Studio Code</a></li>
</ul></div></div>
<p>Life is a journey of learning.  Let’s stay tuned!</p>]]></content:encoded>
            <category>serverless-september</category>
            <category>zero-to-hero</category>
            <category>azure-functions</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
        </item>
        <item>
            <title><![CDATA[🚀 | Journey to the Cloud With ACA]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/zero2hero-aca-04</link>
            <guid>https://azure.github.io/Cloud-Native/blog/zero2hero-aca-04</guid>
            <pubDate>Mon, 12 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[In this article, we discuss how Azure Container Apps is purpose-built to support Cloud-Native applications.]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 12</code> of #30DaysOfServerless!</p>
<p>Today, we have a special set of posts from our <a href="https://azure.github.io/Cloud-Native/serverless-september/ZeroToHero">Zero To Hero 🚀</a> initiative, featuring blog posts authored by our Product Engineering teams for #ServerlessSeptember. <em>Posts were originally published on the <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/journey-to-the-cloud-with-azure-container-apps/ba-p/3622609?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Apps on Azure</a> blog on Microsoft Tech Community.</em></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-04#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>Using Visual Studio</li>
<li>Using Visual Studio Code: Docker, ACA extensions</li>
<li>Using Azure CLI</li>
<li>Using CI/CD Pipelines</li>
</ul>
<p><img loading="lazy" alt="Anthony Chu presents Azure Container Apps, guiding you on building cloud-native apps for scalable deployments." src="https://azure.github.io/Cloud-Native/assets/images/zero-to-hero-anthony-2bc58afc7d6bdff1e92a0c3b87ae02cc.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<p>Last week, <a href="https://techcommunity.microsoft.com/t5/user/viewprofilepage/user-id/296868?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">@kendallroden</a> wrote about <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/go-cloud-native-with-azure-container-apps/ba-p/3616407" target="_blank" rel="noopener noreferrer">what it means to be Cloud-Native</a> and how Azure Container Apps provides a serverless containers platform for hosting all of your Cloud-Native applications. Today, we’ll walk through a few ways to get your apps up and running on Azure Container Apps.</p>
<p>Depending on where you are in your Cloud-Native app development journey, you might choose to use different tools to deploy your apps.</p>
<ul>
<li><strong>“Right-click, publish”</strong> – Deploying an app directly from an IDE or code editor is often seen as a bad practice, but it’s one of the quickest ways to test out an app in a cloud environment.</li>
<li><strong>Command line interface</strong> – CLIs are useful for deploying apps from a terminal. Commands can be run manually or in a script.</li>
<li><strong>Continuous integration/deployment</strong> – To deploy production apps, the recommended approach is to automate the process in a robust CI/CD pipeline.</li>
</ul>
<p>Let's explore some of these options in more depth.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="visual-studio">Visual Studio<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-04#visual-studio" class="hash-link" aria-label="Direct link to Visual Studio" title="Direct link to Visual Studio">​</a></h2>
<p>Visual Studio 2022 has built-in support for deploying .NET applications to Azure Container Apps. You can use the familiar publish dialog to provision Container Apps resources and deploy to them directly. This helps you prototype an app and see it run in Azure Container Apps with the least amount of effort.</p>
<p><img loading="lazy" alt="Journey to the cloud with Azure Container Apps" src="https://azure.github.io/Cloud-Native/assets/images/anthony-create-new-3b4fb5406c400d538bab76fe7afe145f.png" width="400" height="306" class="img_ev3q"></p>
<p>Once you’re happy with the app and it’s ready for production, Visual Studio allows you to push your code to GitHub and set up a GitHub Actions workflow to build and deploy your app every time you push changes. You can do this by checking a box.</p>
<p><img loading="lazy" alt="Journey to the cloud with Azure Container Apps" src="https://azure.github.io/Cloud-Native/assets/images/anthony-deployment-type-7bdc05a874a9ccd029d95d29f291fa21.png" width="400" height="281" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="visual-studio-code">Visual Studio Code<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-04#visual-studio-code" class="hash-link" aria-label="Direct link to Visual Studio Code" title="Direct link to Visual Studio Code">​</a></h2>
<p>There are a couple of valuable extensions that you’ll want to install if you’re working in VS Code.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="docker-extension">Docker extension<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-04#docker-extension" class="hash-link" aria-label="Direct link to Docker extension" title="Direct link to Docker extension">​</a></h3>
<p>The Docker extension provides commands for building a container image for your app and pushing it to a container registry. It can even do this without requiring Docker Desktop on your local machine --- the “Build image in Azure” command remotely builds and pushes a container image to Azure Container Registry.</p>
<p><img loading="lazy" alt="Journey to the cloud with Azure Container Apps" src="https://azure.github.io/Cloud-Native/assets/images/anthony-vscode-docker-6ea4d15571d8ece1448056dc390e467f.png" width="400" height="170" class="img_ev3q"></p>
<p>And if your app doesn’t have a dockerfile, the extension will generate one for you.</p>
<p><img loading="lazy" alt="Journey to the cloud with Azure Container Apps" src="https://azure.github.io/Cloud-Native/assets/images/anthony-vscode-dockerfile-139bab8d59d5b6c201294b5bc8a24b5a.png" width="399" height="54" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="azure-container-apps-extension">Azure Container Apps extension<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-04#azure-container-apps-extension" class="hash-link" aria-label="Direct link to Azure Container Apps extension" title="Direct link to Azure Container Apps extension">​</a></h3>
<p>Once you’ve built your container image and pushed it to a registry, the Azure Container Apps VS Code extension provides commands for creating a container app and deploying revisions using the image you’ve built.</p>
<p><img loading="lazy" alt="Journey to the cloud with Azure Container Apps" src="https://azure.github.io/Cloud-Native/assets/images/anthony-aca-extension-420d267387b72d29143f03f8833da305.png" width="399" height="199" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="azure-cli">Azure CLI<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-04#azure-cli" class="hash-link" aria-label="Direct link to Azure CLI" title="Direct link to Azure CLI">​</a></h2>
<p>The Azure CLI can be used to manage pretty much anything in Azure. For Azure Container Apps, you’ll find commands for creating, updating, and managing your Container Apps resources.</p>
<p>Just like in VS Code, with a few commands in the Azure CLI, you can create your Azure resources, build and push your container image, and then deploy it to a container app.</p>
<p>To make things as simple as possible, the Azure CLI also has an “az containerapp up” command. This single command takes care of everything that’s needed to turn your source code from your local machine to a cloud-hosted application in Azure Container Apps.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp up --name myapp --source ./src</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We saw earlier that Visual Studio can generate a GitHub Actions workflow to automatically build and deploy your app on every commit. “az containerapp up” can do this too. The following adds a workflow to a repo.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az containerapp up --name myapp --repo https://github.com/myorg/myproject</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="cicd-pipelines">CI/CD pipelines<a href="https://azure.github.io/Cloud-Native/blog/zero2hero-aca-04#cicd-pipelines" class="hash-link" aria-label="Direct link to CI/CD pipelines" title="Direct link to CI/CD pipelines">​</a></h2>
<p>When it’s time to take your app to production, it’s strongly recommended to set up a CI/CD pipeline to automatically and repeatably build, test, and deploy it. We’ve already seen that tools such as Visual Studio and Azure CLI can automatically generate a workflow for GitHub Actions. You can set up a pipeline in Azure DevOps too. This is an example Azure DevOps pipeline.</p>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">trigger</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">branches</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">include</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> main</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">pool</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">vmImage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">stages</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">stage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Build</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">jobs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">job</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> build</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Build app</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">steps</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">task</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Docker@2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">inputs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">containerRegistry</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'myregistry'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">repository</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'hello-aca'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">command</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'buildAndPush'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">Dockerfile</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'hello-container-apps/Dockerfile'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">tags</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'$(Build.BuildId)'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">stage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Deploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">jobs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">job</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> deploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Deploy app</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">steps</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">task</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> AzureCLI@2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">inputs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">azureSubscription</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'my-subscription(5361b9d6-46ea-43c3-a898-15f14afb0db6)'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">scriptType</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'bash'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">scriptLocation</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'inlineScript'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">inlineScript</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token scalar string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">          # automatically install Container Apps CLI extension</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">          az config set extension.use_dynamic_install=yes_without_prompt</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token comment" style="color:#999988;font-style:italic"># ensure registry is configured in container app</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          az containerapp registry set \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">name hello</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">aca \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">resource</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">group mygroup \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">server myregistry.azurecr.io \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">identity system</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token comment" style="color:#999988;font-style:italic"># update container app</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          az containerapp update \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">name hello</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">aca \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">resource</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">group mygroup \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">image myregistry.azurecr.io/hello</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">aca</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">$(Build.BuildId)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Conclusion</p>
<p>In this article, we looked at a few ways to deploy your Cloud-Native applications to Azure Container Apps and how to decide which one to use based on where you are in your app’s journey to the cloud.</p>
<p>To learn more, visit <a href="https://azure.microsoft.com/services/container-apps/?WT.mc_id=javascript-99907-cxa" target="_blank" rel="noopener noreferrer">Azure Container Apps | Microsoft Azure</a> today!</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>ASK THE EXPERT: LIVE Q&amp;A</div><div class="admonitionContent_BuS1"><p>The Azure Container Apps team will answer questions live on <strong>September 29</strong>.</p><ul>
<li><a href="https://reactor.microsoft.com/reactor/events/17004/?WT.mc_id=javascript-99907-ninarasi" target="_blank" rel="noopener noreferrer">Sign up to attend</a> for live Q&amp;A with the team</li>
<li><a href="https://github.com/Azure/Cloud-Native/issues/new?assignees=&amp;labels=ask+the+expert&amp;template=---ask-the-expert-.md&amp;title=%5BAsk+The+Expert%5D++" target="_blank" rel="noopener noreferrer">submit your questions</a> ahead of time, for prioritization.</li>
</ul></div></div>]]></content:encoded>
            <category>serverless-september</category>
            <category>zero-to-hero</category>
            <category>azure-functions</category>
            <category>azure-container-apps</category>
            <category>dapr</category>
        </item>
        <item>
            <title><![CDATA[11. Scaling Container Apps]]></title>
            <link>https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps</link>
            <guid>https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps</guid>
            <pubDate>Sun, 11 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[<FIXME>]]></description>
            <content:encoded><![CDATA[
<hr>
<p>Welcome to <code>Day 11</code> of #30DaysOfServerless!</p>
<p>Yesterday we explored Azure Container Concepts related to environments, networking and microservices communication - and illustrated these with a deployment example. Today, we turn our attention to <em>scaling</em> your container apps with demand.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2>
<ul>
<li>What makes ACA Serverless?</li>
<li>What is Keda?</li>
<li>Scaling Your ACA</li>
<li>ACA Scaling In Action</li>
<li>Exercise: Explore <a href="https://aka.ms/oss-labs" target="_blank" rel="noopener noreferrer">azure-opensource-labs</a> examples</li>
<li>Resources: For self-study!</li>
</ul>
<p><img loading="lazy" alt="Event slide featuring Paul Yu discussing Azure Container Apps scaling with KEDA, including serverless features and scaling rules." src="https://azure.github.io/Cloud-Native/assets/images/banner-3e6ce6ac4f59bb1c536972dced457df3.png" width="1600" height="672" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="so-what-makes-azure-container-apps-serverless">So, what makes Azure Container Apps "serverless"?<a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps#so-what-makes-azure-container-apps-serverless" class="hash-link" aria-label="Direct link to So, what makes Azure Container Apps &quot;serverless&quot;?" title="Direct link to So, what makes Azure Container Apps &quot;serverless&quot;?">​</a></h2>
<p>Today we are going to focus on what makes Azure Container Apps (ACA) a "serverless" offering. But what does the term "<em>serverless</em>" really mean? As much as we'd like to think there aren't any servers involved, that is certainly not the case. In general, "serverless" means that most (if not all) server maintenance has been abstracted away from you.</p>
<p>With serverless, you don't spend any time managing and patching servers. This concern is offloaded to Azure and you simply focus on adding business value through application delivery. In addition to operational efficiency, cost efficiency can be achieved with serverless on-demand pricing models. Your workload horizontally scales out based on need and you only pay for what you use. To me, this is <strong>serverless</strong>, and my teammate <a href="https://github.com/smurawski" target="_blank" rel="noopener noreferrer">@StevenMurawski</a> said it best... "*being able to **scale to zero *<em>is what gives ACA it's serverless magic</em>."</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="scaling-your-container-apps">Scaling your Container Apps<a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps#scaling-your-container-apps" class="hash-link" aria-label="Direct link to Scaling your Container Apps" title="Direct link to Scaling your Container Apps">​</a></h2>
<p>If you don't know by now, ACA is built on a solid open-source foundation. Behind the scenes, it runs on a managed Kubernetes cluster and includes several open-source components out-of-the box including <a href="https://dapr.io/" target="_blank" rel="noopener noreferrer">Dapr</a> to help you build and run microservices, <a href="https://www.envoyproxy.io/" target="_blank" rel="noopener noreferrer">Envoy Proxy</a> for ingress capabilities, and <a href="https://keda.sh/" target="_blank" rel="noopener noreferrer">KEDA</a> for event-driven autoscaling. Again, you do not need to install these components yourself. All you need to be concerned with is enabling and/or configuring your container app to leverage these components.</p>
<p>Let's take a closer look at autoscaling in ACA to help you optimize your container app.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-keda">What is KEDA?<a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps#what-is-keda" class="hash-link" aria-label="Direct link to What is KEDA?" title="Direct link to What is KEDA?">​</a></h3>
<p>KEDA stands for <strong>K</strong>ubernetes <strong>E</strong>vent-<strong>D</strong>riven <strong>A</strong>utoscaler. It is an open-source project initially started by Microsoft and Red Hat and has been donated to the <a href="https://www.cncf.io/" target="_blank" rel="noopener noreferrer">Cloud-Native Computing Foundation (CNCF)</a>. It is being maintained by a <a href="https://keda.sh/community/" target="_blank" rel="noopener noreferrer">community of 200+ contributors and adopted by many large organizations</a>. In terms of its status as a CNCF project it is currently in the <a href="https://github.com/cncf/toc/blob/main/process/graduation_criteria.md#incubating-stage" target="_blank" rel="noopener noreferrer"><strong>Incubating Stage</strong></a> which means the project has gone through significant due diligence and on its way towards the <a href="https://github.com/cncf/toc/blob/main/process/graduation_criteria.md#graduation-stage" target="_blank" rel="noopener noreferrer"><strong>Graduation Stage</strong></a>.</p>
<p>Prior to KEDA, horizontally scaling your Kubernetes deployment was achieved through the <a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/" target="_blank" rel="noopener noreferrer">Horizontal Pod Autoscaler (HPA)</a> which relies on resource metrics such as CPU and memory to determine when additional replicas should be deployed. Being limited to CPU and memory falls a bit short for certain workloads. This is especially true for apps that need to processes messages from a queue or HTTP-based apps that can handle a specific amount of incoming HTTP requests at a time. KEDA aims to fill that gap and provides a much more robust framework for scaling by working in conjunction with HPA. It offers many <a href="https://keda.sh/docs/scalers/" target="_blank" rel="noopener noreferrer">scalers</a> for you to implement and even allows your deployments to <strong>scale to zero</strong>! 🥳</p>
<p><img loading="lazy" alt="KEDA architecture" src="https://azure.github.io/Cloud-Native/assets/images/keda-arch-78fe1c48e2a47e18e6a933d96b90450a.png" width="1183" height="966" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="configuring-aca-scale-rules">Configuring ACA scale rules<a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps#configuring-aca-scale-rules" class="hash-link" aria-label="Direct link to Configuring ACA scale rules" title="Direct link to Configuring ACA scale rules">​</a></h3>
<p>As I mentioned above, ACA's autoscaling feature leverages KEDA and gives you the ability to configure the number of replicas to deploy based on rules (event triggers). The number of replicas can be configured as a static number or a range (minimum and maximum). So if you need your containers to run 24/7, set the min and max to be the same value. By default, when you deploy a container app, it is set to scale from 0 to 10 replicas. The default scaling rule uses <strong>HTTP scaling</strong> and defaults to a <a href="https://docs.microsoft.com/azure/container-apps/scale-app#http" target="_blank" rel="noopener noreferrer">minimum of 10 concurrent requests</a> per second. Once the threshold of 10 concurrent request per second is met, another replica will be deployed until it reaches the maximum number of replicas.</p>
<blockquote>
<p>At the time of this writing, a container app can have up to 30 replicas.</p>
</blockquote>
<p><img loading="lazy" alt="Default autoscaler" src="https://azure.github.io/Cloud-Native/assets/images/default-autoscaler-0be6a2dc11199a7e41b54c6902c80cf1.png" width="908" height="724" class="img_ev3q"></p>
<p>As a best practice, if you have a <strong>Min / max replicas</strong> range configured, you should configure a scaling rule even if it is just explicitly setting the default values.</p>
<p><img loading="lazy" alt="Adding HTTP scaling rule" src="https://azure.github.io/Cloud-Native/assets/images/http-rule-0bab06ac77d779fb39cb439bd5e8d40f.png" width="896" height="723" class="img_ev3q"></p>
<p>In addition to <strong>HTTP scaling</strong>, you can also configure an <strong>Azure queue</strong> rule, which allows you to use <a href="https://docs.microsoft.com/azure/storage/queues/storage-queues-introduction" target="_blank" rel="noopener noreferrer">Azure Storage Queues</a> as an event data source.</p>
<p><img loading="lazy" alt="Adding Azure Queue scaling rule" src="https://azure.github.io/Cloud-Native/assets/images/queue-rule-3405f4470633607d27599bedf3698d3f.png" width="890" height="725" class="img_ev3q"></p>
<p>The most flexibility comes with the <strong>Custom</strong> rule type. This opens up a LOT more options for scaling. All of <a href="https://keda.sh/docs/scalers/" target="_blank" rel="noopener noreferrer">KEDA's event-based scalers</a> are supported with this option 🚀</p>
<p><img loading="lazy" alt="Adding Custom scaling rule" src="https://azure.github.io/Cloud-Native/assets/images/custom-rule-8b8243abebed96f7510e03e130741648.png" width="894" height="723" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="translating-keda-templates-to-azure-templates">Translating KEDA templates to Azure templates<a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps#translating-keda-templates-to-azure-templates" class="hash-link" aria-label="Direct link to Translating KEDA templates to Azure templates" title="Direct link to Translating KEDA templates to Azure templates">​</a></h3>
<p>When you implement <strong>Custom</strong> rules, you need to become familiar with translating KEDA templates to <a href="https://docs.microsoft.com/azure/container-apps/azure-resource-manager-api-spec?tabs=arm-template" target="_blank" rel="noopener noreferrer">Azure Resource Manager templates</a> or <a href="https://docs.microsoft.com/azure/container-apps/azure-resource-manager-api-spec?tabs=yaml" target="_blank" rel="noopener noreferrer">ACA YAML manifests</a>. The <a href="https://keda.sh/docs/scalers/" target="_blank" rel="noopener noreferrer">KEDA scaler</a> documentation is great and it should be simple to translate KEDA template <code>metadata</code> to an ACA rule <code>metadata</code>.</p>
<p>The images below shows how to translated a scaling rule which uses Azure Service Bus as an event data source. The custom rule type is set to <code>azure-servicebus</code> and details of the service bus is added to the Metadata section. One important thing to note here is that the connection string to the service bus was added as a secret on the container app and the trigger parameter must be set to <code>connection</code>.</p>
<p><img loading="lazy" alt="Azure Container App custom rule metadata" src="https://azure.github.io/Cloud-Native/assets/images/keda-metadata-cb6407e6b7c4f9265d18904fd60f417a.png" width="1169" height="885" class="img_ev3q"></p>
<p><img loading="lazy" alt="Azure Container App custom rule metadata" src="https://azure.github.io/Cloud-Native/assets/images/aca-metadata-0e2c72a8f725a134927c493dde7d6c3e.png" width="1167" height="888" class="img_ev3q"></p>
<p>Additional examples of KEDA scaler conversion can be found in the resources section and example video below.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="see-container-app-scaling-in-action">See Container App scaling in action<a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps#see-container-app-scaling-in-action" class="hash-link" aria-label="Direct link to See Container App scaling in action" title="Direct link to See Container App scaling in action">​</a></h2>
<p>Now that we've built up some foundational knowledge on how ACA autoscaling is implemented and configured, let's look at a few examples.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="autoscaling-based-on-http-traffic-load">Autoscaling based on HTTP traffic load<a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps#autoscaling-based-on-http-traffic-load" class="hash-link" aria-label="Direct link to Autoscaling based on HTTP traffic load" title="Direct link to Autoscaling based on HTTP traffic load">​</a></h3>
<div style="padding:56.25% 0 0 0;position:relative"><iframe src="https://player.vimeo.com/video/746678347?h=8f5ada4431&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" style="position:absolute;top:0;left:0;width:100%;height:100%" title="http-scaling"></iframe></div>
<script src="https://player.vimeo.com/api/player.js"></script>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="autoscaling-based-on-azure-service-bus-message-queues">Autoscaling based on Azure Service Bus message queues<a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps#autoscaling-based-on-azure-service-bus-message-queues" class="hash-link" aria-label="Direct link to Autoscaling based on Azure Service Bus message queues" title="Direct link to Autoscaling based on Azure Service Bus message queues">​</a></h3>
<div style="padding:56.25% 0 0 0;position:relative"><iframe src="https://player.vimeo.com/video/746678266?h=89701121ed&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" style="position:absolute;top:0;left:0;width:100%;height:100%" title="event-driven-scaling.mp4"></iframe></div>
<script src="https://player.vimeo.com/api/player.js"></script>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="summary">Summary<a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary">​</a></h2>
<p>ACA brings you a true serverless experience and gives you the ability to configure autoscaling rules based on KEDA scaler templates. This gives you flexibility to scale based on a wide variety of data sources in an event-driven manner. With the amount built-in scalers currently available, there is probably a scaler out there for all your use cases. If not, I encourage you to get involved with the <a href="https://keda.sh/community/" target="_blank" rel="noopener noreferrer">KEDA community</a> and help make it better!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2>
<p>By now, you've probably read and seen enough and now ready to give this autoscaling thing a try. The example I walked through in the videos above can be found at the <a href="https://aka.ms/oss-labs" target="_blank" rel="noopener noreferrer">azure-opensource-labs</a> repo. I highly encourage you to head over to the <a href="https://github.com/Azure-Samples/azure-opensource-labs/tree/main/cloud-native/containerapps-terraform" target="_blank" rel="noopener noreferrer">containerapps-terraform</a> folder and try the lab out. There you'll find instructions which will cover all the steps and tools you'll need implement autoscaling container apps within your own Azure subscription.</p>
<p>If you have any questions or feedback, please let us know in the comments below or reach out on Twitter <a href="https://twitter.com/pauldotyu" target="_blank" rel="noopener noreferrer">@pauldotyu</a></p>
<p>Have fun scaling your containers!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="https://azure.github.io/Cloud-Native/blog/11-scaling-container-apps#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2>
<ul>
<li><a href="https://docs.microsoft.com/azure/container-apps/scale-app" target="_blank" rel="noopener noreferrer">Set scaling rules in Azure Container Apps</a></li>
<li><a href="https://keda.sh/" target="_blank" rel="noopener noreferrer">Kubernetes Event-driven Autoscaling (KEDA)</a></li>
<li><a href="https://keda.sh/docs/scalers/" target="_blank" rel="noopener noreferrer">KEDA Scalers</a></li>
<li><a href="https://docs.microsoft.com/azure/container-apps/scale-app#keda-scalers-conversion" target="_blank" rel="noopener noreferrer">KEDA scalers conversion</a></li>
</ul>]]></content:encoded>
            <category>serverless-september</category>
            <category>30-days-of-serverless</category>
            <category>azure-container-apps</category>
            <category>keda</category>
            <category>autoscaling</category>
        </item>
    </channel>
</rss>