<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Ashwin's Blog]]></title><description><![CDATA[<p>I'm a software consultant who loves to build projects and share my learnings on this blog.</p>
]]></description><link>https://kumarashwinhubert.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1752744367529/8255cd70-ad59-420c-9ea1-8077f8d73505.png</url><title>Ashwin&apos;s Blog</title><link>https://kumarashwinhubert.com</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 09 Mar 2026 00:08:38 GMT</lastBuildDate><atom:link href="https://kumarashwinhubert.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><atom:link rel="first" href="https://kumarashwinhubert.com/rss.xml"/><atom:link rel="next" href="https://kumarashwinhubert.com/rss.xml?after=NjAyODQ1NzMzNTVjNjY2OWZkMTdiNWM0XzIwMTgtMDgtMTJUMTg6MzA6MDAuMDAwWg=="/><item><title><![CDATA[Microsoft Foundry (New) vs Foundry (Classic) — What Actually Changed?]]></title><description><![CDATA[<p>If youve been exploring Azure AI learning paths or watching older demos, youve probably run into something confusing:</p>
<ul>
<li><p>The documentation and training links often reference <strong>Foundry (Classic)</strong></p>
</li>
<li><p>But the portal youre using today might show <strong>Foundry (New)</strong></p>
</li>
<li><p>And the way you create <strong>projects</strong> and <strong>resources</strong> looks slightly different</p>
</li>
</ul>
<p>This blog is a practical guide on what changed, how Classic and New relate, and what youll actually see in your Azure subscription.</p>
<h2 id="heading-1-what-is-microsoft-foundry">1. What is Microsoft Foundry?</h2>
<p>At a high level, <strong>Microsoft Foundry</strong> is Azures unified platform for building, deploying and governing modern AI applicationsespecially those built around <strong>agents</strong>, <strong>AI workflows</strong>, <strong>evaluations</strong>, <strong>tools</strong>, and <strong>observability</strong>.</p>
<p>Instead of stitching together isolated services for model hosting, agent orchestration, monitoring, and governance, Foundry brings all of these capabilities into a single experience.</p>
<p>Think of it as Azures all-in-one platform for AI development.</p>
<h2 id="heading-2-project-types-in-microsoft-foundry">2. Project Types in Microsoft Foundry</h2>
<p>Before comparing Classic and New Foundry portals, its important to get one thing right:</p>
<p><strong>Foundry has two project types.</strong></p>
<ol>
<li><p><strong>Hub-based Projects</strong> (older model)</p>
</li>
<li><p><strong>Foundry Projects</strong> (modern unified model)</p>
</li>
</ol>
<p>Everything elseClassic vs New portalsis essentially different UX layers sitting on top of these project types.</p>
<h3 id="heading-hub-based-projects-older-model">Hub-based Projects (Older Model)</h3>
<p>This is the <strong>pre-Foundry architecture</strong>, built around:</p>
<ul>
<li><p><strong>Azure AI Hub</strong></p>
</li>
<li><p><strong>Azure AI Project</strong></p>
</li>
<li><p>Supporting resources (storage accounts, managed identities, network components, etc.)</p>
</li>
</ul>
<p>This was the default model before Foundry unified the platform.<br />As a result, <strong>Foundry (Classic)</strong> continued to support and create these hub-based setups.</p>
<p>When you create a hub-based project, Azure provisions:</p>
<ul>
<li><p><code>Azure AI Hub</code> resource</p>
</li>
<li><p><code>Azure AI Project</code> resource</p>
</li>
</ul>
<p>Youll still see references such as:</p>
<ul>
<li><p><em>Azure AI Hub</em></p>
</li>
<li><p><em>AI Project</em></p>
</li>
<li><p><em>Project under a hub</em></p>
</li>
</ul>
<p>Most older tutorials, Prompt Flow documentation, and Learn modules are based on this model. Also, <strong>Prompt Flow is currently supported only in hub-based projects</strong>.</p>
<blockquote>
<p><strong>Foundry Classic = supporting the old Hub-based architecture.</strong></p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764010146370/e51f5fbf-0afa-4638-9766-6ce1a051582d.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-foundry-projects-modern-model">Foundry Projects (Modern Model)</h3>
<p>This is the <strong>recommended</strong>, <strong>simplified</strong>, and <strong>future-facing</strong> project type.</p>
<p>A Foundry project includes:</p>
<ul>
<li><p><strong>Foundry</strong> resource</p>
</li>
<li><p><strong>Foundry Project</strong> resource</p>
</li>
</ul>
<p>There is <strong>no hub</strong> in this model.</p>
<p>This architecture simplifies:</p>
<ul>
<li><p>Access control</p>
</li>
<li><p>Monitoring &amp; observability</p>
</li>
<li><p>Resource management</p>
</li>
<li><p>Agent workflows</p>
</li>
<li><p>Tooling integrations</p>
</li>
<li><p>Lifecycle operations</p>
</li>
</ul>
<p>When you create a Foundry project, Azure provisions:</p>
<ul>
<li><p><code>Foundry</code> resource</p>
</li>
<li><p><code>Foundry Project</code> resource</p>
</li>
</ul>
<blockquote>
<p><strong>Foundry New = hub-less, modern, and the future of the platform.</strong></p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764010554623/d73b1f0b-ecad-4efd-a7b4-2a884e63d8eb.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-3-two-portals-one-platform">3. Two Portals  One platform</h2>
<p>There are two Foundry portal experiences, but both operate on the same platform.</p>
<h3 id="heading-foundry-classic"><strong>Foundry (Classic)</strong></h3>
<p>This is the older UI, and most existing training content still references it.</p>
<ul>
<li><p>Lets you create <strong>both</strong> Hub-based Projects and Foundry Projects</p>
</li>
<li><p>Still widely used because of older documentation</p>
</li>
<li><p>Provides the UI that hub-based resources depend on</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764009654896/889e6644-6050-4ba6-8e33-4b0e78a4cc19.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-foundry-new"><strong>Foundry (New)</strong></h3>
<p>This is the modern experience with a cleaner UI and a project model aligned to the future of Azure AI development.</p>
<ul>
<li><p>Only allows creation of <strong>Foundry Projects</strong></p>
</li>
<li><p>Streamlined navigation</p>
</li>
<li><p>Better integrations for agents, tools, workflows and evaluations</p>
</li>
<li><p>A unified structure without hubs</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764009713206/c58733b6-c533-4766-8cbb-c1fb4b25511b.png" alt class="image--center mx-auto" /></p>
<p>In the Foundry portal, you can switch between Classic and New using the toggle at the top:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763992842604/1c8e0348-afae-4bbb-80ed-c64e3cefc5d4.png" alt class="image--center mx-auto" /></p>
<p>The official docs also include a <strong>Version</strong> toggle for Classic vs Newvery useful when your UI doesnt match the tutorial:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763988428486/cf291898-a0f4-4534-9fc3-29b65d4134bf.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-4-foundry-classic-vs-foundry-new-side-by-side">4. Foundry Classic vs Foundry New  Side-by-Side</h2>
<p>Now that weve seen both portals, heres a simple comparison to keep in mind:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Area</strong></td><td><strong>Foundry (Classic)</strong></td><td><strong>Foundry (New)</strong></td></tr>
</thead>
<tbody>
<tr>
<td>UI model</td><td>Older portal experience</td><td>Modern, simplified UI</td></tr>
<tr>
<td>Supports Hub-based Projects</td><td> Yes</td><td> No</td></tr>
<tr>
<td>Supports Foundry Projects</td><td> Yes</td><td> Yes</td></tr>
<tr>
<td>Recommended for new apps</td><td> No</td><td> Yes</td></tr>
<tr>
<td>Prompt Flow availability</td><td>Only in Hub-based Projects</td><td>Not yet supported</td></tr>
<tr>
<td>Architecture focus</td><td>Hub + AI Project</td><td>Foundry + Foundry Project</td></tr>
</tbody>
</table>
</div><p>When in doubt:</p>
<ul>
<li><p>If youre starting <strong>something new</strong>, use <strong>Foundry (New)</strong> with a <strong>Foundry Project</strong>.</p>
</li>
<li><p>If youre following an <strong>older tutorial</strong> or managing an existing hub-based environment, you may still need <strong>Foundry (Classic)</strong>.</p>
</li>
</ul>
<h2 id="heading-5-migration-amp-following-training-material">5. Migration &amp; Following Training Material</h2>
<p>If your team is still running on hub-based projects, Microsoft supports migrating to the modern Foundry Project model. The migration involves moving:</p>
<ul>
<li><p>Model deployments</p>
</li>
<li><p>Data connections</p>
</li>
<li><p>Tools &amp; workflows</p>
</li>
<li><p>Identity &amp; access policies</p>
</li>
</ul>
<p>Depending on how the old project was structured, some steps may be manual.</p>
<h3 id="heading-tips-when-learning-or-following-training-modules">Tips when learning or following training modules</h3>
<ul>
<li><p><strong>If a tutorial shows Classic</strong>, just switch the docs to the matching version.</p>
</li>
<li><p><strong>If youre creating something new</strong>, always choose a <strong>Foundry Project</strong> in the new portal.</p>
</li>
<li><p>Prompt flow is currently supported only in Hub based projects.</p>
</li>
<li><p>Expect naming confusion initiallyAI Hub, Foundry, AI Project, Foundry Projectbecause the platform has been evolving.</p>
</li>
</ul>
<h2 id="heading-6-final-thoughts">6. Final Thoughts</h2>
<p>The difference between Foundry (New) and Foundry (Classic) is not about two different products.<br />Its about <strong>one platform moving from an older Hub-based architecture to a cleaner, unified project model</strong>.</p>
<p>To keep it simple in your mind:</p>
<ul>
<li><p><strong>Foundry (New)</strong> + <strong>Foundry Project</strong><br />   Modern, streamlined, and the recommended default for all new scenarios</p>
</li>
<li><p><strong>Foundry (Classic)</strong> + <strong>Hub-based Projects</strong><br />   Older architecture, still supported, primarily used when following legacy tutorials or working with older deployments</p>
</li>
</ul>
<p>As the Azure AI ecosystem continues to evolve, the Foundry Project model is where Microsoft is investingso thats where youll want to be.</p>
]]></description><link>https://kumarashwinhubert.com/microsoft-foundry-new-vs-foundry-classic-what-actually-changed</link><guid isPermaLink="true">https://kumarashwinhubert.com/microsoft-foundry-new-vs-foundry-classic-what-actually-changed</guid><category><![CDATA[Azure]]></category><category><![CDATA[AI]]></category><category><![CDATA[Azure AI Foundry]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[How Fast is ASP.NET Core Web API? A Performance Analysis]]></title><description><![CDATA[<p>In today's digital age, speed is paramount for web and mobile applications. Users expect instantaneous responses, and any delay can lead to a poor user experience and loss of engagement. Therefore, as developers, it's crucial to build web APIs that are not only functional but also optimized for performance.<br />ASP.NET Core offers multiple options for creating APIs, with minimal APIs and controller-based APIs being two of the most favored choices.</p>
<p>In this blog, we'll explore the performance of ASP.NET Core Web API by creating a simple response API using <strong>ASP.NET Core 8.0</strong>. The goal of this article is not to test real-world performance scenarios but to see how quickly we can process the simplest request through the ASP.NET Core pipeline using <em>k6</em> tests, both <strong>locally</strong> and on <strong>Azure App Service with B2 and P2V3 plans</strong>.</p>
<h2 id="heading-setting-up-the-test-environment">Setting up the test environment</h2>
<p>Before we dive into testing, let's set up the test environment. We will create two types of APIs using ASP.NET Core:</p>
<ol>
<li><p><strong>Minimal API:</strong> A lightweight approach introduced in .NET 6 that allows for a more streamlined and concise way to define endpoints.</p>
</li>
<li><p><strong>Controller-based API</strong>: The traditional approach, providing a structured way to build APIs.</p>
</li>
</ol>
<h3 id="heading-create-the-aspnet-core-project">Create the ASP.NET Core Project</h3>
<p>Create the project using either the <code>dotnet new webapi -o "Web API Performance"</code> command or the Visual Studio GUI.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718127780196/cee10f03-4f8c-4b91-8260-d77da8c5907c.png" alt class="image--center mx-auto" /></p>
<p>The <code>.csproj</code> would be:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">Project</span> <span class="hljs-attr">Sdk</span>=<span class="hljs-string">"Microsoft.NET.Sdk.Web"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">PropertyGroup</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">TargetFramework</span>&gt;</span>net8.0<span class="hljs-tag">&lt;/<span class="hljs-name">TargetFramework</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Nullable</span>&gt;</span>enable<span class="hljs-tag">&lt;/<span class="hljs-name">Nullable</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ImplicitUsings</span>&gt;</span>enable<span class="hljs-tag">&lt;/<span class="hljs-name">ImplicitUsings</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">RootNamespace</span>&gt;</span>Web_API_Performance<span class="hljs-tag">&lt;/<span class="hljs-name">RootNamespace</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">PropertyGroup</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">Project</span>&gt;</span>
</code></pre>
<p><strong>Define the minimal API</strong> in the <code>Program.cs</code> file:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Program.cs</span>
<span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();

<span class="hljs-keyword">var</span> app = builder.Build();

app.UseHttpsRedirection();
app.MapControllers();

app.MapGet(<span class="hljs-string">"/api/hello"</span>, () =&gt; <span class="hljs-string">"Hello, World!"</span>);
app.MapGet(<span class="hljs-string">"/api/weather"</span>, () =&gt;
{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> { Temperature = <span class="hljs-string">"20C"</span>, Condition = <span class="hljs-string">"Sunny"</span> };
});

app.Run();
</code></pre>
<p><strong>Define the controller</strong> in the <code>Controllers</code> folder:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// SimpleController.cs</span>
<span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Web_API_Performance.Controllers</span>
{
    [<span class="hljs-meta">ApiController</span>]
    [<span class="hljs-meta">Route(<span class="hljs-meta-string">"api/[controller]"</span>)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">SimpleController</span> : <span class="hljs-title">ControllerBase</span>
    {
        [<span class="hljs-meta">HttpGet(<span class="hljs-meta-string">"hello"</span>)</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">Get</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello, World!"</span>;
        }

        [<span class="hljs-meta">HttpGet(<span class="hljs-meta-string">"weather"</span>)</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">GetWeather</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">var</span> weather = <span class="hljs-keyword">new</span>
            {
                Temperature = <span class="hljs-string">"20C"</span>,
                Condition = <span class="hljs-string">"Sunny"</span>
            };
            <span class="hljs-keyword">return</span> Ok(weather);
        }
    }
}
</code></pre>
<p>This setup will yield four APIs:</p>
<ul>
<li><p>Minimal APIs: <code>/api/hello</code> and <code>/api/weather</code></p>
</li>
<li><p>Controller APIs: <code>/api/simple/hello</code> and <code>/api/simple/weather</code></p>
</li>
</ul>
<h2 id="heading-deploying-to-azure-app-service">Deploying to Azure App Service</h2>
<p>Once the APIs are set up and running locally, the next step is to deploy them to Azure App Service. This will allow us to test the performance of our APIs on different Azure App Service Plan SKUs.</p>
<p>We'll create a web app with the runtime stack <strong>.NET 8 (LTS)</strong> in Azure and deploy our web API to the Central India region.</p>
<p>The deployed web app now contains the 4 APIs ready &amp; running.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717743152784/3e5ae563-5002-4537-89b5-0c3a816904f4.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-azure-app-service-plan-skus-for-testing">Azure App Service Plan SKUs for Testing</h4>
<p>We will test the performance of our APIs on the following Azure App Service Plan SKUs:</p>
<ul>
<li><p><strong>Basic B2 -</strong> 2 core vCPU | 3.5 GB RAM</p>
</li>
<li><p><strong>Premium v3 P2V3 -</strong> 4 core vCPU | 16 GB RAM</p>
</li>
</ul>
<h2 id="heading-unveiling-performance-with-k6">Unveiling Performance with k6</h2>
<p>To effectively measure the performance of our basic APIs, we will use <a target="_blank" href="https://k6.io/"><strong>k6</strong></a>, a modern load testing tool, running tests locally and on the deployed Azure App Service. The results will be exported to a Grafana cloud instance for visual representation.</p>
<p>The k6 test script would be:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> http <span class="hljs-keyword">from</span> <span class="hljs-string">'k6/http'</span>;
<span class="hljs-keyword">import</span> { check, sleep } <span class="hljs-keyword">from</span> <span class="hljs-string">'k6'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> options = {
  <span class="hljs-attr">vus</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr">duration</span>: <span class="hljs-string">'2m'</span>
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> res1 = http.get(<span class="hljs-string">'https://&lt;url&gt;/api/hello'</span>, {
    <span class="hljs-attr">tags</span>: { <span class="hljs-attr">name</span>: <span class="hljs-string">'&lt;Local/Deployed&gt; - Minimal hello'</span> },
  });
  <span class="hljs-keyword">const</span> res2 = http.get(<span class="hljs-string">'https://&lt;url&gt;/api/weather'</span>, {
    <span class="hljs-attr">tags</span>: { <span class="hljs-attr">name</span>: <span class="hljs-string">'&lt;Local/Deployed&gt; - Minimal weather'</span> },
  });
  <span class="hljs-keyword">const</span> res3 = http.get(<span class="hljs-string">'https://&lt;url&gt;/api/simple/hello'</span>, {
    <span class="hljs-attr">tags</span>: { <span class="hljs-attr">name</span>: <span class="hljs-string">'&lt;Local/Deployed&gt; - Controller hello'</span> },
  });
  <span class="hljs-keyword">const</span> res4 = http.get(<span class="hljs-string">'https://&lt;url&gt;/api/simple/hello'</span>, {
    <span class="hljs-attr">tags</span>: { <span class="hljs-attr">name</span>: <span class="hljs-string">'&lt;Local/Deployed&gt; - Controller weather'</span> },
  });

  check(res1, {
    <span class="hljs-string">'status is 200 of &lt;Local/Deployed&gt; minimal hello'</span>: <span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> r.status === <span class="hljs-number">200</span>,
  })
  check(res2, {
    <span class="hljs-string">'status is 200 of &lt;Local/Deployed&gt; minimal weather'</span>: <span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> r.status === <span class="hljs-number">200</span>,
  })
  check(res3, {
    <span class="hljs-string">'status is 200 of &lt;Local/Deployed&gt; controller hello'</span>: <span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> r.status === <span class="hljs-number">200</span>,
  })
  check(res4, {
    <span class="hljs-string">'status is 200 of &lt;Local/Deployed&gt; controller weather'</span>: <span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> r.status === <span class="hljs-number">200</span>,
  })
}
</code></pre>
<h3 id="heading-running-the-test-locally">Running the Test Locally:</h3>
<p>Running the ASP.NET Web API application in Release configuration on a local machine with an 11th Gen Intel(R) Core(TM) i7 processor &amp; 32GB RAM, and testing it using k6 with 1 VUS for 2 mins yielded the following result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718096708114/f5a70839-c68b-4d0a-9c9b-480478c2a7ce.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718096715758/a3b654a7-7be8-4f20-92c8-80b6b4c6e420.png" alt class="image--center mx-auto" /></p>
<p>The P95 for both minimal and controller APIs are <strong><mark>~0.69ms</mark></strong>; that's sub-millisecond execution locally. Total requests made were 371K in 2-minute test duration with Peak RPS being ~4K req/s.</p>
<h3 id="heading-running-the-test-on-basic-b2-plan">Running the Test on Basic B2 plan:</h3>
<p>Running the Web API on the Azure App Service Basic B2 plan and testing it using k6 with 1 VU for 2 minutes yielded the following results:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718096756525/c405149c-61e2-4846-a18c-f39a36cf7350.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718096766669/d3ffd7a9-847b-43b6-a0b8-6e4128515ce4.png" alt class="image--center mx-auto" /></p>
<p>The P95 for both minimal and controller APIs is <strong><mark>~26ms</mark></strong> when deployed to Azure App Service. A total of 5.5K requests were made during the 2-minute test duration, with a peak RPS of 47.3 req/s.</p>
<p><a target="_blank" href="https://www.azurespeed.com/Azure/Latency">Azure Speed Test</a> shows an average latency of 23ms to 26ms from the local machine to the deployed Azure Central India data center which justifies the time taken by the API. In summary, the deployed instance is also performing efficiently, with response time close to or under one millisecond, excluding network latency.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718097616960/cf1d444e-9fa8-41de-9420-11991a40598a.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-running-the-test-on-premium-v3-p2v3-plan">Running the Test on Premium v3 P2v3 plan:</h3>
<p>Running the Web API on the Azure App Service Premium P2v3 plan and testing it using k6 with 1 VU for 2 minutes yielded the following result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718096761438/b4095cb2-0c61-48dd-a6d2-d2bdea874f56.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718096783376/65a709f1-17a2-4828-a7b5-23f5e4686af4.png" alt class="image--center mx-auto" /></p>
<p>The P95 for both minimal and controller APIs are <strong><mark>~26ms</mark></strong> when deployed to Azure App Service P2V3 plan. Total requests made were 5.7K in the 2-minute test duration with Peak RPS being 50 req/s. The results are nearly indistinguishable, with minor discrepancies due to network latency between the test machine and the datacenter.</p>
<h3 id="heading-analyzing-the-results">Analyzing the Results</h3>
<p>After running the tests and gathering the performance metrics, several points stand out:</p>
<ul>
<li><p>Minimal vs. Controller APIs: In .NET 8, there's negligible execution time disparity between the two.</p>
</li>
<li><p>Local Performance: Sub-millisecond response time underscores ASP.NET Core's efficiency.</p>
</li>
<li><p>Azure Realms: Network latency emerges as the primary factor, resulting in comparable performance across App Service Plan SKUs.</p>
</li>
</ul>
<h2 id="heading-summary">Summary</h2>
<p>Our tests on basic ASP.NET Web APIs present a clear picture: both minimal and controller-based APIs demonstrate impressive performance with sub-millisecond response time in a local environment. However, when deployed to Azure, performance differences emerge due to network latency and the chosen App Service Plan's capabilities. The Azure App Service Premium tier offers marginally better performance than the Basic tier, but network latency remains a critical factor.</p>
<p>It's important to note that this test was conducted to measure basic performance characteristics with very simple APIs, not real-world scenarios. As a result, there isn't much difference in performance between the Basic B2 and Premium P2V3 tiers. However, in real-world applications, where higher processing power is required, the Premium tier will definitely outperform.</p>
<p>These insights highlight not only the importance of considering both infrastructure and network conditions when optimizing API performance but also demonstrate how efficiently ASP.NET Core Web API can handle requests.</p>
]]></description><link>https://kumarashwinhubert.com/how-fast-is-aspnet-core-web-api-a-performance-analysis</link><guid isPermaLink="true">https://kumarashwinhubert.com/how-fast-is-aspnet-core-web-api-a-performance-analysis</guid><category><![CDATA[dotnet]]></category><category><![CDATA[asp.net core]]></category><category><![CDATA[Web API]]></category><category><![CDATA[performance]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[Comparing List Loop Performance in .NET: From .NET Framework to .NET 9-preview]]></title><description><![CDATA[<p>Loops are fundamental constructs in any programming language. But have you ever wondered if there are any performance differences between them? For small collections, the difference might be negligible, but what about handling a million or 10 million records? In such cases, will there be a noticeable performance difference?</p>
<p>In this article, we aim to determine the performance of different loops across various .NET target frameworks (.NET Framework 4.7.2, .NET Core 3.1, .NET 6.0, .NET 8.0, .NET 9.0-preview-4) when iterating over a <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1">List</a> of strings.</p>
<h2 id="heading-setup">Setup</h2>
<p>To compare list loop performance, we will iterate over <mark>10 million strings</mark> using a <code>List&lt;string&gt;</code>. To ensure consistency, we will generate the dataset using C#'s Random method with the same "seed" value.</p>
<p>We will utilize the <a target="_blank" href="https://github.com/dotnet/BenchmarkDotNet">BenchmarkDotNet</a> library to benchmark the performance of various loops. This is a widely used library for benchmarking, even by the dotnet product teams.</p>
<p>Here is the snippet of our benchmark's "GlobalSetup" :</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-title">List</span>&lt;<span class="hljs-title">string</span>&gt; list</span> = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt;();

<span class="hljs-comment">// 10 million elements</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">int</span> size = <span class="hljs-number">10000000</span>;

[<span class="hljs-meta">GlobalSetup</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Setup</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> random = <span class="hljs-keyword">new</span> Random(<span class="hljs-number">580</span>);
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; size; i++)
    {
        list.Add(random.Next().ToString());
    }
}
</code></pre>
<h2 id="heading-the-loops">The Loops</h2>
<p>We will test the following looping methods on the list of strings:</p>
<ul>
<li><p><strong>for</strong> loop</p>
</li>
<li><p><strong>foreach</strong> loop</p>
</li>
<li><p><strong>List.ForEach</strong> loop</p>
</li>
<li><p><strong>while</strong> loop</p>
</li>
<li><p><strong>do-while</strong> loop</p>
</li>
</ul>
<p>Additionally, we will compare performance across these dotnet versions:</p>
<ul>
<li><p><strong>.NET Framework 4.7.2</strong></p>
</li>
<li><p><strong>.NET Core 3.1</strong></p>
</li>
<li><p><strong>.NET 6.0</strong></p>
</li>
<li><p><strong>.NET 8.0</strong></p>
</li>
<li><p><strong>.NET 9.0-preview-4</strong></p>
</li>
</ul>
<p>Here is the benchmark test class:</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">SimpleJob(RuntimeMoniker.Net472, baseline: true)</span>]
[<span class="hljs-meta">SimpleJob(RuntimeMoniker.NetCoreApp31)</span>]
[<span class="hljs-meta">SimpleJob(RuntimeMoniker.Net60)</span>]
[<span class="hljs-meta">SimpleJob(RuntimeMoniker.Net80)</span>]
[<span class="hljs-meta">SimpleJob(RuntimeMoniker.Net90)</span>]
[<span class="hljs-meta">MemoryDiagnoser</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ListLoopingPerformanceBenchmark</span>
{
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-title">List</span>&lt;<span class="hljs-title">string</span>&gt; list</span> = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt;();

    <span class="hljs-comment">// 10 million elements</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">int</span> size = <span class="hljs-number">10</span>_000_000;

    [<span class="hljs-meta">GlobalSetup</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Setup</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> random = <span class="hljs-keyword">new</span> Random(<span class="hljs-number">580</span>);
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; size; i++)
        {
            list.Add(random.Next().ToString());
        }
    }

    [<span class="hljs-meta">Benchmark(Description = <span class="hljs-meta-string">"for"</span>)</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">For</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">string</span>.Empty;
        <span class="hljs-keyword">var</span> size = list.Count;
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; size; i++)
        {
            result = list[i];
        }
        <span class="hljs-keyword">return</span> result;
    }

    [<span class="hljs-meta">Benchmark(Description = <span class="hljs-meta-string">"foreach"</span>)</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">Foreach</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">string</span>.Empty;
        <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> item <span class="hljs-keyword">in</span> list)
        {
            result = item;
        }
        <span class="hljs-keyword">return</span> result;
    }

    [<span class="hljs-meta">Benchmark(Description = <span class="hljs-meta-string">"ForEach"</span>)</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">ForEach</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">string</span>.Empty;
        list.ForEach(item =&gt; result = item);
        <span class="hljs-keyword">return</span> result;
    }

    [<span class="hljs-meta">Benchmark(Description = <span class="hljs-meta-string">"while"</span>)</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">While</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">string</span>.Empty;
        <span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">int</span> size = list.Count;
        <span class="hljs-keyword">while</span> (i &lt; size)
        {
            result = list[i];
            i++;
        }
        <span class="hljs-keyword">return</span> result;
    }

    [<span class="hljs-meta">Benchmark(Description = <span class="hljs-meta-string">"do-while"</span>)</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">DoWhile</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">string</span>.Empty;
        <span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">int</span> size = list.Count;
        <span class="hljs-keyword">do</span>
        {
            result = list[i];
            i++;
        } <span class="hljs-keyword">while</span> (i &lt; size);
        <span class="hljs-keyword">return</span> result;
    }
}
</code></pre>
<p>For the complete code setup, you can visit <a target="_blank" href="https://github.com/Kumar-Ashwin-Hubert/BestLoopingOfListBenchmark">GitHub repository</a>.</p>
<h2 id="heading-results">Results</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716735034735/09ada501-61c9-4c6e-befa-d7cf5ae1539d.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716735197987/a203f49d-e53f-4120-8272-d36805c34b40.png" alt class="image--center mx-auto" /></p>
<p>Based on the benchmarking setup, the results vary across different .NET versions, showcasing improvements over time. Here's a summary:</p>
<ul>
<li><p>The <code>for</code> loop shows significant performance improvements from .NET Framework 4.7.2 to .NET 9.0-preview, with .NET 9.0-preview being <em><mark>1.28x faster</mark></em> than the baseline.</p>
</li>
<li><p>The <code>foreach</code> loop exhibits substantial gains, especially from .NET Framework 4.7.2 to .NET 9.0-preview, being <em><mark>3.82x faster</mark></em>.</p>
</li>
<li><p>The <code>List.ForEach</code> method is generally <mark>slower compared to other loops</mark>, though it shows some improvements in .NET 9.0-preview.</p>
</li>
<li><p>Both <code>while</code> and <code>do-while</code> loops demonstrate similar performance enhancements, with .NET 9.0-preview versions being approximately <em><mark>1.30x faster</mark></em> than .NET Framework 4.7.2.</p>
</li>
</ul>
<h2 id="heading-bonus-high-performance-looping-with-latest-net">Bonus high performance looping with latest .NET</h2>
<p>.NET 5 introduced <strong>CollectionsMarshal.AsSpan&lt;T&gt;</strong>, which provides direct access to the underlying array of a list as a <strong>span</strong>, providing a more efficient way to work with list elements. However, this should be used with caution, as modifying the list during iteration can lead to unexpected behavior.</p>
<p>Let's test the benchmark for this with different loop sizes of 1 million and 10 million records and see if it provides better results than looping over the list directly.</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">SimpleJob(RuntimeMoniker.Net60, baseline: true)</span>]
[<span class="hljs-meta">SimpleJob(RuntimeMoniker.Net80)</span>]
[<span class="hljs-meta">SimpleJob(RuntimeMoniker.Net90)</span>]
[<span class="hljs-meta">MemoryDiagnoser</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ListLoopingPerformanceBenchmark</span>
{
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-title">List</span>&lt;<span class="hljs-title">string</span>&gt; list</span> = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt;();

    [<span class="hljs-meta">Params(1_000_000, 10_000_000)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> size;

    [<span class="hljs-meta">GlobalSetup</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Setup</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> random = <span class="hljs-keyword">new</span> Random(<span class="hljs-number">580</span>);
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; size; i++)
        {
            list.Add(random.Next().ToString());
        }
    }

    <span class="hljs-comment">// Adding `for` loop as comparision with `span`.</span>
    [<span class="hljs-meta">Benchmark(Description = <span class="hljs-meta-string">"for"</span>)</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">For</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">string</span>.Empty;
        <span class="hljs-keyword">var</span> size = list.Count;
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; size; i++)
        {
            result = list[i];
        }
        <span class="hljs-keyword">return</span> result;
    }

    [<span class="hljs-meta">Benchmark</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">Span</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">string</span>.Empty;
        <span class="hljs-keyword">int</span> size = list.Count;
        Span&lt;<span class="hljs-keyword">string</span>&gt; span = CollectionsMarshal.AsSpan(list);

        <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; size; i++)
        {
            result = span[i];
        }
        <span class="hljs-keyword">return</span> result;
    }
}
</code></pre>
<p>Running these tests yields the following results for the Span loop:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716795181366/66b517ae-2866-4eff-9006-27425d752472.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-findings">Findings:</h4>
<ul>
<li><p><strong>For smaller data sizes (1,000,000 elements):</strong></p>
<ul>
<li><p>The <code>span</code> loop in .NET 9.0-preview is almost <strong>1.80x faster</strong> than in .NET 6.0 and nearly <strong>1.6x faster</strong> when compared to <code>for</code> loop in .NET 9.0-preview.</p>
</li>
<li><p>This demonstrates a significant performance gain, making Span loops an attractive choice for handling smaller data sizes efficiently.</p>
</li>
<li><p>Do note the time taken to loop the entire list is mere micro seconds.</p>
</li>
</ul>
</li>
<li><p><strong>For larger data sizes (10,000,000 elements)</strong>:</p>
<ul>
<li><p>The Span loop in .NET 9.0-preview is <strong>1.14x faster</strong> than in .NET 6.0 and nearly <strong>1.14x faster</strong> when compared to <code>for</code> loop in .NET 9.0-preview.</p>
</li>
<li><p>Although the improvement is more moderate compared to smaller data sizes, it still shows noticeable performance gains.</p>
</li>
</ul>
</li>
<li><p>This method should only be used when you understand its implications and there is a clear benefit.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This article explored the performance of different loop constructs in various .NET versions. We observed significant performance improvements over time, particularly from .NET Framework to .NET 9.</p>
<p>Except for the <strong>List.ForEach</strong> method, the other loop methods perform similarly in terms of time and memory usage in the latest .NET versions. The Span loop using <strong>CollectionsMarshal.AsSpan&lt;T&gt;</strong> method introduced in .NET 5 can offer substantial performance gains for small and medium data sizes.</p>
<p>However, while the Span loop offers excellent performance, it should be used with understanding of its implications and only when there is a clear benefit. Since the time difference between loops on a list of 10 millions records is very less, choosing the right loop construct should also consider readability, maintainability, and the specific use case requirements. By understanding these performance characteristics, developers can make more informed decisions to optimize their applications effectively.</p>
<p>For the complete code setup and benchmarks, visit <a target="_blank" href="https://github.com/Kumar-Ashwin-Hubert/BestLoopingOfListBenchmark">GitHub repository</a>.</p>
<p>Happy coding! 🚀</p>
]]></description><link>https://kumarashwinhubert.com/comparing-list-loop-performance-in-net-from-net-framework-to-net-9-preview</link><guid isPermaLink="true">https://kumarashwinhubert.com/comparing-list-loop-performance-in-net-from-net-framework-to-net-9-preview</guid><category><![CDATA[.NET]]></category><category><![CDATA[performance]]></category><category><![CDATA[benchmarkdotnet]]></category><category><![CDATA[C#]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[Secure Your Azure Functions: Use Managed Identity for AzureWebJobsStorage]]></title><description><![CDATA[<p>When using an Azure Function app, it is necessary to connect it to a storage account, often referred to as Host storage. This storage is utilized by the Functions runtime, as well as by various triggers and bindings to coordinate between multiple running instances. It is also used for host logs and managing state, among other purposes. The Azure Function app establishes a connection to this storage account through the <code>AzureWebJobsStorage</code> configuration. By default, <code>AzureWebJobsStorage</code> is configured with a connection string to the storage account that uses an <strong>account key</strong>. However, this approach poses a security risk, as it requires careful management of key storage, key rotation, and other security considerations.</p>
<p>As a best practice, it is recommended to use <em>Azure Managed Identity</em> (often referred to as MSI) whenever possible when connecting to storage accounts and other Azure services. With managed identity, Azure automatically manages secure access to Azure resources without the need for providing explicit credentials in code or configuration.</p>
<p>This article guides you through the process of using managed identity for <code>AzureWebJobsStorage</code>. At a high level, the following steps are required:</p>
<ol>
<li><p>Enable system-assigned managed identity for the function app.</p>
</li>
<li><p>Grant the function's identity access to the storage account.</p>
</li>
<li><p>Edit the <code>AzureWebJobsStorage</code> configuration.</p>
</li>
</ol>
<h3 id="heading-enable-system-assigned-managed-identity-for-the-function-app">Enable system-assigned managed identity for the function app</h3>
<ol>
<li><p>In the Azure portal, navigate to the Azure Function app.</p>
</li>
<li><p>Select the <strong>Identity</strong> option from the menu blade.</p>
</li>
<li><p>On the <strong>System assigned</strong> tab, set the status to "<strong>On</strong>" and <strong>Save</strong> it.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700075505278/837551b6-cc5f-4a33-a532-7234a25c6173.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<h3 id="heading-grant-the-functions-identity-access-to-the-storage-account">Grant the function's identity access to the storage account</h3>
<p>Create a role assignment granting the system-assigned identity access to the storage account.</p>
<ol>
<li><p>Navigate to the storage account that was created with the function app.</p>
</li>
<li><p>Select <strong>Access Control (IAM)</strong>. You can view and configure who has access to the resources from IAM.</p>
</li>
<li><p>Click <strong>Add</strong> and select <strong>Add Role Assignment</strong>.</p>
</li>
<li><p>Search for the '<strong>Storage Blob Data Owner</strong>' role, select it, and click <strong>Next</strong>.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700074195364/ecd11bea-713c-4ecd-a577-67b2f0b5bf7c.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>On the <strong>Members</strong> tab, under <strong>Assign access to</strong>, select <strong>Managed Identity</strong>.</p>
</li>
<li><p>Click <strong>Select members</strong> to open the identities side panel.</p>
</li>
<li><p>Choose the right <strong>Subscription</strong>, and in the managed identity selector, choose <strong>Function App</strong> from the <strong>System-assigned managed identity</strong> category.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700074365123/0b45bf24-860c-4f8f-9563-b6e8714b4fe8.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>The function app should appear in a list below the input fields. Click on the function app name, and it should now be part of the selected members section. Click <strong>Select</strong>.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700074663019/911ce561-59f0-4f57-be93-b38d2b82bcb1.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Back on the <strong>Add Role Assignment</strong> page, click <strong>Review + assign</strong>. Review the changes, and then click <strong>Review + assign</strong>.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700074792788/abbbeaae-914b-4840-bdae-5de011753401.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<h3 id="heading-edit-the-azurewebjobsstorage-configuration">Edit the 'AzureWebJobsStorage' configuration</h3>
<p>Next, update your function app to use the system-assigned identity when connecting to the blob service.</p>
<ol>
<li><p>Navigate to your function app, and under <strong>Settings</strong>, select <strong>Configuration</strong>.</p>
</li>
<li><p>Select the <strong>Edit</strong> button next to the <strong>AzureWebJobsStorage</strong> application setting.</p>
</li>
<li><p>Under <strong>Name</strong>, change the text from '<strong>AzureWebJobsStorage</strong>' to '<strong>AzureWebJobsStorage__accountName</strong>' This modified setting instructs the host to use the identity instead of looking for a stored secret. Please note that the new setting uses <code>__</code> (double underscore), which is a special character in application settings.</p>
</li>
<li><p>Under <strong>Value</strong>, input your <strong>storage account name</strong>, i.e., replace the connection string with just the storage account name.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700074966971/a49f8ca7-d861-4d2d-a5e7-a9cabb76ec85.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Select <strong>OK</strong>, and then click on <strong>Save</strong> &gt; <strong>Continue</strong> to save your changes.</p>
</li>
</ol>
<p>You have now successfully configured the Azure function to connect to the storage account using managed identity instead of the storage connection string containing credentials.</p>
<h2 id="heading-final-thoughts">Final thoughts</h2>
<p>In this article, we have looked at the essential steps to fortify the security of your Azure Functions when connecting to the host storage account. By embracing the best practice of utilizing Azure Managed Identity (MSI), we mitigate security risks associated with managing account keys and elevate the overall protection of our applications.</p>
<p>This article used the system-assigned managed identity of the function app to connect to the storage account, but even a user-assigned managed identity can be used while granting necessary access to the function &amp; storage account. The use of Managed Identity streamlines the authentication process, eliminating the need for explicit credentials in your code or configurations.</p>
<p>Take charge of your application's security journey, and let Managed Identity be your trusted companion in the realm of Azure services.</p>
<p>Happy coding and stay secure!</p>
]]></description><link>https://kumarashwinhubert.com/secure-your-azure-functions-use-managed-identity-for-azurewebjobsstorage</link><guid isPermaLink="true">https://kumarashwinhubert.com/secure-your-azure-functions-use-managed-identity-for-azurewebjobsstorage</guid><category><![CDATA[Azure]]></category><category><![CDATA[Azure Functions]]></category><category><![CDATA[Azure Managed Identities]]></category><category><![CDATA[azure blob storage]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[How to Disable Azure Functions for Local and Azure Cloud]]></title><description><![CDATA[<p>When working with Azure Functions, you often have multiple functions as part of a single function app. When debugging or running the function app locally, all the associated functions start and run together. However, during debugging, you may want to disable the functions that you are not interested in. This article covers how to disable a function in Azure Functions when running locally and in Azure.</p>
<h2 id="heading-disabling-a-function-locally">Disabling a function locally</h2>
<p>The best way to disable a function while running locally is by using an app setting in the <strong>local.settings.json</strong> file in the format <code>AzureWebJobs.&lt;FUNCTION_NAME&gt;.Disabled</code> set to <code>true</code>. For example, if you have three functions: <strong><em>ProcessOrder, SendEmailNotification, and GeneratePDFReport,</em></strong> and you want to disable only the <code>SendEmailNotification</code> function, add the following entry to the Values collection in the local.settings.json file:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"IsEncrypted"</span>: <span class="hljs-literal">false</span>,
  <span class="hljs-attr">"Values"</span>: {
    <span class="hljs-attr">"FUNCTIONS_WORKER_RUNTIME"</span>: <span class="hljs-string">"dotnet"</span>,
    <span class="hljs-attr">"AzureWebJobsStorage"</span>: <span class="hljs-string">"UseDevelopmentStorage=true"</span>,
    <span class="hljs-comment">// The below line disables the 'SendEmailNotification' function</span>
    <span class="hljs-attr">"AzureWebJobs.SendEmailNotification.Disabled"</span>: <span class="hljs-literal">true</span>
  }
}
</code></pre>
<p>While there are other ways to disable functions, these methods can vary depending on the language and runtime version used. Therefore, the application setting mentioned above is the recommended approach for all languages and all runtime versions.</p>
<h2 id="heading-disabling-a-function-in-azure">Disabling a function in Azure</h2>
<p>To disable a function in a deployed Azure Function App, the same configuration method as mentioned above can be used.</p>
<p>Going by the same example as above, if you have three functions: <strong><em>ProcessOrder, SendEmailNotification, and GeneratePDFReport,</em></strong> and you want to disable only the <code>SendEmailNotification</code> function, navigate to the <strong>Configuration</strong> tab of your Azure Function App and add a "<strong>New Application Setting"</strong> with the name <code>AzureWebJobs.SendEmailNotification.Disabled</code> and Value <code>true</code>. If you want to re-enable the function, simply change the value to <code>false</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684324149151/60b0c0f1-4a67-4cc4-9819-5cf523c26a8d.png" alt class="image--center mx-auto" /></p>
<p>Another option is to use the "Disable" button in the Azure Portal against the function to disable it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684323830278/d168653a-ca40-46ac-b15f-1350360f3457.png" alt class="image--center mx-auto" /></p>
<p>Once the function is disabled, any attempt to invoke it will result in an <strong>HTTP 404 Not Found</strong> error.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684324460048/cb9efca5-0e16-40a3-83bf-14a08fe2539b.png" alt class="image--center mx-auto" /></p>
<p>In conclusion, knowing how to disable Azure Functions locally and in the Azure cloud is essential for efficient development and debugging. By leveraging app settings and configuration options, you can selectively disable specific functions, optimizing your workflow and improving overall performance. With this knowledge, you gain control over your function app's behavior, maximizing productivity in your Azure projects.</p>
]]></description><link>https://kumarashwinhubert.com/how-to-disable-azure-functions-for-local-and-azure-cloud</link><guid isPermaLink="true">https://kumarashwinhubert.com/how-to-disable-azure-functions-for-local-and-azure-cloud</guid><category><![CDATA[Azure]]></category><category><![CDATA[Azure Functions]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[Azure Timer Function: How to Force Immediate Execution with Manual Triggering]]></title><description><![CDATA[<p>Azure Functions is a serverless solution that allows you to write less code, maintain less infrastructure, and save on costs. Azure Functions provide a powerful way to execute code in response to various triggers, such as a file being uploaded to blob storage, an event pushed to EventHub, a call to a webhook, or a message added to Service Bus.</p>
<p>One of the most commonly used triggers is the <em>Timer trigger.</em> This trigger lets you run your Azure function on a predefined schedule. The schedule is defined via a CRON expression, and in some cases, the scheduled trigger is often hours apart. However, there could be scenarios where you need to run a timer function immediately rather than waiting for the scheduled time. Some of the most common examples include - a code bug that caused many executions to fail, and you want to clear the backlog immediately; or you made changes to the function and want to test immediately instead of waiting, or you have business scenarios that require you to sometimes trigger the timer function manually. One way to do this is to use the CRON expression from a configuration, update the configuration, and restart the Function. But that's clunky and inconvenient. In this article, we will see how to force immediate execution with manual triggering in an Azure Timer Function without changing the CRON expression.</p>
<h3 id="heading-get-the-functions-master-key">Get the Function's Master Key</h3>
<p>To trigger the Timer function manually, you need to get the Function's Master Key. To do this,</p>
<ol>
<li><p>Navigate to the function app in Azure Portal, select App Keys, and then select the <code>_master</code> key.</p>
</li>
<li><p>Copy the key value as this would be used in the next step.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683571354845/731dc952-4c60-4f53-8ba9-7e197a43bdbc.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<h3 id="heading-make-the-http-request">Make the HTTP request</h3>
<p>To trigger the Timer function manually, make an HTTP <strong>POST</strong> request in the following form:<br /><strong>https://&lt;function base-url&gt;/admin/functions/&lt;function-name&gt;</strong><br />with a header key of <code>x-functions-key</code> and the value of <code>_master</code> key copied earlier, and an empty JSON <code>{}</code> request body.</p>
<p>For example, if you have a function named <code>TimerTrigger1</code> deployed in <code>demoblogfunctions.azurewebsites.net</code> you can trigger it manually with the following request:</p>
<pre><code class="lang-http"><span class="hljs-attribute">POST 
https://demoblogfunctions.azurewebsites.net/admin/functions/TimerTrigger1

Request Headers:
x-functions-key</span>: S5zxMCvMuDvQVegJEEmALUJEiLC1Rlj7Qz3QO_T3IB_vAzFuhlWa2w==
<span class="hljs-attribute">Content-Type</span>: application/json

<span class="css"><span class="hljs-selector-tag">Request</span> <span class="hljs-selector-tag">Body</span>:
{}</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683571536173/f8d89fa9-66e1-4763-bfe5-d1577b6626b2.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683571627287/d2ec29b4-7a5c-4149-81a5-b844fd6e02cc.png" alt class="image--center mx-auto" /></p>
<p>If the request is sent successfully, you should receive an HTTP status code of <strong>202 Accepted</strong>, and the timer function will be triggered immediately.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683571695163/f7cb3d66-29cd-4a4f-baa7-227a4c84c2df.png" alt class="image--center mx-auto" /></p>
<p>The function logs, as well as application insights if connected, will also indicate the trigger.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683572020232/f4df60d9-7d7d-410d-9f3d-0890e0e823fa.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>Caution:</strong> Due to the elevated permissions in your function app granted by the master key, you should not share this key with third parties or distribute it in an application. The key should only be sent to an HTTPS endpoint.</p>
</blockquote>
<p>This approach to immediate execution using the admin APIs is not limited to Timer Trigger and can be used to run any non-HTTP-Triggered azure function by passing in the required input in the request body.</p>
]]></description><link>https://kumarashwinhubert.com/azure-timer-function-how-to-force-immediate-execution-with-manual-triggering</link><guid isPermaLink="true">https://kumarashwinhubert.com/azure-timer-function-how-to-force-immediate-execution-with-manual-triggering</guid><category><![CDATA[Azure Functions]]></category><category><![CDATA[Azure]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[Azure DevOps Pull Request build validation pipeline for .Net 5 project]]></title><description><![CDATA[<p>When working in teams, we always want to ensure that any new PR (Pull Request) doesn't break the main build pipeline, deploy broken code or cause unit test cases to fail. We never want the PR to be merged to the <code>master</code>/<code>main</code> branch and then revert it back once the build pipeline fails, instead we always prefer a proactive approach of preventing the PR from merging if the build is failing.</p>
<p>This article covers creating a <code>YAML</code> based PR build validation pipeline for the .Net 5 project and setting build policies in Azure DevOps to ensure all PRs to the master branch are automatically validated using the pipeline and only build validated PRs can be merged.</p>
<p>We will be using a sample Azure DevOps repo having the Getting started ASP<span>.</span>NET Core Web App project running on .Net 5 checked in. The same set of steps can be used for other <code>.Net 5</code> projects as well.</p>
<p>This article will perform the following on the Azure DevOps project:</p>
<ul>
<li>Setup PR Build validation YAML pipeline</li>
<li>Add the pipeline to Azure DevOps pipelines</li>
<li>Add build validation policy for master/main branch</li>
<li>Create PRs &amp; test it</li>
</ul>
<h1 id="setup-pr-build-validation-pipeline">Setup PR Build validation pipeline</h1>
<p>The first step is to set up a PR build validation yaml pipeline. I usually prefer to keep the pull request pipelines in the <code>deployment\devops-pipelines\pull-requests</code> folder from the root of the repository.</p>
<p>Create a <code>WebApplication-pr.yml</code> file (any file name that suits your project) in the <code>deployment\devops-pipelines\pull-requests</code> folder with the following content to create the PR pipeline which restores, builds, and tests the .Net 5 project code.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># File: WebApplication-pr.yml</span>
<span class="hljs-comment"># Description:</span>
<span class="hljs-comment">#   PR build pipeline for WebApplication solution.</span>
<span class="hljs-comment">#   This job performs the following activities:</span>
<span class="hljs-comment">#     - Restores</span>
<span class="hljs-comment">#     - Builds</span>
<span class="hljs-comment">#     - Tests projects &amp; collects code coverage</span>

<span class="hljs-attr">trigger:</span> <span class="hljs-string">none</span>

<span class="hljs-attr">variables:</span>
  <span class="hljs-comment"># Working Directory</span>
  <span class="hljs-attr">workingDirectory:</span> <span class="hljs-string">'$(System.DefaultWorkingDirectory)/'</span>
  <span class="hljs-attr">buildPlatform:</span> <span class="hljs-string">'Any CPU'</span>
  <span class="hljs-attr">buildConfiguration:</span> <span class="hljs-string">'Release'</span>

<span class="hljs-attr">stages:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">stage:</span> <span class="hljs-string">Build</span>
    <span class="hljs-attr">displayName:</span> <span class="hljs-string">Build</span> <span class="hljs-string">stage</span>

    <span class="hljs-attr">jobs:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">job:</span> <span class="hljs-string">Build</span>
        <span class="hljs-attr">displayName:</span> <span class="hljs-string">Build</span>
        <span class="hljs-attr">pool:</span>
          <span class="hljs-attr">name:</span> <span class="hljs-string">'Azure Pipelines'</span>
          <span class="hljs-attr">vmImage:</span> <span class="hljs-string">'windows-latest'</span>

        <span class="hljs-attr">steps:</span>
          <span class="hljs-comment"># Install .Net 5.0</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">task:</span> <span class="hljs-string">UseDotNet@2</span>
            <span class="hljs-attr">displayName:</span> <span class="hljs-string">'Install .NET 5.0 SDK'</span>
            <span class="hljs-attr">inputs:</span>
              <span class="hljs-attr">packageType:</span> <span class="hljs-string">'sdk'</span>
              <span class="hljs-attr">version:</span> <span class="hljs-string">'5.0.x'</span>

          <span class="hljs-comment"># Restore dependencies</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">task:</span> <span class="hljs-string">DotNetCoreCLI@2</span>
            <span class="hljs-attr">displayName:</span> <span class="hljs-string">'Restore NuGet packages'</span>
            <span class="hljs-attr">inputs:</span>
              <span class="hljs-attr">command:</span> <span class="hljs-string">'restore'</span>
              <span class="hljs-attr">projects:</span> <span class="hljs-string">'**\WebApplication.sln'</span>
              <span class="hljs-attr">feedsToUse:</span> <span class="hljs-string">'select'</span>
              <span class="hljs-attr">includeNuGetOrg:</span> <span class="hljs-literal">true</span>
              <span class="hljs-attr">noCache:</span> <span class="hljs-literal">false</span>

          <span class="hljs-comment"># Build the solution</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">task:</span> <span class="hljs-string">DotNetCoreCLI@2</span>
            <span class="hljs-attr">displayName:</span> <span class="hljs-string">'Build solution file'</span>
            <span class="hljs-attr">inputs:</span>
              <span class="hljs-attr">command:</span> <span class="hljs-string">'build'</span>
              <span class="hljs-attr">projects:</span> <span class="hljs-string">'**\WebApplication.sln'</span>
              <span class="hljs-attr">arguments:</span> <span class="hljs-string">'--configuration $(BuildConfiguration)'</span>

          <span class="hljs-comment"># Run the tests and collect code coverage</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">task:</span> <span class="hljs-string">DotNetCoreCLI@2</span>
            <span class="hljs-attr">displayName:</span> <span class="hljs-string">'Test .Net Core Project in code'</span>
            <span class="hljs-attr">inputs:</span>
              <span class="hljs-attr">command:</span> <span class="hljs-string">'test'</span>
              <span class="hljs-attr">projects:</span> <span class="hljs-string">|
                src\Tests\**\*.csproj
</span>              <span class="hljs-attr">publishTestResults:</span> <span class="hljs-literal">true</span>
              <span class="hljs-attr">arguments:</span> <span class="hljs-string">'--configuration $(BuildConfiguration) --collect:"Code coverage"'</span>
</code></pre>
<p>The pipeline does <code>4 tasks</code> in the <code>Build stage</code> - i.e., </p>
<ul>
<li>Install .Net 5.0 in the agent</li>
<li>Restore dependencies</li>
<li>Build the solution</li>
<li>Run the tests and collect code coverage</li>
</ul>
<p>This is the bare minimum PR pipeline, but you could add in other tasks as required.</p>
<p>The above DevOps pipeline doesn't have any <code>trigger</code> defined as we will use the Azure DevOps Build Validation policies for triggering it. Also, the agent being used is a <a target="_blank" href="https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&amp;tabs=yaml">Microsoft Hosted Agent</a>, in case your choice of agent is different, please change the <code>pool</code> in the <code>build job</code>.<br /></p>
<p>Check-in the above pipeline to your code repository, and let's trigger it from Azure DevOps so that we can test the pipeline.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619981942452/ni0buu1p8.png" alt="Repo.png" /></p>
<h1 id="add-the-pipeline-to-azure-devops-pipelines">Add the pipeline to Azure DevOps pipelines</h1>
<p>To add the above checked-in yaml pipeline to Azure DevOps pipelines,</p>
<ol>
<li>Navigate to 'Pipelines' in Azure DevOps. Select 'Create Pipeline' or 'New Pipeline' to create a new pipeline.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619983107097/a9zCFiOEz.png" alt="Create new pipeline.png" /></li>
<li>Select the code repo.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619983256833/VL0NRHXSu.png" alt="Code Repo.png" /></li>
<li>Click on 'Existing Azure Pipelines YAML file' from the pipeline configuration page.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619983656006/av0aO0m_4.png" alt="Existing Azure Pipelines selection.png" /></li>
<li>Add in the YAML pipeline file path and click 'Continue'
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619984614541/DIhbE5p41.png" alt="YAML file path.png" /></li>
<li>Click on 'Run' to trigger the pipeline.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619984633421/SxpfP64tU.png" alt="Run Pipeline.png" /></li>
<li>This will queue the build and the build will be completed in some time.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619984720171/pWEkKuGMn.png" alt="Build Complete.png" /></li>
<li>Navigate back and rename the pipeline to a more meaningful one, so that it's clear to identify.</li>
</ol>
<p><strong><em>Note:</em></strong> <em>Please run the PR pipeline at least once before proceeding to the next step, as only in that case the pipeline will be visible on the Build Validation policy settings page</em>.</p>
<h1 id="add-build-validation-policy-for-mastermain-branch">Add build validation policy for master/main branch</h1>
<p>Now that you have the PR pipeline ready and <strong>executed at least once</strong>, it's time to update the build validation policy for the <code>master</code>/<code>main</code> branch so that subsequent PRs will result in the pipeline being executed and completed successfully for the PR to be merged.</p>
<p>To add the build validation policy,</p>
<ol>
<li>Navigate to 'Branches' under 'Repos' in Azure DevOps. Click on the kebab menu icon against the master/main branch and select 'Branch Policies' from the context menu.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619985247360/AryGwavkr.png" alt="Branch Policies.png" /></li>
<li>In the branch policies settings page, Add a 'Build Validation' policy. Select the PR pipeline that ran earlier from the dropdown of the policy page. Review other settings and click 'Save' to enable the build validation.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619987408656/XNJYQutNw.png" alt="Add Build Validation.png" />
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619986467831/X4xR3PQnG.png" alt="Branch Policies Details.png" /></li>
<li>Build Validation policy is now in place and future PRs will require this build validation to pass i.e. the PR pipeline to run successfully.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619987260210/8076yJjep.png" alt="Build Validation Policy Ready.png" /></li>
</ol>
<h1 id="create-prs-and-test-it">Create PRs &amp; test it</h1>
<p>Create a Pull Request and the pipeline should get triggered automatically as part of the 'Required' checks.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619988120141/8sngtEw_v.png" alt="PR Create.png" />
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619988134061/GT2G0lbE9.png" alt="PR Success.png" /></p>
<p>In case of build-failure, the Pull Request won't be allowed to merge.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619988145421/OWWdn9qxo.png" alt="PR Fail.png" /></p>
<p>That's it!! Azure DevOps Pull Request build validation pipeline has been set up for .Net 5 project and this policy plus pipeline will ensure only successfully building code is merged to master/main branch.</p>
]]></description><link>https://kumarashwinhubert.com/azure-devops-pull-request-build-validation-pipeline-for-net-5-project</link><guid isPermaLink="true">https://kumarashwinhubert.com/azure-devops-pull-request-build-validation-pipeline-for-net-5-project</guid><category><![CDATA[Devops]]></category><category><![CDATA[.NET]]></category><category><![CDATA[YAML]]></category><category><![CDATA[build]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[Problem Details - The right way to specify errors in Web API responses]]></title><description><![CDATA[<h2 id="the-need-for-problem-details">The need for Problem Details</h2>
<p>Often when you are developing REST APIs, one of the tough conversations to have with the consumers of your API (web client, mobile app, other 3rd parties, etc.) is defining the way your API would specify errors. Now, this is a crucial piece of design as depending on it the client/consumer will design their part of showing errors to the end-users. For example, imagine an API that allows customers to book movie tickets online and this call returns a Bad request (400) response without any other additional info. The user doesn't understand why the Client UI is showing an error and the Client UI doesn't know why the API has failed.</p>
<p>Many people have different designs for specifying the errors in the API response - some just return status code without any response message, while some describe a simple text message in the body and others specify custom JSON schema for specifying the errors.</p>
<p>Due to this, the <a target="_blank" href="https://tools.ietf.org/">Internet Engineering Task Force (IETF)</a> proposed the <a target="_blank" href="https://tools.ietf.org/html/rfc7807">"Problem Details for HTTP APIs"</a> specification in March 2016. As per it,</p>
<blockquote>
<p>"Problem Details" is a way to carry machine-readable details of errors in a HTTP response to avoid the need to define new error response formats for HTTP APIs.</p>
</blockquote>
<p>A simple example of HTTP response of JSON problem details is :</p>
<pre><code class="lang-json">HTTP/<span class="hljs-number">1.1</span> <span class="hljs-number">400</span> Bad Request
Content-Type: application/problem+json

{
    <span class="hljs-attr">"type"</span>: <span class="hljs-string">"https://tools.ietf.org/html/rfc7231#section-6.5.1"</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"One or more validation errors occurred."</span>,
    <span class="hljs-attr">"status"</span>: <span class="hljs-number">400</span>,
    <span class="hljs-attr">"errors"</span>: {
        <span class="hljs-attr">"Id"</span>: [
            <span class="hljs-string">"The Id field is required."</span>
        ],
        <span class="hljs-attr">"Fact"</span>: [
            <span class="hljs-string">"The Fact field is required."</span>
        ]
    }
}
</code></pre>
<p>The format of the message is <code>application/problem+json</code> or <code>application/problem+xml</code> media type and the response body must at bare minimum contain the below fields:</p>
<ul>
<li><code>type</code> : A URI that defines the problem detail type.</li>
<li><code>title</code> : A title that summarizes the problem.</li>
<li><code>status</code> : HTTP status code.</li>
</ul>
<p>We can extend the problem details with additional properties, for example, the above error message defined "errors" to communicate additional information to the client.</p>
<h2 id="problem-details-in-asplessspangreaterlessspangreaternet-core">Problem details in ASP<span>.</span>NET Core</h2>
<p>In <strong>ASP<span>.</span>NET Core 2.1</strong>, the team added <a target="_blank" href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.problemdetails"><code>ProblemDetails</code></a> class to support problem details model. And in <strong>ASP<span>.</span>NET Core 3.0</strong>, the <a target="_blank" href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.problem"><code>ControllerBase.Problem</code></a> method was added to produce a ProblemDetails response from controller action methods.</p>
<p>In the rest of the article, we will look at handling different error types from ASP<span>.</span>NET Core and how to use the inbuilt functionality already provided to specify the errors in ProblemDetails response format. <br />
We will look at specifying error responses for :</p>
<ul>
<li>400 Bad Request</li>
<li>404 Not Found</li>
<li>500 Internal Server Error</li>
</ul>
<p>We will primarily be using the <code>ControllerBase.Problem</code> method to specify errors manually and leaving it to the ASP<span>.</span>NET Core to generate for others.</p>
<h3 id="400-bad-request">400 Bad Request</h3>
<p>We have 2 scenarios here: <strong>Failed model validations using DataAnnotations</strong> and <strong>Custom bad request</strong></p>
<ul>
<li><p><strong><em>Failed model validations using DataAnnotations</em></strong>: In this case, you don't need to do any additional work. ASP<span>.NET Core will take care of it for you, given that you are using the <code>[ApiController]</code> attribute to the API controller and <code>DataAnnotations</code> for validating the model.</span></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615757947760/QFqZpaNgk.png" alt="400-BadRequest-DataAnnotations.png" />
  In the above example, we have a POST API and the input data model is validated using the <code>Required</code> attribute of the <code>DataAnnotations</code> class. When this API is called without passing in the required parameters of the model, a 400-Bad Request in the ProblemDetails format is generated.
  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615758373473/c2TPgDirX.png" alt="400-BadRequest-DataAnnotations-Postman-Edited.png" /></p>
</li>
<li><p><strong><em>Custom bad request</em></strong>: Maybe the business rule failed or some other logic check failed and you need to return 400-Bad Request. In this case, you can use <code>this.Problem(detail, statusCode: 400)</code> inside the Controller to return the error in problem details format.
  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616335845117/Y1cuJwrhy.png" alt="400-Custom Bad Request-Updated.png" /></p>
<p>  In the above example code, we are sending 400 from the controller using the <code>Problem</code> method when the business logic fails. Hitting the API with an invalid request will result in a 400-Bad Request in the ProblemDetails format.
  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616332573014/u5klYr5sV.png" alt="400-BadRequest-Custom-Updated-Postman-Edited.png" /></p>
</li>
</ul>
<h3 id="404-not-found">404 Not Found</h3>
<p>For the 404 wherein the route didn't match, there isn't much you can do, but for scenarios where you want to return "Not Found" when data for the specified Id is not found, etc.; using the <code>NotFound()</code> method in Controller will return the 404 in Problem Details format.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616335593060/lYN1Bb-Wn.png" alt="404-Not Found-Updated.png" />
In the above example code, we are returning <code>NotFound()</code> from the controller when the result is not found for the specified Id. Hitting the API with an invalid Id will result in 404-Not Found in the ProblemDetails format.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616334542195/8C8L5-DSv.png" alt="404-NotFound-Postman-Edited.png" /></p>
<h3 id="500-internal-server-error">500 Internal Server Error</h3>
<p>In case of 500 Internal server error, you don't want to expose off any exception object details as it will contain crucial code and system-related information; but should still adhere to the Problem Details format by giving a vague "An error occurred while processing your request." error message to the API caller. In this case, you can use <code>this.Problem()</code> inside the Controller to return the error in problem details format with the default 500 error message and status code. In some very exceptional cases wherein you would like to send custom messages for the exception, use the <code>this.Problem(customErrorMessage)</code> inside the Controller.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616337674582/Hnl24dJEI.png" alt="500-Internal Server Error.png" /></p>
<p>Hitting the above API which might result in some exceptions will return the response in the right format.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1616337965493/VXdZWvAeN.png" alt="500--Postman-Edited.png" /></p>
<h2 id="summary">Summary</h2>
<p>Problem Details standard is proposed by IETF and has been around for quite some time, but still, its usage or adherence is very low. Often people reinvent the wheel or follow different approaches while specifying errors in the Web API responses. In this article, we looked at the <code>ProblemDetails</code> specification and also using the <code>Problem()</code> method in the ControllerBase of ASP<span>.</span>Net Core application to return errors in this standard format.</p>
]]></description><link>https://kumarashwinhubert.com/problem-details-the-right-way-to-specify-errors-in-web-api-responses</link><guid isPermaLink="true">https://kumarashwinhubert.com/problem-details-the-right-way-to-specify-errors-in-web-api-responses</guid><category><![CDATA[.NET]]></category><category><![CDATA[error handling]]></category><category><![CDATA[coding]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[How to Dockerize your ASP.NET Core app directly from Visual Studio]]></title><description><![CDATA[<p>In this article we will see how to add docker support to ASP<span>.</span>NET core app directly from Visual Studio with just <code>3 Clicks</code> <strong>without manually creating or writing any code</strong> to <code>Dockerfile</code>.</p>
<ol>
<li>Navigate to the Solution Explorer of your project and <br />
Right-click on the ASP<span>.</span>NET project -&gt; Select <code>Add</code> -&gt; Click <code>Docker Support</code>
 <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615131535248/RMDluBrGN.png" alt="Add Support Edited.png" /></li>
<li>Choose the Target OS where the docker image will run <code>Windows / Linux</code>, and click <code>OK</code>
 <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615134727875/N00WjYN4k.png" alt="Target OS.png" /></li>
<li><p>Visual Studio will create a <code>Dockerfile</code> for you, which specifies how to create the container image for your ASP.NET Core app project. 
 <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615134812429/F5ruAAzHs.png" alt="Dockerfile.png" /></p>
</li>
<li><p>Click on the <code>Docker</code> button to build the image and run it inside a Docker container, rather than in IIS Express.
 <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615132587750/CWcV8ezK1.png" alt="Docker Run.png" />
 <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615133910042/E2jfyd93Z.png" alt="Running WebAPP Edited.png" /></p>
</li>
<li><p>You could verify that your container is running using the Docker command-line tools; open a cmd or Terminal and type in <code>docker container ls</code> to view the containers.
 <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615134060515/55HdFcAY3.png" alt="Docker Container ls.png" /></p>
</li>
</ol>
<p>That's it, you have successfully added Docker support to your ASP<span>.</span>NET core app and your app is now running inside a Docker container.</p>
]]></description><link>https://kumarashwinhubert.com/how-to-dockerize-your-aspnet-core-app-directly-from-visual-studio</link><guid isPermaLink="true">https://kumarashwinhubert.com/how-to-dockerize-your-aspnet-core-app-directly-from-visual-studio</guid><category><![CDATA[Docker]]></category><category><![CDATA[visual studio]]></category><category><![CDATA[asp.net core]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[10 Exception handling best practices in C#]]></title><description><![CDATA[<p>Writing software is a complex task, and it's quite common to see applications crash due to bad code, bad user input, unavailable resources or unexpected conditions at runtime, and so on. And when this happens, we say an exception has occurred that caused the app to crash.</p>
<blockquote>
<p>An exception is a runtime error in a program that violates a system or application constraint, or a condition that is not expected to occur during the normal execution of the program.</p>
</blockquote>
<p>A well-designed app must handle exceptions and prevent the app from crashing. This article describes some of the best practices to follow while handling exceptions in C#.</p>
<ol>
<li>Use <code>throw</code> instead of <code>throw ex</code>.</li>
<li>Log the exception object while logging exceptions.</li>
<li>Avoid catch block that just rethrows it.</li>
<li>Do not swallow the exception.</li>
<li>Throw exceptions instead of returning an error code.</li>
<li>Common failure conditions should be handled without throwing exceptions.</li>
<li>Use grammatically correct and meaningful error messages. </li>
<li><code>ApplicationException</code> should never be thrown from code.</li>
<li>Use the predefined exception types.</li>
<li>End custom exception class names with the word <code>Exception</code>.</li>
</ol>
<h2 id="1-use-throw-instead-of-throw-ex">1. Use <code>throw</code> instead of <code>throw ex</code></h2>
<p>Using <code>throw ex</code> inside a catch block <em>does not preserve</em> the stack trace and the original offender would be lost. Instead use <code>throw</code> as it preserves the stack track and the original offender would be available. </p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Bad code</span>
<span class="hljs-keyword">catch</span>(Exception ex)
{
    <span class="hljs-keyword">throw</span> ex; <span class="hljs-comment">// Stack trace will show this line as the original offender.</span>
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-comment">// Good code</span>
<span class="hljs-keyword">catch</span>(Exception ex)
{
    <span class="hljs-keyword">throw</span>; <span class="hljs-comment">// The original offender would be rightly pointed.</span>
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1614446972925/o02041xjt.png" alt="throw vs throw ex.png" /></p>
<p>Read more about this on my blog - <a target="_blank" href="https://kumarashwinhubert.com/exception-handling-in-csharp-throw-or-throw-ex">Exception handling in C# - throw or throw ex</a></p>
<h2 id="2-log-the-exception-object-while-logging-exceptions">2. Log the exception object while logging exceptions</h2>
<p>Often developers log just the exception message to the logging system without the exception object. The exception object contains crucial information such as exception type, stack trace, etc. and it's very important to log it.</p>
<p>If you are using the <code>ILogger</code>, there are extension methods to LogError, LogCritical, Log, etc that accepts exception object as a parameter; use those instead of just the message ones. <br />
<code>LogCritical(Exception exception, string message, params object[] args)</code> <br />
<code>LogError(Exception exception, string message, params object[] args)</code> <br />
<code>Log(LogLevel logLevel, Exception exception, string message, params object[] args)</code> <br /></p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Bad code</span>
<span class="hljs-keyword">catch</span> (DivideByZeroException ex)
{
    <span class="hljs-comment">// The exception object ex is not logged, thus crucial info is lost</span>
    <span class="hljs-keyword">this</span>.logger.LogError(<span class="hljs-string">"Divide By Zero Exception occurred"</span>);
}
</code></pre>
<p>In the above example, the exception object <code>ex</code> is not logged resulting in loss of stack trace.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Good code</span>
<span class="hljs-keyword">catch</span> (DivideByZeroException ex)
{
    <span class="hljs-keyword">this</span>.logger.LogError(ex, <span class="hljs-string">"Divide By Zero Exception occurred"</span>);
}
</code></pre>
<h2 id="3-avoid-catch-block-that-just-rethrows-it">3. Avoid catch block that just rethrows it</h2>
<p>Don't simply catch an exception and just re-throw it. If the catch block has no other purpose, remove the try-catch block and let the calling function catch the exception and do something with it.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Bad code</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Method1</span>(<span class="hljs-params"></span>)</span> {
    <span class="hljs-keyword">try</span> {
        Method2();
    }
    <span class="hljs-keyword">catch</span> (Exception ex) {
        <span class="hljs-comment">// Code to handle the exception</span>
        <span class="hljs-comment">// Log the exception</span>
        <span class="hljs-keyword">this</span>.logger.LogError(ex);
        <span class="hljs-keyword">throw</span>;
    }
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Method2</span>(<span class="hljs-params"></span>)</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Code that will throw exception</span>
    }
    <span class="hljs-keyword">catch</span> (Exception) {
        <span class="hljs-keyword">throw</span>;
    }
}
</code></pre>
<p>In the above example, <code>Method1</code> is calling <code>Method2</code> and there is a possibility of an exception occurring in <code>Method2</code>. The <code>catch</code> block in Method2 does nothing with the exception and just re-throws it. <br />
Instead, the <code>try-catch</code> block in Method2 can be removed and the caller which is <code>Method1</code> in this case can catch the exception and handle it.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Good code</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Method1</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">try</span>
    {
        Method2();
    }
    <span class="hljs-keyword">catch</span> (Exception ex) {
        <span class="hljs-comment">// Code to handle the exception</span>
        <span class="hljs-comment">// Log the exception</span>
        <span class="hljs-keyword">this</span>.logger.LogError(ex);
        <span class="hljs-keyword">throw</span>;
    }
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Method2</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-comment">// Code that will throw exception</span>

    <span class="hljs-comment">// No try-catch block here  </span>
    <span class="hljs-comment">// as this method doesn't know how to handle the exception</span>
}
</code></pre>
<h2 id="4-do-not-swallow-the-exception">4. Do not swallow the exception</h2>
<p>One of the worst things to do in exception handling is swallowing the exception without doing anything. If the exception is swallowed without even logging there won't be any trace of the issue that occurred. If you are not sure of what to do with the exception, don't catch it or at least re-throw it.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Bad code</span>
<span class="hljs-keyword">try</span>
{
    <span class="hljs-comment">// Code that will throw exception</span>
}
<span class="hljs-keyword">catch</span> (Exception ex)
{
}
</code></pre>
<h2 id="5-throw-exceptions-instead-of-returning-an-error-code">5. Throw exceptions instead of returning an error code</h2>
<p>Sometimes instead of throwing exceptions developers return error codes to the calling function, this might lead to exceptions going unnoticed as the calling functions might not always check for the return code.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Bad code</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">Method2</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">try</span> 
    {
        <span class="hljs-comment">// Code that might throw exception</span>
    }
    <span class="hljs-keyword">catch</span> (Exception) 
    {
        LogError(ex);
        <span class="hljs-comment">// This is bad approach as the caller function </span>
        <span class="hljs-comment">// might miss to check the error code.</span>
        <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
    }
}
</code></pre>
<h2 id="6-common-failure-conditions-should-be-handled-without-throwing-exceptions">6. Common failure conditions should be handled without throwing exceptions</h2>
<p>For conditions that are likely to occur and trigger an exception, consider handling them in a way that will avoid the exception. Example - </p>
<ul>
<li>Close the connection only after checking if it's not already closed.</li>
<li>Before opening a file, check if it exists using the <code>File.Exists(path)</code> method.</li>
<li>Use fail-safe methods like - <code>CreateTableIfNotExists</code> while dealing with databases and tables.</li>
<li>Before dividing, ensure the divisor is not 0.</li>
<li>Check <code>null</code> before assigning value inside a null object.</li>
<li>While dealing with parsing, consider using the <code>TryParse</code> methods.</li>
</ul>
<pre><code class="lang-csharp"><span class="hljs-comment">// Bad code</span>
<span class="hljs-keyword">int</span>.Parse(input);

<span class="hljs-comment">// Good code</span>
<span class="hljs-keyword">int</span>.TryParse(input, <span class="hljs-keyword">out</span> <span class="hljs-keyword">int</span> output);
</code></pre>
<h2 id="7-use-grammatically-correct-and-meaningful-error-messages">7. Use grammatically correct and meaningful error messages</h2>
<p>Ensure that the error messages are clear and <strong>end with a period</strong>. The exception message should not be abrupt and open-ended. Clear and meaningful messages give the developer a good idea of what the issue could have been while trying to replicate and fix the issue.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Bad code</span>
<span class="hljs-keyword">catch</span> (FileNotFoundException ex)
{
    <span class="hljs-keyword">this</span>.logger.LogError(ex, <span class="hljs-string">"Something went wrong"</span>);
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-comment">// Good code</span>
<span class="hljs-keyword">catch</span> (FileNotFoundException ex)
{
    <span class="hljs-keyword">this</span>.logger.LogError(ex, <span class="hljs-string">"Could not find the requested file."</span>);
}
</code></pre>
<h2 id="8-applicationexception-should-never-be-thrown-from-code">8. <code>ApplicationException</code> should never be thrown from code</h2>
<p>In the initial design of .NET, it was planned that the framework will throw <code>SystemException</code> while user applications will throw <code>ApplicationException</code>. However, a lot of exception classes didn't follow this pattern and the <code>ApplicationException</code> class lost all the meaning, and in practice, this found to add no significant value.</p>
<p>Hence it's advised that you should not throw an <code>ApplicationException</code> from your code and you should not catch an <code>ApplicationException</code> too unless you intend to re-throw the original exception. Also custom exceptions <strong>should not be derived</strong> from <code>ApplicationException</code>.</p>
<h2 id="9-use-the-predefined-exception-types">9. Use the predefined exception types</h2>
<p>There are many exceptions already predefined in .NET. Some of them being:</p>
<ul>
<li><code>DivideByZeroException</code> is thrown if the divisor is 0. </li>
<li><code>ArgumentException</code>, <code>ArgumentNullException</code>, or <code>ArgumentOutOfRangeException</code> is thrown if invalid parameters are passed. </li>
<li><code>InvalidOperationException</code> is thrown if a method call or property set is not appropriate in the object's current state. </li>
<li><code>FileNotFoundException</code> is thrown if the file is not present.</li>
<li><code>IndexOutOfRangeException</code> is thrown if the item being accessed from an array/collection is outside its bounds.</li>
</ul>
<p>The predefined exceptions are sufficient in most of the cases. Hence introduce a new custom exception class only when a predefined one doesn't apply or you would like to have some additional business analytics based on some custom exception, e.g. A custom exception - <code>TransferFundsException</code> can be used to keep track of fund transfer exceptions and generate business analytics &amp; insights from it.</p>
<h2 id="10-end-custom-exception-class-names-with-the-word-exception">10. End custom exception class names with the word <code>Exception</code></h2>
<p>As mentioned earlier, the predefined exception types are sufficient in most of the cases, but when a custom exception is necessary, name it appropriately and end the exception name with the word "Exception". </p>
<p>Also, ensure that the custom exception derives from the <code>Exception</code> class and <strong>includes at least the three common constructors</strong> : </p>
<ul>
<li>Parameterless constructor</li>
<li>Constructor that takes a string message</li>
<li>Constructor that takes a string message and an inner exception</li>
</ul>
<p>Example:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TransferFundsException</span> : <span class="hljs-title">Exception</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TransferFundsException</span>(<span class="hljs-params"></span>)</span>
    {
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TransferFundsException</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message</span>)
        : <span class="hljs-title">base</span>(<span class="hljs-params">message</span>)</span>
    {
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TransferFundsException</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message, Exception inner</span>)
        : <span class="hljs-title">base</span>(<span class="hljs-params">message, inner</span>)</span>
    {
    }
}
</code></pre>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>These are some of the exception handling practices that I use and find very helpful in my day-to-day work. Some of the above ones might look obvious, but often go unnoticed by many. Let me know your thoughts and do mention any other exception handling practices that you follow. </p>
]]></description><link>https://kumarashwinhubert.com/10-exception-handling-best-practices-in-csharp</link><guid isPermaLink="true">https://kumarashwinhubert.com/10-exception-handling-best-practices-in-csharp</guid><category><![CDATA[C#]]></category><category><![CDATA[.NET]]></category><category><![CDATA[best practices]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[Flurl - The elegant way to build URLs & set query params in .Net]]></title><description><![CDATA[<p>A common task when calling web apis or resources from code is building a URL and adding the necessary query string and parameters.</p>
<p>The most common, naive and frequent code that we see to achieve this is :</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> userId = <span class="hljs-number">1</span>;
<span class="hljs-keyword">var</span> completed = <span class="hljs-literal">true</span>;
<span class="hljs-keyword">var</span> someParamValue = <span class="hljs-string">"abc"</span>;

Uri baseAddress = <span class="hljs-keyword">new</span> Uri(<span class="hljs-string">"https://jsonplaceholder.typicode.com/"</span>);
Uri apiUrl = <span class="hljs-keyword">new</span> Uri(<span class="hljs-string">$"/todos?userId=<span class="hljs-subst">{userId}</span>&amp;completed=<span class="hljs-subst">{completed}</span>"</span> +
                <span class="hljs-string">$"&amp;someParam=<span class="hljs-subst">{someParamValue}</span>"</span>, UriKind.Relative);
</code></pre>
<p>And the typical issue with the above code is that you could accidentally miss the starting <code>?</code> or the <code>&amp;</code> and <code>=</code> in the query parameters and create bugs; another issue is the <strong>readability</strong> of the code. When there is a high number of query parameters in the url, the code tends to be messy and unclean.</p>
<h3 id="flurlhttpsflurldev-to-the-rescue"><a target="_blank" href="https://flurl.dev/">Flurl</a> to the rescue.</h3>
<blockquote>
<p>Flurl is a modern, fluent, asynchronous, testable, portable, buzzword-laden URL builder and HTTP client library for .NET</p>
</blockquote>
<p>Flurl adds extension methods to strings which helps us easily add path segment, set query params, set fragment, etc. in a clean and elegant manner.</p>
<h4 id="installing-flurl">Installing Flurl</h4>
<p>Flurl can be installed via NuGet Package manager console as: <br />
<code>PM&gt; Install-Package Flurl</code></p>
<p>Or via the NuGet Package manager UI:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1614286743694/AoB1b9-vk.png" alt="Installing flurl.png" /></p>
<p>Once installed, import the <code>Flurl</code> namespace and convert the messy URLs to more readable ones.</p>
<p>The initial code can now be modified and constructed with flurl as :</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Flurl;

<span class="hljs-keyword">string</span> url = <span class="hljs-string">"https://jsonplaceholder.typicode.com/"</span>
    .AppendPathSegment(<span class="hljs-string">"todos"</span>)
    .SetQueryParam(<span class="hljs-string">"userId"</span>, userId)
    .SetQueryParam(<span class="hljs-string">"completed"</span>, completed)
    .SetQueryParam(<span class="hljs-string">"someParam"</span>, someParamValue);
</code></pre>
<p>Apart from <code>SetQueryParam</code> there's also <code>SetQueryParams</code> extension that accepts object, any collection of key-value pairs, Tuples, or a Dictionary object.</p>
<p>Flurl extension methods are available on <code>String</code> as well on <code>System.Uri</code>. In either case, it's easy to convert back and forth using the <code>ToString()</code> and <code>ToUri()</code> methods.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Flurl;

Uri url = <span class="hljs-string">"https://jsonplaceholder.typicode.com/"</span>
    .AppendPathSegment(<span class="hljs-string">"todos"</span>)
    .SetQueryParams(<span class="hljs-keyword">new</span>
    {
        userId = userId,
        completed = completed,
        someParam = someParamValue
    })
    .ToUri();
</code></pre>
<p>Flurl provides lots of other utilities and extension methods too. Do check out <a target="_blank" href="https://flurl.dev/docs/fluent-url/">flurl documentation</a> for more details.</p>
]]></description><link>https://kumarashwinhubert.com/flurl-the-elegant-way-to-build-urls-and-set-query-params-in-net</link><guid isPermaLink="true">https://kumarashwinhubert.com/flurl-the-elegant-way-to-build-urls-and-set-query-params-in-net</guid><category><![CDATA[.NET]]></category><category><![CDATA[coding]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[Exception handling in C# - throw or throw ex]]></title><description><![CDATA[<h2 id="what-are-exceptions">What are Exceptions?</h2>
<p>An exception is a runtime error in a program that violates a system or application constraint, or a condition that is not expected to occur during the normal execution of the program. </p>
<p>Exceptions occur due to bad user input or bad code, unexpected conditions at runtime, unavailable resources, and so on. For example, attempting to read a file that doesn't exist, trying to divide a number by zero, attempting to insert data to a table that doesn't exist, etc. will all throw exceptions. When exceptions are not handled properly, it leads to the crashing of the application!</p>
<h2 id="handling-exceptions">Handling Exceptions</h2>
<p>Handling exceptions ensures that our application does not crash, also it gives us a chance to exit gracefully with some meaningful message or in some scenarios a second chance to fix the issue.</p>
<p>C# provides built-in support to handle the exception using <code>try</code>, <code>catch</code> &amp; <code>finally</code> blocks.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">try</span>
{
    <span class="hljs-comment">// Code to try goes here.</span>
}
<span class="hljs-keyword">catch</span> (SomeSpecificException ex)
{
    <span class="hljs-comment">// Code to handle the exception goes here.</span>
}
<span class="hljs-keyword">finally</span>
{
    <span class="hljs-comment">// Code to execute after the try (and possibly catch) block goes here.</span>
}
</code></pre>
<p>After an exception is thrown, the runtime checks the current statement to see whether it is within a <code>try</code> block. If it is, any <code>catch</code> blocks associated with the <code>try</code> block are checked to see whether they can catch the exception. <code>Catch</code> blocks typically specify exception types; if the type of the <code>catch</code> block is the same type as the exception or a base class of the exception, the <code>catch</code> block can handle the method.</p>
<p>If the statement that throws an exception isn't within a <code>try</code> block or if the <code>try</code> block that encloses it has no matching <code>catch</code> block, the runtime checks the calling method for a <code>try</code> statement and <code>catch</code> blocks. The runtime continues up the calling stack, searching for a compatible <code>catch</code> block. After the catch block is found and executed, control is passed to the next statement after that <code>catch</code> block.</p>
<p>One of the crucial best practices in exception handling is to ensure that the exception is not swallowed, rather it should bubble up to the caller or the topmost part of your application so that the entire stack trace is maintained.</p>
<h2 id="difference-between-throw-and-throw-ex">Difference between <code>throw</code> and <code>throw ex</code></h2>
<p>So what's the fuss here? Exception handling seems simple right? <br />
Well, many times developers often use <code>throw;</code> or <code>throw ex;</code> interchangeably inside the catch block, and that's where the main difference occurs.</p>
<p>To better understand the difference let's take an example of a simple Calculator Application that implements just division for now. </p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">CalculatorApp</span>
{
    <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
        {
            Console.WriteLine(<span class="hljs-string">"Enter the dividend"</span>);
            <span class="hljs-keyword">int</span>.TryParse(Console.ReadLine(), <span class="hljs-keyword">out</span> <span class="hljs-keyword">int</span> dividend);

            Console.WriteLine(<span class="hljs-string">"Enter the divisor"</span>);
            <span class="hljs-keyword">int</span>.TryParse(Console.ReadLine(), <span class="hljs-keyword">out</span> <span class="hljs-keyword">int</span> divisor);

            Console.WriteLine(Divide(dividend, divisor));
        }

        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">Divide</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> dividend, <span class="hljs-keyword">int</span> divisor</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-keyword">return</span> dividend / divisor;
            }
            <span class="hljs-keyword">catch</span> (DivideByZeroException ex)
            {
                Console.WriteLine(<span class="hljs-string">"Cannot divide by 0"</span>);
                <span class="hljs-keyword">throw</span>; <span class="hljs-comment">//Re-throw the error</span>
            }
        }
    }
}
</code></pre>
<p>Here, we have the <code>Divide</code> method which does the division of inputted numbers and is called from the <code>Main</code> function. When a number is divided by 0, it throws the <code>DivideByZeroException</code> and in our code, we catch this exception and log it to the console.</p>
<p>Now let's look at the stack trace being printed with just <code>throw;</code> statement from the catch block when a divide by zero exception occurs:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">catch</span> (DivideByZeroException ex)
{
    Console.WriteLine(<span class="hljs-string">"Cannot divide by 0"</span>);
    <span class="hljs-keyword">throw</span>; <span class="hljs-comment">//Re-throw the error</span>
}
</code></pre>
<pre><code class="lang-text">Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.
   at CalculatorApp.Program.Divide(Int32 dividend, Int32 divisor) in C:\Blog\CalculatorApp\Program.cs:line 22
   at CalculatorApp.Program.Main(String[] args) in C:\Blog\CalculatorApp\Program.cs:line 15
</code></pre>
<p>From the stack trace we see the <strong>exact method</strong> and <strong>line number</strong> where the exception occurred, in this case, line number <strong>22</strong> of the <code>Divide</code> function in <code>Program</code> class.<br /> 
<code>throw;</code> propagated the error while preserving the information on <strong>where exactly it occurred</strong>.</p>
<p>Now let's change the catch block to throw the caught exception object - <code>throw ex</code> and analyze the stack trace being printed.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">catch</span> (DivideByZeroException ex)
{
    Console.WriteLine(<span class="hljs-string">"Cannot divide by 0"</span>);
    <span class="hljs-keyword">throw</span> ex; <span class="hljs-comment">//throwing the caught exception object</span>
}
</code></pre>
<pre><code class="lang-text">Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.
   at CalculatorApp.Program.Divide(Int32 dividend, Int32 divisor) in C:\Blog\CalculatorApp\Program.cs:line 27
   at CalculatorApp.Program.Main(String[] args) in C:\Blog\CalculatorApp\Program.cs:line 15
</code></pre>
<p>You can see that the stack trace points to line number <strong>27</strong> as the cause of the exception, but in fact, it's the line where the <strong>exception was thrown</strong> and <strong>not where it occurred</strong>. We missed the crucial information of where the exception exactly occurred.</p>
<h2 id="throw-or-throw-ex-the-conclusion"><code>throw</code> or <code>throw ex</code> : The Conclusion</h2>
<p>Handling exceptions is a crucial part of software development. It's necessary to understand the basics and the implication of using different <code>throw</code> statements. Developers often spend hours debugging an issue just because they don't have the right stack trace to point the line where the exception exactly occurred due to the way exception was thrown.</p>
<p><strong>In simple terms:</strong><br />
<code>throw</code> <em>preserves </em>the stack trace (the original offender would be available)<br />
<code>throw ex</code> <em>does not preserve</em> the stack trace (the original offender would be lost)</p>
<p>The stack trace loss is very evident when the exceptions bubble up the call stack. Use of <code>throw ex</code> will lead to loss of crucial stack trace.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1614023912220/Edi2uhvcW.png" alt="throw vs throw ex.png" /></p>
<p>To conclude, always ensure that you <strong>re-throw an exception</strong> - that is simply calling <strong>throw without an exception object</strong>.</p>
]]></description><link>https://kumarashwinhubert.com/exception-handling-in-csharp-throw-or-throw-ex</link><guid isPermaLink="true">https://kumarashwinhubert.com/exception-handling-in-csharp-throw-or-throw-ex</guid><category><![CDATA[C#]]></category><category><![CDATA[best practices]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[How to migrate your blog from WordPress to Hashnode]]></title><description><![CDATA[<p>This is a step-by-step guide for migrating a blog from WordPress to Hashnode. </p>
<p>Thanks to <a class="user-mention" href="https://hashnode.com/@tinaciousdesign">Tina Holly</a>'s  <a target="_blank" href="https://blog.tinaciousdesign.com/migrating-my-blog-from-wordpress-to-hashnode">blog post</a> and  <a target="_blank" href="https://github.com/tinacious/migrate-wordpress-blog-hashnode">scripts </a> which helped me migrate my WordPress blog site to Hashnode. This blog post builds on the same but provides a more detailed guide on the migration.</p>
<p>We will cover the migration in <strong>4 main steps</strong> :</p>
<ul>
<li>Download post content from WordPress</li>
<li>Download images</li>
<li>Publish posts to Hashnode using their API<ul>
<li>Get migration scripts</li>
<li>Clean the downloaded posts</li>
<li>Publish posts to Hashnode</li>
</ul>
</li>
<li>Backdate the posts and manually fix the images</li>
</ul>
<h2 id="download-post-content-from-wordpress">Download post content from WordPress</h2>
<p>To begin the migration, you would need to first download your existing posts on WordPress. By default, these are in XML format, but we will use the <a target="_blank" href="https://wordpress.org/plugins/wp-import-export-lite/">WP Import Export Lite</a> to export the posts as JSON.</p>
<ol>
<li>Head to your WordPress site's <em>admin panel</em>.</li>
<li>Navigate to <strong>Plugins</strong> -&gt; <strong>Add New</strong> and search for wp import export lite. <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613370432855/RpkSlVbZ1.png" alt="Wp Import export install.png" /></li>
<li><strong>Install</strong> and <strong>Activate</strong> the 'WP Import Export Lite' plugin.</li>
<li>Now that the plugin is installed and activated, click on the <code>Export</code> option in the plugin. <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613369457086/E_yAeqWL8.png" alt="WP Export plugin.png" /></li>
<li>On the <em>New Export</em> options page, <ol>
<li>Choose export type as <code>Post</code>.</li>
<li>Leave the filtering options &amp; fields section as is.</li>
<li>In the advanced options section, choose export file type as <code>JSON</code>.</li>
<li>Click on the <code>Customize Export File</code> button at the top right corner to begin the export. <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613371016444/5j3Tbw5CK.png" alt="Wp Export Options Page.png" /></li>
<li>Once the export process is completed, click on the <code>Download</code> button to download the post's json file. <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613371735437/rLYHMy5oV.png" alt="WP Export download - 1.png" /></li>
<li>The downloaded file will have an array of objects having the following shape.<pre><code class="lang-json">{
 <span class="hljs-attr">"ID"</span>: <span class="hljs-string">"161"</span>,
 <span class="hljs-attr">"Title"</span>: <span class="hljs-string">"Understanding CRON Expressions"</span>,
 <span class="hljs-attr">"Content"</span>: <span class="hljs-string">"Many Azure resources like web jobs, Azure functions, logic apps use CRON expression [...]"</span>,
 <span class="hljs-attr">"Excerpt"</span>: <span class="hljs-string">""</span>,
 <span class="hljs-attr">"Date"</span>: <span class="hljs-string">"August 29, 2018"</span>,
 <span class="hljs-attr">"Post Type"</span>: <span class="hljs-string">"post"</span>,
 <span class="hljs-attr">"Permalink"</span>: <span class="hljs-string">"http:\/\/kumarashwinhubert.com\/2018\/08\/29\/understanding-cron-expressions\/"</span>
}
</code></pre>
</li>
<li>Rename the downloaded json file to <code>posts.json</code></li>
</ol>
</li>
</ol>
<h2 id="download-images">Download images</h2>
<p>Next, you will need to download all your images from WordPress. Images are stored in the <code>./wp-content/uploads</code> directory by year and month. There are many ways to download the images, but the easiest one is to use an SFTP tool to download this folder.</p>
<pre><code><span class="hljs-string">wp-content/</span>
<span class="hljs-string"></span> <span class="hljs-string">uploads</span>
    <span class="hljs-string"></span> <span class="hljs-number">2018</span>
    <span class="hljs-string"></span>   <span class="hljs-string"></span> <span class="hljs-number">01</span>
    <span class="hljs-string"></span>   <span class="hljs-string"></span> <span class="hljs-number">02</span>
    <span class="hljs-string"></span>   <span class="hljs-string"></span> <span class="hljs-number">03</span>
    <span class="hljs-string"></span> <span class="hljs-number">2019</span>
        <span class="hljs-string"></span> <span class="hljs-number">01</span>
        <span class="hljs-string"></span> <span class="hljs-number">02</span>
        <span class="hljs-string"></span> <span class="hljs-number">03</span>
</code></pre><p><strong><em>Note:</em></strong> <em>Currently there's no automatic way to migrate the images along with your blog post content. This article targets manually uploading the image to hashnode's CDN and updating the migrated blog posts at the end. In case you wish to <strong>use some other storage provider</strong>, please upload the images and replace the url in the <code>posts.json</code> file before proceeding further.</em></p>
<h2 id="publish-posts-to-hashnode-using-their-api">Publish posts to Hashnode using their API</h2>
<p>Hashnode has a <a target="_blank" href="https://api.hashnode.com/">GraphQL API</a>. It's somewhat limited in functionality but has most of the basic features. The API we intend to use is the <code>createPublicationStory</code>; but instead of manually cleaning the downloaded posts json and creating the request body to hit the API, we can use the migration scripts present in <a target="_blank" href="https://github.com/tinacious/migrate-wordpress-blog-hashnode">WordPress-Hashnode Migrator</a> GitHub project. </p>
<p>The next set of steps will use this GitHub project to clean and publish the posts. This project is a node application hence ensure <code>node</code> is installed on your system.</p>
<h3 id="get-migration-scripts">Get migration scripts</h3>
<ol>
<li>Clone the <a target="_blank" href="https://github.com/tinacious/migrate-wordpress-blog-hashnode">WordPress-Hashnode Migrator</a> project from GitHub.</li>
<li>Copy the downloaded <code>posts.json</code> from the earlier step to the root of the cloned project.</li>
<li>Rename the <code>.env.sample</code> to <code>.env</code>
The folder structure will look like this:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613365479463/ZaGj3tWmDB.png" alt="Project Structure.png" /></li>
<li>Open a terminal in the cloned project and install the dependencies:<pre><code class="lang-bash">npm install
</code></pre>
</li>
</ol>
<h3 id="clean-the-downloaded-posts">Clean the downloaded posts</h3>
<p>This step processes the posts in <code>./posts.json</code> and performs the following actions:</p>
<ul>
<li>removes dirty attributes from content HTML</li>
<li>converts post content to Markdown</li>
<li>writes a new file in ./posts/cleaned.json</li>
</ul>
<p>Run the following command to clean the posts.</p>
<pre><code class="lang-bash">npm run cleanse
</code></pre>
<h3 id="publish-posts-to-hashnode">Publish posts to Hashnode</h3>
<p>Ensure that you have already created a Hashnode site; if not, now would be a good time to create one as we need the <code>Publication_Id</code> and <code>API_Key</code> to continue.</p>
<ol>
<li>Head to the dashboard of your hashnode site. Copy and keep the <strong>publicationId</strong> from the url which would be in the form <code>https://hashnode.com/[Publication_Id]/dashboard</code></li>
<li>Navigate to the Developer settings page - https://hashnode.com/settings/developer and <code>Generate New Token</code>.</li>
<li>Open the <code>.env</code> file in the project. Replace the <code>HASHNODE_PUBLICATION_ID</code> value with your publication id and <code>HASHNODE_API_KEY</code> with your generated key. </li>
</ol>
<p>The <code>.env</code> file should look like this : </p>
<pre><code class="lang-text">HASHNODE_PUBLICATION_ID=602xxxa999eabxxxxxxx1a9b
HASHNODE_API_KEY=030xx44x-exx6-4xx4-8xxe-52xxxxxxxx1a
</code></pre>
<p>Save the .env file and head back to the terminal and run the following command to publish the posts to hashnode.</p>
<pre><code class="lang-bash">npm run migrate
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613365530861/6S--AxLmM.png" alt="migrate script output.png" /></p>
<p>Once the script executes successfully, the blog posts would have been published to your hashnode site.</p>
<h2 id="backdate-the-posts-and-manually-fix-the-images">Backdate the posts and manually fix the images</h2>
<p>Currently backdating the posts is not supported in Hashnode's GraphQL API, hence it's required to manually update the backdate on each of the posts.</p>
<p>Navigate to each of the migrated posts and click on <code>Edit -&gt; Settings</code> and set the <code>backdate</code>. Also set the <code>tags</code> &amp; <code>Cover Image</code> if required.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613381175241/HMmh-kddc.png" alt="Publish on backdate.png" /></p>
<p>As mentioned earlier, there isn't an easy way to migrate the images from your WordPress blog. You need to manually update the image in each blog post. </p>
<p>Navigate to each of the migrated posts and you would see the references to old images in the form of <code>/wp-content/uploads/2020/08/filename.png</code>. Use the <code>Upload an image</code> option in hashnode editor to upload the image from the WordPress images downloaded earlier.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613365653259/lT8w_sn5t.png" alt="Upload an Image.png" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>That's it !!! <br />
Your hashnode blog is up and running with all your migrated WordPress posts. </p>
<p>Hope this helped you in your migration journey from WordPress to Hashnode.</p>
]]></description><link>https://kumarashwinhubert.com/how-to-migrate-your-blog-from-wordpress-to-hashnode</link><guid isPermaLink="true">https://kumarashwinhubert.com/how-to-migrate-your-blog-from-wordpress-to-hashnode</guid><category><![CDATA[WordPress]]></category><category><![CDATA[Hashnode]]></category><category><![CDATA[migration]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[Async Main in Console App Visual Studio]]></title><description><![CDATA[<p>Many times we want to create some Pocs for our project wherein we test out other libraries, frameworks, NuGet packages, etc., and a lot of these would be implementing asynchronous programming. Which means, to call these methods exposed by the libraries, NuGet packages, etc. you would have to do a <code>await</code> in your console app. And as you are aware, Main method of Console App needs to be a <code>static void Main(string[] args)</code> and if you try to make the Main method <code>async</code>, you would get the error : 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613303034898/sesP6AFUS.png" alt="Error-on-trying-async-1.png" /></p>
<p>There are many workarounds for making the async calls from Main method, but I like to keep the Main method <code>async</code> and do an <code>await</code> inside it just like any other method. And this is now possible with <strong>C# version greater than 7.1</strong> </p>
<p>To do so, Right click on your project and select <code>Properties</code> and navigate to the <code>Build</code> Tab. There, click on <code>Advanced</code> button at the bottom. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613303079964/blXjRpjl4.png" alt="Advanced-1.png" /></p>
<p>In the Advanced menu, for the <code>Language Version</code> chose any c# version greater than 7.1
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613303103942/eGduia_AW.png" alt="7.1-1.png" /></p>
<p>In case you can't see C# 7.1 or greater, please install any pending updates to your Visual Studio. And now you can change the Main method to :</p>
<pre><code class="lang-csharp"> <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
</code></pre>
<p>and do the <code>await</code> inside it. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613303143272/6RgIQh_LX.png" alt="async-1.png" /></p>
]]></description><link>https://kumarashwinhubert.com/async-main-in-console-app-visual-studio</link><guid isPermaLink="true">https://kumarashwinhubert.com/async-main-in-console-app-visual-studio</guid><category><![CDATA[visual studio]]></category><category><![CDATA[.NET]]></category><category><![CDATA[C#]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[Understanding CRON Expressions]]></title><description><![CDATA[<p>Many Azure resources like web jobs, Azure functions, logic apps use CRON expression when they need to work with Time Triggers. A CRON expression lets you define a time trigger with the help of <strong>six fields</strong>. All the possible time triggers let it be 'Once an hour' to '14 times a day' can be defined using a CRON expression.</p>
<h2 id="heading-understanding-the-expression">Understanding the expression</h2>
<p>As mentioned earlier, a CRON expression includes six fields: </p>
<p><code>{second} {minute} {hour} {day} {month} {day-of-week}</code> </p>
<p>And each field can have one of the following values:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Type</td><td>Example</td><td>Triggered</td></tr>
</thead>
<tbody>
<tr>
<td>Specific Value</td><td>0 5 * * * *</td><td>At every hour at that hour past 5 minutes</td></tr>
<tr>
<td>All Values (*)</td><td>0 * 5 * * *</td><td>At the 5th hour of day (05:mm:00), trigger it every minute of the hour</td></tr>
<tr>
<td>A range ( - )</td><td>8-10 * * * * *</td><td>At hh:mm:08,hh:mm:09,hh:mm:10 where hh:mm is every minute of every hour. 3 times a minute at 8,9,10th second</td></tr>
<tr>
<td>A set ( , )</td><td>1,5,25 * * * * *</td><td>At hh:mm:01, hh:mm:05, hh:mm:25 where hh:mm is every minute of every hour. 3 times a minute at 1, 5, 25th second</td></tr>
<tr>
<td>An Interval ( / )</td><td>0 */5 * * * *</td><td>At hh:05:00, hh:10:00, hh:15:00 and so on till hh:55:00, hh:00:00 where hh is every hour. 12 times an hour</td></tr>
</tbody>
</table>
</div><h2 id="heading-cron-examples">CRON Examples</h2>
<p>Some of the frequently used CRON expression samples</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Expression</td><td>Triggered</td></tr>
</thead>
<tbody>
<tr>
<td>*/10 * * * *  *</td><td>Every 15 seconds</td></tr>
<tr>
<td>0 * * * * *</td><td>Every minute</td></tr>
<tr>
<td>15 * * * * *</td><td>Every minute at 15th Second of that minute</td></tr>
<tr>
<td>0 */10 * * * *</td><td>Once every 10 minutes</td></tr>
<tr>
<td>0 0 * * * *</td><td>Once every hour at 0th minute</td></tr>
<tr>
<td>0 0 */4 * * *</td><td>Once every 4 hours</td></tr>
<tr>
<td>0 0 9-17 * * *</td><td>Once every hour from 9AM to 5pm</td></tr>
<tr>
<td>0 0 0 * * *</td><td>Every day at 00:00:00</td></tr>
<tr>
<td>0 30 10 * * *</td><td>at 10:30 am every day</td></tr>
<tr>
<td>0 30 10 2 * *</td><td>at 10:30 am every 2nd day of every month</td></tr>
<tr>
<td>0 30 10 * * 0,6</td><td>at 10:30 am every weekend (Sat, Sun)</td></tr>
<tr>
<td>0 30 10 * * 1-5</td><td>at 10:30 am every weekday</td></tr>
<tr>
<td>0 0 * * * WED,FRI</td><td>Every hour on Wednesday and Friday</td></tr>
<tr>
<td>0 0 0 * * SUN</td><td>Every Sunday at 00:00:00</td></tr>
<tr>
<td>0 0 0 1-7 * SUN</td><td>Every first Sunday of the month at 00:00:00</td></tr>
<tr>
<td>0 0 0 1 * *</td><td>Every 1st of month at 00:00:00</td></tr>
<tr>
<td>0 0 0 1 1 *</td><td>Every 1st of January every year</td></tr>
<tr>
<td>0 0 * * 1 *</td><td>Every hour in January</td></tr>
<tr>
<td>30 5 */6 * * *</td><td>Every 6 hours at 5 minute 30 seconds</td></tr>
</tbody>
</table>
</div><h3 id="heading-common-pitfalls">Common pitfalls:</h3>
<p>The CRON expression <strong>0 0 */5 * * *</strong> means every 5 hours. So it executes at 00:00:00, 05:00:00, 10:00:00, 15:00:00, 20:00:00, 00:00:00 ... So it's not exactly every 5 hours. If you want a regular frequency, the following  expressions are good:</p>
<ul>
<li>For minutes and seconds : /2, /3, /4, /5, /6, /10, /12, /15, /20 and /30 (60 is divisible by these numbers)</li>
<li>For hours : /2, /3, /4, /6, /8 and /12</li>
<li>For Months : /2, /3, /4 and /6</li>
<li>For days : Nothing actually because there are leap years and months with 28, 29, 30 or 31 days.</li>
</ul>
<p>If you want a cyclic approach, all other values can lead to "wrong" executions at the end of the cycle. e.g. Every 10 hours executes at 00:00:00, 10:00:00, <strong>20:00:00, 00:00:00 (only 4 hours, not 10).</strong> </p>
<p>You can find CRON expression examples online, but many of them omit the <code>{second}</code> field. In case you copy one of them, remember to add the missing <code>{second}</code> field. Also, you will want a zero in that field and not an asterisk</p>
<h2 id="heading-additional-references">Additional references:</h2>
<p>Time trigger for Azure Functions: <a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer">https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer</a> </p>
<p>CRON Expression Descriptor: <a target="_blank" href="https://cronexpressiondescriptor.azurewebsites.net/">https://cronexpressiondescriptor.azurewebsites.net/</a></p>
]]></description><link>https://kumarashwinhubert.com/understanding-cron-expressions</link><guid isPermaLink="true">https://kumarashwinhubert.com/understanding-cron-expressions</guid><category><![CDATA[cron]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[Using LUIS inside FormFlow – Bot Framework]]></title><description><![CDATA[<p>FormFlow is highly powerful and highly useful when you want to collect a set of predefined field data from user and don't wish to create separate dialogs for that. But there are some limitations to it. One such limitation is that, when prompted for an integer or any specific type data type question, say for e.g. "What is your age?", the end user might tend to enter a response like "My age is 23". But here since the bot is expecting an integer type input, it won't understand the user's response and throw in an error and re-prompt the question. This highly disrupts the conversion flow, user experience and makes the bot less likely to be re-used. </p>
<p>So what we need is to add more intelligence to the fields inside the FormFlow and LUIS is the perfect cognitive service which does this. As it is we use LUIS in a BOT (most of the time), now we need to make the FormFlow fields also be processed through LUIS. </p>
<p>The approach we are gonna take is call the LUIS API in the <code>validate</code> method of the form flow field.</p>
<ol>
<li><p>Add a <code>LuisModelEndpoint</code> key to your <code>web.config</code> file. The value would be the LUIS endpoint URL exposed by your Luis app. You can find the endpoint by going to the <em>Publish tab</em> of your Luis app. <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613300942508/lhtxe8LC7.png" alt="luis-publish-tab.png" /></p>
<p>Your web.config will look something like this :</p>
<pre><code class="lang-csharp">&lt;appSettings&gt;
  &lt;!-- update these with your BotId, Microsoft App Id and your Microsoft App Password--&gt;
  &lt;<span class="hljs-keyword">add</span> key=<span class="hljs-string">"BotId"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">"YourBotId"</span> /&gt;
  &lt;<span class="hljs-keyword">add</span> key=<span class="hljs-string">"MicrosoftAppId"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">""</span> /&gt;
  &lt;<span class="hljs-keyword">add</span> key=<span class="hljs-string">"MicrosoftAppPassword"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">""</span> /&gt;
  &lt;<span class="hljs-keyword">add</span> key=<span class="hljs-string">"LuisModelEndpoint"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">"https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/YOUR_MODEL_ID?subscription-key=YOUR_SUBSCRIPTION_KEY&amp;verbose=true&amp;timezoneOffset=0&amp;q="</span>/&gt;
&lt;/appSettings&gt;
</code></pre>
</li>
<li><p>Now let's add the Luis response class so that we can deserialize the API response. Create a class called <code>LUISOutput</code> and paste in the below code.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">LUISOutput</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> query { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> LUISIntent[] intents { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> LUISEntity[] entities { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">LUISEntity</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Entity { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Type { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> StartIndex { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> EndIndex { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">float</span> Score { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">LUISIntent</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Intent { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">float</span> Score { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
</li>
<li><p>Inside your <code>FormFlow</code> class, add a method named <code>GetIntentAndEntitiesFromLUIS</code> which will query Luis for the user input and find in the entities and the intents. The code would be:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> Task&lt;LUISOutput&gt; <span class="hljs-title">GetIntentAndEntitiesFromLUIS</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> Query</span>)</span>
    {
        Query = Uri.EscapeDataString(Query);
        LUISOutput luisData = <span class="hljs-keyword">new</span> LUISOutput();
        <span class="hljs-keyword">try</span>
        {
            <span class="hljs-keyword">using</span> (HttpClient client = <span class="hljs-keyword">new</span> HttpClient())
            {
                <span class="hljs-keyword">string</span> RequestURI = WebConfigurationManager.AppSettings[<span class="hljs-string">"LuisModelEndpoint"</span>] + Query;
                HttpResponseMessage msg = <span class="hljs-keyword">await</span> client.GetAsync(RequestURI);
                <span class="hljs-keyword">if</span> (msg.IsSuccessStatusCode)
                {
                    <span class="hljs-keyword">var</span> JsonDataResponse = <span class="hljs-keyword">await</span> msg.Content.ReadAsStringAsync();
                    luisData = JsonConvert.DeserializeObject&lt;LUISOutput&gt; (JsonDataResponse);
                }
            }
        }
        <span class="hljs-keyword">catch</span> (Exception ex)
        {

        }
        <span class="hljs-keyword">return</span> luisData;
    }
</code></pre>
</li>
<li><p>The base structure is ready. Now you could call this method in the validate function of your individual form flow fields. For example, lets take a Patient registration form flow which asks for 'Name', 'Gender', 'Phone Number', 'DOB'. If I want to apply luis to the Name field, the code would be :</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> FormBuilder&lt;RegisterPatientForm&gt;()
        .Field(<span class="hljs-keyword">nameof</span>(person_name),
        validate: <span class="hljs-keyword">async</span> (state, response) =&gt;
        {
            <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">new</span> ValidateResult { IsValid = <span class="hljs-literal">true</span>, Value = response };

            <span class="hljs-comment">//Query LUIS and get the response</span>
            LUISOutput LuisOutput = <span class="hljs-keyword">await</span> GetIntentAndEntitiesFromLUIS((<span class="hljs-keyword">string</span>)response);

            <span class="hljs-comment">//Now you have the intents and entities in LuisOutput object</span>
            <span class="hljs-comment">//See if your entity is present in the intent and then retrieve the value</span>
            <span class="hljs-keyword">if</span> (LuisOutput != <span class="hljs-literal">null</span> &amp;&amp; Array.Find(LuisOutput.intents, intent =&gt; intent.Intent == <span class="hljs-string">"GetName"</span>) != <span class="hljs-literal">null</span>)
            {
                LUISEntity LuisEntity = Array.Find(LuisOutput.entities, element =&gt; element.Type == <span class="hljs-string">"name"</span>);

                <span class="hljs-keyword">if</span> (LuisEntity != <span class="hljs-literal">null</span>)
                {
                    <span class="hljs-comment">//Store the found response in resut</span>
                    result.Value = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(LuisEntity.Entity);
                }
                <span class="hljs-keyword">else</span>
                {
                    <span class="hljs-comment">//Name not found in the response</span>
                    result.IsValid = <span class="hljs-literal">false</span>;
                }
            }
            <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (LuisOutput != <span class="hljs-literal">null</span> &amp;&amp; Array.Find(LuisOutput.intents, intent =&gt; intent.Intent == <span class="hljs-string">"None"</span>) != <span class="hljs-literal">null</span>)
            {
                <span class="hljs-comment">//In case of none intent assume that the user entered a name</span>
                result.Value = LuisOutput.query;
            }
            <span class="hljs-keyword">else</span>
            {
                result.IsValid = <span class="hljs-literal">false</span>;
            }
            <span class="hljs-keyword">return</span> result;
        })
</code></pre>
<p>That's all, now on user input, the formflow will call luis and based on the response, the values would be set into the form fields. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613301093830/MUWy_Ofok.gif" alt="emulator-sample-3.gif" /></p>
</li>
</ol>
<p>You can find the complete project solution in my <a target="_blank" href="https://github.com/Kumar-Ashwin-Hubert/LuisInsideFormFlow">GitHub repo</a>.</p>
]]></description><link>https://kumarashwinhubert.com/using-luis-inside-formflow-bot-framework</link><guid isPermaLink="true">https://kumarashwinhubert.com/using-luis-inside-formflow-bot-framework</guid><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[Visual Studio Code top 10 useful keyboard shortcuts]]></title><description><![CDATA[<p>Keyboard shortcuts can greatly improve your productivity and are sometimes more helpful than mouse clicks. We will see some of the top 10 keyboard shortcuts that are very powerful and highly useful while using Visual Studio Code. I am gonna talk about the shortcuts for Windows, for Mac, just replace <code>ctrl</code> with <code>cmd</code> key.</p>
<h2 id="heading-open-andamp-close-sidebar-ctrl-b">Open &amp; Close Sidebar - <code>Ctrl + b</code></h2>
<p>You can easily open and close the sidebar with <code>Ctrl + b</code> . This really comes in handy when you are on a small screen and would like to save the display area. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613301322175/KymTXgrwT.gif" alt="ctrl-b-1.gif" /></p>
<h2 id="heading-quick-open-ctrl-p">Quick open - <code>Ctrl + p</code></h2>
<p>When you want to open the recent files or open a specific file, you can use <code>Ctrl + p</code> to get a search bar and open the file from there. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613301350010/Hd5dRR41A.gif" alt="ctrl-p-new-1.gif" /> </p>
<h2 id="heading-keep-open-ctrl-k-enter">Keep Open - <code>Ctrl + k</code> <code>Enter</code></h2>
<p>When you open the file by a single click from the sidebar or through the quick open, the file will be replaced by the next file you open. So in case you want to keep open the current file, type in <code>Ctrl + k</code> <code>Enter</code> You can also notice the changes in the file name in the top bar once you "keep open" the file. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613301385326/U75OLwELm.gif" alt="ctrl-k-enter-1.gif" /></p>
<h2 id="heading-integrated-terminal-ctrl">Integrated Terminal - <code>Ctrl + ` </code></h2>
<p>To quickly open/close the integrated terminal use <code>Ctrl + ` </code> . Integrated Terminal is a really handy tool when you want to execute commands without opening a separate terminal or command prompt.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613301414716/3XXGxrb1H.gif" alt="ctrl-1.gif" /> </p>
<h2 id="heading-code-formatting-alt-shift-f">Code Formatting - <code>Alt + Shift + f</code></h2>
<p>To format the entire document you can use <code>Alt + Shift + f</code> . This is really useful when you want to follow same formatting rules across files.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613301624021/Qu7E26NZ3.gif" alt="altshiftenter-1.gif" /></p>
<h2 id="heading-search-within-folder-ctrl-shift-f">Search within folder - <code>Ctrl + Shift + f</code></h2>
<p>While <code>Ctrl + f</code> allows you to search within the current file, <code>Ctrl + Shift + f</code> allows you to search within your open folder. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613301450286/1ktITbzZq.gif" alt="ctrlshiftf-1.gif" />  </p>
<h2 id="heading-select-word-ctrl-d">Select Word - <code>Ctrl + d</code></h2>
<p>To select the entire word where your cursor is on, use <code>Ctrl + d</code> , If you hit <code>Ctrl + d</code> more than once, youll add another occurrence of the same keyword to your selection. This is very useful when you want to change the multiple occurrences of the same word. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613301490150/DeiTkH702.gif" alt="ctrld-1.gif" /></p>
<h2 id="heading-select-all-occurrences-of-selection-ctrl-shift-l">Select all occurrences of selection - <code>Ctrl + Shift + L</code></h2>
<p>In case you want to change a particular word or get the cursor across all the occurrences of word or selection use <code>Ctrl + Shift + L</code>. Alternatively, you can also use <code>Ctrl+F2</code> to get the same behavior. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613301517529/-CuMz6oW2.gif" alt="ctrlshift-l-1.gif" /></p>
<h2 id="heading-close-the-currently-open-file-ctrl-w">Close the currently open file - <code>Ctrl + w</code></h2>
<p>Close the open file with this shortcut instead of hovering over the tab finding the 'x' and clicking it. To close all the open files, use <code>Ctrl + k</code> <code>w</code>.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613301541161/giOepw0Tw.gif" alt="ctrlw-2.gif" /></p>
<h2 id="heading-command-palette-ctrl-shift-p">Command Palette - <code>Ctrl + Shift + p</code></h2>
<p>One of the most important feature of VS Code is Command Palette. It lets you execute tasks in VS code. Use <code>Ctrl + Shift + p</code> to bring up the command palette. You can type in any task you want to achieve and VS Code will search for the task for you. If a keyboard shortcut exists, it will show that too. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613301587345/Y8rA9fM2j.gif" alt="ctrlshift-p-1.gif" /></p>
<p>That's it! The top 10 keyboard shortcuts for VS code. To view all the available shortcuts use <code>Ctrl + k</code> <code>Ctrl + s</code> or <code>Ctrl + k</code> <code>s</code> To read more about all the key bindings, visit the <a target="_blank" href="https://code.visualstudio.com/docs/getstarted/keybindings">official keybindings document .</a></p>
]]></description><link>https://kumarashwinhubert.com/visual-studio-code-top-10-useful-keyboard-shortcuts</link><guid isPermaLink="true">https://kumarashwinhubert.com/visual-studio-code-top-10-useful-keyboard-shortcuts</guid><category><![CDATA[Visual Studio Code]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[Adding Swagger help page to Web API project]]></title><description><![CDATA[<p>Documentation is a key integral of any project. And when it comes to a Web API project, it's a must, mainly for the client side to know the APIs to call on the server and to handle the expected response objects. Manual documentation of the APIs, their request body, their responses is definitely out of the question as the APIs keep changing through the life cycle of the project. This is where Swagger comes into the picture.</p>
<blockquote>
<p>The evolution of your APIs functionality is inevitable, but the headache of maintaining API docs doesnt have to be. Swagger tools takes the hard work out of generating and maintaining your API docs, ensuring your documentation stays up-to-date as your API evolves.</p>
<p> <a target="_blank" href="https://swagger.io/solutions/api-documentation/">swagger.io</a></p>
</blockquote>
<h2 id="heading-installing-swagger">Installing Swagger</h2>
<p>To add swagger to your web API project, you need to install the <a target="_blank" href="https://www.nuget.org/packages/Swashbuckle/">Swashbuckle</a> NuGet to the project.</p>
<p>Right click on your API project and choose "<strong>Manage NuGet Packages"</strong>. In the Package manager window, search for "Swagger" or "Swashbuckle" and install it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613300298093/GH7ou1KQE.png" alt="nuget-install-1.png" /></p>
<p><strong>And that's it</strong>, swagger would be enabled on your project. Run the project and navigate to "http://YOUR_PROJECT_URL/swagger" for e.g. "<a target="_blank" href="http://localhost:1357/swagger">http://localhost:1357/swagger</a>" and you would see the swagger API documentation for your project.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613300332321/CgokxECQy.png" alt="swagger-page-e1534859513906-1.png" /></p>
<h2 id="heading-what-happened-in-the-back">What happened in the back</h2>
<p>Well, though just installing a NuGet got the job done, it's good if you know how things are wired up and what changes are recommended to do.</p>
<p>If you look inside your <code>App_Start</code> folder, you would notice a new auto-generated file called <code>SwaggerConfig.cs</code> and this is where the configuration for Swagger exists.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613300366761/OolqISsht.png" alt="swagger-auto-initialization-1.png" /></p>
<p>At the minimum, you will need the following configuration to enable swagger. (This is the one that's already there inside the SwaggerConfig.cs)</p>
<pre><code class="lang-csharp">GlobalConfiguration.Configuration
    .EnableSwagger(c =&gt;
    {
        c.SingleApiVersion(<span class="hljs-string">"v1"</span>, <span class="hljs-string">"API Title"</span>);
    })
    .EnableSwaggerUi(c =&gt;{});
</code></pre>
<p>And if you notice the line above the namespace, you would find this line of code that does the wiring up ( registering it )</p>
<p><code>[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]</code></p>
<p>We generally don't want Config registrations lying around here and there and always prefer to keep it in a single place - the <code>Global.asax</code> file. Go ahead and comment/delete that line from your SwaggerConfig and add <code>SwaggerConfig.Register();</code> to your <code>Global.asax</code> file. So your Global.asax file should look something like this at the bare minimum :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613300487780/NRivKSZaH.png" alt="change-in-global-asax-file-1.png" /></p>
<p>So now the registration happens from the <code>Application_Start()</code> method, and all our config registrations are in a single file.</p>
<h2 id="heading-why-use-swagger">Why use Swagger</h2>
<p>The next important question, why swagger? What benefits does it provide?</p>
<p>The main thing is that each public action method in your controllers can be tested from the Swagger UI. Click a method name to expand the section, add the necessary parameters, if any and click <strong>Try it out!</strong>. You can see the responses as well as the expected model.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613300522630/0aqntewK8.png" alt="try-it-out-e1534859034647-1.png" /></p>
<p>Similar one goes for a POST request as well. You can see the expected model for the request and test it out with a sample model from the Swager UI itself.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613300552203/cJmcfzq9Z.png" alt="post-request-e1534859016913-1.png" /></p>
<p>No need for POSTMAN or other tools for testing the API. Pretty cool right!! Don't forget to try out Swagger in your next project.</p>
]]></description><link>https://kumarashwinhubert.com/adding-swagger-help-page-to-web-api-project</link><guid isPermaLink="true">https://kumarashwinhubert.com/adding-swagger-help-page-to-web-api-project</guid><category><![CDATA[.NET]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[How to keep track of active files inside Solution Explorer of Visual Studio]]></title><description><![CDATA[<p>While working with complex projects and multiple files, it's very natural to get lost in the code flow. On top of that, going through the code flow can be even more difficult as Visual Studio by default shows the file in the Solution Explorer which you opened by double-clicking. When you move across project files, by default solution explorer doesn't show the current active file.</p>
<p>But there is a simple way to have Visual Studio show the active files in solution explorer. Goto <strong>Tools</strong>  <strong>Options</strong> and Select <strong>Projects and Solutions</strong> and enable <strong>"Track Active Item in Solution Explorer "</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613299838904/LrmwmvAf2.png" alt="options-1.png" />
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613299850776/vjEhQz9Hx.png" alt="options-panel-1.png" /></p>
<p>And that's it. Navigate across files and the solution explorer will also navigate along with you.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613300222748/RVPz9pyj-.gif" alt="solution-explorer1.gif" /></p>
]]></description><link>https://kumarashwinhubert.com/how-to-keep-track-of-active-files-inside-solution-explorer-of-visual-studio</link><guid isPermaLink="true">https://kumarashwinhubert.com/how-to-keep-track-of-active-files-inside-solution-explorer-of-visual-studio</guid><category><![CDATA[visual studio]]></category><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item><item><title><![CDATA[How to remove unused (stale) branches in Git]]></title><description><![CDATA[<p>Many times while completing a pull request we delete the source branch, this deletes the branch from the git server, but still, the reference to that branch would appear in Visual Studio. Even if you do a <code>fetch</code>, <code>pull</code> or <code>sync</code>, the deleted branch from the server would still appear in Visual Studio.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613281790739/ae2U1ICfm.png" alt="server-branches1-1.png" /></td><td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613281803867/o5w8vifnE.png" alt="visual-studio-branch-status-1.png" /></td></tr>
</thead>
<tbody>
<tr>
<td></td></tr>
</tbody>
</table>
</div><p>As you can see in the above image, a deleted branch (<strong>feature1</strong> branch) still shows up in visual studio.</p>
<p>So to remove, first let's check which branches have to be pruned (remove reference). Run</p>
<pre><code class="lang-bash">git remote prune origin --dry-run
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613281856830/tsnRWFJ8q.png" alt="prune-dry-run1-1.png" /></p>
<p>The argument <code>--dry-run</code> just mimics the prune and <strong>does not actually remove it.</strong></p>
<p>Now to remove the branches, run the prune command without the <code>--dry-run</code> argument.</p>
<pre><code class="lang-bash">git remote prune origin
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613281915391/09pSfgk7d.png" alt="git-prune-1.png" /></p>
<p>If you go ahead and check in visual studio, you wouldn't find the pruned branches inside remote.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613281968109/ELraY__tr.png" alt="post-pruning-visual-studio-1.png" /></p>
<p>If you want to <strong>remove the local branch</strong> as well; right-click on that branch in visual studio and choose delete from the context menu.</p>
<p>Alternatively, you could also run</p>
<pre><code class="lang-bash">git branch -d feature1
</code></pre>
<p>in a terminal window.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613282015262/J6UaRKMTc.png" alt="delete-local-branch-1.png" /></p>
<p>That's it!! You have removed references to your unused local and remote branches!</p>
]]></description><link>https://kumarashwinhubert.com/how-to-remove-unused-stale-branches-in-git</link><guid isPermaLink="true">https://kumarashwinhubert.com/how-to-remove-unused-stale-branches-in-git</guid><dc:creator><![CDATA[Kumar Ashwin Hubert]]></dc:creator></item></channel></rss>