<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tatsuro Shibamura</title>
    <description>The latest articles on DEV Community by Tatsuro Shibamura (@shibayan).</description>
    <link>https://dev.to/shibayan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg</url>
      <title>DEV Community: Tatsuro Shibamura</title>
      <link>https://dev.to/shibayan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shibayan"/>
    <language>en</language>
    <item>
      <title>OpenApiWeaver: Generate Type-Safe C# Clients from OpenAPI at Compile Time with Source Generators</title>
      <dc:creator>Tatsuro Shibamura</dc:creator>
      <pubDate>Fri, 10 Apr 2026 06:59:59 +0000</pubDate>
      <link>https://dev.to/polymind/openapiweaver-generate-type-safe-c-clients-from-openapi-at-compile-time-with-source-generators-5e79</link>
      <guid>https://dev.to/polymind/openapiweaver-generate-type-safe-c-clients-from-openapi-at-compile-time-with-source-generators-5e79</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;I built &lt;strong&gt;OpenApiWeaver&lt;/strong&gt;, a C# library that generates HTTP clients from OpenAPI definitions at &lt;strong&gt;compile time&lt;/strong&gt; using Source Generators. Just drop your OpenAPI file into your project, add one &lt;code&gt;ItemGroup&lt;/code&gt; entry, and build — no codegen CLI, no reflection at runtime, full NRT and &lt;code&gt;required&lt;/code&gt; support, and clean handling of string-based enums via &lt;code&gt;readonly record struct&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/shibayan" rel="noopener noreferrer"&gt;
        shibayan
      &lt;/a&gt; / &lt;a href="https://github.com/shibayan/openapi-weaver" rel="noopener noreferrer"&gt;
        openapi-weaver
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      OpenAPI documents into strongly typed C# HTTP clients at build time with an incremental Roslyn source generator.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;OpenApiWeaver&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/shibayan/openapi-weaver/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/shibayan/openapi-weaver/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;
&lt;a href="https://www.nuget.org/packages/OpenApiWeaver/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/be008e002c946c2526eb9b50222631cdc5c5a6973a1c136578a914ebca2321cc/68747470733a2f2f62616467656e2e6e65742f6e756765742f64742f4f70656e417069576561766572" alt="Downloads"&gt;&lt;/a&gt;
&lt;a href="https://www.nuget.org/packages/OpenApiWeaver" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/67dba0420bd7a5429b07b735645e71c19a5dac4b3b4d14246326a87ab6105ebb/68747470733a2f2f696d672e736869656c64732e696f2f6e756765742f762f4f70656e417069576561766572" alt="NuGet"&gt;&lt;/a&gt;
&lt;a href="https://github.com/shibayan/openapi-weaver/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d747b780724c413b5075cdcd04f89094a38a2e4d87c4623ee60b24c0786b00f5/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f736869626179616e2f6f70656e6170692d776561766572" alt="License"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OpenApiWeaver&lt;/strong&gt; is an incremental Roslyn source generator that turns OpenAPI 3.x documents, including OpenAPI 3.2, into strongly typed C# HTTP clients at build time. No runtime code generation, no reflection - just plain C# emitted during compilation.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick Start&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;1. Install the package&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight highlight-text-xml notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&amp;lt;&lt;span class="pl-ent"&gt;ItemGroup&lt;/span&gt;&amp;gt;
  &amp;lt;&lt;span class="pl-ent"&gt;PackageReference&lt;/span&gt; &lt;span class="pl-e"&gt;Include&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;OpenApiWeaver&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;Version&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;x.y.z&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;PrivateAssets&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;all&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; /&amp;gt;
&amp;lt;/&lt;span class="pl-ent"&gt;ItemGroup&lt;/span&gt;&amp;gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;2. Add your OpenAPI document&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight highlight-text-xml notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&amp;lt;&lt;span class="pl-ent"&gt;ItemGroup&lt;/span&gt;&amp;gt;
  &amp;lt;&lt;span class="pl-ent"&gt;OpenApiWeaverDocument&lt;/span&gt; &lt;span class="pl-e"&gt;Include&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;openapi\petstore.yaml&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
                         &lt;span class="pl-e"&gt;ClientName&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;PetstoreClient&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
                         &lt;span class="pl-e"&gt;Namespace&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Contoso.Generated&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; /&amp;gt;
&amp;lt;/&lt;span class="pl-ent"&gt;ItemGroup&lt;/span&gt;&amp;gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Use &lt;code&gt;OpenApiWeaverDocument&lt;/code&gt; rather than &lt;code&gt;AdditionalFiles&lt;/code&gt;; the package's MSBuild targets project these items into compiler inputs automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Use the generated client&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight highlight-source-cs notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-s1"&gt;client&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-smi"&gt;PetstoreClient&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;accessToken&lt;/span&gt;&lt;span class="pl-c1"&gt;:&lt;/span&gt; &lt;span class="pl-s"&gt;"your-token"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-c"&gt;// Operations are grouped by OpenAPI tag&lt;/span&gt;
&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-s1"&gt;pet&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-s1"&gt;client&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-s1"&gt;Pets&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;GetAsync&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;petId&lt;/span&gt;&lt;span class="pl-c1"&gt;:&lt;/span&gt; &lt;span class="pl-c1"&gt;1&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/shibayan/openapi-weaver" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Why another OpenAPI client generator?
&lt;/h2&gt;

&lt;p&gt;If you've needed a C# client from an OpenAPI definition, you've probably reached for OpenAPI Generator, AutoRest, or NSwag. They all work, but each has its quirks, and I've often found myself compromising on one thing or another.&lt;/p&gt;

&lt;p&gt;What I really wanted was dead simple: &lt;strong&gt;drop an OpenAPI file in my project, and have the client appear seamlessly at build time&lt;/strong&gt; — no external tools, no checked-in generated files, no separate codegen step in CI. That's exactly what Source Generators are for, so I built &lt;strong&gt;OpenApiWeaver&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design goals
&lt;/h2&gt;

&lt;p&gt;The core idea is to push as much work as possible into compile time via Source Generators. This gives us two nice properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No runtime reflection&lt;/strong&gt; in the generated code itself&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type-safe output&lt;/strong&gt; that takes full advantage of modern C# features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the generated code leans on recent language features, consumers need &lt;strong&gt;.NET 8 or later&lt;/strong&gt;. In practice, this shouldn't be a real constraint for anyone today.&lt;/p&gt;

&lt;p&gt;There are plenty of similar libraries out there, so I put a lot of effort into the &lt;strong&gt;quality of the generated code&lt;/strong&gt;. Specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nullable reference types and &lt;code&gt;required&lt;/code&gt; modifiers are applied faithfully based on the OpenAPI schema&lt;/li&gt;
&lt;li&gt;Enums — particularly string-based ones — are generated in a form that's actually pleasant to use from C#&lt;/li&gt;
&lt;li&gt;XML doc comments are emitted from OpenAPI &lt;code&gt;description&lt;/code&gt; and &lt;code&gt;summary&lt;/code&gt; fields, so IntelliSense just works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The generated client code itself contains no reflection. However, because it relies on &lt;code&gt;System.Text.Json&lt;/code&gt;, reflection is still used internally there. That means &lt;strong&gt;NativeAOT is not supported yet&lt;/strong&gt; — but once the &lt;code&gt;System.Text.Json&lt;/code&gt; source generator can be composed cleanly with this one, it should be achievable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Usage is about as simple as I could make it: install the &lt;code&gt;OpenApiWeaver&lt;/code&gt; package from NuGet, and you're done. Once installed, you get a new MSBuild item type called &lt;code&gt;OpenApiWeaverDocument&lt;/code&gt;. Point its &lt;code&gt;Include&lt;/code&gt; attribute at your OpenAPI definition file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;OutputType&amp;gt;&lt;/span&gt;Exe&lt;span class="nt"&gt;&amp;lt;/OutputType&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;net10.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ImplicitUsings&amp;gt;&lt;/span&gt;enable&lt;span class="nt"&gt;&amp;lt;/ImplicitUsings&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Nullable&amp;gt;&lt;/span&gt;enable&lt;span class="nt"&gt;&amp;lt;/Nullable&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"OpenApiWeaver"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"1.0.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;OpenApiWeaverDocument&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"petstore.json"&lt;/span&gt; &lt;span class="na"&gt;ClientName=&lt;/span&gt;&lt;span class="s"&gt;"PetStoreClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;OpenApiWeaverDocument&lt;/code&gt; also accepts &lt;code&gt;ClientName&lt;/code&gt; and &lt;code&gt;Namespace&lt;/code&gt; attributes, which let you override the generated client's class name and namespace.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get after a build
&lt;/h2&gt;

&lt;p&gt;That's the whole setup. Build the project, and the client is generated from the OpenAPI definition. For larger specs, the generator splits clients per OpenAPI &lt;strong&gt;Tag&lt;/strong&gt;, so you end up with one client class per logical grouping in your API — which keeps things manageable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnprp8sh7umc68e7ef5sr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnprp8sh7umc68e7ef5sr.png" alt="Generated clients split per OpenAPI tag" width="438" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The sample &lt;code&gt;petstore.json&lt;/code&gt; has &lt;code&gt;Pet&lt;/code&gt;, &lt;code&gt;Store&lt;/code&gt;, and &lt;code&gt;User&lt;/code&gt; tags, and you can see a client was generated for each.&lt;/p&gt;

&lt;p&gt;Each client exposes its operations as methods, so for the most part you can drive development purely through IntelliSense. (The naming of auto-generated methods still has room for improvement, I'll admit.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq1l5qbii2rvfskr5xsos.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq1l5qbii2rvfskr5xsos.png" alt="IntelliSense showing generated client methods" width="415" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the OpenAPI definition includes &lt;code&gt;description&lt;/code&gt; or &lt;code&gt;summary&lt;/code&gt; fields, those flow through to XML doc comments on the generated classes and methods, so you get nice tooltips in the editor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxgl8h4ud7jq9l5gynpae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxgl8h4ud7jq9l5gynpae.png" alt="Tooltip showing XML doc comments from OpenAPI descriptions" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The generated type definitions
&lt;/h2&gt;

&lt;p&gt;Operations are relatively straightforward, but the type definitions generated from &lt;code&gt;Schemas&lt;/code&gt; are where I spent most of my effort. Take the &lt;code&gt;Pet&lt;/code&gt; class from the sample — here's what actually gets generated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// Pet&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pet&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Id&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonIgnore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Condition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonIgnoreCondition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WhenWritingNull&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonPropertyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Name&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonPropertyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Category&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonIgnore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Condition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonIgnoreCondition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WhenWritingNull&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonPropertyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Category&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// PhotoUrls&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonPropertyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"photoUrls"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;PhotoUrls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Tags&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonIgnore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Condition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonIgnoreCondition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WhenWritingNull&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonPropertyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Tag&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;?&lt;/span&gt; &lt;span class="n"&gt;Tags&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Status&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// pet status in the store&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonIgnore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Condition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonIgnoreCondition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WhenWritingNull&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonPropertyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusEnum&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Pet.StatusEnum&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// pet status in the store&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonConverter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StatusEnumJsonConverter&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;StatusEnum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;StatusEnum&lt;/span&gt; &lt;span class="n"&gt;Available&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"available"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;StatusEnum&lt;/span&gt; &lt;span class="n"&gt;Pending&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pending"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;StatusEnum&lt;/span&gt; &lt;span class="n"&gt;Sold&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sold"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StatusEnumJsonConverter&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;JsonConverter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StatusEnum&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;StatusEnum&lt;/span&gt; &lt;span class="nf"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;Utf8JsonReader&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="n"&gt;typeToConvert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JsonSerializerOptions&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StatusEnum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;()!);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Utf8JsonWriter&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StatusEnum&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JsonSerializerOptions&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteStringValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth pointing out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NRT and &lt;code&gt;required&lt;/code&gt; are applied correctly, so mistakes get caught at compile time&lt;/li&gt;
&lt;li&gt;String-based enums are &lt;strong&gt;not&lt;/strong&gt; mapped to C# &lt;code&gt;enum&lt;/code&gt;. Instead they become &lt;code&gt;readonly record struct&lt;/code&gt;, which lets you treat them as strings while still keeping named well-known values like &lt;code&gt;Available&lt;/code&gt;, &lt;code&gt;Pending&lt;/code&gt;, &lt;code&gt;Sold&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This string-enum pattern has become pretty common in modern .NET libraries, and I think it strikes a good balance between type safety and the reality that string enums in OpenAPI often need to tolerate unknown values.&lt;/p&gt;

&lt;p&gt;There are a few other niceties I won't cover here — the full documentation goes into more detail:&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://shibayan.github.io/openapi-weaver/" rel="noopener noreferrer"&gt;OpenApiWeaver documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A note on the OpenAPI parser
&lt;/h2&gt;

&lt;p&gt;OpenApiWeaver only owns the "generate a client from an already-parsed OpenAPI document" half of the problem. Parsing itself is delegated to &lt;strong&gt;&lt;code&gt;Microsoft.OpenApi&lt;/code&gt;&lt;/strong&gt;, which keeps the surface area small. The docs say OpenAPI 3.x is supported, but really it's whatever that library supports:&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://devblogs.microsoft.com/openapi/openapi-net-release-announcements/" rel="noopener noreferrer"&gt;OpenAPI.NET release announcements (Microsoft DevBlogs)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing note: this was built with AI coding tools
&lt;/h2&gt;

&lt;p&gt;One last thing worth sharing. This entire library — Source Generator, runtime pieces, and documentation — was built heavily with AI coding assistance. I did the PoC in Codex with GPT-5.4, then moved to GitHub Copilot Chat using GPT-5.4 and Opus 4.6 High for the actual implementation.&lt;/p&gt;

&lt;p&gt;Honestly, I've always considered hand-writing Source Generator code to be a painful endeavor, and I'd been putting off projects like this for exactly that reason. Leaning on AI coding tools let me focus on &lt;strong&gt;design decisions&lt;/strong&gt; — API shape, code quality goals, naming — while the assistant handled most of the mechanical work of emitting C# source.&lt;/p&gt;

&lt;p&gt;From PoC to release, including docs, it took about &lt;strong&gt;three days&lt;/strong&gt; of real work. That still surprises me.&lt;/p&gt;

&lt;p&gt;If you try OpenApiWeaver out, I'd love to hear what you think — issues and PRs welcome on the repo.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>openapi</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Built a Lightweight GitHub Action for Deploying to Azure Static Web Apps</title>
      <dc:creator>Tatsuro Shibamura</dc:creator>
      <pubDate>Mon, 06 Apr 2026 06:17:15 +0000</pubDate>
      <link>https://dev.to/polymind/built-a-lightweight-github-action-for-deploying-to-azure-static-web-apps-1ame</link>
      <guid>https://dev.to/polymind/built-a-lightweight-github-action-for-deploying-to-azure-static-web-apps-1ame</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;I created &lt;a href="https://github.com/marketplace/actions/deploy-azure-static-web-apps" rel="noopener noreferrer"&gt;&lt;code&gt;shibayan/swa-deploy&lt;/code&gt;&lt;/a&gt; — a lightweight GitHub Action that &lt;strong&gt;only deploys&lt;/strong&gt; to Azure Static Web Apps, without the Docker-based build overhead of the official action. It wraps the same &lt;code&gt;StaticSitesClient&lt;/code&gt; that SWA CLI uses internally, includes automatic caching, and supports both Deployment Token and &lt;code&gt;azure/login&lt;/code&gt; authentication.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with the Official Action
&lt;/h2&gt;

&lt;p&gt;When deploying static sites (built with Astro, Vite, etc.) to Azure Static Web Apps, the standard approach is to use the official &lt;a href="https://github.com/marketplace/actions/azure-static-web-apps-deploy" rel="noopener noreferrer"&gt;&lt;code&gt;Azure/static-web-apps-deploy&lt;/code&gt;&lt;/a&gt; action that gets auto-generated when you link a GitHub repo to your SWA resource.&lt;/p&gt;

&lt;p&gt;Unlike other Azure deployment actions (e.g., for App Service or Azure Functions), this action uses &lt;strong&gt;Oryx&lt;/strong&gt; — the build engine used across Azure App Service — to build your application internally. It runs inside Docker, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The build process is a black box with hidden behaviors&lt;/li&gt;
&lt;li&gt;Docker image creation adds significant overhead&lt;/li&gt;
&lt;li&gt;Customizing the build pipeline is limited&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While Oryx is a capable multi-platform build engine, the Docker-based approach makes deploys slower than they need to be, especially when you just want to push pre-built static files.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;skip_app_build&lt;/code&gt; Option Isn't Enough
&lt;/h2&gt;

&lt;p&gt;You can set &lt;code&gt;skip_app_build: true&lt;/code&gt; in the official action to skip the application build step. This lets you build in GitHub Actions and only deploy through the action. However, it still needs to pull/build the Docker image, so the overhead remains.&lt;/p&gt;

&lt;p&gt;For reference, the official documentation covers this configuration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/static-web-apps/build-configuration?tabs=aat&amp;amp;pivots=github-actions" rel="noopener noreferrer"&gt;Build configuration for Azure Static Web Apps | Microsoft Learn&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using SWA CLI: Better, But Not Ideal
&lt;/h2&gt;

&lt;p&gt;To avoid the Docker overhead, I switched to using the &lt;a href="https://learn.microsoft.com/en-us/azure/static-web-apps/static-web-apps-cli-deploy" rel="noopener noreferrer"&gt;Static Web Apps CLI&lt;/a&gt; for deploy-only workflows. This approach works well — it's lighter than Docker — but comes with its own trade-offs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Installation time&lt;/strong&gt;: &lt;code&gt;npm install -g @azure/static-web-apps-cli&lt;/code&gt; takes a while&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache complexity&lt;/strong&gt;: To speed things up, you need to add npm global cache steps, which adds more workflow YAML than the actual deploy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cognitive overhead&lt;/strong&gt;: You end up thinking more about caching npm packages than deploying your app&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Solution: &lt;code&gt;shibayan/swa-deploy&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;I finally decided to build a dedicated GitHub Action that does one thing well: &lt;strong&gt;deploy to Azure Static Web Apps&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/shibayan" rel="noopener noreferrer"&gt;
        shibayan
      &lt;/a&gt; / &lt;a href="https://github.com/shibayan/swa-deploy" rel="noopener noreferrer"&gt;
        swa-deploy
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A GitHub Action to deploy prebuilt frontend assets and Azure Functions APIs to Azure Static Web Apps
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Deploy Azure Static Web Apps&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/shibayan/swa-deploy/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/shibayan/swa-deploy/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/shibayan/swa-deploy/./badges/coverage.svg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fshibayan%2Fswa-deploy%2FHEAD%2F.%2Fbadges%2Fcoverage.svg" alt="Coverage"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A GitHub Action that deploys prebuilt frontend assets, Azure Functions APIs, and
&lt;code&gt;staticwebapp.config.json&lt;/code&gt; to
&lt;a href="https://learn.microsoft.com/azure/static-web-apps/" rel="nofollow noopener noreferrer"&gt;Azure Static Web Apps&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It follows the same deployment model as &lt;code&gt;swa deploy&lt;/code&gt; from the
&lt;a href="https://azure.github.io/static-web-apps-cli/" rel="nofollow noopener noreferrer"&gt;Azure Static Web Apps CLI&lt;/a&gt; —
download the &lt;code&gt;StaticSitesClient&lt;/code&gt; binary, resolve paths, and upload content using
a deployment token. When &lt;code&gt;deployment-token&lt;/code&gt; is omitted, this action can also
resolve the token at runtime through Azure Resource Manager after &lt;code&gt;azure/login&lt;/code&gt;
The binary is cached automatically across workflow runs.&lt;/p&gt;
&lt;div class="markdown-alert markdown-alert-note"&gt;
&lt;p class="markdown-alert-title"&gt;Note&lt;/p&gt;
&lt;p&gt;This action &lt;strong&gt;does not build&lt;/strong&gt; your application. Run your build step before
calling this action.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Deploy a built frontend&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-yaml notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-ent"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;Deploy&lt;/span&gt;
&lt;span class="pl-ent"&gt;on&lt;/span&gt;:
  &lt;span class="pl-ent"&gt;push&lt;/span&gt;:
    &lt;span class="pl-ent"&gt;branches&lt;/span&gt;: &lt;span class="pl-s"&gt;[master]&lt;/span&gt;

&lt;span class="pl-ent"&gt;jobs&lt;/span&gt;:
  &lt;span class="pl-ent"&gt;deploy&lt;/span&gt;:
    &lt;span class="pl-ent"&gt;runs-on&lt;/span&gt;: &lt;span class="pl-s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="pl-ent"&gt;steps&lt;/span&gt;:
      - &lt;span class="pl-ent"&gt;uses&lt;/span&gt;: &lt;span class="pl-s"&gt;actions/checkout@v4&lt;/span&gt;

      - &lt;span class="pl-ent"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;Build&lt;/span&gt;
        &lt;span class="pl-ent"&gt;run&lt;/span&gt;: &lt;span class="pl-s"&gt;npm ci &amp;amp;&amp;amp; npm run build&lt;/span&gt;

      - &lt;span class="pl-ent"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;Deploy to Azure Static Web Apps&lt;/span&gt;
        &lt;span class="pl-ent"&gt;id&lt;/span&gt;: &lt;span class="pl-s"&gt;deploy&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/shibayan/swa-deploy" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Under the hood, this action uses the same &lt;code&gt;StaticSitesClient&lt;/code&gt; binary that SWA CLI uses. It's essentially a thin wrapper around that CLI with automatic caching built in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using a Deployment Token
&lt;/h3&gt;

&lt;p&gt;The simplest approach — just pass your deployment token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Azure Static Web Apps&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shibayan/swa-deploy@v1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app-location&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dist&lt;/span&gt;
    &lt;span class="na"&gt;deployment-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using &lt;code&gt;azure/login&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If you prefer using &lt;code&gt;azure/login&lt;/code&gt; with a service principal or federated credentials, pass &lt;code&gt;app-name&lt;/code&gt; instead. The action will automatically look up the resource via the Azure Resource Manager API, retrieve the deployment token, and deploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Azure login&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure/login@v2&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;client-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AZURE_CLIENT_ID }}&lt;/span&gt;
    &lt;span class="na"&gt;tenant-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AZURE_TENANT_ID }}&lt;/span&gt;
    &lt;span class="na"&gt;subscription-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AZURE_SUBSCRIPTION_ID }}&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Azure Static Web Apps&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shibayan/swa-deploy@v1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app-location&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dist&lt;/span&gt;
    &lt;span class="na"&gt;app-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-static-web-app&lt;/span&gt;
    &lt;span class="na"&gt;resource-group-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-resource-group&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;resource-group-name&lt;/code&gt; parameter is optional. You only need it if you have multiple SWA resources with the same name across different resource groups in your subscription — since SWA names are unique at the resource group scope, not the subscription scope.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Use This?
&lt;/h2&gt;

&lt;p&gt;Compared to the official action and SWA CLI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Docker overhead&lt;/strong&gt; — no image build step&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic caching&lt;/strong&gt; — the &lt;code&gt;StaticSitesClient&lt;/code&gt; binary is cached automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple workflow YAML&lt;/strong&gt; — no npm cache boilerplate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight&lt;/strong&gt; — does exactly one thing: deploy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've migrated all of my SWA deployments to this action and it's been working great.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Note
&lt;/h2&gt;

&lt;p&gt;The entire action was built using GitHub Copilot Chat with GPT-5.4 and Claude Opus 4.6, starting from the official template. AI-assisted development made it straightforward to implement and test.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>github</category>
      <category>actions</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Deep Dive into Azure Cosmos DB Physical Partitions</title>
      <dc:creator>Tatsuro Shibamura</dc:creator>
      <pubDate>Tue, 31 Mar 2026 14:21:33 +0000</pubDate>
      <link>https://dev.to/polymind/deep-dive-into-azure-cosmos-db-physical-partitions-49bb</link>
      <guid>https://dev.to/polymind/deep-dive-into-azure-cosmos-db-physical-partitions-49bb</guid>
      <description>&lt;h1&gt;
  
  
  Deep Dive into Azure Cosmos DB Physical Partitions
&lt;/h1&gt;

&lt;p&gt;When using Azure Cosmos DB effectively, the most important aspect is designing the partition key. However, when we talk about “partitions” in Cosmos DB, there are actually two types: &lt;strong&gt;logical partitions&lt;/strong&gt; and &lt;strong&gt;physical partitions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This topic is briefly covered in the official documentation, so it’s a good idea to review it first. In most cases, physical partitions are fully managed by Azure, so you rarely need to think about them.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/partitioning-overview#physical-partitions" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/partitioning-overview#physical-partitions" rel="noopener noreferrer" class="c-link"&gt;
            Partitioning and horizontal scaling - Azure Cosmos DB | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Learn about partitioning, logical, physical partitions in Azure Cosmos DB, best practices when choosing a partition key, and how to manage logical partitions.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;When designing your data model, the partition key corresponds to logical partitions. Both logical and physical partitions have their own limits, but in most cases, you only need to care about the &lt;strong&gt;20 GB limit of logical partitions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Although you usually don’t need to think about physical partitions, understanding them can be very helpful during design. So here’s a concise summary based on my experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  Basics of Physical Partitions
&lt;/h2&gt;

&lt;p&gt;As described in the official documentation, physical partitions are part of Cosmos DB’s internal implementation and represent the &lt;strong&gt;unit of compute that processes queries and operations&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each physical partition has &lt;strong&gt;four replicas&lt;/strong&gt;, and quorum-based consistency is implemented across them.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/global-dist-under-the-hood" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/global-dist-under-the-hood" rel="noopener noreferrer" class="c-link"&gt;
            Global Distribution With - Under the Hood - Azure Cosmos DB | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            This article provides technical details relating to global distribution of Azure Cosmos DB
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;In globally distributed configurations, replication is performed at the &lt;strong&gt;physical partition level&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A container always has at least one physical partition. However, Azure automatically increases the number of physical partitions when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storage exceeds &lt;strong&gt;50 GB&lt;/strong&gt;, or&lt;/li&gt;
&lt;li&gt;Provisioned throughput exceeds &lt;strong&gt;10,000 RU/s&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Throughput and Physical Partitions
&lt;/h2&gt;

&lt;p&gt;Each physical partition has a maximum throughput of &lt;strong&gt;10,000 RU/s&lt;/strong&gt;. In practice, however, I’ve found that hitting the &lt;strong&gt;50 GB storage limit&lt;/strong&gt; happens more often than hitting the RU limit.&lt;/p&gt;

&lt;p&gt;A common issue occurs when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A container originally has &lt;strong&gt;4000 RU/s&lt;/strong&gt; on a single physical partition&lt;/li&gt;
&lt;li&gt;Storage exceeds 50 GB&lt;/li&gt;
&lt;li&gt;The system splits into &lt;strong&gt;2 physical partitions&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since RU is evenly distributed across physical partitions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 partition → 4000 RU&lt;/li&gt;
&lt;li&gt;2 partitions → 2000 RU each&lt;/li&gt;
&lt;li&gt;4 partitions → 1000 RU each&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This effectively &lt;strong&gt;reduces the throughput available per partition&lt;/strong&gt;, which can lead to sudden &lt;strong&gt;429 Too Many Requests&lt;/strong&gt; errors.&lt;/p&gt;

&lt;p&gt;In such cases, you should follow the official guidance and &lt;strong&gt;adjust RU accordingly&lt;/strong&gt;:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/scaling-provisioned-throughput-best-practices" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/scaling-provisioned-throughput-best-practices" rel="noopener noreferrer" class="c-link"&gt;
            Best Practices for Scaling Provisioned Throughput - Azure Cosmos DB | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Learn about best practices for scaling manual and autoscale provisioned throughput for databases and containers.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;If you already know your data will exceed 50 GB, it can be a good strategy to &lt;strong&gt;provision enough RU upfront&lt;/strong&gt; so that the required number of physical partitions are allocated early.&lt;/p&gt;

&lt;p&gt;Also note that when new physical partitions are created, data replication occurs, temporarily consuming additional RU. This can lead to &lt;strong&gt;temporary throughput degradation&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Connection Modes and Physical Partitions
&lt;/h2&gt;

&lt;p&gt;To improve performance, the C# and Java SDKs recommend using &lt;strong&gt;Direct mode&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/sql/sql-sdk-connection-modes" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/sql/sql-sdk-connection-modes" rel="noopener noreferrer" class="c-link"&gt;
            SQL SDK Connectivity Modes - Azure Cosmos DB | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Learn about the different connectivity modes available on the Azure Cosmos DB SQL SDKs.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;As the name suggests, Direct mode connects directly to backend physical partitions, reducing overhead.&lt;/p&gt;

&lt;p&gt;To make this work, the SDK must know &lt;strong&gt;which physical partition stores a given partition key&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you’ve enabled Application Insights, you may have seen requests to &lt;code&gt;pkranges&lt;/code&gt; during application startup. This API returns the mapping between partition keys and physical partitions:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/rest/api/cosmos-db/get-partition-key-ranges" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/rest/api/cosmos-db/get-partition-key-ranges" rel="noopener noreferrer" class="c-link"&gt;
            Get Partition Key Ranges - Azure Cosmos DB REST API | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Get partition key ranges REST API syntax. Request and response headers, body, status codes and examples.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This API is not intended for direct use in user code.&lt;/p&gt;

&lt;p&gt;Because this mapping is fetched when a container is first accessed, the &lt;strong&gt;first request can be slower&lt;/strong&gt;. However, recent versions of the .NET SDK provide an API to explicitly initialize this mapping:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.cosmos.cosmosclient.createandinitializeasync?view=azure-dotnet" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.cosmos.cosmosclient.createandinitializeasync?view=azure-dotnet" rel="noopener noreferrer" class="c-link"&gt;
            CosmosClient.CreateAndInitializeAsync Method (Microsoft.Azure.Cosmos) - Azure for .NET Developers | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Creates a new CosmosClient with the account endpoint URI string and TokenCredential. In addition to that it initializes the client with containers provided i.e The SDK warms up the caches and connections before the first call to the service is made. Use this to obtain lower latency while startup of your application. CosmosClient is thread-safe. Its recommended to maintain a single instance of CosmosClient per lifetime of the application which enables efficient connection management and performance. Please refer to the performance guide. 
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;By calling this during application warm-up, you can &lt;strong&gt;minimize overhead for subsequent requests&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cross-Partition Queries and Physical Partitions
&lt;/h2&gt;

&lt;p&gt;In Cosmos DB design, &lt;strong&gt;cross-partition queries should generally be avoided&lt;/strong&gt;. However, this rule can be relaxed if all data fits within a single physical partition.&lt;/p&gt;

&lt;p&gt;In the following documentation, the term “partition” refers to &lt;strong&gt;physical partitions&lt;/strong&gt;:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/how-to-query-container" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/how-to-query-container" rel="noopener noreferrer" class="c-link"&gt;
            Query a Container - Azure Cosmos DB | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Learn how to query containers in Azure Cosmos DB by using both in-partition and cross-partition queries.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;If all logical partitions are contained within a single physical partition, indexes can be used effectively, making cross-partition queries relatively low-cost.&lt;/p&gt;

&lt;p&gt;Problems arise when a container spans multiple physical partitions, as queries must be executed across all of them, increasing cost.&lt;/p&gt;

&lt;p&gt;The most efficient cross-partition query is one that targets &lt;strong&gt;only partition keys within a single physical partition&lt;/strong&gt;, but this is not something you can control directly from user code.&lt;/p&gt;

&lt;p&gt;Instead, you should rely on SDK features. A good example is the &lt;code&gt;ReadMany&lt;/code&gt; API, which efficiently handles cross-partition access.&lt;/p&gt;

&lt;p&gt;That said, designing everything around cross-partition queries should always be avoided.&lt;/p&gt;




&lt;h2&gt;
  
  
  Change Feed and Physical Partitions
&lt;/h2&gt;

&lt;p&gt;Physical partitions are closely related to the &lt;strong&gt;Change Feed&lt;/strong&gt; feature.&lt;/p&gt;

&lt;p&gt;While Change Feed guarantees ordering at the logical partition level, its actual processing is based on &lt;strong&gt;physical partitions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is easier to understand when looking at the Pull model.&lt;/p&gt;

&lt;p&gt;In the Pull model, parallel processing is achieved using the &lt;code&gt;FeedRange&lt;/code&gt; class, which is assigned per physical partition. By distributing &lt;code&gt;FeedRange&lt;/code&gt; across multiple machines, you can process Change Feed in parallel.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/change-feed-pull-model?tabs=dotnet" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/change-feed-pull-model?tabs=dotnet" rel="noopener noreferrer" class="c-link"&gt;
            Change Feed Pull Model - Azure Cosmos DB | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Learn how to use the Azure Cosmos DB change feed pull model to read the change feed. Understand the differences between the change feed pull model and the change feed processor.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.cosmos.feedrange?view=azure-dotnet" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.cosmos.feedrange?view=azure-dotnet" rel="noopener noreferrer" class="c-link"&gt;
            FeedRange Class (Microsoft.Azure.Cosmos) - Azure for .NET Developers | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Represents a unit of feed consumption that can be used as unit of parallelism. 
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;As a result, even a single Change Feed Processor can only scale up to the number of physical partitions. In other words, processing is effectively &lt;strong&gt;single-threaded per physical partition&lt;/strong&gt;, which simplifies writing logic that depends on ordering.&lt;/p&gt;

&lt;p&gt;However, this also means that &lt;strong&gt;scale-out limits are reached relatively quickly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To address this, you should minimize processing within each Change Feed Processor and instead create &lt;strong&gt;multiple smaller processors for different purposes&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Metrics and Physical Partitions
&lt;/h2&gt;

&lt;p&gt;By now, you should have a solid understanding of physical partitions, so let’s move on to monitoring.&lt;/p&gt;

&lt;p&gt;Even with careful partition key design, data can still become skewed toward specific physical partitions (so-called &lt;strong&gt;hot partitions&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;To identify them, you can split metrics by &lt;code&gt;PartitionKeyRangeId&lt;/code&gt;.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/monitor-normalized-request-units#how-to-monitor-for-hot-partitions" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/monitor-normalized-request-units#how-to-monitor-for-hot-partitions" rel="noopener noreferrer" class="c-link"&gt;
            Monitor Normalized Request Units - Azure Cosmos DB | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Learn how to monitor the normalized request unit usage of an operation in Azure Cosmos DB. Owners of an Azure Cosmos DB account can understand which operations are consuming more request units.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Recently, new metrics such as &lt;strong&gt;Physical Partition Throughput&lt;/strong&gt; have been introduced, making it easier to troubleshoot partition-level issues.&lt;/p&gt;

&lt;p&gt;You can also view these metrics in &lt;strong&gt;Cosmos DB Insights in Azure Monitor&lt;/strong&gt;, which significantly improves observability.&lt;/p&gt;




&lt;h2&gt;
  
  
  Operations on Physical Partitions (Preview)
&lt;/h2&gt;

&lt;p&gt;At Build 2022, several Cosmos DB updates were announced, including preview features that allow &lt;strong&gt;direct operations on physical partitions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One of them is &lt;strong&gt;Merge partitions&lt;/strong&gt;, which combines physical partitions.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/merge" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/merge" rel="noopener noreferrer" class="c-link"&gt;
            Merge partitions (preview) - Azure Cosmos DB | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Reduce the number of physical partitions used for your container with the merge capability in Azure Cosmos DB.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Since RU is evenly distributed across physical partitions, fewer partitions can result in &lt;strong&gt;higher effective throughput per partition&lt;/strong&gt;. Merging excess partitions helps optimize performance.&lt;/p&gt;

&lt;p&gt;Another feature allows &lt;strong&gt;redistributing throughput across physical partitions&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/sql/distribute-throughput-across-partitions" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fmedia%2Fopen-graph-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/sql/distribute-throughput-across-partitions" rel="noopener noreferrer" class="c-link"&gt;
            Redistribute Throughput Across Partitions (Preview) - Azure Cosmos DB | Microsoft Learn
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Learn how to redistribute throughput across partitions in Azure Cosmos DB to optimize performance. To improve partition performance, follow these step-by-step instructions and best practices.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          learn.microsoft.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;No matter how carefully you design your partition key, data skew is inevitable in real-world scenarios. This feature allows you to assign more RU to hot partitions without increasing total RU, improving overall efficiency.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By understanding physical partitions, you can push Cosmos DB optimization further in terms of both performance and cost.&lt;/p&gt;

&lt;p&gt;However, this is &lt;strong&gt;not mandatory knowledge&lt;/strong&gt; for most use cases.&lt;/p&gt;

&lt;p&gt;Rather than focusing on physical partitions from the beginning, the most important thing is to &lt;strong&gt;design a good partition key&lt;/strong&gt; during data modeling.&lt;/p&gt;

&lt;p&gt;Most physical partition-related optimizations can be handled later, so invest your effort where it matters most: &lt;strong&gt;your initial data model design&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>cosmosdb</category>
    </item>
    <item>
      <title>Migrating Azure Functions Monitoring to OpenTelemetry</title>
      <dc:creator>Tatsuro Shibamura</dc:creator>
      <pubDate>Tue, 31 Mar 2026 14:05:40 +0000</pubDate>
      <link>https://dev.to/polymind/migrating-azure-functions-monitoring-to-opentelemetry-17o</link>
      <guid>https://dev.to/polymind/migrating-azure-functions-monitoring-to-opentelemetry-17o</guid>
      <description>&lt;p&gt;A while ago, version 3.0 of the Application Insights SDK was released, and its internal implementation was migrated to be based on OpenTelemetry. While it is generally recommended to use the OpenTelemetry Distro directly, being able to support OpenTelemetry just by updating the Application Insights SDK is a clear advantage.&lt;/p&gt;

&lt;p&gt;Along with this change, one of the Application Insights SDKs used in Azure Functions .NET Isolated—&lt;code&gt;Microsoft.ApplicationInsights.WorkerService&lt;/code&gt;—has also been updated to version 3.0. If you are managing both Azure Functions and ASP.NET Core projects in a single solution, you may often update them together.&lt;/p&gt;

&lt;p&gt;In a typical .NET Worker application, this update does not cause any issues. However, in Azure Functions, simply updating the package leads to runtime exceptions like the one below. Since the build succeeds without errors, this can be particularly tricky to notice.&lt;/p&gt;

&lt;p&gt;This issue occurs because the &lt;code&gt;Microsoft.Azure.Functions.Worker.ApplicationInsights&lt;/code&gt; package—required for Azure Functions' built-in Application Insights integration—has a strong dependency on the v2 SDK. While this would be resolved if the package were updated for v3, it appears from GitHub issues that there are no plans to provide a v3-compatible version. Therefore, in the long term, migrating to an OpenTelemetry-based approach will be necessary.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Azure/azure-functions-dotnet-worker/issues/3322#issuecomment-4050282773" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Comment for
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#3322&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/RohitRanjanMS" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F90008725%3Fu%3Dcef322ae933f4fb1cb94f6a94e20ae5f1a996ee9%26v%3D4" alt="RohitRanjanMS avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/RohitRanjanMS" rel="noopener noreferrer"&gt;RohitRanjanMS&lt;/a&gt;
        &lt;/strong&gt; commented on &lt;a href="https://github.com/Azure/azure-functions-dotnet-worker/issues/3322#issuecomment-4050282773" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 12, 2026&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;We do not plan to release a new version of &lt;code&gt;Microsoft.Azure.Functions.Worker.ApplicationInsights&lt;/code&gt; that is compatible with the 3.0 release of &lt;code&gt;Microsoft.ApplicationInsights.WorkerService&lt;/code&gt;. Our current package relies heavily on Telemetry Initializers and Telemetry Processors, and the new 3.0 SDK no longer supports these extensibility points. Supporting it would require a full rewrite of the Functions worker package. The same limitation may also affect customers who depend on Initializers or Processors in their applications.
Our recommendation is to move to OpenTelemetry‑based monitoring. This is the direction we are investing in, and we are committed to improving observability by aligning with the OpenTelemetry ecosystem. You can follow Functions OpenTelemetry guidance here:
&lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/opentelemetry-howto?tabs=app-insights%2Cihostapplicationbuilder%2Cmaven&amp;amp;pivots=programming-language-csharp" rel="nofollow noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/azure-functions/opentelemetry-howto?tabs=app-insights%2Cihostapplicationbuilder%2Cmaven&amp;amp;pivots=programming-language-csharp&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Azure/azure-functions-dotnet-worker/issues/3322#issuecomment-4050282773" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Azure Functions now supports OpenTelemetry, but if you create a project from the default template, it still uses the Application Insights SDK. Therefore, some additional steps are required to switch.&lt;/p&gt;

&lt;p&gt;You can follow the official documentation below for the migration steps, but there are a few pitfalls I encountered during the process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/opentelemetry-howto" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/azure-functions/opentelemetry-howto&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing Application Insights Packages
&lt;/h2&gt;

&lt;p&gt;First, check your existing Azure Functions project. You will likely find the following two Application Insights-related packages installed. Remove them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Microsoft.ApplicationInsights.WorkerService&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Microsoft.Azure.Functions.Worker.ApplicationInsights&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These packages depend on the Application Insights SDK and are no longer needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding OpenTelemetry Packages
&lt;/h2&gt;

&lt;p&gt;Instead, install the following OpenTelemetry-related packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Microsoft.Azure.Functions.Worker.OpenTelemetry&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Azure.Monitor.OpenTelemetry.Exporter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OpenTelemetry.Extensions.Hosting&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In ASP.NET Core, a single package is often sufficient, but in Azure Functions, you need to install them individually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating Program.cs
&lt;/h2&gt;

&lt;p&gt;At this point, your project will no longer build. Remove the existing Application Insights initialization code in &lt;code&gt;Program.cs&lt;/code&gt; and replace it with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Azure.Monitor.OpenTelemetry.Exporter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Azure.Functions.Worker.Builder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Azure.Functions.Worker.OpenTelemetry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.DependencyInjection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Hosting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FunctionsApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureFunctionsWebApplication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenTelemetry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseFunctionsWorkerDefaults&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAzureMonitorExporter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you need customization, you can pass options to &lt;code&gt;UseAzureMonitorExporter&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Local Development Pitfall
&lt;/h2&gt;

&lt;p&gt;After this change, the project builds successfully. However, when running locally, you may encounter an error indicating that the Application Insights connection string is missing, causing the application to fail at startup.&lt;/p&gt;

&lt;p&gt;With the Application Insights SDK, telemetry was automatically disabled if no connection string was provided. However, with the OpenTelemetry Distro, it is now required.&lt;/p&gt;

&lt;p&gt;To avoid forcing Application Insights in local development, you could disable it using preprocessor directives. However, I personally found that approach messy.&lt;/p&gt;

&lt;p&gt;Instead, I added a dummy connection string like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"IsEncrypted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AzureWebJobsStorage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UseDevelopmentStorage=true"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"FUNCTIONS_WORKER_RUNTIME"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dotnet-isolated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"APPLICATIONINSIGHTS_CONNECTION_STRING"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"InstrumentationKey=00000000-0000-0000-0000-000000000000"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This allows the application to start correctly in a local development environment.&lt;/p&gt;
&lt;h2&gt;
  
  
  Verifying Telemetry
&lt;/h2&gt;

&lt;p&gt;Finally, connect to Application Insights and verify that telemetry is being sent correctly.&lt;/p&gt;

&lt;p&gt;You will notice that property names follow the OpenTelemetry schema. However, telemetry generated by the Azure Functions host remains unchanged.&lt;/p&gt;
&lt;h2&gt;
  
  
  Real-World Example
&lt;/h2&gt;

&lt;p&gt;Here is the Pull Request where I migrated Acmebot to an OpenTelemetry-based setup:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/polymind-inc/acmebot/pull/996" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add OpenTelemetry support and remove Application Insights initializer
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#996&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/shibayan" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F1356444%3Fv%3D4" alt="shibayan avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/shibayan" rel="noopener noreferrer"&gt;shibayan&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/polymind-inc/acmebot/pull/996" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 20, 2026&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;This pull request updates the application's telemetry and monitoring stack by migrating from Application Insights to OpenTelemetry with Azure Monitor Exporter. This modernizes observability, aligns with current best practices, and simplifies related configuration and code. The most important changes are grouped below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Migration to OpenTelemetry and Azure Monitor Exporter:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Removed dependencies on &lt;code&gt;Microsoft.ApplicationInsights.WorkerService&lt;/code&gt; and &lt;code&gt;Microsoft.Azure.Functions.Worker.ApplicationInsights&lt;/code&gt;, and added new dependencies for &lt;code&gt;Azure.Monitor.OpenTelemetry.Exporter&lt;/code&gt;, &lt;code&gt;Microsoft.Azure.Functions.Worker.OpenTelemetry&lt;/code&gt;, and &lt;code&gt;OpenTelemetry.Extensions.Hosting&lt;/code&gt; in &lt;code&gt;Acmebot.App.csproj&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Replaced Application Insights telemetry setup in &lt;code&gt;Program.cs&lt;/code&gt; with OpenTelemetry initialization using &lt;code&gt;AddOpenTelemetry()&lt;/code&gt;, &lt;code&gt;UseFunctionsWorkerDefaults()&lt;/code&gt;, and &lt;code&gt;UseAzureMonitorExporter()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Updated &lt;code&gt;host.json&lt;/code&gt; to set &lt;code&gt;"telemetryMode": "OpenTelemetry"&lt;/code&gt; and removed Application Insights-specific logging configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Codebase cleanup:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Removed the custom &lt;code&gt;ApplicationVersionInitializer&lt;/code&gt; class and its registration, as it was specific to Application Insights. [1] [2]
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;General code and dependency updates:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Updated &lt;code&gt;using&lt;/code&gt; statements in &lt;code&gt;Program.cs&lt;/code&gt; to remove Application Insights references and add OpenTelemetry/Azure Monitor references as needed.&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/polymind-inc/acmebot/pull/996" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;The changes are relatively simple—for example, removing &lt;code&gt;ITelemetryInitializer&lt;/code&gt;. Equivalent functionality is now built in, so it is no longer necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Migrating applications that rely heavily on &lt;code&gt;ITelemetryProcessor&lt;/code&gt; or other advanced customizations may require more effort. However, it seems feasible to migrate even filtering logic to OpenTelemetry.&lt;/p&gt;

&lt;p&gt;If I get the time, I plan to write another post covering those advanced scenarios.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>dotnet</category>
      <category>opentelemetry</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Generate sequence numbers in Cosmos DB</title>
      <dc:creator>Tatsuro Shibamura</dc:creator>
      <pubDate>Sun, 15 Jan 2023 17:10:44 +0000</pubDate>
      <link>https://dev.to/shibayan/generate-sequence-numbers-in-cosmos-db-1e9i</link>
      <guid>https://dev.to/shibayan/generate-sequence-numbers-in-cosmos-db-1e9i</guid>
      <description>&lt;p&gt;Azure Cosmos DB does not provide a function to generate sequence numbers like RDB such as SQL Server in order to achieve very high availability and global distribution.&lt;/p&gt;

&lt;p&gt;Since RDB can always achieve strong consistency, sequence numbers can be easily generated as described in the following document, but they can be a bottleneck in scaling.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/sequence-numbers/sequence-numbers?view=sql-server-ver16" rel="noopener noreferrer"&gt;Sequence Numbers - SQL Server | Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Data modeling is the most important part of using Cosmos DB, and the key to maximizing the benefits of Cosmos DB is to design a system that does not require sequence numbers at that point (a design that allows for high data distribution).&lt;/p&gt;

&lt;p&gt;However, there are rare cases in which sequence numbers are required even at the expense of availability.&lt;/p&gt;

&lt;p&gt;While it was possible to safely generate sequence numbers in RDB, it used to be surprisingly difficult to safely generate sequence numbers using Cosmos DB until Partial Update became available.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/partial-document-update" rel="noopener noreferrer"&gt;Partial document update in Azure Cosmos DB | Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that Cosmos DB supports partial updates and provides increments to arbitrary properties as operations, it is now surprisingly easy to generate sequence numbers.&lt;/p&gt;

&lt;p&gt;The following is a sample code. The data model to be stored in Cosmos DB is very simple as follows. The &lt;code&gt;value&lt;/code&gt; property holds the current sequence number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Sequence&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following JSON is stored in Cosmos DB in advance. Since partial update is a process to an already existing document, it is necessary to create the document itself separately.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sample"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpn7tv53a61pfxc3myqk7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpn7tv53a61pfxc3myqk7.png" alt="initial item" width="562" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you have probably figured out by now, all that is left is for the Cosmos DB SDK to perform a &lt;code&gt;+1&lt;/code&gt; operation on the &lt;code&gt;value&lt;/code&gt; property using partial updates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connectionString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;connection_string&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cosmosClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CosmosClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cosmosClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my-database"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"my-sequence"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;operations&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;PatchOperation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PatchItemAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"sample"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PartitionKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sample"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;operations&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Seq = &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Executing this code, you can see that the property increment is performed by Cosmos DB on the server side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zg40r69wkw8b39gsr0c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zg40r69wkw8b39gsr0c.png" alt="generate single" width="517" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6jzjyu1bo96lpd3z48y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6jzjyu1bo96lpd3z48y.png" alt="updated item" width="519" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The difficulty with sequence numbers is whether they can be correctly generated without duplication when a large number of them are generated at the same time. &lt;/p&gt;

&lt;p&gt;The sample code is extended as shown below to try parallel generation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ItemResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&amp;gt;();&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PatchItemAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"sample"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PartitionKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sample"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;operations&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WhenAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;itemResponse&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Seq : &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;itemResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, Consumed RU/s = &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;itemResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestCharge&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Next Seq : &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I run the extended code, it generates sequence numbers without duplication. Although requests are thrown at the same time, it can be confirmed that atomic processing is performed on the server side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feh0myf7ruo4ybg1vi5gj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feh0myf7ruo4ybg1vi5gj.png" alt="generate multiple" width="466" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Previously, read and update had to be executed separately, which was complicated in Cosmos DB, where transactions are not available like in RDB. However, with partial updates, everything is done on the server side, including conflict resolution, so there is no need to worry about this.&lt;/p&gt;

&lt;p&gt;Container for generating sequence numbers can reduce RU consumption slightly by turning off the index policy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"indexingMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"automatic"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"includedPaths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"excludedPaths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you know that you do not need the indexes completely, you can reduce the cost of Cosmos DB by explicitly turning them off.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to quickly setup a Let's Encrypt certificate in Azure Container Apps</title>
      <dc:creator>Tatsuro Shibamura</dc:creator>
      <pubDate>Sat, 14 May 2022 03:04:52 +0000</pubDate>
      <link>https://dev.to/shibayan/how-to-quickly-setup-a-lets-encrypt-certificate-in-azure-container-apps-3nd7</link>
      <guid>https://dev.to/shibayan/how-to-quickly-setup-a-lets-encrypt-certificate-in-azure-container-apps-3nd7</guid>
      <description>&lt;p&gt;Azure Container Apps now supports custom domain assignment in the latest update. Now you can easily publish your own web application with your own domain without using Front Door.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1525264037432684544-637" src="https://platform.twitter.com/embed/Tweet.html?id=1525264037432684544"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1525264037432684544-637');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1525264037432684544&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;However, it does not currently support free managed certificates, and you must upload your own certificates.&lt;/p&gt;

&lt;p&gt;Free certificates are issued by Let's Encrypt, so I developed an application to use them. This is based on code written by &lt;a class="mentioned-user" href="https://dev.to/jeffhollan"&gt;@jeffhollan&lt;/a&gt; of the Azure Apps team.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/shibayan" rel="noopener noreferrer"&gt;
        shibayan
      &lt;/a&gt; / &lt;a href="https://github.com/shibayan/containerapps-acmebot" rel="noopener noreferrer"&gt;
        containerapps-acmebot
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Automated ACME SSL/TLS certificates issuer for Azure Container Apps (Custom domain / Custom DNS Suffix)
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
  Container Apps Acmebot
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;
  Automated ACME SSL/TLS certificates issuer for Azure Container Apps
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://github.com/shibayan/containerapps-acmebot/actions/workflows/build.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/shibayan/containerapps-acmebot/workflows/Build/badge.svg" alt="Build"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/shibayan/containerapps-acmebot/releases/latest" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b023d82ab6eda70729d8bd6e7baa803eac7b2ca1864244328359e03337bd1195/68747470733a2f2f62616467656e2e6e65742f6769746875622f72656c656173652f736869626179616e2f636f6e7461696e6572617070732d61636d65626f74" alt="Release"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/shibayan/containerapps-acmebot/stargazers" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/239cdc8b1af5aa155b7efed0010fde0367066ec8b6df34d818b560a2f5193ac4/68747470733a2f2f62616467656e2e6e65742f6769746875622f73746172732f736869626179616e2f636f6e7461696e6572617070732d61636d65626f74" alt="Stargazers"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/shibayan/containerapps-acmebot/network/members" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c5142b51595235ace8908533512563c5ea1796c1c0777127f9010ea5c6fdf0c9/68747470733a2f2f62616467656e2e6e65742f6769746875622f666f726b732f736869626179616e2f636f6e7461696e6572617070732d61636d65626f74" alt="Forks"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/shibayan/containerapps-acmebot/blob/master/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/417416cf4a675394777c8a2f6d7601361da7a37fc3a8a32dde246b831eba2058/68747470733a2f2f62616467656e2e6e65742f6769746875622f6c6963656e73652f736869626179616e2f636f6e7461696e6572617070732d61636d65626f74" alt="License"&gt;&lt;/a&gt;
  &lt;a href="https://registry.terraform.io/modules/shibayan/containerapps-acmebot/azurerm/latest" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ee9d171694a8a3ed5d4b855c3c4c0e12e27760d2714152790fce2cf4ee0ae773/68747470733a2f2f62616467656e2e6e65742f62616467652f7465727261666f726d2f72656769737472792f356334656535" alt="Terraform"&gt;&lt;/a&gt;
  &lt;br&gt;
  &lt;a href="https://github.com/shibayan/containerapps-acmebot/commits/master" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5bba600d2d7494fb29af26e3dc569e73a29ae7bde32d0fbbd48094a10f48f580/68747470733a2f2f62616467656e2e6e65742f6769746875622f6c6173742d636f6d6d69742f736869626179616e2f636f6e7461696e6572617070732d61636d65626f74" alt="Last commit"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/shibayan/containerapps-acmebot/wiki" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a863b6472a734c00c00bd2bd860822bffc3c2858920a0b6f25ef20109c0bb8ee/68747470733a2f2f62616467656e2e6e65742f62616467652f646f63756d656e746174696f6e2f617661696c61626c652f666637373333" alt="Documentation"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/shibayan/containerapps-acmebot/discussions" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dceb29b137c4575cae6a4c07083ff7ea1451193801a25124046d60b43c7292e0/68747470733a2f2f62616467656e2e6e65742f62616467652f64697363757373696f6e732f77656c636f6d652f666637373333" alt="Discussions"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-alert markdown-alert-important"&gt;
&lt;p class="markdown-alert-title"&gt;Important&lt;/p&gt;
&lt;p&gt;This project has been retired as Azure Container Apps now supports Key Vault certificates. Please use Key Vault Acmebot from now on.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/shibayan/keyvault-acmebot" rel="noopener noreferrer"&gt;https://github.com/shibayan/keyvault-acmebot&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Motivation&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;We have started to address the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for multiple Container Apps and Container Apps Environment&lt;/li&gt;
&lt;li&gt;Easy to deploy and configure&lt;/li&gt;
&lt;li&gt;Highly reliable implementation&lt;/li&gt;
&lt;li&gt;Ease of Monitoring (Application Insights, Webhook)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can add multiple certificates to a single Container Apps.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Feature Support&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Issuing certificates for Zone Apex / Multi-domain / Wildcard&lt;/li&gt;
&lt;li&gt;Automatic binding of custom domains and certificates to Container App&lt;/li&gt;
&lt;li&gt;Support for multiple Container Apps in a single application&lt;/li&gt;
&lt;li&gt;ACME-compliant Certification Authorities
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://letsencrypt.org/" rel="nofollow noopener noreferrer"&gt;Let's Encrypt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.buypass.com/ssl/resources/acme-free-ssl" rel="nofollow noopener noreferrer"&gt;Buypass Go SSL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://zerossl.com/features/acme/" rel="nofollow noopener noreferrer"&gt;ZeroSSL&lt;/a&gt; (Requires EAB Credentials)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Deployment&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;br&gt;
&lt;thead&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;th&gt;Azure (Public)&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Azure China&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Azure Government&lt;/th&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/thead&gt;
&lt;br&gt;
&lt;tbody&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fshibayan%2Fcontainerapps-acmebot%2Fmaster%2Fazuredeploy.json" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3958108d59aa2748ddc31edfa3e510d89c27efbf3d308bdeec8e8aa57a4072e6/68747470733a2f2f616b612e6d732f6465706c6f79746f617a757265627574746f6e"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://portal.azure.cn/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fshibayan%2Fcontainerapps-acmebot%2Fmaster%2Fazuredeploy.json" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3958108d59aa2748ddc31edfa3e510d89c27efbf3d308bdeec8e8aa57a4072e6/68747470733a2f2f616b612e6d732f6465706c6f79746f617a757265627574746f6e"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fshibayan%2Fcontainerapps-acmebot%2Fmaster%2Fazuredeploy.json" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3958108d59aa2748ddc31edfa3e510d89c27efbf3d308bdeec8e8aa57a4072e6/68747470733a2f2f616b612e6d732f6465706c6f79746f617a757265627574746f6e"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;
&lt;br&gt;
&lt;/table&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Learn more at &lt;a href="https://github.com/shibayan/containerapps-acmebot/wiki/Getting-Started" rel="noopener noreferrer"&gt;https://github.com/shibayan/containerapps-acmebot/wiki/Getting-Started&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Thanks&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Based on &lt;a href="https://github.com/jeffhollan/containerapps-acmebot" rel="noopener noreferrer"&gt;containerapps-acmebot&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/jeffhollan"&gt;@jeffhollan&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/PKISharp/ACMESharpCore" rel="noopener noreferrer"&gt;ACMESharp Core&lt;/a&gt; by @ebekker&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Azure/azure-functions-durable-extension" rel="noopener noreferrer"&gt;Durable Functions&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/cgillum"&gt;@cgillum&lt;/a&gt; and contributors&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/MichaCo/DnsClient.NET" rel="noopener noreferrer"&gt;DnsClient.NET&lt;/a&gt; by @MichaCo&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/shibayan/containerapps-acmebot" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;It has the same functionality as other Acmebot products, but supports Container Apps specific features. Azure DNS is currently required for use.&lt;/p&gt;

&lt;p&gt;From here, I will actually use Acmebot to add a custom domain and certificate to the Container App.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy Acmebot
&lt;/h2&gt;

&lt;p&gt;Deploy Acmebot using the "Deploy to Azure" button in the README on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2pmft6jkl1fojbxseqj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2pmft6jkl1fojbxseqj.png" alt="Created resources" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After deployment is complete, add Azure AD authentication using App Service Authentication. Detailed instructions are provided in the README.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup RBAC (IAM) for Acmebot
&lt;/h2&gt;

&lt;p&gt;Add the &lt;code&gt;Contributor&lt;/code&gt; RBAC role to the deployed Acmebot for the resource group where Container Apps and Container Apps Environment are deployed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7qp1wbpr4t2qg4e3n97.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7qp1wbpr4t2qg4e3n97.png" alt="Adding RBAC setting" width="800" height="420"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Currently there is no RBAC role for Container Apps, so &lt;code&gt;Contributor&lt;/code&gt; RBAC role must be assigned.&lt;/p&gt;

&lt;p&gt;Since Acmebot requires Azure DNS for certificate issuance, assign the role of &lt;code&gt;DNS Zone Contributor&lt;/code&gt; to Acmebot for Azure DNS as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue certificate
&lt;/h2&gt;

&lt;p&gt;If the setup was successful, accessing the application will show a list of DNS Zones and Container Apps Environment.&lt;/p&gt;

&lt;p&gt;The following simple screen allows you to select a DNS zone and issue a certificate for the required domain name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1duvp9s7clsosxpolc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1duvp9s7clsosxpolc3.png" alt="Add certificate view" width="800" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Container Apps certificates are associated with the Container App Environment, so the Container Apps Environment must be explicitly specified when the certificate is issued.&lt;/p&gt;

&lt;p&gt;If the certificate is successfully issued, it can be found in the list of certificates in the Container Apps Environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4wqkrbtmivx3v196zlyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4wqkrbtmivx3v196zlyw.png" alt="Issued certificates" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Acmebot is designed to attempt to automatically renew certificates associated with the Container Apps Environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bind to Container App
&lt;/h2&gt;

&lt;p&gt;An additional option is to add custom domain settings to any Container App at the same time the certificate is issued.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65bpgxip6mwcc8ojsbct.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65bpgxip6mwcc8ojsbct.png" alt="Bind custom domain to Container App" width="800" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A custom domain is added to the Container App, but the actual A or CNAME DNS record is not automatically added and must be added manually. This is by design for safety.&lt;/p&gt;

&lt;p&gt;After manually adding the A record, the browser will be able to view the Container App hosted in the HTTPS-protected Zone apex domain, as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnj0pzd9kzehupvcnmjkp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnj0pzd9kzehupvcnmjkp.png" alt="Custom domain and certificate" width="588" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this way, Acmebot greatly reduces the effort of issuing certificates for Container Apps and automates their management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Renew certificates
&lt;/h2&gt;

&lt;p&gt;The default setting is to automatically renew certificates 30 days before they expire.&lt;/p&gt;

&lt;p&gt;Upon successful renewal of the certificate by Acmebot, Container Apps will automatically use the new certificate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related post
&lt;/h2&gt;

&lt;p&gt;If you are interested in the App Service and Key Vault version of Acmebot, please refer to the following post.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/shibayan/the-fastest-way-to-use-let-s-encrypt-in-azure-58pk" class="crayons-story__hidden-navigation-link"&gt;The fastest way to use Let's Encrypt in Azure&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/shibayan" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" alt="shibayan profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/shibayan" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Tatsuro Shibamura
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Tatsuro Shibamura
                
              
              &lt;div id="story-author-preview-content-455589" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/shibayan" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Tatsuro Shibamura&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/shibayan/the-fastest-way-to-use-let-s-encrypt-in-azure-58pk" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Sep 14 '20&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/shibayan/the-fastest-way-to-use-let-s-encrypt-in-azure-58pk" id="article-link-455589"&gt;
          The fastest way to use Let's Encrypt in Azure
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/azure"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;azure&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/appservice"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;appservice&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/keyvault"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;keyvault&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/letsencrypt"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;letsencrypt&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/shibayan/the-fastest-way-to-use-let-s-encrypt-in-azure-58pk" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;15&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/shibayan/the-fastest-way-to-use-let-s-encrypt-in-azure-58pk#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              3&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;Enjoy Azure Container Apps and Let's Encrypt!&lt;/p&gt;

</description>
      <category>azure</category>
      <category>tutorial</category>
      <category>containerapps</category>
      <category>letsencrypt</category>
    </item>
    <item>
      <title>Collecting Cosmos DB dependency telemetry with Application Insights</title>
      <dc:creator>Tatsuro Shibamura</dc:creator>
      <pubDate>Tue, 15 Feb 2022 17:29:45 +0000</pubDate>
      <link>https://dev.to/shibayan/collecting-cosmos-db-dependency-telemetry-with-application-insights-17pg</link>
      <guid>https://dev.to/shibayan/collecting-cosmos-db-dependency-telemetry-with-application-insights-17pg</guid>
      <description>&lt;p&gt;In this article, we will use Application Insights to collect the requests made to Azure Cosmos DB so that we can easily understand the performance issues.&lt;/p&gt;

&lt;p&gt;Cosmos DB is very fast, but depending on the query to be executed, it can consume a lot of Request Units or worsen the latency in some cases.&lt;/p&gt;

&lt;p&gt;In order to understand the problem at the application level, you can create an extension to Cosmos DB SDK v3 and send the request information to Application Insights.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Azure" rel="noopener noreferrer"&gt;
        Azure
      &lt;/a&gt; / &lt;a href="https://github.com/Azure/azure-cosmos-dotnet-v3" rel="noopener noreferrer"&gt;
        azure-cosmos-dotnet-v3
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      .NET SDK for Azure Cosmos DB for the core SQL API
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://www.nuget.org/packages/Microsoft.Azure.Cosmos" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ecb0e6c8fdbc7a1b8eaf1c6d8b0f4a641d4477d6c0547341f4cd99bb0ac5728d/68747470733a2f2f696d672e736869656c64732e696f2f6e756765742f762f4d6963726f736f66742e417a7572652e436f736d6f732e737667" alt="NuGet"&gt;&lt;/a&gt;
&lt;a href="https://www.nuget.org/packages/Microsoft.Azure.Cosmos" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6eb46a34e83b5329c1aebfa448eddcffd4994dea192a94ce0f0631f9c9c51379/68747470733a2f2f696d672e736869656c64732e696f2f6e756765742f767072652f4d6963726f736f66742e417a7572652e436f736d6f732e737667" alt="NuGet Prerelease"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Microsoft Azure Cosmos DB .NET SDK Version 3&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This client library enables client applications to connect to Azure Cosmos DB for NoSQL. Azure Cosmos DB is a globally distributed, multi-model database service. For more information, refer to &lt;a href="https://azure.microsoft.com/services/cosmos-db/" rel="nofollow noopener noreferrer"&gt;https://azure.microsoft.com/services/cosmos-db/&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight highlight-source-cs notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-smi"&gt;CosmosClient&lt;/span&gt; &lt;span class="pl-s1"&gt;client&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-smi"&gt;CosmosClient&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"https://mycosmosaccount.documents.azure.com:443/"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s"&gt;"mysupersecretkey"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-smi"&gt;Database&lt;/span&gt; &lt;span class="pl-s1"&gt;database&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-s1"&gt;client&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;CreateDatabaseIfNotExistsAsync&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"MyDatabaseName"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-smi"&gt;Container&lt;/span&gt; &lt;span class="pl-s1"&gt;container&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-s1"&gt;database&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;CreateContainerIfNotExistsAsync&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;
    &lt;span class="pl-s"&gt;"MyContainerName"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;"/partitionKeyPath"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-c1"&gt;400&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-c"&gt;// Create an item&lt;/span&gt;
&lt;span class="pl-smi"&gt;dynamic&lt;/span&gt; &lt;span class="pl-s1"&gt;testItem&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;id&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;"MyTestItemId"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;partitionKeyPath&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;"MyTestPkValue"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;details&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;"it's working"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;status&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;"done"&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-smi"&gt;ItemResponse&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-smi"&gt;dynamic&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-s1"&gt;createResponse&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-s1"&gt;container&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;CreateItemAsync&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;testItem&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-c"&gt;// Query for an item&lt;/span&gt;
&lt;span class="pl-k"&gt;using&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;FeedIterator&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-smi"&gt;dynamic&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-s1"&gt;feedIterator&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;container&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-smi"&gt;GetItemQueryIterator&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-smi"&gt;dynamic&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;
    &lt;span class="pl-s"&gt;"select * from T where T.status = 'done'"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
&lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-k"&gt;while&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Azure/azure-cosmos-dotnet-v3" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Cosmos DB SDK v3 provides an extension point called &lt;code&gt;RequestHandler&lt;/code&gt;, which can be used to implement the Application Insights dependency collector.&lt;/p&gt;

&lt;p&gt;It is very easy to send dependency telemetry to Application Insights. Please refer to the official documentation available here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/custom-operations-tracking" rel="noopener noreferrer"&gt;Track custom operations with Azure Application Insights .NET SDK - Azure Monitor | Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;RequestHandler&lt;/code&gt; to send dependency telemetry to Application Insights that we implemented is as follows.&lt;/p&gt;

&lt;p&gt;Once you have decided what to send to Application Insights, the sending itself can be done with a very simple code. In this example, we are sending the name of the resource in Cosmos DB and the Request Units that were consumed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppInsightsRequestHandler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RequestHandler&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SimpleAppInsightsRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TelemetryClient&lt;/span&gt; &lt;span class="n"&gt;telemetryClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_telemetryClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;telemetryClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;TelemetryClient&lt;/span&gt; &lt;span class="n"&gt;_telemetryClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RequestMessage&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dependency&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_telemetryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartOperation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DependencyTelemetry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestUri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OriginalString&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;telemetry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Telemetry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Used to identify Cosmos DB in Application Insights&lt;/span&gt;
        &lt;span class="n"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Azure DocumentDB"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestUri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OriginalString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResultCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Success&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsSuccessStatusCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Send with Metrics&lt;/span&gt;
        &lt;span class="n"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Metrics&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"RequestCharge"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestCharge&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use the implemented &lt;code&gt;RequestHandler&lt;/code&gt;, you just need to write the following code with Dependency Injection. Don't forget to install the Application Insights SDK for your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppInsightsRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;requestHandler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppInsightsRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connectionString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CosmosConnection"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CosmosClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CosmosClientOptions&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;CustomHandlers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;requestHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run the application with the above code, you will be able to check the Cosmos DB request information from Dependency in Application Insights.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc55tn2znl84jx9jqizwz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc55tn2znl84jx9jqizwz.png" alt="Dependency performance in Application Insights" width="635" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The telemetry details can be viewed from the E2E transaction view to see the Request Units consumed by the request and the resource URIs executed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp42ijxdeqq6iaw6zqows.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp42ijxdeqq6iaw6zqows.png" alt="Dependency details in Application Insights" width="548" height="698"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Request Units that are sent at the same time as dependency telemetry are treated as metrics and can be displayed graphically from the Metric view of Application Insights. Of course, advanced aggregation using KQL can also be done easily.&lt;/p&gt;

&lt;p&gt;The simple implementation so far provides a minimum of information, but we will make the information to be sent more detailed.&lt;/p&gt;

&lt;p&gt;The Application Insights SDK implements a dependency collector for Cosmos DB, but it is only available when the connection mode is Gateway. However, the implementation can be reused, so we will refer to it to detail the telemetry.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/microsoft/ApplicationInsights-dotnet/blob/main/WEB/Src/DependencyCollector/DependencyCollector/Implementation/HttpParsers/DocumentDbHttpParser.cs" rel="noopener noreferrer"&gt;ApplicationInsights-dotnet/DocumentDbHttpParser.cs at main · microsoft/ApplicationInsights-dotnet · GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following is an implementation that uses the Application Insights SDK implementation to flesh out the telemetry.&lt;/p&gt;

&lt;p&gt;Some methods that are not related to Cosmos DB are omitted, so please copy them from the Application Insights SDK if necessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppInsightsRequestHandler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RequestHandler&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;AppInsightsRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TelemetryClient&lt;/span&gt; &lt;span class="n"&gt;telemetryClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_telemetryClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;telemetryClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;TelemetryClient&lt;/span&gt; &lt;span class="n"&gt;_telemetryClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RequestMessage&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dependency&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_telemetryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartOperation&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DependencyTelemetry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cosmos"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;telemetry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Telemetry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;resourcePath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpParsingHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseResourcePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestUri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OriginalString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// populate properties&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;resourcePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;propertyName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetPropertyNameForResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;propertyName&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;propertyName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;operation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpParsingHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BuildOperationMoniker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;resourcePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;operationName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetOperationName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Azure DocumentDB"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;operationName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestUri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OriginalString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResultCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Success&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsSuccessStatusCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Metrics&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"RequestCharge"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestCharge&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;OperationNames&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Database operations&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"POST /dbs"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Create database"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"GET /dbs"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"List databases"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"GET /dbs/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Get database"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"DELETE /dbs/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Delete database"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="c1"&gt;// Collection operations&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"POST /dbs/*/colls"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Create collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"GET /dbs/*/colls"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"List collections"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"POST /dbs/*/colls/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Query documents"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"GET /dbs/*/colls/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Get collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"DELETE /dbs/*/colls/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Delete collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"PUT /dbs/*/colls/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Replace collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="c1"&gt;// Document operations&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"POST /dbs/*/colls/*/docs"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Create document"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"GET /dbs/*/colls/*/docs"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"List documents"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"GET /dbs/*/colls/*/docs/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Get document"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"PUT /dbs/*/colls/*/docs/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Replace document"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"DELETE /dbs/*/colls/*/docs/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Delete document"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;GetPropertyNameForResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;resourceType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ignore high cardinality resources (documents, attachments, etc.)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resourceType&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"dbs"&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Database"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"colls"&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetOperationName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OperationNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;operationName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;operationName&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run the application using this implementation, you can check the dependency telemetry for each operation against Cosmos DB in Application Insights.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F570z0f4ea7mi1a07gn12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F570z0f4ea7mi1a07gn12.png" alt="More dependency performance in Application Insights" width="679" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, you can see the Request Units consumed for the query in Application Insights.&lt;/p&gt;

&lt;p&gt;At the same time, the DB name and container name will be sent as custom properties, so you can easily grasp the RU consumption per container.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kzopm24ojlkotqk5y8y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kzopm24ojlkotqk5y8y.png" alt="More dependency details in Application Insights" width="546" height="762"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it is simply the Request Units consumed, it can be understood by transferring the Cosmos DB logs to Log Analytics, but it is not possible to understand how many Cosmos DB queries are executed by which operations in the actual application, so it is best combined with Application Insights.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>cosmosdb</category>
      <category>dotnet</category>
      <category>performance</category>
    </item>
    <item>
      <title>How to build an interactive command-line application in .NET</title>
      <dc:creator>Tatsuro Shibamura</dc:creator>
      <pubDate>Mon, 23 Aug 2021 16:27:19 +0000</pubDate>
      <link>https://dev.to/shibayan/how-to-build-an-interactive-command-line-application-in-net-4oic</link>
      <guid>https://dev.to/shibayan/how-to-build-an-interactive-command-line-application-in-net-4oic</guid>
      <description>&lt;p&gt;Development using Node.js often provides highly interactive command line applications such as &lt;code&gt;vue-cli&lt;/code&gt; and &lt;code&gt;create-nuxt-app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As an example, &lt;code&gt;create-nuxt-app&lt;/code&gt; has an interactive interface that allows even beginners to start development right away by simply answering questions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo7s37za7bmnq19f2r7kv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo7s37za7bmnq19f2r7kv.gif" alt="create-nuxt-app" width="850" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I find this interface to be very beautiful and easy to use.&lt;/p&gt;

&lt;p&gt;On the other hand, C# / .NET developers are provided with a powerful integrated development environment called Visual Studio, so they do not need to operate on the command line to start development, but Windows Terminal and WSL 2 increasingly require a command line interface.&lt;/p&gt;

&lt;p&gt;Since there were not many ways to implement an interactive command line interface for C# like Node.js, I developed a library to implement it easily.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/shibayan" rel="noopener noreferrer"&gt;
        shibayan
      &lt;/a&gt; / &lt;a href="https://github.com/shibayan/Sharprompt" rel="noopener noreferrer"&gt;
        Sharprompt
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Interactive command-line based application framework for C#
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Sharprompt&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/shibayan/Sharprompt/actions/workflows/build.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/shibayan/Sharprompt/workflows/Build/badge.svg" alt="Build"&gt;&lt;/a&gt;
&lt;a href="https://www.nuget.org/packages/Sharprompt/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/72337efb1abfda2b5880131ffa655d4ebf26b3aa51ea5e6b610d7cbb3dda9291/68747470733a2f2f62616467656e2e6e65742f6e756765742f64742f5368617270726f6d7074" alt="Downloads"&gt;&lt;/a&gt;
&lt;a href="https://www.nuget.org/packages/Sharprompt/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c6c1a2c24c84fdfd550f0f0b054a9b23e9bee45dc81eb2ab539104430db72874/68747470733a2f2f62616467656e2e6e65742f6e756765742f762f5368617270726f6d7074" alt="NuGet"&gt;&lt;/a&gt;
&lt;a href="https://github.com/shibayan/Sharprompt/blob/master/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3014bd37a963668ca8aad83e85e4541822e99522f1685367f21c8263a033b079/68747470733a2f2f62616467656e2e6e65742f6769746875622f6c6963656e73652f736869626179616e2f5368617270726f6d7074" alt="License"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interactive command-line based application framework for C#&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/1356444/62227794-87506e00-b3f7-11e9-84ae-06c9a900448b.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F1356444%2F62227794-87506e00-b3f7-11e9-84ae-06c9a900448b.gif" alt="sharprompt"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Multi-platform support&lt;/li&gt;
&lt;li&gt;Supports the popular prompts (&lt;code&gt;Input&lt;/code&gt; / &lt;code&gt;Password&lt;/code&gt; / &lt;code&gt;Select&lt;/code&gt; / etc)&lt;/li&gt;
&lt;li&gt;Supports model-based prompts&lt;/li&gt;
&lt;li&gt;Validation of input value&lt;/li&gt;
&lt;li&gt;Automatic generation of data source using Enum type&lt;/li&gt;
&lt;li&gt;Customizable symbols and color schema&lt;/li&gt;
&lt;li&gt;Unicode support (Multi-byte characters and Emoji😀🎉)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-powershell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;Install-Package&lt;/span&gt; Sharprompt&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;dotnet add package Sharprompt&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick start&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-cs notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;// Simple input&lt;/span&gt;
&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-s1"&gt;name&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;Prompt&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-smi"&gt;Input&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-smi"&gt;string&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"What's your name?"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-s1"&gt;Console&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;WriteLine&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-s"&gt;$&lt;/span&gt;"Hello, &lt;span class="pl-kos"&gt;{&lt;/span&gt;&lt;span class="pl-s1"&gt;name&lt;/span&gt;&lt;span class="pl-kos"&gt;}&lt;/span&gt;!"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-c"&gt;// Password input&lt;/span&gt;
&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-s1"&gt;secret&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;Prompt&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;Password&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"Type new password"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;validators&lt;/span&gt;&lt;span class="pl-c1"&gt;:&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt;&lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;Validators&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;Required&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;Validators&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;MinLength&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-c1"&gt;8&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-s1"&gt;Console&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;WriteLine&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"Password OK"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-c"&gt;// Confirmation&lt;/span&gt;
&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-s1"&gt;answer&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;Prompt&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;Confirm&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"Are you ready?"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;defaultValue&lt;/span&gt;&lt;span class="pl-c1"&gt;:&lt;/span&gt; &lt;span class="pl-c1"&gt;true&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-s1"&gt;Console&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/shibayan/Sharprompt" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;It can be easily installed in a console application project from NuGet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Install-Package Sharprompt
or
dotnet add package Sharprompt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;First, let's create an application with two very simple input fields.&lt;/p&gt;

&lt;p&gt;In Sharprompt, all the APIs are defined in the class &lt;code&gt;Prompt&lt;/code&gt;, so your application will use only the methods you need. This time we will use &lt;code&gt;Prompt.Input&amp;lt;T&amp;gt;&lt;/code&gt; because I need an arbitrary value entered by the user.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Prompt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"What's your name?"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Prompt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enter any number"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Hello, &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"The number entered is &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The type parameter specifies the type of the final value required. Sharprompt automatically performs type conversion and error handling according to the specified type.&lt;/p&gt;

&lt;p&gt;You now have a console application that allows you to enter a name and an arbitrary number.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuezzix1p0khwf8d79b97.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuezzix1p0khwf8d79b97.gif" alt="Simple application" width="721" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The APIs include password input, selectable from a list, etc., so that complex console applications can be developed.&lt;/p&gt;

&lt;p&gt;As a NET / C# developer, you often want to define input values and validation on a class and attribute-based.&lt;/p&gt;

&lt;p&gt;For such use cases, Sharprompt provides an API to create forms automatically on a model-based.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Prompt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AutoForms&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PromptModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Hello, &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"The number entered is &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PromptModel&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Prompt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"What's your name?"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Required&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Prompt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Enter any number"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Required&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you have experience developing with ASP.NET Core, you are probably familiar with this class definition.&lt;/p&gt;

&lt;p&gt;If you call &lt;code&gt;Prompt.AutoForms&amp;lt;T&amp;gt;&lt;/code&gt; with this class definition, it will automatically create an input form with validation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faput1ca7upy09z2n2xyi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faput1ca7upy09z2n2xyi.gif" alt="Model-based application" width="721" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the validation uses standard .NET attributes, it is also possible to easily add custom validations.&lt;/p&gt;

&lt;p&gt;Now you can see how easy it is to development an interactive console application in .NET / C#.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example: create-function-app
&lt;/h3&gt;

&lt;p&gt;Finally, here is a mock of &lt;code&gt;create-function-app&lt;/code&gt;, a CLI tool for Azure Functions with an interface like &lt;code&gt;create-nuxt-app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Being able to interactively create Azure Functions projects will make it easier to start developing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fefmq8ncle1pz5h8w6i66.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fefmq8ncle1pz5h8w6i66.gif" alt="create-function-app" width="721" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This mock source code is here!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/shibayan" rel="noopener noreferrer"&gt;
        shibayan
      &lt;/a&gt; / &lt;a href="https://github.com/shibayan/create-function-app-mock" rel="noopener noreferrer"&gt;
        create-function-app-mock
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Sharprompt demo application
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;If you have any feedback, please feel free to visit GitHub.&lt;/p&gt;

&lt;p&gt;Enjoy the development!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>commandline</category>
      <category>cli</category>
    </item>
    <item>
      <title>How to use Netherite Storage Provider in Durable Functions</title>
      <dc:creator>Tatsuro Shibamura</dc:creator>
      <pubDate>Tue, 20 Jul 2021 16:23:47 +0000</pubDate>
      <link>https://dev.to/shibayan/how-to-use-netherite-storage-provider-in-durable-functions-4mff</link>
      <guid>https://dev.to/shibayan/how-to-use-netherite-storage-provider-in-durable-functions-4mff</guid>
      <description>&lt;p&gt;Netherite Storage Provider is a backend implementation of Durable Functions that delivers high performance.&lt;/p&gt;

&lt;p&gt;It's still a preview version, but if you are using Functions Premium (EP1-3), it's worth evaluating it now.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/microsoft" rel="noopener noreferrer"&gt;
        microsoft
      &lt;/a&gt; / &lt;a href="https://github.com/microsoft/durabletask-netherite" rel="noopener noreferrer"&gt;
        durabletask-netherite
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A new engine for Durable Functions. https://microsoft.github.io/durabletask-netherite
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/microsoft/durabletask-netherite/src/DurableTask.Netherite/icon.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmicrosoft%2Fdurabletask-netherite%2FHEAD%2Fsrc%2FDurableTask.Netherite%2Ficon.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Netherite&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Netherite is a distributed workflow execution engine for &lt;a href="https://github.com/Azure/azure-functions-durable-extension" rel="noopener noreferrer"&gt;Durable Functions&lt;/a&gt; (DF) and the &lt;a href="https://github.com/Azure/durabletask/" rel="noopener noreferrer"&gt;Durable Task Framework&lt;/a&gt; (DTFx).&lt;/p&gt;
&lt;p&gt;It is of potential interest to anyone developing applications on those platforms who has an appetite for performance, scalability, and reliability.&lt;/p&gt;
&lt;p&gt;As Netherite is intended to be a drop-in backend replacement, it does not modify the application API. Existing DF and DTFx applications can switch to this backend with little effort
However, we do not support migrating existing task hub contents between different backends.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;To get started, you can either try out the sample, or take an existing DF app and switch it to the Netherite backend. You can also read our &lt;a href="https://microsoft.github.io/durabletask-netherite/#/README" rel="nofollow noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The hello sample.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For a comprehensive quick start on using Netherite with Durable Functions, take a look at &lt;a href="https://microsoft.github.io/durabletask-netherite/#/hello-sample.md" rel="nofollow noopener noreferrer"&gt;hello sample walkthrough&lt;/a&gt;, and the associated &lt;a href="https://microsoft.github.io/durabletask-netherite/#/hello-sample.md?id=walk-through-on-youtube-%f0%9f%8e%a5" rel="nofollow noopener noreferrer"&gt;video content&lt;/a&gt;
We included several scripts that make it easy…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/microsoft/durabletask-netherite" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-storage-providers#comparing-storage-providers" rel="noopener noreferrer"&gt;Durable Functions storage providers - Azure | Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The use of Netherite requires some additional work, so we will briefly introduce how to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Netherite
&lt;/h2&gt;

&lt;p&gt;First, install the &lt;code&gt;Microsoft.Azure.DurableTask.Netherite.AzureFunctions&lt;/code&gt; package in your Azure Functions project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.nuget.org/packages/Microsoft.Azure.DurableTask.Netherite.AzureFunctions/" rel="noopener noreferrer"&gt;NuGet Gallery | Microsoft.Azure.DurableTask.Netherite.AzureFunctions&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Install-Package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Microsoft.Azure.DurableTask.Netherite.AzureFunctions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;0.4.0-alpha&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Microsoft.Azure.DurableTask.Netherite.AzureFunctions &lt;span class="nt"&gt;--version&lt;/span&gt; 0.4.0-alpha
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing the package, declare that you want to use Netherite in &lt;code&gt;host.json&lt;/code&gt;. There are many configurations in the &lt;code&gt;storageProvider&lt;/code&gt;, please refer to the official documentation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"logging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"applicationInsights"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"samplingSettings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"isEnabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"excludedTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Request"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"durableTask"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"hubName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;YourHubName&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"useGracefulShutdown"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"storageProvider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Netherite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"StorageConnectionName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AzureWebJobsStorage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"EventHubsConnectionName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EventHubsConnection"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the connection string names for Storage and Event Hubs to the key names in the Azure Functions App Settings or &lt;code&gt;local.settings.json&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preserve &lt;code&gt;System.Threading.Channels.dll&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The current version &lt;code&gt;0.4.0-alpha&lt;/code&gt; does not work with an error when deployed to Azure Functions, so you need to add &lt;code&gt;FunctionsPreservedDependencies&lt;/code&gt; to the csproj file to avoid this problem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;netcoreapp3.1&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;AzureFunctionsVersion&amp;gt;&lt;/span&gt;v3&lt;span class="nt"&gt;&amp;lt;/AzureFunctionsVersion&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Azure.DurableTask.Netherite.AzureFunctions"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"0.4.0-alpha"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Azure.WebJobs.Extensions.DurableTask"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"2.5.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk.Functions"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"3.0.13"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;FunctionsPreservedDependencies&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"System.Threading.Channels.dll"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;None&lt;/span&gt; &lt;span class="na"&gt;Update=&lt;/span&gt;&lt;span class="s"&gt;"host.json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;CopyToOutputDirectory&amp;gt;&lt;/span&gt;PreserveNewest&lt;span class="nt"&gt;&amp;lt;/CopyToOutputDirectory&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/None&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;None&lt;/span&gt; &lt;span class="na"&gt;Update=&lt;/span&gt;&lt;span class="s"&gt;"local.settings.json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;CopyToOutputDirectory&amp;gt;&lt;/span&gt;PreserveNewest&lt;span class="nt"&gt;&amp;lt;/CopyToOutputDirectory&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;CopyToPublishDirectory&amp;gt;&lt;/span&gt;Never&lt;span class="nt"&gt;&amp;lt;/CopyToPublishDirectory&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/None&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a setting to prevent &lt;code&gt;System.Threading.Channels.dll&lt;/code&gt; from being removed on deployment. This fix will allow it to work on Azure Functions.&lt;/p&gt;

&lt;p&gt;This problem is expected to be fixed in a future version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Function App and Event Hubs
&lt;/h2&gt;

&lt;p&gt;Create Function App and Event Hubs Namespace by using Azure Portal or ARM Template.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Functions Premium (EP1-3)

&lt;ul&gt;
&lt;li&gt;Consumption Plan is not supported.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Event Hubs Namespace (Standard, 1TU)

&lt;ul&gt;
&lt;li&gt;Event Hubs are automatically created by Netherite&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Since Netherite creates the Event Hub automatically, it is easier to use &lt;code&gt;RootManageSharedAccessKey&lt;/code&gt; for the SAS key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use 64-bit worker process
&lt;/h2&gt;

&lt;p&gt;FASTER needs to run in a 64-bit process, so change the Platform setting of Azure Functions to 64-bit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqgm7x7voq1tls9ziue4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqgm7x7voq1tls9ziue4.png" alt="64-bit worker process" width="564" height="318"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;If you run the application with the 32-bit Platform setting, the following exception will be thrown at runtime and it will not work properly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Part** !!! Encountered exception while working on store in StoreWorker.Process: FASTER.core.FasterException: Overflow in AddressInfo - consider running the program in x64 mode for larger address space support
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that when you deploy Azure Functions (Windows) from Azure Portal, 32-bit Platform will be selected by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable Runtime Scale Monitoring
&lt;/h2&gt;

&lt;p&gt;Durable Functions with Netherite installed running on Functions Premium (EP1-3) need to have Runtime Scale Monitoring enabled in order to scale out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonbhrzz57vecjdp6raxe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonbhrzz57vecjdp6raxe.png" alt="Runtime Scale Monitoring" width="606" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since Runtime Scale Monitoring requires warmed-up instances, set &lt;code&gt;preWarmedInstanceCount&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt; when creating resources with ARM Template or Terraform.&lt;/p&gt;

&lt;p&gt;After these steps, Azure Functions using Netherite is now working perfectly. Now you can verify the performance and have fun.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>functions</category>
      <category>severless</category>
      <category>workflow</category>
    </item>
    <item>
      <title>Writing Static Web Apps configuration with JSON Schema</title>
      <dc:creator>Tatsuro Shibamura</dc:creator>
      <pubDate>Thu, 27 May 2021 14:58:10 +0000</pubDate>
      <link>https://dev.to/shibayan/writing-static-web-apps-configuration-with-json-schema-1l4a</link>
      <guid>https://dev.to/shibayan/writing-static-web-apps-configuration-with-json-schema-1l4a</guid>
      <description>&lt;p&gt;Azure Static Web Apps now supports login using external IdPs such as Azure AD and Facebook at the same time as GA.&lt;/p&gt;

&lt;p&gt;You do not need to write any additional code for authentication, but you do need to create &lt;code&gt;staticwebapp.config.json&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/static-web-apps/configuration" rel="noopener noreferrer"&gt;Configure Azure Static Web Apps | Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-custom?tabs=aad" rel="noopener noreferrer"&gt;Custom authentication in Azure Static Web Apps | Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have read the documentation, you must have found it difficult to write the configuration file correctly. I was one of those who felt that way.&lt;/p&gt;

&lt;p&gt;Let's use JSON Schema to write a configuration file easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load from Schema Store
&lt;/h2&gt;

&lt;p&gt;JSON Schema for &lt;code&gt;staticwebapp.config.json&lt;/code&gt; is already shared by a service called Schema Store.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.schemastore.org/json/" rel="noopener noreferrer"&gt;JSON Schema Store&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The URL of the actual JSON Schema is as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://json.schemastore.org/staticwebapp.config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can load this JSON Schema into any supported editor or IDE for autocompletion and format validation.&lt;/p&gt;

&lt;p&gt;My recommendation is Visual Studio Code, but the same feature is available in Visual Studio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual Studio Code
&lt;/h2&gt;

&lt;p&gt;Visual Studio Code has built-in support for JSON Schema, but additional configuration is required to use JSON Schema in certain files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/docs/languages/json#_json-schemas-and-settings" rel="noopener noreferrer"&gt;JSON schemas and settings | JSON editing in Visual Studio Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open the settings of Visual Studio Code and search for JSON Schema to find the item.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs18az0u3olhfbx5xbvr3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs18az0u3olhfbx5xbvr3.png" alt="JSON Schema setting" width="707" height="329"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Add the following definition to &lt;code&gt;json.schemas&lt;/code&gt;. As you can see from the fact that it is an array, multiple definitions can be added.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"json.schemas"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"fileMatch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"/staticwebapp.config.json"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://json.schemastore.org/staticwebapp.config.json"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you add the JSON Schema definition, the JSON Schema will be automatically loaded when you open &lt;code&gt;staticwebapp.config.json&lt;/code&gt; from now on.&lt;/p&gt;

&lt;p&gt;As a result, autocomplete using JSON Schema will work in Visual Studio Code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tadi5bk9y2jyxvd80x1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tadi5bk9y2jyxvd80x1.gif" alt="Writing with JSON Schema" width="634" height="386"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Since there is no need to manually enter the required properties, the possibility of making a mistake is very low.&lt;/p&gt;

&lt;p&gt;Of course, the validation is performed in real time in the editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual Studio
&lt;/h2&gt;

&lt;p&gt;If you are using Visual Studio, the Schema Store catalog file has already been set up.&lt;/p&gt;

&lt;p&gt;If it is not set, manually add the URL of the catalog file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://schemastore.org/api/json/catalog.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xuc0dfu9fpbm5c3evlh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xuc0dfu9fpbm5c3evlh.png" alt="JSON Schema catalog setting" width="763" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to the file name, the corresponding JSON Schema will be downloaded and used.&lt;/p&gt;

&lt;p&gt;Just open &lt;code&gt;staticwebapp.config.json&lt;/code&gt; in Visual Studio and you can use IntelliSense for autocompletion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1y6fbvs4jt1w8vuv25d.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1y6fbvs4jt1w8vuv25d.gif" alt="Writing with JSON Schema" width="626" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By using JSON Schema, you can write complex routing and authentication definitions without making any mistakes.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>visualstudio</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Follow-up on the session at Cosmos DB Conf</title>
      <dc:creator>Tatsuro Shibamura</dc:creator>
      <pubDate>Fri, 23 Apr 2021 16:32:49 +0000</pubDate>
      <link>https://dev.to/shibayan/follow-up-on-the-session-at-cosmos-db-conf-1mcm</link>
      <guid>https://dev.to/shibayan/follow-up-on-the-session-at-cosmos-db-conf-1mcm</guid>
      <description>&lt;p&gt;This is a follow-up post to the session "Design and implementation of Cosmos DB Change Feed-centric architecture" that &lt;a class="mentioned-user" href="https://dev.to/miyake"&gt;@miyake&lt;/a&gt; and I spoke at Cosmos DB Conf.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gotcosmos.com/conf" rel="noopener noreferrer"&gt;Azure Cosmos DB Conf&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It introduces an actual example and implementation of the architecture using Cosmos DB Change Feed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live stream and slides
&lt;/h2&gt;

&lt;p&gt;The video and slides of the session are already available. The session itself is conducted in Japanese, but all the slides are prepared in English.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/eaIF58ISC4c"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;iframe class="speakerdeck-iframe ltag_speakerdeck" src="https://speakerdeck.com/player/d385529c509143d693a3aad1cec58f47"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;It takes advantage of the high availability and performance of the Cosmos DB Change Feed to make the lambda architecture completely serverless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;p&gt;Cosmos DB is very reliable, but there are a few caveats that need to be taken into account in order to increase the reliability of the overall architecture.&lt;/p&gt;

&lt;p&gt;Here is a related post that picks up on some of the important points.&lt;/p&gt;

&lt;h3&gt;
  
  
  Batch processing - Change Feed pull model
&lt;/h3&gt;

&lt;p&gt;Use the Pull model to control the pace at which data is read from the Change Feed. This is important when implementing batch processing.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/shibayan/first-steps-of-the-change-feed-pull-model-in-azure-cosmos-db-34p" class="crayons-story__hidden-navigation-link"&gt;First steps of the Change Feed pull model in Azure Cosmos DB&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/shibayan" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" alt="shibayan profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/shibayan" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Tatsuro Shibamura
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Tatsuro Shibamura
                
              
              &lt;div id="story-author-preview-content-590988" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/shibayan" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Tatsuro Shibamura&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/shibayan/first-steps-of-the-change-feed-pull-model-in-azure-cosmos-db-34p" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Feb 5 '21&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/shibayan/first-steps-of-the-change-feed-pull-model-in-azure-cosmos-db-34p" id="article-link-590988"&gt;
          First steps of the Change Feed pull model in Azure Cosmos DB
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/azure"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;azure&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/cosmosdb"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;cosmosdb&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/changefeed"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;changefeed&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/serverless"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;serverless&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/shibayan/first-steps-of-the-change-feed-pull-model-in-azure-cosmos-db-34p" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;8&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/shibayan/first-steps-of-the-change-feed-pull-model-in-azure-cosmos-db-34p#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;h3&gt;
  
  
  Improving resiliency - Retry policy
&lt;/h3&gt;

&lt;p&gt;The best practice for Change Feed is to use &lt;code&gt;CosmosDBTrigger&lt;/code&gt;, but you also need to think about what happens if the funtions fails.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/shibayan/a-quick-review-of-the-azure-functions-new-feature-retry-policy-p56" class="crayons-story__hidden-navigation-link"&gt;A quick review of the Azure Functions new feature "Retry Policy"&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/shibayan" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" alt="shibayan profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/shibayan" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Tatsuro Shibamura
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Tatsuro Shibamura
                
              
              &lt;div id="story-author-preview-content-507336" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/shibayan" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Tatsuro Shibamura&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/shibayan/a-quick-review-of-the-azure-functions-new-feature-retry-policy-p56" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Nov 5 '20&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/shibayan/a-quick-review-of-the-azure-functions-new-feature-retry-policy-p56" id="article-link-507336"&gt;
          A quick review of the Azure Functions new feature "Retry Policy"
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/azure"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;azure&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/functions"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;functions&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/serverless"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;serverless&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/eventdriven"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;eventdriven&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/shibayan/a-quick-review-of-the-azure-functions-new-feature-retry-policy-p56" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;13&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/shibayan/a-quick-review-of-the-azure-functions-new-feature-retry-policy-p56#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              1&lt;span class="hidden s:inline"&gt; comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;h3&gt;
  
  
  Avoid inconsistency - Graceful shutdown
&lt;/h3&gt;

&lt;p&gt;We need to be prepared for randomly timed restarts, which is a characteristic of serverless.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/shibayan/best-practices-for-graceful-shutdown-in-azure-functions-21b2" class="crayons-story__hidden-navigation-link"&gt;Best Practices for Graceful shutdown in Azure Functions&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/shibayan" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" alt="shibayan profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/shibayan" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Tatsuro Shibamura
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Tatsuro Shibamura
                
              
              &lt;div id="story-author-preview-content-591584" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/shibayan" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Tatsuro Shibamura&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/shibayan/best-practices-for-graceful-shutdown-in-azure-functions-21b2" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Feb 4 '21&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/shibayan/best-practices-for-graceful-shutdown-in-azure-functions-21b2" id="article-link-591584"&gt;
          Best Practices for Graceful shutdown in Azure Functions
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/azure"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;azure&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/functions"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;functions&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/serverless"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;serverless&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dotnet"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dotnet&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/shibayan/best-practices-for-graceful-shutdown-in-azure-functions-21b2" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;21&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/shibayan/best-practices-for-graceful-shutdown-in-azure-functions-21b2#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  Coolest tweets
&lt;/h2&gt;

&lt;p&gt;The session was held at the end of the APAC time zone, but it was watched by many people. Thank you!&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1384735423021211650-157" src="https://platform.twitter.com/embed/Tweet.html?id=1384735423021211650"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1384735423021211650-157');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1384735423021211650&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1384737466733645824-411" src="https://platform.twitter.com/embed/Tweet.html?id=1384737466733645824"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1384737466733645824-411');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1384737466733645824&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Have fun developing with Cosmos DB Change Feed and Azure Functions!&lt;/p&gt;

</description>
      <category>azure</category>
      <category>cosmosdb</category>
      <category>serverless</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>What I'm doing to implement a modern Azure Functions application</title>
      <dc:creator>Tatsuro Shibamura</dc:creator>
      <pubDate>Mon, 15 Mar 2021 17:31:33 +0000</pubDate>
      <link>https://dev.to/shibayan/what-i-m-doing-to-implement-a-modern-azure-functions-application-5f0k</link>
      <guid>https://dev.to/shibayan/what-i-m-doing-to-implement-a-modern-azure-functions-application-5f0k</guid>
      <description>&lt;p&gt;In the past few years, I have been implementing many applications that fully utilize Azure Functions, and at the same time, I have learned how to use Azure Functions without failing.&lt;/p&gt;

&lt;p&gt;Recently, I've been doing a lot of hackathons, especially Azure Light-up, and I always try to explain this area whenever I use Azure Functions. In short, we are talking about understanding the advantages and characteristics of Azure Functions and using them wisely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Always prioritize the use of Bindings / Triggers
&lt;/h2&gt;

&lt;p&gt;One of the best features of Azure Functions is the rich and extensible Bindings and Triggers that I always use.&lt;/p&gt;

&lt;p&gt;You don't need to know how to use SDKs such as Azure Storage or Event Hub to use these useful features. Recently, I've been using &lt;code&gt;CosmosDBTrigger&lt;/code&gt; a lot.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings?tabs=csharp" rel="noopener noreferrer"&gt;Azure Functions triggers and bindings concepts | Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reading and writing Blobs and Queues is a rather boring part of the code since it is almost the same code, but it requires a fair amount of code, so we use Bindings / Triggers to hide it.&lt;/p&gt;

&lt;p&gt;It's also important to focus on the actual business logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the Function implementation as small
&lt;/h2&gt;

&lt;p&gt;If the implementation of one function is large, it is often difficult to ensure idempotency and retry, so we basically let one function do only one process.&lt;/p&gt;

&lt;p&gt;By using Durable Functions, you can implement applications that work with multiple Functions without being aware of calls between instances, making it easier to keep your Function implementations small.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Azure" rel="noopener noreferrer"&gt;
        Azure
      &lt;/a&gt; / &lt;a href="https://github.com/Azure/azure-functions-durable-extension" rel="noopener noreferrer"&gt;
        azure-functions-durable-extension
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Durable Task Framework extension for Azure Functions
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;By combining single-feature Function with Queue Triger and Cosmos DB Change Feed, we can implement the desired application.&lt;/p&gt;

&lt;p&gt;If the responsibilities of the functions are not clearly defined, even deployment will be difficult.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the latest patterns in .NET
&lt;/h2&gt;

&lt;p&gt;The latest patterns in .NET does not mean using the latest C# language features, but trying to write code according to the base framework.&lt;/p&gt;

&lt;p&gt;Since Azure Functions v3 is based on .NET Core 3.1 / ASP.NET Core 3.1, it is possible to write simple code by following its style. In particular, Dependency Injection has become a must, so I immediately discard static classes and methods that are generated when Visual Studio is created.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/shibayan/a-new-era-of-azure-functions-development-6f2" class="crayons-story__hidden-navigation-link"&gt;A New Era of Azure Functions Development&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/shibayan" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" alt="shibayan profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/shibayan" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Tatsuro Shibamura
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Tatsuro Shibamura
                
              
              &lt;div id="story-author-preview-content-457720" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/shibayan" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Tatsuro Shibamura&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/shibayan/a-new-era-of-azure-functions-development-6f2" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Sep 17 '20&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/shibayan/a-new-era-of-azure-functions-development-6f2" id="article-link-457720"&gt;
          A New Era of Azure Functions Development
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/azure"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;azure&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/functions"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;functions&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dotnet"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dotnet&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/serverless"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;serverless&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/shibayan/a-new-era-of-azure-functions-development-6f2" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;31&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/shibayan/a-new-era-of-azure-functions-development-6f2#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;However, if you use complex DI, it will have the opposite effect, so I mainly use simple dependency resolution and instance lifetime management as DI without overdoing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design to be retryable
&lt;/h2&gt;

&lt;p&gt;By implementing a function as a single feature, it is easier to deal with retries because there is less to think about. It also makes it easier to ensure idempotency.&lt;/p&gt;

&lt;p&gt;The Azure SDK has retries built in from the beginning, so I basically use the built-in retries as is, and use Polly or Azure Function Retry Policy as needed.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/shibayan/a-quick-review-of-the-azure-functions-new-feature-retry-policy-p56" class="crayons-story__hidden-navigation-link"&gt;A quick review of the Azure Functions new feature "Retry Policy"&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/shibayan" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" alt="shibayan profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/shibayan" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Tatsuro Shibamura
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Tatsuro Shibamura
                
              
              &lt;div id="story-author-preview-content-507336" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/shibayan" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Tatsuro Shibamura&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/shibayan/a-quick-review-of-the-azure-functions-new-feature-retry-policy-p56" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Nov 5 '20&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/shibayan/a-quick-review-of-the-azure-functions-new-feature-retry-policy-p56" id="article-link-507336"&gt;
          A quick review of the Azure Functions new feature "Retry Policy"
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/azure"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;azure&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/functions"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;functions&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/serverless"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;serverless&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/eventdriven"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;eventdriven&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/shibayan/a-quick-review-of-the-azure-functions-new-feature-retry-policy-p56" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;13&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/shibayan/a-quick-review-of-the-azure-functions-new-feature-retry-policy-p56#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              1&lt;span class="hidden s:inline"&gt; comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;One of the implementations that I try to avoid these days is the case where a single function writes to multiple storage devices. In such a case, use the Event Grid for Blobs to detect event-driven writes to Blobs and perform subsequent writes.&lt;/p&gt;

&lt;p&gt;Recently, using Cosmos DB Change Feed, the main function writes to Cosmos DB, while the SQL DB and Blob writes are implemented as separate functions in many cases.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/cosmos-db/change-feed-design-patterns" rel="noopener noreferrer"&gt;Change feed design patterns in Azure Cosmos DB | Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This simplifies the processing of each function and makes it easier to retry.&lt;/p&gt;

&lt;p&gt;The following is an example of using Cosmos DB Change Feed to write from a single data source to SQL DB and Blob Storage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Function1&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FunctionName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Function1"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthorizationLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="n"&gt;HttpRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;CosmosDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;databaseName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"TestDB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;collectionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Events"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ConnectionStringSetting&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"CosmosConnectionString"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="n"&gt;IAsyncCollector&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EventData&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Process using Function input and write to Cosmos DB&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;collector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;EventData&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OkResult&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// SQL DB Writer Function&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Function2&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Function2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;appDbContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_appDbContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;appDbContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;_appDbContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FixedDelayRetry&lt;/span&gt;&lt;span class="p"&gt;(-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"00:00:10"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FunctionName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Function2&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;CosmosDBTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;databaseName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"TestDB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;collectionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Events"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ConnectionStringSetting&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"CosmosConnectionString"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;LeaseCollectionName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"leases"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;LeaseCollectionPrefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Function2&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
        &lt;span class="n"&gt;JArray&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EventData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Write the data received by the Change Feed to SQL DB&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_appDbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRangeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_appDbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Blob Writer Function&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Function3&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FixedDelayRetry&lt;/span&gt;&lt;span class="p"&gt;(-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"00:00:10"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FunctionName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Function3&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;CosmosDBTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;databaseName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"TestDB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;collectionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Events"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ConnectionStringSetting&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"CosmosConnectionString"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;LeaseCollectionName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"leases"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;LeaseCollectionPrefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Function3&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
        &lt;span class="n"&gt;JArray&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"workitems/sample.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FileAccess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="n"&gt;CloudAppendBlob&lt;/span&gt; &lt;span class="n"&gt;appendBlob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EventData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Documents modified "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"First document Id "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Write the data received by the Change Feed to Append Blob&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;appendBlob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendTextAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SerializeObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Since each Function does only one thing, the implementation is easy to understand, and you will find that error handling and retry handling are simple.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/architecture/data-guide/big-data/#lambda-architecture" rel="noopener noreferrer"&gt;Lambda architecture - Big data architectures - Azure Architecture Center | Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combining Azure Functions with Cosmos DB Change Feed is an easy way to implement a lambda architecture. Both services are highly scalable, making them an excellent choice.&lt;/p&gt;
&lt;h2&gt;
  
  
  Write code to support Graceful Shutdown
&lt;/h2&gt;

&lt;p&gt;In the past, before deploying to a running Azure Functions, I would check that no processing was taking place in Application Insights, but since Graceful Shutdown started working correctly a while ago, I implemented it to support it, and deployment can be done without being aware of the timing.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/shibayan/best-practices-for-graceful-shutdown-in-azure-functions-21b2" class="crayons-story__hidden-navigation-link"&gt;Best Practices for Graceful shutdown in Azure Functions&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/shibayan" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" alt="shibayan profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/shibayan" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Tatsuro Shibamura
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Tatsuro Shibamura
                
              
              &lt;div id="story-author-preview-content-591584" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/shibayan" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468463%2Fa8aa3ed9-f87b-4b21-86fb-3800032a37bf.jpeg" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Tatsuro Shibamura&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/shibayan/best-practices-for-graceful-shutdown-in-azure-functions-21b2" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Feb 4 '21&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/shibayan/best-practices-for-graceful-shutdown-in-azure-functions-21b2" id="article-link-591584"&gt;
          Best Practices for Graceful shutdown in Azure Functions
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/azure"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;azure&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/functions"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;functions&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/serverless"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;serverless&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dotnet"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dotnet&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/shibayan/best-practices-for-graceful-shutdown-in-azure-functions-21b2" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;21&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/shibayan/best-practices-for-graceful-shutdown-in-azure-functions-21b2#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Some people may think that Graceful Shutdown is not necessary if you use Deployment Slot, but Deployment Slot in App Service / Azure Functions restarts the non-production slot after the warm-up is complete, and replaces the routing.&lt;/p&gt;

&lt;p&gt;Therefore, it is important to support Graceful Shutdown even when deploying using Deployment Slot, because there is no guarantee that the process will finish normally before the swap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate the Function App project by feature
&lt;/h2&gt;

&lt;p&gt;To be precise, it is correct to divide the Function App project by the unit of scaling and deployment, but since there are few cases where you can see that area from the beginning, I try to think about separate it by the unit of feature first.&lt;/p&gt;

&lt;p&gt;Sometimes I see an application that implements a large number of functions in one Function App, but if the reason for grouping them in one Function App is cost, it is better to reconsider.&lt;/p&gt;

&lt;p&gt;Keep in mind that scaling App Service / Azure Functions can only be done per App Service Plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up a CI / CD pipeline early on
&lt;/h2&gt;

&lt;p&gt;I think it goes without saying that, with the exception of very small applications, we usually create more than one Function App. Since it is not practical to deploy them manually from Visual Studio, we will automate them using GitHub Actions and Azure Pipelines.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-how-to-github-actions?tabs=dotnet" rel="noopener noreferrer"&gt;Use GitHub Actions to make code updates in Azure Functions | Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-how-to-azure-devops?tabs=csharp" rel="noopener noreferrer"&gt;Continuously update function app code using Azure DevOps | Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you need a more practical example, please refer to the Azure Functions Boilerplate repository that I created.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/shibayan" rel="noopener noreferrer"&gt;
        shibayan
      &lt;/a&gt; / &lt;a href="https://github.com/shibayan/azure-functions-boilerplate" rel="noopener noreferrer"&gt;
        azure-functions-boilerplate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A boilerplate project for getting started with Azure Functions v4
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Deployment itself should not be a problem since it is very easy and Action/Task is provided. In recent years, I've even built a CI/CD pipeline in the middle of a hackathon.&lt;/p&gt;

&lt;p&gt;Hope this helps your Azure Serverless life!&lt;/p&gt;

</description>
      <category>azure</category>
      <category>functions</category>
      <category>dotnet</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
