<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Venkatesan Rethinam</title>
    <description>The latest articles on DEV Community by Venkatesan Rethinam (@vengi83644).</description>
    <link>https://dev.to/vengi83644</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F446698%2F6f3af86d-b960-4ae9-9107-a43b6abfbf54.png</url>
      <title>DEV Community: Venkatesan Rethinam</title>
      <link>https://dev.to/vengi83644</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vengi83644"/>
    <language>en</language>
    <item>
      <title>Metrics with IMeterFactory and Azure Application Insights</title>
      <dc:creator>Venkatesan Rethinam</dc:creator>
      <pubDate>Wed, 05 Mar 2025 14:44:02 +0000</pubDate>
      <link>https://dev.to/vengi83644/metrics-with-imeterfactory-and-azure-application-insights-1k4b</link>
      <guid>https://dev.to/vengi83644/metrics-with-imeterfactory-and-azure-application-insights-1k4b</guid>
      <description>&lt;h2&gt;
  
  
  Level Up Your .NET 8 ASP.NET Core App: Metrics with IMeterFactory and Azure Application Insights
&lt;/h2&gt;

&lt;p&gt;In the world of modern application development, observability is king. You need to know how your application is performing, and metrics are a crucial part of that. In .NET 8, &lt;code&gt;IMeterFactory&lt;/code&gt; provides a powerful and standardized way to instrument your code. Coupled with Azure Application Insights, you can gain deep insights into your application's behavior. Let's dive into how to set this up in your ASP.NET Core application.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Project Setup and Dependencies
&lt;/h2&gt;

&lt;p&gt;First, create a new ASP.NET Core Web API project (or use an existing one). Then, add the necessary NuGet packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet add package Microsoft.Extensions.Diagnostics.Abstractions
dotnet add package Microsoft.Extensions.Diagnostics.Metrics
dotnet add package Azure.Monitor.OpenTelemetry.AspNetCore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Microsoft.Extensions.Diagnostics.Abstractions&lt;/code&gt;: Provides core abstractions for diagnostics.&lt;br&gt;
&lt;code&gt;Microsoft.Extensions.Diagnostics.Metrics&lt;/code&gt;: Contains the IMeterFactory and related types.&lt;br&gt;
&lt;code&gt;Azure.Monitor.OpenTelemetry.AspNetCore&lt;/code&gt;: Enables OpenTelemetry integration with Azure Application Insights.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Configuring IMeterFactory and Application Insights
&lt;/h2&gt;

&lt;p&gt;Modify your &lt;code&gt;Program.cs&lt;/code&gt; file to configure &lt;code&gt;IMeterFactory&lt;/code&gt; and enable Application Insights:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Diagnostics.Metrics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;span class="c1"&gt;// Add Application Insights&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddApplicationInsightsTelemetry&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Add MeterFactory&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMetrics&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// ... other services ...&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// ... middleware ...&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This snippet does the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;builder.Services.AddApplicationInsightsTelemetry();&lt;/code&gt;: Configures Application Insights with OpenTelemetry, automatically collecting telemetry data.&lt;br&gt;
&lt;code&gt;builder.Services.AddMetrics();&lt;/code&gt;: Registers the IMeterFactory with the dependency injection container.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Instrumenting Your Code
&lt;/h2&gt;

&lt;p&gt;Now, let's add some instrumentation to your code. For example, we'll track the number of HTTP requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Diagnostics.Metrics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyWebApi.Controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WeatherForecastController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;Summaries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"Freezing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bracing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Chilly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Cool"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Mild"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Warm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Balmy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Sweltering"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Scorching"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WeatherForecastController&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_requestCounter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;WeatherForecastController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WeatherForecastController&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IMeterFactory&lt;/span&gt; &lt;span class="n"&gt;meterFactory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;meter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;meterFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyWebApi.Requests"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_requestCounter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;meter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateCounter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"http.requests.count"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"requests"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Counts incoming HTTP requests."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"GetWeatherForecast"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WeatherForecast&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_requestCounter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Enumerable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;WeatherForecast&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Date&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateOnly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="n"&gt;TemperatureC&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(-&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;55&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;Summary&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Summaries&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Summaries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We inject IMeterFactory into the controller's constructor.&lt;/li&gt;
&lt;li&gt;We create a Meter with a meaningful name ("MyWebApi.Requests").&lt;/li&gt;
&lt;li&gt;We create a Counter to track the request count.&lt;/li&gt;
&lt;li&gt;We increment the counter each time the endpoint is called.&lt;/li&gt;
&lt;li&gt;Remember to use descriptive names and units.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Visualizing Metrics in Azure Application Insights
&lt;/h2&gt;

&lt;p&gt;After deploying your application to Azure, navigate to your Application Insights resource in the Azure portal.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Metrics Explorer:

&lt;ul&gt;
&lt;li&gt;Go to "Metrics" in the left-hand menu.&lt;/li&gt;
&lt;li&gt;In the "Metric Namespace" dropdown, you'll find your custom meter namespace ("MyWebApi.Requests" in our example).&lt;/li&gt;
&lt;li&gt;Select your counter ("http.requests.count").&lt;/li&gt;
&lt;li&gt;You can then visualize the request count over time.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;*Logs (Analytics):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to "Logs" in the left-hand menu.&lt;/li&gt;
&lt;li&gt;Use Kusto Query Language (KQL) to query your metrics data. For example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;customMetrics
| where customMetricName == "http.requests.count"
| summarize sum(valueCount) by bin(timestamp, 1m)
| render timechart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This query will display a time chart of the total request count aggregated by minute.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Adding Tags for Context
&lt;/h2&gt;

&lt;p&gt;To add more context to your metrics, use tags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;_requestCounter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;KeyValuePair&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"http.method"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you can filter and aggregate metrics by these tags in Application Insights.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use meaningful meter and instrument names.&lt;/li&gt;
&lt;li&gt;Choose the appropriate instrument type (Counter, Gauge, Histogram).&lt;/li&gt;
&lt;li&gt;Leverage tags for filtering and aggregation.&lt;/li&gt;
&lt;li&gt;Use UCUM for units.&lt;/li&gt;
&lt;li&gt;Monitor Application Insights regularly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these steps, you can effectively use IMeterFactory and Azure Application Insights to gain valuable insights into your .NET 8 ASP.NET Core application's performance. Happy monitoring!&lt;/p&gt;

</description>
      <category>opentelemetry</category>
      <category>monitoring</category>
      <category>azureapplicationinsights</category>
    </item>
    <item>
      <title>Clean as you code approach — SonarQube Analysis</title>
      <dc:creator>Venkatesan Rethinam</dc:creator>
      <pubDate>Sun, 25 Feb 2024 15:22:23 +0000</pubDate>
      <link>https://dev.to/vengi83644/clean-as-you-code-approach-sonarqube-analysis-48cb</link>
      <guid>https://dev.to/vengi83644/clean-as-you-code-approach-sonarqube-analysis-48cb</guid>
      <description>&lt;h1&gt;
  
  
  What is "clean as you code" approach?
&lt;/h1&gt;

&lt;p&gt;Clean as you code is an approach to code quality that eliminates many of the challenges that come with traditional approaches. As a developer, you focus on maintaining high standards and taking responsibility specifically in the new code you’re working on. SonarQube gives you the tools to set high standards and take pride in knowing that your code meets those standards.&lt;/p&gt;

&lt;p&gt;This approach lets you focus on whether the new code you write is clean and safe and you take responsibility only for the code you write. This approach also lets the reviewer see only the analysis of the new code and not the code that was written before introducing SonarQube analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite
&lt;/h2&gt;

&lt;p&gt;For you to follow this approach, the project in the SonarQube server should know the analysis report of the branch or a particular code version or a specific analysis or code version with a floating period which will be used for comparison.&lt;/p&gt;

&lt;p&gt;Setting your new code definition is explained here — &lt;a href="https://docs.sonarqube.org/latest/project-administration/defining-new-code"&gt;https://docs.sonarqube.org/latest/project-administration/defining-new-code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, the prerequisite is an analysis report to which the changed code in PR’s analysis report can be compared.&lt;/p&gt;

&lt;h2&gt;
  
  
  Branch(main/master) analysis for a new project in SonarQube
&lt;/h2&gt;

&lt;p&gt;When a new project is added in SonarQube for your source code, the analysis would be empty, and you must feed the base analysis report (Overall Code) which you decide to go with.&lt;/p&gt;

&lt;p&gt;This is a step that should be done before any PR pipeline with SonarQube analysis is created.&lt;/p&gt;

&lt;p&gt;For this documentation purpose, the default branch is analyzed and fed into the SonarQube server.&lt;/p&gt;

&lt;p&gt;This base analysis can be done in two ways,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;From the DevOps pipeline&lt;/li&gt;
&lt;li&gt;Using the dotnet-sonarscanner tool — &lt;a href="https://www.nuget.org/packages/dotnet-sonarscanner"&gt;https://www.nuget.org/packages/dotnet-sonarscanner&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is a one-time step based on your new code definition.&lt;/p&gt;

&lt;p&gt;The usual setup for SonarQube analysis would be in the PR build pipeline which would do the following,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pull the source (task) branch&lt;/li&gt;
&lt;li&gt;Prepare the SonarQube analysis&lt;/li&gt;
&lt;li&gt;Build the source code&lt;/li&gt;
&lt;li&gt;Run the SonarQube Analysis&lt;/li&gt;
&lt;li&gt;Publish the Analysis to the SonarQube server in the PR’s name&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The same pipeline would be triggered after the PR is completed to run the analysis against the destination (main/master) branch. This will update the existing base report (Overall Code) analysis with the latest analysis.&lt;/p&gt;

&lt;p&gt;If this is the flow that the project needs, then the recommended approach is to use the dotnet-sonarscanner tool as a one-time step after the project is created.&lt;/p&gt;

&lt;p&gt;If your project needs to set the new code definition dynamically or want scan the main branch without setting up the source code in your machine, then running the analysis in the pipeline would be useful.&lt;/p&gt;

&lt;p&gt;However, for the first-time setup, if you take the DevOps pipeline approach to feed the base analysis report, then you must override the Quality gate and complete the PR to trigger the analysis on the main branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dotnet tool dotnet-sonarscanner
&lt;/h2&gt;

&lt;p&gt;Using this tool, you can scan any branch in your source code and publish it to the SonarQube server. The tool will detect the git branch name for you and will be pushed along with the analysis.&lt;/p&gt;

&lt;p&gt;Once you add the project in SonarQube for your source code repo, you will be shown a page like the one below. Choose the manual approach here,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3kcqnnj19p3xmgqx6wop.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3kcqnnj19p3xmgqx6wop.png" alt="Image description" width="700" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow the below steps,&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1: Setup your token for analysis
&lt;/h1&gt;

&lt;p&gt;Give the token a name and generate it,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ulosz3s95fh3vnt46ap.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ulosz3s95fh3vnt46ap.png" alt="Image description" width="700" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can always use an existing token if you have one. This is the token you will use in the dotnet tool for authenticating you and publishing the analysis report on your machine.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 2: Run the analysis
&lt;/h1&gt;

&lt;p&gt;Prerequisite for this step,&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite 1
&lt;/h2&gt;

&lt;p&gt;Install the dotnet tool dotnet-sonarscanner using the below command,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet tool install --global dotnet-sonarscanner --version 6.2.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;6.2.0 is the latest version when writing this documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite 2
&lt;/h2&gt;

&lt;p&gt;Checkout the source code of the project you are configuring the analysis and make sure you have the branch you want to scan and set as the base report (Overall Code) analysis.&lt;/p&gt;

&lt;p&gt;Once the prerequisites are completed, you can execute the scanner on the root of your source code.&lt;/p&gt;

&lt;p&gt;Running a SonarQube analysis is straightforward. You just need to execute the following commands at the root of your solution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SonarScanner begin command&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This command will ensure the tracking of code analysis when you build the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet sonarscanner begin /k:"Project.Name" /d:sonar.host.url="https://sonarqubeapp.azurewebsites.net"  /d:sonar.login="login.id.here"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dotnet build command&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now you can build the project with the dotnet build command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;SonarScanner end command&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This command will collect the code analysis and publish it to the SonarQube server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet sonarscanner end /d:sonar.login="login.id.here"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All these commands and instructions are shown in the setup page as like below,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5p4rjgp3gujh5jde0xco.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5p4rjgp3gujh5jde0xco.png" alt="Image description" width="700" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using the DevOps pipeline for branch analysis
&lt;/h1&gt;

&lt;p&gt;This is the usual step you do in a build pipeline using the SonarQube tasks in the DevOps. Check the below blog on how to do this,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/vengi83644/sonarqube-deployment-integration-and-configuration-2fp1"&gt;https://dev.to/vengi83644/sonarqube-deployment-integration-and-configuration-2fp1&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Overall Code
&lt;/h1&gt;

&lt;p&gt;Once the branch analysis and publishing are done from the above steps either using the dotnet tool or the DevOps pipeline, you should see the measures in the Overall Code tab as shown below,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuviyldsprhmi1iy7j9dj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuviyldsprhmi1iy7j9dj.png" alt="Image description" width="700" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will be the default base report analysis which will be used for comparison(until the next scan happens on the same branch) when a PR analysis report is published.&lt;/p&gt;

&lt;p&gt;The new code tab will be empty at this point.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwbldtves6afwo8amcupw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwbldtves6afwo8amcupw.png" alt="Image description" width="700" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  PR pipeline analysis report comparison
&lt;/h1&gt;

&lt;p&gt;Now, let's introduce a code smell issue in a task branch and see the analysis report.&lt;/p&gt;

&lt;p&gt;In the New Code tab, you will now see the issue that was identified in the PR as shown below. Note that the 33 code smells in the Overall Code are not reported here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqittrrydlkapfb50jbdv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqittrrydlkapfb50jbdv.png" alt="Image description" width="700" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Only the new issues are reported which lets you focus on them and ignore the existing code. This is how we follow the “Clean as you code” approach.&lt;/p&gt;

</description>
      <category>sonarqube</category>
      <category>staticcodeanalysis</category>
      <category>codereview</category>
      <category>codequality</category>
    </item>
    <item>
      <title>SonarQube - Deployment, Integration and Configuration</title>
      <dc:creator>Venkatesan Rethinam</dc:creator>
      <pubDate>Thu, 22 Feb 2024 19:54:08 +0000</pubDate>
      <link>https://dev.to/vengi83644/sonarqube-deployment-integration-and-configuration-2fp1</link>
      <guid>https://dev.to/vengi83644/sonarqube-deployment-integration-and-configuration-2fp1</guid>
      <description>&lt;h1&gt;
  
  
  Deployment
&lt;/h1&gt;

&lt;p&gt;SonarQube is a web service that can run in our Azure App Service. It uses an SQL database to store code analysis reports.&lt;/p&gt;

&lt;p&gt;We can use the SonarQube docker available in Docker Hub to deploy the app into Azure App Service.&lt;/p&gt;

&lt;p&gt;Here is the docker-compose.yml,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sonarqube&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarqube:lts-enterprise&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;SONARQUBE_JDBC_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:sqlserver://testsql.database.windows.net:1433;database=sonarqube-enterprise-edition;user=sonarqube@sql-server-sonarqube;password=Admin@123;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;&lt;/span&gt;
      &lt;span class="na"&gt;SONARQUBE_JDBC_USERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarqube&lt;/span&gt;
      &lt;span class="na"&gt;SONARQUBE_JDBC_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Admin@123&lt;/span&gt;
      &lt;span class="na"&gt;WEBSITES_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sonarqube_data:/opt/sonarqube/data&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sonarqube_extensions:/opt/sonarqube/extensions&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sonarqube_logs:/opt/sonarqube/logs&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sonarqube_temp:/opt/sonarqube/temp&lt;/span&gt;   
    &lt;span class="na"&gt;ulimits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;nproc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;131072&lt;/span&gt;
      &lt;span class="na"&gt;nofile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;soft&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8192&lt;/span&gt;
        &lt;span class="na"&gt;hard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;131072&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:9000"&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sonarqube_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sonarqube_extensions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sonarqube_logs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sonarqube_temp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The credential for the database is added in the docker-compose.yml file. This is needed when the app is started.&lt;/p&gt;

&lt;p&gt;We can also configure the same from the Configuration.&lt;/p&gt;

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

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;p&gt;You can check SonarQube's requirements here - &lt;a href="https://docs.sonarqube.org/latest/requirements/requirements/"&gt;https://docs.sonarqube.org/latest/requirements/requirements/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  App Service
&lt;/h2&gt;

&lt;p&gt;For the app to run in Azure App Service, we need a P2V2 plan. This is because the app internally has an Elastic Search service, and it needs more memory. Otherwise, you will see the app running and getting stopped after some time.&lt;/p&gt;

&lt;p&gt;You can always use the Log Stream in the App Service to watch the logs from the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database
&lt;/h2&gt;

&lt;p&gt;MS SQL Database must have case-sensitive and accent-sensitive collation.&lt;/p&gt;

&lt;p&gt;SQL_Latin1_General_CP1_CS_AS&lt;/p&gt;

&lt;p&gt;When you start the application for the first time, it will ask you to reset the default password. Default credentials will be - username: admin, password: admin.&lt;/p&gt;

&lt;h1&gt;
  
  
  Integration
&lt;/h1&gt;

&lt;p&gt;You have the below integration steps to do the SonarQube analysis,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adding your DevOps repo in SonarQube&lt;/li&gt;
&lt;li&gt;Updating your DevOps pipelines with SonarQube Analysis and Reporting tasks&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the SonarQube documentation for the same,&lt;br&gt;
&lt;a href="https://docs.sonarqube.org/latest/analysis/azuredevops-integration"&gt;https://docs.sonarqube.org/latest/analysis/azuredevops-integration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below you will see the simplified steps of the same documentation,&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Personal Access Token must be generated with Read and Write Access for the Code module. This is needed in the SonarQube project addition module.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install the SonarQube extension in Azure DevOps - &lt;a href="https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarqube"&gt;https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarqube&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access to your DevOps repo settings for adding the SonarQube service connection to it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Adding your DevOps repo in SonarQube
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Repo addition
&lt;/h2&gt;

&lt;p&gt;Start by clicking on the "Add Project" button and selecting DevOps. This will be a self-explanatory form.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Feed in the PAT you obtained for your account in DevOps with Read and Write Access for the Code module.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using the PAT, SonarQube will list the Projects in DevOps. Find your DevOps project and choose the repo.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This will create the project in SonarQube.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating your DevOps pipelines with SonarQube Analysis and Reporting tasks
&lt;/h2&gt;

&lt;p&gt;Once you add the project, you can configure the analysis in your DevOps pipeline. Add the SonarQube server URL as a service connection in your project settings.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Configure Analysis
&lt;/h2&gt;

&lt;p&gt;In your DevOps pipeline, do the following,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the SonarQube Preparation task before your Build task&lt;/li&gt;
&lt;li&gt;Add the SonarQube Analysis task after your Build task&lt;/li&gt;
&lt;li&gt;Add the SonarQube Publish task after the analysis task&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk67zv63mt5srm7ii6alp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk67zv63mt5srm7ii6alp.png" alt="" width="750" height="695"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SonarQube preparation task must be fed with the service connection we created in the previous step.&lt;/p&gt;

&lt;p&gt;Now, if you run your pipeline, you should see the analysis report in the SonarQube project below,&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Configuration of SonarQube rules
&lt;/h2&gt;

&lt;p&gt;SonarQube has an inbuilt ruleset that is categorized in different facets, and it is synchronized with new SonarQube release versions too.&lt;/p&gt;

&lt;p&gt;You will find detailed documentation here - &lt;a href="https://docs.sonarqube.org/latest/user-guide/rules"&gt;https://docs.sonarqube.org/latest/user-guide/rules&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we will see the simplified version of the same,&lt;/p&gt;

&lt;p&gt;SonarQube has around 400+ rules spanning several types =&amp;gt; bugs, vulnerability, code smell, and security hotspots for C#.&lt;/p&gt;

&lt;p&gt;Hierarchically, rules come below Quality Profiles. Rules can be grouped under a Quality profile and these profiles can be assigned to the projects as needed.&lt;/p&gt;

&lt;p&gt;SonarQube comes with a default quality profile for each language and cannot be edited. But it can be extended with new rules.&lt;/p&gt;

&lt;p&gt;New Quality profiles can be created based on the existing ones. Under the new quality profiles, rules can be activated/deactivated based on the needs.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Activating/Deactivating a Rule in a Quality Profile
&lt;/h2&gt;

&lt;p&gt;Steps,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the Quality Profile.&lt;/li&gt;
&lt;li&gt;On the left side, you will the rule types with their active and 3. inactive counts.&lt;/li&gt;
&lt;li&gt;You can click on any of the counts to filter and see the rules that are active/inactive.&lt;/li&gt;
&lt;li&gt;Once you are on the Rules page, make sure you are editing the correct Quality profile by seeing that on the left side.
You can also make bulk changes based on your needs.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Once the activation or deactivation of the rules is done, it will immediately reflect in your existing reports as well. So, everything is dynamic.&lt;/p&gt;

&lt;p&gt;Even for your older analysis reports, you can activate new rules.&lt;/p&gt;

&lt;h1&gt;
  
  
  Quality Gates
&lt;/h1&gt;

&lt;p&gt;This is an optional module that can be set up in your Azure DevOps branch policy to ensure that your repo is complying with all the rules you set up. This gate can be used to prevent the PR (Pull Request) from being merged.&lt;/p&gt;

&lt;p&gt;As a process, you do not have to set this up initially and you will have to mandate this once you fix all the rules.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.sonarsource.com/sonarqube/latest/user-guide/quality-gates/"&gt;https://docs.sonarsource.com/sonarqube/latest/user-guide/quality-gates/&lt;/a&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  SonarQube Report summary in DevOps
&lt;/h2&gt;

&lt;p&gt;You will always have a report summary in your pipeline, under extensions and you can open the SonarQube site report from here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjodlxuzo95voy6re4kmf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjodlxuzo95voy6re4kmf.png" alt="" width="750" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  SonarLint Extension in VS
&lt;/h1&gt;

&lt;p&gt;We can install the SonarLint extension in VS and get the analysis while doing the development itself.&lt;/p&gt;

&lt;p&gt;Here is the link for SonarLint Extension,&lt;br&gt;
&lt;a href="https://marketplace.visualstudio.com/items?itemName=SonarSource.SonarLintforVisualStudio2022"&gt;https://marketplace.visualstudio.com/items?itemName=SonarSource.SonarLintforVisualStudio2022&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As SonarQube supports different quality profiles for different projects, the project that you run in VS also needs the same Quality profile so that we can coordinate with the rule sets configured in the project. To do this, we can connect the SonarLint in VS to our SonarQube server.&lt;/p&gt;

&lt;h1&gt;
  
  
  Connect SonarLint to SonarQube Server
&lt;/h1&gt;

&lt;p&gt;Here is the documentation on how to do this,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/SonarSource/sonarlint-visualstudio/wiki/Connected-Mode"&gt;https://github.com/SonarSource/sonarlint-visualstudio/wiki/Connected-Mode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we will see the simplified version of the same,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install SonarLint extension.&lt;/li&gt;
&lt;li&gt;Go to Team Explorer in VS and select SonarQube.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuopblb965sjdo3h514j9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuopblb965sjdo3h514j9.png" alt="" width="778" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Feed the credentials.&lt;/li&gt;
&lt;li&gt;Select the appropriate project and that is all.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>codequality</category>
      <category>codereview</category>
      <category>sonarqube</category>
      <category>codeanalysis</category>
    </item>
    <item>
      <title>C# Extension Methods that come in handy for an ASP.Net Project</title>
      <dc:creator>Venkatesan Rethinam</dc:creator>
      <pubDate>Sun, 04 Feb 2024 08:50:13 +0000</pubDate>
      <link>https://dev.to/vengi83644/c-extension-methods-that-come-in-handy-for-an-aspnet-project-448l</link>
      <guid>https://dev.to/vengi83644/c-extension-methods-that-come-in-handy-for-an-aspnet-project-448l</guid>
      <description>&lt;p&gt;In the realm of C# and ASP.NET development, extension methods serve as invaluable tools, empowering developers to enhance the expressiveness and efficiency of their code. In this blog post, we will delve into some of the basic extension methods that any ASP.Net Core project needs and can elevate your web development projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTPContext Extensions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Get Base Path
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetBasePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;HttpContext&lt;/span&gt; &lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scheme&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;://&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check if the Request Header has a particular key
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;HasRequestHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;HttpContext&lt;/span&gt; &lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ContainsKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check if the Response Header has a particular key
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;HasResponseHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;HttpContext&lt;/span&gt; &lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ContainsKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check if the Request Header key has the required value
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;HasRequestHeaderValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;HttpContext&lt;/span&gt; &lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;headerValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check if the Response Header key has the required value
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;HasResponseHeaderValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;HttpContext&lt;/span&gt; &lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;headerValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  IEnumerable Extensions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Convert any IEnumerable to CSV String
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ConvertToCSVString&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;jObject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ChangeType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

            &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

            &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;////DO NOT include the starting and ending quotes inside the $ string interpolation.&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;valueLines&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                                    &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;','&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"\""&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{((&lt;/span&gt;&lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ChangeType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;))).&lt;/span&gt;&lt;span class="nf"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
                                                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\"\""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                        &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\""&lt;/span&gt;
                                                        &lt;span class="p"&gt;)));&lt;/span&gt;

            &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valueLines&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;GetProperties&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

            &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;//DO NOT include the starting and ending quotes inside the $ string interpolation.&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;valueLines&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                                    &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;','&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"\""&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;GetProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
                                                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\"\""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                        &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\""&lt;/span&gt;
                                                        &lt;span class="p"&gt;)));&lt;/span&gt;

            &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valueLines&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;csvString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\r\n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;csvString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Convert any IEnumerable to DataTable
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;DataTable&lt;/span&gt; &lt;span class="n"&gt;ToDataTable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;DataTable&lt;/span&gt; &lt;span class="n"&gt;dataTable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DataTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;PropertyInfo&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;GetProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Public&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PropertyInfo&lt;/span&gt; &lt;span class="n"&gt;prop&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;dataTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;dataTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Session Extensions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Replace a value in a Session key
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ISession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SerializeObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Get value from a Session key
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;TryGet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ISession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;removeKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;objString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;objString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;removeKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

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

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  ClaimsPrincipal Extensions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Check if the claims has a particular Role
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;HasRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ClaimsPrincipal&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasClaim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                                    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ClaimTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Role&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                                    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Get Roles from the claims
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetRoles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ClaimsPrincipal&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ClaimTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Get a particular claim from the claims
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;GetClaim&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ClaimsPrincipal&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;claim&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Claims&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;claim&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;))?.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ChangeType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  DateTime Extensions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Convert to a different TimeZone
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="nf"&gt;ConvertToTimeZone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;dateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;timeZoneId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TimeZoneInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertTimeFromUtc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TimeZoneInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindSystemTimeZoneById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeZoneId&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check if a given DateTime is between a time range
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsBetweenTimeRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;comparisonTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;endDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasValue&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;comparisonTime&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasValue&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;comparisonTime&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;endDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check if a give DateTimeOffset is between a time range
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsBetweenTimeRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;comparisonTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;endDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;comparisonTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsBetweenTimeRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasValue&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasValue&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;endDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Convert to a DateTimeOffset based on a TimeZone
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;ToDateTimeOffset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;dateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;timeZoneId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasValue&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DateTimeOffset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TimeZoneInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindSystemTimeZoneById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeZoneId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;BaseUtcOffset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Enum Extensions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Get display name of an Enum
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetDisplayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt; &lt;span class="n"&gt;enumValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;displayName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;enumValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;GetMember&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;enumValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;GetCustomAttribute&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DisplayAttribute&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()?.&lt;/span&gt;&lt;span class="nf"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;enumValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  HTTPResponseMessage Extensions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Ensure the HTTPResponseMessage has a Success Status code and log failures
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;EnsureSuccessStatusCodeAndLogFailures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;HttpResponseMessage&lt;/span&gt; &lt;span class="n"&gt;httpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;httpResponseMessage&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentNullException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;httpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentNullException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;httpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsSuccessStatusCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;httpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsStringAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;requestUri&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestMessage&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;RequestUri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"HTTP call to &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;requestUri&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; returned status code &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;httpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; with response &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;httpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnsureSuccessStatusCode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  TokenResponse Extensions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Ensure the TokenResponse has a Success Status and log failures
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;CheckResponseAndLogFailures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;TokenResponse&lt;/span&gt; &lt;span class="n"&gt;tokenResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenResponse&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentNullException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenResponse&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentNullException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SerializeObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Access Token call to returned with error and data: {data}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  String Extensions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Slugify
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Slugify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RemoveAccents&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;@"[^A-Za-z0-9\s-]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;@"\s+"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;@"\s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;RemoveAccents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NormalizationForm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormD&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;CharUnicodeInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetUnicodeCategory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;UnicodeCategory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NonSpacingMark&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NormalizationForm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check if a email is valid
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsValidEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;isValid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;emailAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MailAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Trim&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;catch&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;isValid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



</description>
      <category>csharp</category>
      <category>aspdotnet</category>
      <category>extensions</category>
    </item>
    <item>
      <title>ASP.Net Core Feature Flags - Intro</title>
      <dc:creator>Venkatesan Rethinam</dc:creator>
      <pubDate>Fri, 20 Jan 2023 17:23:48 +0000</pubDate>
      <link>https://dev.to/vengi83644/aspnet-core-feature-flags-intro-l2g</link>
      <guid>https://dev.to/vengi83644/aspnet-core-feature-flags-intro-l2g</guid>
      <description>&lt;p&gt;&lt;a href="http://ASP.Net"&gt;ASP.Net&lt;/a&gt; Core is a free, open-source framework for building web applications and APIs. One of its powerful features is the ability to use feature flags, which allow developers to enable or disable certain functionality in their application without having to deploy new code.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Feature Flag?
&lt;/h2&gt;

&lt;p&gt;A feature flag, also known as a feature toggle or a feature switch, is a simple mechanism that allows developers to control the behavior of their applications at runtime. By using feature flags, developers can easily test new functionality in a production environment without affecting the entire application. This can be especially useful for testing new features with a small subset of users before rolling them out to the entire user base.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Feature Flags in &lt;a href="http://ASP.Net"&gt;ASP.Net&lt;/a&gt; Core
&lt;/h2&gt;

&lt;p&gt;Implementing feature flags in an &lt;a href="http://ASP.Net"&gt;ASP.Net&lt;/a&gt; Core application is easy. You can use the Microsoft.FeatureManagement package, which is available on NuGet, to add feature flags to your application. This package provides a simple API that allows you to configure and manage feature flags in your application.&lt;/p&gt;

&lt;p&gt;Here is an example of how to use feature flags in an &lt;a href="http://ASP.Net"&gt;ASP.Net&lt;/a&gt; Core application:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the Microsoft.FeatureManagement package by running the following command in the package manager console:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Install-Package Microsoft.FeatureManagement
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;In the &lt;code&gt;Startup.cs&lt;/code&gt; file, add the following line to the &lt;code&gt;ConfigureServices&lt;/code&gt; method to enable feature management:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddFeatureManagement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create a new class to represent your feature flag. For example, if you are creating a feature flag for a new feature called "NewFeature", you would create a class like this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NewFeature&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IFeature&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;In the &lt;code&gt;Startup.cs&lt;/code&gt; file, add the following line to the &lt;code&gt;Configure&lt;/code&gt; method to enable the feature flag:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseFeatureManagement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;In your controller or service, you can now use the &lt;code&gt;[FeatureGate]&lt;/code&gt; attribute to enable or disable the feature based on the flag. For example, if you want to enable the "NewFeature" feature flag for a specific action in your controller, you would add the following attribute:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FeatureGate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NewFeature&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;MyAction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// Code for the action goes here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just a basic example of how to use feature flags in an &lt;a href="http://ASP.Net"&gt;ASP.Net&lt;/a&gt; Core application. With the Microsoft.FeatureManagement package, you can also configure feature flags using JSON files, environment variables, or a custom provider. You can also use the package to implement advanced features such as time-based rollouts and user-based targeting.&lt;/p&gt;

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

&lt;p&gt;Feature flags are a powerful tool that can help you improve the development and deployment process of your &lt;a href="http://ASP.Net"&gt;ASP.Net&lt;/a&gt; Core application. By using feature flags, you can easily test new functionality in a production environment without affecting the entire application. This can save you time and resources and help you deliver new features to your users faster.&lt;/p&gt;

</description>
      <category>aspnetcore</category>
      <category>feature</category>
      <category>featureflags</category>
      <category>testing</category>
    </item>
    <item>
      <title>Attribute-Based Access Control Sample for a .Net Core API Application</title>
      <dc:creator>Venkatesan Rethinam</dc:creator>
      <pubDate>Sun, 02 Jan 2022 21:15:02 +0000</pubDate>
      <link>https://dev.to/vengi83644/attribute-based-access-control-sample-for-a-net-core-api-application-pde</link>
      <guid>https://dev.to/vengi83644/attribute-based-access-control-sample-for-a-net-core-api-application-pde</guid>
      <description>&lt;p&gt;GitHub Link: github.com/venbacodes/ABAC-Sample-for-API&lt;/p&gt;

&lt;p&gt;This is a simple demo sample on implementing ABAC in a .Net Core API Application. This uses three main aspects of Attributes =&amp;gt; ACCESS, SCOPE, and MODULE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Points
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Access, Scope, and Module attributes are used&lt;/li&gt;
&lt;li&gt;It is possible to extend this sample to accommodate as many attributes as needed&lt;/li&gt;
&lt;li&gt;No External libraries were used&lt;/li&gt;
&lt;li&gt;Handled all the necessary authn and authz in the handlers itself.&lt;/li&gt;
&lt;li&gt;Optional takeaway - added an additional path for restricting resources in &lt;a href="https://github.com/venbacodes/ABAC-Sample-for-API/blob/main/Authorization/PermissionsAuthHandler.cs#L60"&gt;PermissionsAuthHandler.cs#L60&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  To Explore
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Clone and run the code&lt;/li&gt;
&lt;li&gt;Generate a JWT token with email/sub and exp. Applicable emails can be found in &lt;a href="https://github.com/venbacodes/ABAC-Sample-for-API/blob/main/Model/TestUsers.cs"&gt;TestUsers.cs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Add the generated JWT token in the swagger authorization menu and call the APIs&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>dotnet</category>
      <category>authorization</category>
      <category>authentication</category>
      <category>permissions</category>
    </item>
    <item>
      <title>How to setup Azure App Configuration and Key Vault in a .Net Core project</title>
      <dc:creator>Venkatesan Rethinam</dc:creator>
      <pubDate>Thu, 16 Dec 2021 19:24:35 +0000</pubDate>
      <link>https://dev.to/vengi83644/how-to-setup-azure-app-configuration-and-key-vault-in-a-net-core-project-724</link>
      <guid>https://dev.to/vengi83644/how-to-setup-azure-app-configuration-and-key-vault-in-a-net-core-project-724</guid>
      <description>&lt;p&gt;This is a basic "how-to document" blog on configuring Azure App Configuration and Key Vault in a .Net Core project. &lt;br&gt;
Topics covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup Azure App Configuration&lt;/li&gt;
&lt;li&gt;Setup Azure Key Vault&lt;/li&gt;
&lt;li&gt;Configuring a .Net Core project with sample code

&lt;ul&gt;
&lt;li&gt;Setting up access policies in Key Vault&lt;/li&gt;
&lt;li&gt;Authenticating your application code to fetch secrets from Key Vault&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disclaimer: Probably, you could have seen this how-to information in the MSFT official documentation. But this blog will give you the curated steps removing all the clutters.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Make sure you have access to do the below in Azure,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create Azure App Configuration&lt;/li&gt;
&lt;li&gt;Create Azure Key Vault&lt;/li&gt;
&lt;li&gt;Edit Access policy in the newly created Key Vault&lt;/li&gt;
&lt;li&gt;Enable System assigned managed identity for the Application hosted in Azure&lt;/li&gt;
&lt;li&gt;Register an app in Azure Active Directory (optional)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Intro on the said Azure jargons
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-app-configuration/"&gt;Azure App Configuration&lt;/a&gt; lets you maintain the config details of your app in Azure so that your app can be free of any environment dependency. It has labels that can be used to maintain values of different environments for a single config property.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/key-vault/general"&gt;Key Vault&lt;/a&gt; is a resource in Azure to store secret information that can be accessed by your apps through managed identities or service principal authentication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/"&gt;Managed Identities&lt;/a&gt; are used to authenticate across azure resources through an identity thereby eliminating the need to manage credentials. In this blog, we will use the &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview#managed-identity-types"&gt;System-assigned managed identity&lt;/a&gt; of an Azure App Service which we will enable in it to access the secrets in a Key Vault.&lt;/p&gt;
&lt;h2&gt;
  
  
  Create Azure App Configuration
&lt;/h2&gt;

&lt;p&gt;Follow &lt;a href="https://docs.microsoft.com/en-us/azure/azure-app-configuration/quickstart-aspnet-core-app?tabs=core5x#create-an-app-configuration-store"&gt;this&lt;/a&gt; to create a new Azure App Configuration resource and add your config properties to the store.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Configuration Explorer&lt;/code&gt; under &lt;code&gt;Operations&lt;/code&gt;, is where the config properties can be seen and edited.&lt;/p&gt;

&lt;p&gt;Every key has options to add more values with different labels which can be used for different environments. Here is a screenshot of the Configuration Explorer displaying 2 values for a single key with one having a label and another empty.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z2GgQv-U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/146384520-866bca50-5918-4479-99dc-a61327011739.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z2GgQv-U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/146384520-866bca50-5918-4479-99dc-a61327011739.png" alt="image" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To retrieve these values in an application, &lt;code&gt;Connection String&lt;/code&gt; that is uniquely generated under &lt;code&gt;Access Keys&lt;/code&gt; is needed. Get the connection string from this page which will be used in our application to connect to the App Configuration store.&lt;/p&gt;
&lt;h2&gt;
  
  
  Create Azure Key Vault
&lt;/h2&gt;

&lt;p&gt;Follow &lt;a href="https://docs.microsoft.com/en-us/azure/key-vault/general/quick-create-portal#create-a-vault"&gt;this&lt;/a&gt; to create a new Azure Key Vault resource. For this blog, we will look into secrets alone to store our passwords/client secrets. Check &lt;a href="https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal"&gt;this&lt;/a&gt; on how to create a secret in the Key Vault.&lt;/p&gt;

&lt;p&gt;Retrieving secrets' value from the Key Vault can be done using the &lt;code&gt;Azure.Identity&lt;/code&gt; package. But if you want to load the secrets in the &lt;code&gt;ConfigurationSection&lt;/code&gt;, then there is a way in the &lt;code&gt;ConfigurationBuilder&lt;/code&gt; to include both App Configuration key-values and Key Vault secrets.&lt;/p&gt;

&lt;p&gt;To do this, the secrets are to be referenced in the App Configuration as a new key-value. Check &lt;a href="https://docs.microsoft.com/en-us/azure/azure-app-configuration/use-key-vault-references-dotnet-core?tabs=core5x#add-a-key-vault-reference-to-app-configuration"&gt;this&lt;/a&gt; article on how to add a KV reference in the App Configuration.&lt;/p&gt;

&lt;p&gt;App Configuration will use the identity that is used to load itself for accessing the secrets in the Key Vault. This is something we will set up in the next steps. As of now, your App Configuration should look something like the below screenshot,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A_GzXs-q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/146396433-b48d387b-bbb2-4e96-9849-697f667277cd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A_GzXs-q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/146396433-b48d387b-bbb2-4e96-9849-697f667277cd.png" alt="image" width="800" height="137"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Configuring a .Net Core project with sample code
&lt;/h2&gt;

&lt;p&gt;Here is the sample app in GitHub.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/venbacodes/AppConfigKVSample"&gt;https://github.com/venbacodes/AppConfigKVSample&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To connect with the Azure App Configuration, you will need the package &lt;code&gt;Microsoft.Extensions.Configuration.AzureAppConfiguration&lt;/code&gt; which has the extension method &lt;code&gt;AddAzureAppConfiguration&lt;/code&gt; for the &lt;code&gt;ConfigurationBuilder&lt;/code&gt;. This extension method will get the Connection String of the App Configuration and can also configure the Key Vault using the &lt;code&gt;ConfigureKeyVault&lt;/code&gt; method in its options.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.Host.ConfigureAppConfiguration((webHostBuilderContext, config) =&amp;gt;
{
    var isDevelopment = webHostBuilderContext.HostingEnvironment.IsDevelopment();
    var environment = webHostBuilderContext.HostingEnvironment.EnvironmentName.ToLower();

    config
    .AddJsonFile("appsettings.json", false, true)
    .AddJsonFile($"appsettings.{webHostBuilderContext.HostingEnvironment.EnvironmentName}.json", true, true);

    var settings = config.Build();

    var appConfigConnectionString = settings.GetSection(AppConfigConnectionStringSection);

    if (appConfigConnectionString != null &amp;amp;&amp;amp; !string.IsNullOrWhiteSpace(appConfigConnectionString.Value))
    {
        config.AddAzureAppConfiguration(options =&amp;gt;
        {
            options
            .Connect(appConfigConnectionString.Value)
            .ConfigureKeyVault(kv =&amp;gt;
            {
                if (isDevelopment)
                {
                                    ///You WON'T need this if you are logged into Visual Studio and your account has been setup 
                                    ///with access policy in the Key Vault you are trying to connect. You can just use the DefaultAzureCredential
                                    ///that is set in the else part.
                                    var cred = new ClientSecretCredential(
                        settings.GetSection("DevCredential:TenantId").Value,
                        settings.GetSection("DevCredential:ClientId").Value,
                        settings.GetSection("DevCredential:ClientSecret").Value);

                    kv.SetCredential(cred);
                }
                else
                {
                    kv.SetCredential(new DefaultAzureCredential());
                }
            })
            .Select(KeyFilter.Any, LabelFilter.Null)
            .Select(KeyFilter.Any, environment ?? LabelFilter.Null);
        });
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, here are the explanations on the above code,&lt;/p&gt;

&lt;p&gt;This reads the app config connection string we have in our appsettings.json file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var appConfigConnectionString = settings.GetSection(AppConfigConnectionStringSection);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will now use this connection string in the AddAzureAppConfiguration method,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;options
.Connect(appConfigConnectionString.Value)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we are configuring the Key Vault in the config builder to load its secrets also as configuration into the application's Configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.ConfigureKeyVault(kv =&amp;gt; {
  ///Code removed for simplicity
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are trying to connect to the Key Vault using our registered identity in AD for development and the default credential when not in development. We will see about this more in the next section.&lt;/p&gt;

&lt;p&gt;While getting the data from the app config, we are actually filtering the keys and values based on the environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.Select(KeyFilter.Any, LabelFilter.Null)
.Select(KeyFilter.Any, environment ?? LabelFilter.Null)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code tries to filter the values based on the label filter. Actually, this will include all keys without any labels and all keys with the specified label and finally will overwrite the values in the first filter. The order of filters is important here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Access Policies in Key Vault
&lt;/h2&gt;

&lt;p&gt;Access policies section in the Key Vault is where we will assign permissions for applications and users using the managed identities that are formed from the Azure Active Directory.&lt;/p&gt;

&lt;p&gt;Here is a screenshot of this section,&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FYe0U24N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/146415530-25996094-3dd3-40a4-8f3b-2f9f87779eec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FYe0U24N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/146415530-25996094-3dd3-40a4-8f3b-2f9f87779eec.png" alt="image" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Azure AD Identities
&lt;/h2&gt;

&lt;p&gt;You can either use an Azure App Services' System-assigned managed identity or your azure account's identity to connect to the Key Vault. I recommend to use your own azure account to authenticate and connect to the Key Vault by logging into Visual Studio and using &lt;code&gt;kv.SetCredential(new DefaultAzureCredential());&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you don't want to use your azure account, there is another possibility to register an App in the Azure AD and use its identity in this Access Policy.&lt;/p&gt;
&lt;h3&gt;
  
  
  App Registration in Azure AD
&lt;/h3&gt;

&lt;p&gt;Follow &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app"&gt;this&lt;/a&gt; to register an application in the Azure AD and get the below details from it to set the credentials while configuring the KV.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TenantId - This will be the common id for your azure tenant
ClientId - This will be the unique id for the registered app
ClientSecret - You have to create this secret after registering the app. This is covered in the below link
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app#add-a-client-secret"&gt;https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app#add-a-client-secret&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Azure App Service System Assigned Managed Identity
&lt;/h3&gt;

&lt;p&gt;To use the Azure App Services' identity, you would have to enable it as like below,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8pgO-6yw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/146416998-4704e9b0-215e-4f83-9110-6f10124e57e6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8pgO-6yw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/146416998-4704e9b0-215e-4f83-9110-6f10124e57e6.png" alt="image" width="800" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once this is done, &lt;code&gt;kv.SetCredential(new DefaultAzureCredential());&lt;/code&gt; will automatically use the app's identity and try to authenticate and get values from the KV.&lt;/p&gt;

&lt;p&gt;To complete a successful authentication, add this newly registered app in the access policy section under the KV as a principal and give access to read secrets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally seeing the values from the app config
&lt;/h2&gt;

&lt;p&gt;After completing the above steps, you can now access the Configuration with the &lt;code&gt;key&lt;/code&gt; name &lt;code&gt;ACDemo&lt;/code&gt; which I used in the App Configuration. For this demo, I have read the key during startup and added it to a singleton service so that I can get them injected in all places.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var acDemo = new ACDemo();
builder.Configuration.Bind("ACDemo", acDemo);

builder.Services.AddSingleton(acDemo);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Using counters in Azure DevOps pipeline to increment assembly version numbers</title>
      <dc:creator>Venkatesan Rethinam</dc:creator>
      <pubDate>Fri, 10 Dec 2021 15:13:57 +0000</pubDate>
      <link>https://dev.to/vengi83644/using-counters-in-azure-devops-pipeline-to-increment-assembly-version-numbers-3afj</link>
      <guid>https://dev.to/vengi83644/using-counters-in-azure-devops-pipeline-to-increment-assembly-version-numbers-3afj</guid>
      <description>&lt;p&gt;There are &lt;a href="https://marketplace.visualstudio.com/search?term=versioning&amp;amp;target=AzureDevOps&amp;amp;category=All%20categories&amp;amp;sortBy=Relevance"&gt;many pipeline task extensions&lt;/a&gt; in the Azure Marketplace which can be installed directly to your DevOps instance. But for funny 😁 reasons, I want to do this myself where I ended up using the counter function and found it satisfied.&lt;/p&gt;

&lt;p&gt;I hope you also will find this helpful 🎉🎉🎉.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops#counter"&gt;Counter&lt;/a&gt; function maintains a seed value that should be variable in your pipeline and will increment it on each pipeline run.&lt;/p&gt;

&lt;p&gt;So, here is my complete pipeline yml file before going further,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: '$(Build.DefinitionName)_$(SourceBranchName)_$(Year:yyyy).$(Month).$(DayOfMonth).$(revision)'

trigger:
    branches:
        include:
            - master
            - develop    

pool:
  vmImage: 'windows-latest'

variables:
  solution: '*/.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'  
  buildNumber: 'Will be set dynamically'
  revision: $[counter(format('{0:dd}', pipeline.startTime), 1)]

steps:
- task: PowerShell@2
  displayName: 'Preparing Build Number'
  inputs:
    targetType: 'inline'
    script: |
      $currentDate = $(Get-Date)
      $year = $currentDate.Year
      $month = $currentDate.Month
      $day = $currentDate.Day
      Write-Host $currentDate
      Write-Host $day
      Write-Host $env:revision
      Write-Host "##vso[task.setvariable variable=buildNumber]$year.$month.$day.$env:revision"

- task: UseDotNet@2
  displayName: 'Use .NET 6'
  inputs:
    packageType: 'sdk'
    version: '6.0.x'
    includePreviewVersions: true

- task: NuGetToolInstaller@1
  displayName: 'Update Nuget'
  inputs:
    checkLatest: true

- task: NuGetCommand@2
  displayName: 'NuGet restore'
  inputs:
    command: 'restore'
    restoreSolution: '$(solution)'
    feedsToUse: config
    nugetConfigPath: nuget.config

- task: DotNetCoreCLI@2
  displayName: Build
  inputs:
    projects: 'ProjectName.csproj'
    arguments: '--configuration $(buildConfiguration) /p:AssemblyVersion=$(buildNumber)'

- task: DotNetCoreCLI@2
  displayName: Publish
  inputs:
    command: publish
    publishWebProjects: false
    projects: 'ProjectName.csproj'
    arguments: '--configuration $(BuildConfiguration) --output $(build.artifactstagingdirectory) /p:Version=$(buildNumber)'
    zipAfterPublish: True

- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact'
  inputs:
    PathtoPublish: '$(build.artifactstagingdirectory)'
  condition: succeededOrFailed()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will focus only on the &lt;code&gt;variables section&lt;/code&gt; and the &lt;code&gt;PowerShell task&lt;/code&gt; in this blog.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;variables section&lt;/code&gt;, I have added a variable &lt;code&gt;revision&lt;/code&gt; that is set from the counter function.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;revision: $[counter(format('{0:dd}', pipeline.startTime), 1)]&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;This counter function is using &lt;code&gt;startTime&lt;/code&gt; of the pipeline in the format of day number as its seed. The counter starts from 1.&lt;/p&gt;

&lt;p&gt;On each pipeline run, the counter will check for changes in the day number in the pipeline.startTime, and if it's new, the counter will reset to the default value which is 1. &lt;/p&gt;

&lt;p&gt;As of now, we have achieved a revision number that gets incremented on each pipeline run on the same day and also resets to 1 on the next day.&lt;/p&gt;

&lt;p&gt;Now, in the &lt;code&gt;PowerShell task&lt;/code&gt;, we are going to use this revision to form a build number for our assembly.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Write-Host "##vso[task.setvariable variable=buildNumber]$year.$month.$day.$env:revision"&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;We are trying to achieve a build number in this format - &lt;code&gt;yyyy.mm.dd.revision&lt;/code&gt; =&amp;gt; &lt;code&gt;2021.12.26.13&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the above Write-Host command, we are not printing any values to the output console, instead, we are using the &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&amp;amp;tabs=bash#setvariable-initialize-or-modify-the-value-of-a-variable"&gt;logging command #vso to set the variable&lt;/a&gt; &lt;code&gt;buildNumber&lt;/code&gt; with our required value.&lt;/p&gt;

&lt;p&gt;Finally, in the &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;publish&lt;/code&gt; tasks, I passed the &lt;code&gt;buildNumber&lt;/code&gt; to the &lt;code&gt;/p:AssemblyVersion&lt;/code&gt; and &lt;code&gt;/p:Version&lt;/code&gt; properties respectively.&lt;/p&gt;

&lt;p&gt;You can write your own logic to set the &lt;code&gt;buildNumber&lt;/code&gt; using the counter function and achieve build numbers in any format you want.&lt;/p&gt;

&lt;p&gt;Follow me on the below places for more of my blog posts,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/vengi83644"&gt;dev.to&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogs.aspnet.in"&gt;hashnode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vengi83644.medium.com"&gt;Medium&lt;/a&gt;&lt;/p&gt;

</description>
      <category>azure</category>
      <category>pipeline</category>
      <category>devops</category>
      <category>counter</category>
    </item>
    <item>
      <title>Impersonation in a .Net core application with Identity Server 4</title>
      <dc:creator>Venkatesan Rethinam</dc:creator>
      <pubDate>Wed, 08 Dec 2021 07:11:15 +0000</pubDate>
      <link>https://dev.to/vengi83644/impersonation-in-a-net-core-application-with-identity-server-4-1p52</link>
      <guid>https://dev.to/vengi83644/impersonation-in-a-net-core-application-with-identity-server-4-1p52</guid>
      <description>&lt;p&gt;Identity Server 4 does not provide native impersonation support which I needed for one of my projects. I have implemented one on top of it.&lt;/p&gt;

&lt;p&gt;Here is the sample project I did in GitHub.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/venbacodes/ImpersonationSample-IdentityServer4"&gt;https://github.com/venbacodes/ImpersonationSample-IdentityServer4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a sample application to show a way to implement impersonation when using Identity Server.&lt;/p&gt;

&lt;p&gt;Key Points&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Authorization policy has been setup to restrict impersonation to users with specific role.&lt;/li&gt;
&lt;li&gt;Admin users' email is added as a claim while impersonating so that it can be used while ending the impersonation.&lt;/li&gt;
&lt;li&gt;Logic is simple as authenticating with the victim users' email for impersonation with additional claims to track the impersonation and the impersonating user.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>impersonation</category>
      <category>authentication</category>
      <category>authorization</category>
      <category>identity</category>
    </item>
    <item>
      <title>Nuke Build - best build automation system</title>
      <dc:creator>Venkatesan Rethinam</dc:creator>
      <pubDate>Wed, 08 Dec 2021 05:52:28 +0000</pubDate>
      <link>https://dev.to/vengi83644/nuke-build-best-build-automation-system-n6k</link>
      <guid>https://dev.to/vengi83644/nuke-build-best-build-automation-system-n6k</guid>
      <description>&lt;p&gt;There were a number of build automation systems for the .net ecosystem. All had their own pros which helped many developers in the build teams. Developers in the other teams also had chances to work in the build automation systems. But some build systems needed full-time build engineers to code and run those systems.&lt;/p&gt;

&lt;p&gt;As a web developer, I too had a chance to work in the build automation systems,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.finalbuilder.com/"&gt;FinalBuilder &lt;/a&gt; - with a GUI, it was too easy to prepare and run the builds.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/scripts/powershell?view=azure-devops&amp;amp;tabs=yaml"&gt;PowerShell &lt;/a&gt; - build system with PowerShell scripts was powerful yet complex to write.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cakebuild.net/"&gt;Cake &lt;/a&gt; (C# Make) - simple, easy to set up, and with a lot of extensions scripting with C#.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;BUT, now I had the opportunity to use  &lt;a href="https://nuke.build/"&gt;Nuke.Build&lt;/a&gt;  for my build system and I am obsessed heavily with it that I love it so much.&lt;/p&gt;

&lt;p&gt;Comparing all these 4 build systems, from my point of view, I would recommend Nuke. We would not need a separate build team while using Nuke as it is coupled with your project itself. You would be able to debug Nuke targets in your own IDE.&lt;/p&gt;

&lt;p&gt;Here is a sample nuke project for your reference.&lt;br&gt;
&lt;a href="https://github.com/vengi83644/nuke-build-sample"&gt;https://github.com/vengi83644/nuke-build-sample&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similar blog: &lt;br&gt;
&lt;a href="https://pknopf.com/post/2019-03-10-you-dont-need-cake-anymore-the-way-to-build-dotnet-projects-going-forward/"&gt;https://pknopf.com/post/2019-03-10-you-dont-need-cake-anymore-the-way-to-build-dotnet-projects-going-forward/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>build</category>
      <category>automation</category>
      <category>powershell</category>
      <category>nuke</category>
    </item>
    <item>
      <title>Using Azure automation and Events to monitor a parent Key Vault and update the secret in child Key Vault(s)</title>
      <dc:creator>Venkatesan Rethinam</dc:creator>
      <pubDate>Wed, 08 Dec 2021 05:50:35 +0000</pubDate>
      <link>https://dev.to/vengi83644/using-azure-automation-and-events-to-monitor-a-parent-key-vault-and-update-the-secret-in-child-key-vaults-194k</link>
      <guid>https://dev.to/vengi83644/using-azure-automation-and-events-to-monitor-a-parent-key-vault-and-update-the-secret-in-child-key-vaults-194k</guid>
      <description>&lt;p&gt;Before going into the actual blog, I wanted to explain the Azure resources that we are going to discuss in simple words,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/key-vault/general"&gt;Key Vault&lt;/a&gt; is a resource in Azure to store secret information that can be accessed by your apps through managed identities or service principal authentication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/automation"&gt;Azure Automation&lt;/a&gt; is a service that gives you the ability to automate tasks, do configuration changes, do updates to your azure resources using Az Cmds through runbooks in it. So, practically, we can run any automation using the Az cmds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/event-grid"&gt;Azure Event Grid&lt;/a&gt; is a service that fires events to your chosen event handlers or webhooks for the events that happen in your Azure resources. In this blog, we are going to have KVs as the event source and Webhooks as the handler.&lt;/p&gt;

&lt;p&gt;Now, in this blog, I am going to explain how you can use Azure Automation to detect changes in a KV and update the secret value in another KV. &lt;/p&gt;

&lt;p&gt;Why would someone do that? OK, consider having 100s of KVs in Azure and are being used by 100s of apps. If you have a secret value that is in all these KVs and you don't want your apps connecting to multiple KVs, then it's muscle work to update the secret value in that many KVs.&lt;/p&gt;

&lt;p&gt;So, Azure Automation and Event Grid subscriptions come in to help us detect the new version of the secret in a KV and update its value in the other KVs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;p&gt;Make sure, you have access to do the below in Azure,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create Automation resource&lt;/li&gt;
&lt;li&gt;Create Key Vault&lt;/li&gt;
&lt;li&gt;Create Events in Key Vault&lt;/li&gt;
&lt;li&gt;Edit Access Policies in Key Vault&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 1: Create Azure Automation
&lt;/h2&gt;

&lt;p&gt;Follow &lt;a href="https://docs.microsoft.com/en-us/azure/automation/quickstarts/create-account-portal"&gt;this&lt;/a&gt; to create a new Azure Automation account with System assigned identity. We will use this system assigned identity to access the secrets in the KV.&lt;/p&gt;

&lt;p&gt;By default, the Azure Key Vault module is enabled in the Azure Automation. Make sure you have it in the Modules section. I am using the Runtime version 5.1 for this blog.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wF36Xv5x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/144612469-991f3faf-2271-40b8-98b8-1daea709bfd6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wF36Xv5x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/144612469-991f3faf-2271-40b8-98b8-1daea709bfd6.png" alt="image" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Create Key Vaults
&lt;/h2&gt;

&lt;p&gt;Follow &lt;a href="https://docs.microsoft.com/en-us/azure/key-vault/general/quick-create-portal#create-a-vault"&gt;this&lt;/a&gt; to create a new KV. For this blog, I am creating 2 Key vaults - 1 for parent and 1 for children. I want to update the secret in child KVs when there is a new version of the secret in the parent.&lt;/p&gt;

&lt;p&gt;Both the parent and child KVs needs to be set up with Access policies including the Automation account we created in Step 1 as like in the below pic,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gm6oPlFi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/144611707-a5b2eb2d-dfe0-49e5-8429-e86c01185ab3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gm6oPlFi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/144611707-a5b2eb2d-dfe0-49e5-8429-e86c01185ab3.png" alt="image" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Populate the KVs with secrets in it by following &lt;a href="https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal#add-a-secret-to-key-vault"&gt;this&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Create Runbook in the Azure Automation account
&lt;/h2&gt;

&lt;p&gt;Follow &lt;a href="https://docs.microsoft.com/en-us/azure/automation/learn/automation-tutorial-runbook-textual#create-new-runbook"&gt;this&lt;/a&gt; to create a new Runbook in the Azure Automation account. For this blog, we will use the PowerShell workflow runbook and we will use the Az cmds.&lt;/p&gt;

&lt;p&gt;Follow &lt;a href="https://docs.microsoft.com/en-us/azure/automation/automation-webhooks#from-the-portal"&gt;this&lt;/a&gt; to create a Webhook under the newly created Runbook. Make sure you copy the Webhook URL while creating, as it cannot be retrieved later. We will need this URL to be added to the KV's Event Handler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Setup Event Subscription and handlers in Parent KV
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to your parent KV.&lt;/li&gt;
&lt;li&gt;Select Events from the left section.&lt;/li&gt;
&lt;li&gt;Create an Event Subscription.&lt;/li&gt;
&lt;li&gt;Give the subscription and the topic unique names.&lt;/li&gt;
&lt;li&gt;For the &lt;strong&gt;Event Types&lt;/strong&gt;, choose "Secret New Version Created" as this is what we are going to monitor in this blog.&lt;/li&gt;
&lt;li&gt;For the &lt;strong&gt;Endpoint Type&lt;/strong&gt;, choose "WebHook" and type in the URL we got from Step 3 for the endpoint.&lt;/li&gt;
&lt;li&gt;Click on create to save the Event Subscription&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As of now, we have subscribed to the new secret version create an event in the KV, and set Runbook's Webhook as the event handler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Catch the event data in the Azure Automation Runbook
&lt;/h2&gt;

&lt;p&gt;In this step, we will catch the event data in the webhook as use Az cmds for setting the secret value in our child KV. &lt;/p&gt;

&lt;p&gt;Go to your Runbook's Edit window and type in the below PS code in it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;param
(
[Parameter (Mandatory = $false)]
[object] $WebhookData
)

if ($WebhookData) 
{
    Write-Output $WebhookData.RequestBody

    $bodyJson =  $WebhookData.RequestBody | ConvertFrom-Json # Converting to json for easier manipulation

    # Getting the KV's name, Secret's name and the Event Type
    $secretName = $bodyJson[0].data.ObjectName
    $parentKv = $bodyJson[0].data.VaultName    
    $eventType = $bodyJson[0].eventType
    $childKv = ""

    if($eventType -eq "Microsoft.KeyVault.SecretNewVersionCreated")
    {
        # Authenticate using the System assigned identity of the Azure Automation account
        Connect-AzAccount -Identity

        # Using Az cmd for getting the secret's latest version value from the KV
        $secretValue = Get-AzKeyVaultSecret -VaultName $parentKv -Name $secretName -AsPlainText

        Write-Output "A new version for secret $($secretName) has been created in KV - $($parentKv) with value - $($secretValue)"

        if($secretName -eq "secret-child-1")
        {
            $childKv = "child-1-kv"           
        }
        elseif($secretName -eq "secret-child-2")
        {
            $childKv = "child-2-kv"
        }

        if($childKv -eq "")
        {
            Write-Output "No secrets have been set in the child KVs as the updated key in parent is not associated with the children"
        }
        else
        {
            # Setting the child KV with the secret value that is set in the parent KV
            $Secret = ConvertTo-SecureString -String $secretValue -AsPlainText -Force
            Set-AzKeyVaultSecret -VaultName $childKv -Name $secretName -SecretValue $Secret

            Write-Output "A new version of secret $($secretName) has been created in KV - $($childKv) with value - $($secretValue)"
        }        
    }
}
else
{
    write-Error "No input data found." 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;$WebhookData is the parameter where we will get the event data. I have converted the data into JSON for easier manipulation and ripped the KV's name, Secret name and event type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$bodyJson =  $WebhookData.RequestBody | ConvertFrom-Json
$secretName = $bodyJson[0].data.ObjectName
$parentKv = $bodyJson[0].data.VaultName    
$eventType = $bodyJson[0].eventType
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After checking the event type we needed, I am using the Az cmd to authenticate the current execution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connect-AzAccount -Identity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Getting the secret's latest version value from the KV&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$secretValue = Get-AzKeyVaultSecret -VaultName $parentKv -Name $secretName -AsPlainText
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting the child KV with the secret value that is set in the parent KV&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$Secret = ConvertTo-SecureString -String $secretValue -AsPlainText -Force
Set-AzKeyVaultSecret -VaultName $childKv -Name $secretName -SecretValue $Secret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Publish this runbook and we shall test the setup in the next step. For this blog, I have hardcoded the secret names; you can change the logic as per your need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Test the setup
&lt;/h2&gt;

&lt;p&gt;Now, create a new version in the Parent KV's secret. This will fire an event to the Webhook. You can monitor this in the KV's metric as like in the below pic,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L6YYWWxO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/144619881-3cc645b8-466d-4229-aed9-7899d976cf02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L6YYWWxO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/144619881-3cc645b8-466d-4229-aed9-7899d976cf02.png" alt="image" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also check the Webhook for the Last triggered value,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SyE68y6Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/144620210-bd687145-51ed-47c3-a75a-f38285f864d4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SyE68y6Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://user-images.githubusercontent.com/5276778/144620210-bd687145-51ed-47c3-a75a-f38285f864d4.png" alt="image" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Output section in the Jobs section will give you the output of the PS code that was executed for the event. Here is the example output,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[{"id":"6e1c172c-26f5-49e6-a065-f9ee3818b7e1","topic":"Removing this for security","subject":"secret-child-2","eventType":"Microsoft.KeyVault.SecretNewVersionCreated","data":{"Id":"Removing this for security","VaultName":"parent-kv","ObjectType":"Secret","ObjectName":"secret-child-2","Version":"Removing this for security","NBF":null,"EXP":null},"dataVersion":"1","metadataVersion":"1","eventTime":"2021-12-03T12:18:25.6002045Z"}]


Environments                                                                                                            
------------                                                                                                            
{[AzureChinaCloud, AzureChinaCloud], [AzureCloud, AzureCloud], [AzureGermanCloud, AzureGermanCloud], [AzureUSGovernme...

A new version for secret secret-child-2 has been created in KV - parent-kv with value - 741258963


SecretValue : System.Security.SecureString
Attributes  : Microsoft.Azure.Commands.KeyVault.Models.PSKeyVaultSecretAttributes
Enabled     : True
Expires     : 
NotBefore   : 
Created     : 12/3/2021 12:18:30 PM
Updated     : 12/3/2021 12:18:30 PM
ContentType : 
Tags        : 
TagsTable   : 
VaultName   : child-2-kv
Name        : secret-child-2
Version     : Removing this for security
Id          : Removing this for security

A new version of secret secret-child-2 has been created in KV - child-2-kv with value - 741258963
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>azure</category>
      <category>powershell</category>
      <category>automation</category>
      <category>runbook</category>
    </item>
    <item>
      <title>How to build Azure Log Analytics URL with KQL Query?</title>
      <dc:creator>Venkatesan Rethinam</dc:creator>
      <pubDate>Wed, 08 Dec 2021 05:48:10 +0000</pubDate>
      <link>https://dev.to/vengi83644/how-to-build-azure-log-analytics-url-with-kql-query-3p52</link>
      <guid>https://dev.to/vengi83644/how-to-build-azure-log-analytics-url-with-kql-query-3p52</guid>
      <description>&lt;p&gt;This is a requirement I had for one of my projects where we retrieve app insights data from several azure web apps on their flow performances. I used App Insights API for posting the KQL query and the timespan to get the flow performances which are logged using custom dimensions in the specific insights' logs.&lt;/p&gt;

&lt;p&gt;I also had a requirement where I had to give the users who are seeing the data, the ability to see the query and timespan I used for retrieving the data they are seeing. There is no direct way Azure gives you this ability. So, I researched the Log Analytics 'Share' functionality on how they are sharing the queries in the URLs.&lt;/p&gt;

&lt;p&gt;Here is the format they are using,&lt;br&gt;
&lt;a href="https://portal.azure.com/#blade/Microsoft_Azure_Monitoring_Logs/LogsBlade/resourceId/%2Fsubscriptions%2F%7BsubscriptionId%7D%2FresourceGroups%2F%7Brg%7D%2Fproviders%2Fmicrosoft.insights%2Fcomponents%2F%7Bresourcename%7D/source/LogsBlade.AnalyticsShareLinkToQuery/query/%7Bquery%7D"&gt;https://portal.azure.com/#blade/Microsoft_Azure_Monitoring_Logs/LogsBlade/resourceId/%2Fsubscriptions%2F{subscriptionId}%2FresourceGroups%2F{rg}%2Fproviders%2Fmicrosoft.insights%2Fcomponents%2F{resourcename}/source/LogsBlade.AnalyticsShareLinkToQuery/query/{query}&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The values you see inside {} are to be replaced with actuals. However, for {query}, it does not take the KQL directly.&lt;/p&gt;

&lt;p&gt;I eventually found that they are converting the KQL into Base64 bytes and compressing them. They have this property by default set to true =&amp;gt; isQueryBase64Compressed=true in the query string.&lt;/p&gt;

&lt;p&gt;So, the URL would become like this,&lt;br&gt;
&lt;a href="https://portal.azure.com/#blade/Microsoft_Azure_Monitoring_Logs/LogsBlade/resourceId/%2Fsubscriptions%2F%7BsubscriptionId%7D%2FresourceGroups%2F%7Brg%7D%2Fproviders%2Fmicrosoft.insights%2Fcomponents%2F%7Bresourcename%7D/source/LogsBlade.AnalyticsShareLinkToQuery/query/%7Bquery%7D/isQueryBase64Compressed/true"&gt;https://portal.azure.com/#blade/Microsoft_Azure_Monitoring_Logs/LogsBlade/resourceId/%2Fsubscriptions%2F{subscriptionId}%2FresourceGroups%2F{rg}%2Fproviders%2Fmicrosoft.insights%2Fcomponents%2F{resourcename}/source/LogsBlade.AnalyticsShareLinkToQuery/query/{query}/isQueryBase64Compressed/true&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OK, Here is the code for that KQL query conversion to fit into this URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var queryBytes = Encoding.UTF8.GetBytes(query);
var memoryStream = new MemoryStream();
var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress);

gZipStream.Write(queryBytes, 0, queryBytes.Length);
gZipStream.Close();

var compressedData = memoryStream.ToArray();

var encodedText = Convert.ToBase64String(compressedData);
encodedText = encodedText.Replace("/", "%2F");
encodedText = encodedText.Replace("+", "%2B");
encodedText = encodedText.Replace("=", "%3D");

var portalUrl = "https://portal.azure.com/#@sample.onmicrosoft.com/resource/subscriptions/guid-guid-guid-guid-guid/resourceGroups/rg-name/providers/microsoft.insights/components/app-insights-name/overview";

var (subscriptionId, rg, resourcename) = GetAzureResourceDetailsFromLogUrl(portalUrl);

url = "https://portal.azure.com/#blade/" + $"Microsoft_Azure_Monitoring_Logs/LogsBlade/resourceId/%2Fsubscriptions%2F{subscriptionId}%2FresourceGroups%2F{rg}%2Fproviders%2Fmicrosoft.insights%2Fcomponents%2F{resourcename}/source/LogsBlade.AnalyticsShareLinkToQuery/query/{encodedText}/isQueryBase64Compressed/true";

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Additional Perks&lt;/strong&gt;&lt;br&gt;
Here is an additional perk for getting the Subscription Id, Resource Group Name, and the Resource Name from an Azure App Insights resource URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
private static (string, string, string) GetAzureResourceDetailsFromLogUrl(string portalUrl)
{
  var uri = new Uri(portalUrl.Replace("#", ""));

  var subscriptionId = uri.Segments[uri.Segments.ToList().FindIndex(f =&amp;gt; f.Equals(SubscriptionsUrlSegment, StringComparison.OrdinalIgnoreCase)) + 1].Replace("/", "");

  var rg = uri.Segments[uri.Segments.ToList().FindIndex(f =&amp;gt; f.Equals(RGUrlSegment, StringComparison.OrdinalIgnoreCase)) + 1].Replace("/", "");

  var resourceName = uri.Segments[uri.Segments.ToList().FindIndex(f =&amp;gt; f.Equals(ComponentUrlSegment, StringComparison.OrdinalIgnoreCase)) + 1].Replace("/", "");

  return (subscriptionId, rg, resourceName);
}

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

&lt;/div&gt;



</description>
      <category>azure</category>
      <category>analytics</category>
      <category>insights</category>
      <category>kql</category>
    </item>
  </channel>
</rss>
