<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://www.singhsk.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.singhsk.com/" rel="alternate" type="text/html" /><updated>2026-05-05T22:48:12+00:00</updated><id>https://www.singhsk.com/feed.xml</id><title type="html">Santosh Kumar Singh</title><subtitle>Santosh Kumar Singh&apos;s academic portfolio</subtitle><author><name>Santosh Kumar Singh</name><email>santoshkumar.singh@aristocrat.com</email><uri>https://www.aristocrat.com/</uri></author><entry><title type="html">Refactoring and Code Quality in .NET: Analyzers, Sonar, Style, and Architecture Tests</title><link href="https://www.singhsk.com/posts/2026/04/refactoring_code_quality_dotnet/" rel="alternate" type="text/html" title="Refactoring and Code Quality in .NET: Analyzers, Sonar, Style, and Architecture Tests" /><published>2026-04-04T00:00:00+00:00</published><updated>2026-04-04T00:00:00+00:00</updated><id>https://www.singhsk.com/posts/2026/04/refactoring_code_quality_dotnet</id><content type="html" xml:base="https://www.singhsk.com/posts/2026/04/refactoring_code_quality_dotnet/"><![CDATA[<p>This post covers practical code quality tools and refactoring habits for .NET teams: <strong>Roslyn analyzers, formatting rules, Sonar, architecture tests, and safe refactoring workflows</strong>. Code quality is not about making code look clever. It is about making change safer and cheaper.</p>

<h2 id="refactoring-vs-rewriting">Refactoring vs rewriting</h2>
<p>Refactoring changes internal structure without changing external behavior. Rewriting replaces implementation more broadly.</p>

<p>Good refactoring:</p>
<ul>
  <li>has tests or clear verification</li>
  <li>happens in small steps</li>
  <li>preserves behavior</li>
  <li>improves naming, boundaries, or duplication</li>
</ul>

<p>Risky refactoring:</p>
<ul>
  <li>changes too many behaviors at once</li>
  <li>mixes cleanup with feature work</li>
  <li>lacks tests around the affected paths</li>
  <li>moves code without improving clarity</li>
</ul>

<p>Refactoring should reduce future cost, not create churn.</p>

<h2 id="roslyn-analyzers">Roslyn analyzers</h2>
<p>Roslyn analyzers inspect C# code at compile time.</p>

<p>Common analyzer categories:</p>
<ul>
  <li>correctness</li>
  <li>style</li>
  <li>security</li>
  <li>performance</li>
  <li>API usage</li>
</ul>

<p>Enable built-in analysis in <code class="language-plaintext highlighter-rouge">.csproj</code>:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;PropertyGroup&gt;</span>
  <span class="nt">&lt;AnalysisLevel&gt;</span>latest<span class="nt">&lt;/AnalysisLevel&gt;</span>
  <span class="nt">&lt;TreatWarningsAsErrors&gt;</span>false<span class="nt">&lt;/TreatWarningsAsErrors&gt;</span>
<span class="nt">&lt;/PropertyGroup&gt;</span>
</code></pre></div></div>

<p>For mature projects, teams often turn selected warnings into errors.</p>

<h2 id="editorconfig">EditorConfig</h2>
<p><code class="language-plaintext highlighter-rouge">.editorconfig</code> keeps formatting and style consistent.</p>

<p>Example:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[*.cs]</span><span class="w">
</span><span class="py">dotnet_style_qualification_for_field</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">false:suggestion</span>
<span class="py">csharp_style_namespace_declarations</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">file_scoped:suggestion</span>
<span class="py">dotnet_diagnostic.IDE0060.severity</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">warning</span>
</code></pre></div></div>

<p>Consistent formatting reduces review noise. Developers should discuss design, behavior, and risk instead of whitespace.</p>

<h2 id="sonar-and-static-analysis">Sonar and static analysis</h2>
<p>SonarQube or SonarCloud can identify:</p>
<ul>
  <li>bugs</li>
  <li>vulnerabilities</li>
  <li>code smells</li>
  <li>duplication</li>
  <li>test coverage gaps</li>
</ul>

<p>Use static analysis as a signal, not as a substitute for engineering judgment. Not every finding has equal value, and suppressions should be intentional.</p>

<h2 id="architecture-tests">Architecture tests</h2>
<p>Architecture tests verify dependency rules.</p>

<p>Example rule:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Domain must not depend on Infrastructure.
</code></pre></div></div>

<p>Conceptual test:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Domain_Should_Not_Depend_On_Infrastructure</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">Types</span><span class="p">.</span><span class="nf">InAssembly</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">Order</span><span class="p">).</span><span class="n">Assembly</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">Should</span><span class="p">()</span>
        <span class="p">.</span><span class="nf">NotHaveDependencyOn</span><span class="p">(</span><span class="s">"Store.Infrastructure"</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">GetResult</span><span class="p">();</span>

    <span class="n">Assert</span><span class="p">.</span><span class="nf">True</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">IsSuccessful</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Architecture tests are useful when boundaries are important and easy to accidentally violate.</p>

<h2 id="refactoring-workflow">Refactoring workflow</h2>
<p>A safe workflow:</p>
<ol>
  <li>add or confirm tests around the behavior</li>
  <li>make one structural change</li>
  <li>run tests</li>
  <li>repeat</li>
  <li>keep commits focused</li>
</ol>

<p>For large refactors, avoid mixing:</p>
<ul>
  <li>renames</li>
  <li>behavior changes</li>
  <li>dependency upgrades</li>
  <li>formatting-only changes</li>
</ul>

<p>Separate commits make review and rollback easier.</p>

<h2 id="code-review-signals">Code review signals</h2>
<p>Look for:</p>
<ul>
  <li>unclear names</li>
  <li>hidden side effects</li>
  <li>duplicated business rules</li>
  <li>missing error handling</li>
  <li>weak tests around changed behavior</li>
  <li>abstractions with no clear purpose</li>
</ul>

<p>Do not chase theoretical purity while ignoring real bugs. Code quality should support delivery and reliability.</p>

<h2 id="common-mistakes-to-avoid">Common mistakes to avoid</h2>
<p>Watch for these issues:</p>
<ul>
  <li>treating analyzer output as a checklist without judgment</li>
  <li>doing broad cleanup in unrelated feature PRs</li>
  <li>creating abstractions before duplication proves they are needed</li>
  <li>ignoring architecture drift until it is expensive to fix</li>
  <li>refactoring without a way to verify behavior</li>
</ul>

<p>Sustainable code quality comes from small habits repeated consistently: clear names, focused tests, useful analyzers, architecture boundaries, and disciplined refactoring.</p>

<hr />

<p><strong>Next Article:</strong> Building Production-Ready .NET Systems: A Practical Roadmap</p>]]></content><author><name>Santosh Kumar Singh</name><email>santoshkumar.singh@aristocrat.com</email><uri>https://www.aristocrat.com/</uri></author><category term="dotnet" /><category term="code-quality" /><category term="refactoring" /><category term="analyzers" /><category term="architecture" /><category term="advanced" /><summary type="html"><![CDATA[This post covers practical code quality tools and refactoring habits for .NET teams: Roslyn analyzers, formatting rules, Sonar, architecture tests, and safe refactoring workflows. Code quality is not about making code look clever. It is about making change safer and cheaper.]]></summary></entry><entry><title type="html">Advanced Dependency Injection in .NET: Keyed Services, Decorators, and Composition Roots</title><link href="https://www.singhsk.com/posts/2026/04/advanced_dependency_injection_dotnet/" rel="alternate" type="text/html" title="Advanced Dependency Injection in .NET: Keyed Services, Decorators, and Composition Roots" /><published>2026-04-03T00:00:00+00:00</published><updated>2026-04-03T00:00:00+00:00</updated><id>https://www.singhsk.com/posts/2026/04/advanced_dependency_injection_dotnet</id><content type="html" xml:base="https://www.singhsk.com/posts/2026/04/advanced_dependency_injection_dotnet/"><![CDATA[<p>This post covers advanced dependency injection patterns in .NET: <strong>keyed services, decorators, and composition roots</strong>. Basic DI teaches lifetimes and constructor injection. Advanced DI is about keeping object creation centralized while supporting real variation in behavior.</p>

<h2 id="composition-root">Composition root</h2>
<p>The composition root is where the application wires dependencies together. In ASP.NET Core, this usually lives in <code class="language-plaintext highlighter-rouge">Program.cs</code> and extension methods called from it.</p>

<p>Example:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddOrderProcessing</span><span class="p">(</span><span class="n">builder</span><span class="p">.</span><span class="n">Configuration</span><span class="p">);</span>
<span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddPayments</span><span class="p">(</span><span class="n">builder</span><span class="p">.</span><span class="n">Configuration</span><span class="p">);</span>
<span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddMessaging</span><span class="p">(</span><span class="n">builder</span><span class="p">.</span><span class="n">Configuration</span><span class="p">);</span>
</code></pre></div></div>

<p>The goal is:</p>
<ul>
  <li>register dependencies in one predictable place</li>
  <li>keep business classes free from container usage</li>
  <li>avoid scattering <code class="language-plaintext highlighter-rouge">IServiceProvider</code> calls through the codebase</li>
</ul>

<h2 id="keyed-services">Keyed services</h2>
<p>Keyed services let you register multiple implementations of the same service type and choose by key.</p>

<p>Example:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddKeyedScoped</span><span class="p">&lt;</span><span class="n">IPaymentProcessor</span><span class="p">,</span> <span class="n">StripePaymentProcessor</span><span class="p">&gt;(</span><span class="s">"stripe"</span><span class="p">);</span>
<span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddKeyedScoped</span><span class="p">&lt;</span><span class="n">IPaymentProcessor</span><span class="p">,</span> <span class="n">PaypalPaymentProcessor</span><span class="p">&gt;(</span><span class="s">"paypal"</span><span class="p">);</span>
</code></pre></div></div>

<p>Resolve in a minimal API:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">app</span><span class="p">.</span><span class="nf">MapPost</span><span class="p">(</span><span class="s">"/payments/stripe"</span><span class="p">,</span> <span class="p">(</span>
    <span class="p">[</span><span class="nf">FromKeyedServices</span><span class="p">(</span><span class="s">"stripe"</span><span class="p">)]</span> <span class="n">IPaymentProcessor</span> <span class="n">processor</span><span class="p">)</span> <span class="p">=&gt;</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">processor</span><span class="p">.</span><span class="nf">ProcessAsync</span><span class="p">();</span>
<span class="p">});</span>
</code></pre></div></div>

<p>Use keyed services when the key is a real application concept. Avoid using them to hide unclear design decisions.</p>

<h2 id="decorators">Decorators</h2>
<p>A decorator wraps another implementation to add behavior.</p>

<p>Use cases:</p>
<ul>
  <li>logging</li>
  <li>caching</li>
  <li>metrics</li>
  <li>retries</li>
  <li>validation</li>
</ul>

<p>Example:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">CachedProductService</span><span class="p">(</span>
    <span class="n">IProductService</span> <span class="n">inner</span><span class="p">,</span>
    <span class="n">IMemoryCache</span> <span class="n">cache</span><span class="p">)</span> <span class="p">:</span> <span class="n">IProductService</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">ProductDto</span><span class="p">?&gt;</span> <span class="nf">GetByIdAsync</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">,</span> <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">cache</span><span class="p">.</span><span class="nf">GetOrCreateAsync</span><span class="p">(</span>
            <span class="s">$"products:</span><span class="p">{</span><span class="n">id</span><span class="p">}</span><span class="s">"</span><span class="p">,</span>
            <span class="n">entry</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">entry</span><span class="p">.</span><span class="n">AbsoluteExpirationRelativeToNow</span> <span class="p">=</span> <span class="n">TimeSpan</span><span class="p">.</span><span class="nf">FromMinutes</span><span class="p">(</span><span class="m">5</span><span class="p">);</span>
                <span class="k">return</span> <span class="n">inner</span><span class="p">.</span><span class="nf">GetByIdAsync</span><span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">);</span>
            <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Decorators keep cross-cutting behavior outside the core implementation.</p>

<h2 id="factory-patterns">Factory patterns</h2>
<p>Sometimes runtime values determine which implementation to use.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">PaymentProcessorFactory</span><span class="p">(</span><span class="n">IServiceProvider</span> <span class="n">serviceProvider</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">IPaymentProcessor</span> <span class="nf">GetProcessor</span><span class="p">(</span><span class="kt">string</span> <span class="n">provider</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">provider</span> <span class="k">switch</span>
        <span class="p">{</span>
            <span class="s">"stripe"</span> <span class="p">=&gt;</span> <span class="n">serviceProvider</span><span class="p">.</span><span class="n">GetRequiredKeyedService</span><span class="p">&lt;</span><span class="n">IPaymentProcessor</span><span class="p">&gt;(</span><span class="s">"stripe"</span><span class="p">),</span>
            <span class="s">"paypal"</span> <span class="p">=&gt;</span> <span class="n">serviceProvider</span><span class="p">.</span><span class="n">GetRequiredKeyedService</span><span class="p">&lt;</span><span class="n">IPaymentProcessor</span><span class="p">&gt;(</span><span class="s">"paypal"</span><span class="p">),</span>
            <span class="n">_</span> <span class="p">=&gt;</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">InvalidOperationException</span><span class="p">(</span><span class="s">"Unknown payment provider."</span><span class="p">)</span>
        <span class="p">};</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Use factories carefully. If every class starts asking the container for dependencies, you are drifting toward the service locator anti-pattern.</p>

<h2 id="avoid-service-locator">Avoid service locator</h2>
<p>This is usually a smell:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">OrderService</span><span class="p">(</span><span class="n">IServiceProvider</span> <span class="n">serviceProvider</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">Task</span> <span class="nf">SubmitAsync</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">repository</span> <span class="p">=</span> <span class="n">serviceProvider</span><span class="p">.</span><span class="n">GetRequiredService</span><span class="p">&lt;</span><span class="n">IOrderRepository</span><span class="p">&gt;();</span>
        <span class="k">return</span> <span class="n">Task</span><span class="p">.</span><span class="n">CompletedTask</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Prefer explicit constructor dependencies. They make requirements visible and testing easier.</p>

<h2 id="common-mistakes-to-avoid">Common mistakes to avoid</h2>
<p>Watch for these issues:</p>
<ul>
  <li>injecting <code class="language-plaintext highlighter-rouge">IServiceProvider</code> everywhere</li>
  <li>using keyed services where a strategy object would be clearer</li>
  <li>registering singletons that depend on scoped services</li>
  <li>hiding complex composition in controllers</li>
  <li>creating decorators that change business behavior unexpectedly</li>
</ul>

<p>Advanced DI should clarify composition, not make dependency graphs harder to understand.</p>

<hr />

<p><strong>Next Article:</strong> Refactoring and Code Quality in .NET: Analyzers, Sonar, Style, and Architecture Tests</p>]]></content><author><name>Santosh Kumar Singh</name><email>santoshkumar.singh@aristocrat.com</email><uri>https://www.aristocrat.com/</uri></author><category term="dotnet" /><category term="dependency-injection" /><category term="architecture" /><category term="advanced" /><summary type="html"><![CDATA[This post covers advanced dependency injection patterns in .NET: keyed services, decorators, and composition roots. Basic DI teaches lifetimes and constructor injection. Advanced DI is about keeping object creation centralized while supporting real variation in behavior.]]></summary></entry><entry><title type="html">Real-Time Systems in .NET: SignalR Architecture and Scaling</title><link href="https://www.singhsk.com/posts/2026/04/signalr_architecture_scaling/" rel="alternate" type="text/html" title="Real-Time Systems in .NET: SignalR Architecture and Scaling" /><published>2026-04-02T00:00:00+00:00</published><updated>2026-04-02T00:00:00+00:00</updated><id>https://www.singhsk.com/posts/2026/04/signalr_architecture_scaling</id><content type="html" xml:base="https://www.singhsk.com/posts/2026/04/signalr_architecture_scaling/"><![CDATA[<p>This post covers real-time systems in .NET using SignalR. SignalR lets servers push messages to connected clients over WebSockets and fallback transports. It is useful for <strong>notifications, dashboards, collaborative features, chat, live status updates, and workflow monitoring</strong>.</p>

<h2 id="what-signalr-provides">What SignalR provides</h2>
<p>SignalR abstracts connection management and real-time messaging.</p>

<p>Core concepts:</p>
<ul>
  <li>hub: server-side entry point</li>
  <li>connection: a connected client</li>
  <li>group: named collection of connections</li>
  <li>client method: function invoked on the client</li>
</ul>

<p>Basic hub:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">NotificationsHub</span> <span class="p">:</span> <span class="n">Hub</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">JoinTenantGroup</span><span class="p">(</span><span class="kt">string</span> <span class="n">tenantId</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">await</span> <span class="n">Groups</span><span class="p">.</span><span class="nf">AddToGroupAsync</span><span class="p">(</span><span class="n">Context</span><span class="p">.</span><span class="n">ConnectionId</span><span class="p">,</span> <span class="s">$"tenant:</span><span class="p">{</span><span class="n">tenantId</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Register and map:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddSignalR</span><span class="p">();</span>

<span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span>

<span class="n">app</span><span class="p">.</span><span class="n">MapHub</span><span class="p">&lt;</span><span class="n">NotificationsHub</span><span class="p">&gt;(</span><span class="s">"/hubs/notifications"</span><span class="p">);</span>
</code></pre></div></div>

<h2 id="sending-messages">Sending messages</h2>
<p>Send from outside a hub using <code class="language-plaintext highlighter-rouge">IHubContext</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">NotificationService</span><span class="p">(</span>
    <span class="n">IHubContext</span><span class="p">&lt;</span><span class="n">NotificationsHub</span><span class="p">&gt;</span> <span class="n">hubContext</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">Task</span> <span class="nf">NotifyTenantAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">tenantId</span><span class="p">,</span> <span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">hubContext</span><span class="p">.</span><span class="n">Clients</span>
            <span class="p">.</span><span class="nf">Group</span><span class="p">(</span><span class="s">$"tenant:</span><span class="p">{</span><span class="n">tenantId</span><span class="p">}</span><span class="s">"</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">SendAsync</span><span class="p">(</span><span class="s">"notificationReceived"</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This is useful when background jobs or API endpoints need to push updates.</p>

<h2 id="groups">Groups</h2>
<p>Groups are essential for targeting messages.</p>

<p>Examples:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">tenant:acme</code></li>
  <li><code class="language-plaintext highlighter-rouge">order:42</code></li>
  <li><code class="language-plaintext highlighter-rouge">user:123</code></li>
  <li><code class="language-plaintext highlighter-rouge">dashboard:operations</code></li>
</ul>

<p>Groups are not a security boundary by themselves. You still need to authorize who can join a group.</p>

<h2 id="authentication-and-authorization">Authentication and authorization</h2>
<p>SignalR connections can use the same ASP.NET Core authentication system.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">app</span><span class="p">.</span><span class="n">MapHub</span><span class="p">&lt;</span><span class="n">NotificationsHub</span><span class="p">&gt;(</span><span class="s">"/hubs/notifications"</span><span class="p">)</span>
   <span class="p">.</span><span class="nf">RequireAuthorization</span><span class="p">();</span>
</code></pre></div></div>

<p>Inside the hub, use claims to verify access:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">tenantId</span> <span class="p">=</span> <span class="n">Context</span><span class="p">.</span><span class="n">User</span><span class="p">?.</span><span class="nf">FindFirst</span><span class="p">(</span><span class="s">"tenant_id"</span><span class="p">)?.</span><span class="n">Value</span><span class="p">;</span>
</code></pre></div></div>

<p>Do not let clients join arbitrary tenant or resource groups without server-side validation.</p>

<h2 id="scaling-signalr">Scaling SignalR</h2>
<p>Single-instance SignalR is straightforward. Multiple app instances need a backplane or managed service so messages reach clients connected to any instance.</p>

<p>Common options:</p>
<ul>
  <li>Azure SignalR Service</li>
  <li>Redis backplane</li>
  <li>sticky sessions in limited scenarios</li>
</ul>

<p>For large real-time systems, prefer managed SignalR infrastructure when it fits the cloud platform. It reduces connection scaling burden.</p>

<h2 id="common-mistakes-to-avoid">Common mistakes to avoid</h2>
<p>Watch for these issues:</p>
<ul>
  <li>sending messages to all clients when groups are required</li>
  <li>trusting client-supplied group names</li>
  <li>ignoring reconnect behavior</li>
  <li>assuming in-memory connection state works across multiple servers</li>
  <li>using SignalR for workflows that only need polling or ordinary HTTP</li>
</ul>

<p>SignalR is best when users benefit from immediate updates. Design groups, authorization, and scale-out from the beginning.</p>

<hr />

<p><strong>Next Article:</strong> Advanced Dependency Injection in .NET: Keyed Services, Decorators, and Composition Roots</p>]]></content><author><name>Santosh Kumar Singh</name><email>santoshkumar.singh@aristocrat.com</email><uri>https://www.aristocrat.com/</uri></author><category term="dotnet" /><category term="aspnetcore" /><category term="signalr" /><category term="realtime" /><category term="advanced" /><summary type="html"><![CDATA[This post covers real-time systems in .NET using SignalR. SignalR lets servers push messages to connected clients over WebSockets and fallback transports. It is useful for notifications, dashboards, collaborative features, chat, live status updates, and workflow monitoring.]]></summary></entry><entry><title type="html">Multi-Tenancy Patterns in ASP.NET Core</title><link href="https://www.singhsk.com/posts/2026/04/multitenancy_patterns_aspnetcore/" rel="alternate" type="text/html" title="Multi-Tenancy Patterns in ASP.NET Core" /><published>2026-04-01T00:00:00+00:00</published><updated>2026-04-01T00:00:00+00:00</updated><id>https://www.singhsk.com/posts/2026/04/multitenancy_patterns_aspnetcore</id><content type="html" xml:base="https://www.singhsk.com/posts/2026/04/multitenancy_patterns_aspnetcore/"><![CDATA[<p>This post covers common multi-tenancy patterns in ASP.NET Core. Multi-tenancy means one application serves multiple customers, organizations, or logical tenants while keeping their data and configuration separated. The hard parts are <strong>tenant identification, data isolation, configuration, security, and operations</strong>.</p>

<h2 id="tenant-identification">Tenant identification</h2>
<p>The app needs a reliable way to determine the current tenant.</p>

<p>Common strategies:</p>
<ul>
  <li>subdomain: <code class="language-plaintext highlighter-rouge">acme.example.com</code></li>
  <li>route: <code class="language-plaintext highlighter-rouge">/tenants/acme/orders</code></li>
  <li>header: <code class="language-plaintext highlighter-rouge">X-Tenant-Id</code></li>
  <li>token claim: <code class="language-plaintext highlighter-rouge">tenant_id</code></li>
</ul>

<p>Example middleware concept:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">TenantMiddleware</span><span class="p">(</span><span class="n">RequestDelegate</span> <span class="n">next</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">InvokeAsync</span><span class="p">(</span><span class="n">HttpContext</span> <span class="n">context</span><span class="p">,</span> <span class="n">ITenantResolver</span> <span class="n">resolver</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">tenant</span> <span class="p">=</span> <span class="k">await</span> <span class="n">resolver</span><span class="p">.</span><span class="nf">ResolveAsync</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">tenant</span> <span class="k">is</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">StatusCode</span> <span class="p">=</span> <span class="n">StatusCodes</span><span class="p">.</span><span class="n">Status400BadRequest</span><span class="p">;</span>
            <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="nf">WriteAsync</span><span class="p">(</span><span class="s">"Tenant is required."</span><span class="p">);</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="n">context</span><span class="p">.</span><span class="n">Items</span><span class="p">[</span><span class="s">"Tenant"</span><span class="p">]</span> <span class="p">=</span> <span class="n">tenant</span><span class="p">;</span>
        <span class="k">await</span> <span class="nf">next</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Tenant resolution must happen early enough that downstream services can use it.</p>

<h2 id="data-isolation-patterns">Data isolation patterns</h2>
<p>Common storage models:</p>
<ul>
  <li>shared database, shared schema, tenant column</li>
  <li>shared database, separate schema per tenant</li>
  <li>separate database per tenant</li>
</ul>

<p>Shared database with tenant column:</p>
<ul>
  <li>simplest operationally</li>
  <li>requires strict filters</li>
  <li>works well for many small tenants</li>
</ul>

<p>Separate database per tenant:</p>
<ul>
  <li>strongest isolation</li>
  <li>easier tenant-level backup and restore</li>
  <li>more operational complexity</li>
</ul>

<p>There is no universal best option. The right model depends on tenant count, isolation needs, compliance, and operational maturity.</p>

<h2 id="tenant-aware-ef-core-queries">Tenant-aware EF Core queries</h2>
<p>For shared-schema models, every tenant-owned row needs a tenant key.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">interface</span> <span class="nc">ITenantEntity</span>
<span class="p">{</span>
    <span class="kt">string</span> <span class="n">TenantId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Global query filters can help:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">modelBuilder</span><span class="p">.</span><span class="n">Entity</span><span class="p">&lt;</span><span class="n">Order</span><span class="p">&gt;()</span>
    <span class="p">.</span><span class="nf">HasQueryFilter</span><span class="p">(</span><span class="n">o</span> <span class="p">=&gt;</span> <span class="n">o</span><span class="p">.</span><span class="n">TenantId</span> <span class="p">==</span> <span class="n">_tenantContext</span><span class="p">.</span><span class="n">TenantId</span><span class="p">);</span>
</code></pre></div></div>

<p>This reduces accidental cross-tenant reads, but it is not a substitute for careful testing and authorization.</p>

<h2 id="tenant-specific-configuration">Tenant-specific configuration</h2>
<p>Tenants may have different settings:</p>
<ul>
  <li>feature flags</li>
  <li>branding</li>
  <li>connection strings</li>
  <li>limits and quotas</li>
  <li>integration credentials</li>
</ul>

<p>Model it explicitly:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">record</span> <span class="nc">TenantSettings</span><span class="p">(</span>
    <span class="kt">string</span> <span class="n">TenantId</span><span class="p">,</span>
    <span class="kt">bool</span> <span class="n">EnableAdvancedReports</span><span class="p">,</span>
    <span class="kt">int</span> <span class="n">MaxUsers</span><span class="p">);</span>
</code></pre></div></div>

<p>Cache tenant settings carefully and invalidate them when changed.</p>

<h2 id="security-concerns">Security concerns</h2>
<p>Multi-tenancy raises the cost of mistakes. A cross-tenant data leak is a serious incident.</p>

<p>Controls:</p>
<ul>
  <li>authorize tenant membership from server-side identity</li>
  <li>do not trust tenant IDs supplied by the client alone</li>
  <li>add automated tests for tenant isolation</li>
  <li>log tenant context in security events</li>
  <li>avoid global admin shortcuts without auditing</li>
</ul>

<h2 id="common-mistakes-to-avoid">Common mistakes to avoid</h2>
<p>Watch for these issues:</p>
<ul>
  <li>forgetting tenant filters in one query</li>
  <li>trusting headers from public clients without validation</li>
  <li>mixing tenant configuration with user preferences</li>
  <li>making tenant resolution inconsistent across APIs and workers</li>
  <li>ignoring background jobs that process tenant data</li>
</ul>

<p>Multi-tenancy must be a first-class architectural concern. Add tenant context, isolation, testing, and observability early, because retrofitting them later is expensive.</p>

<hr />

<p><strong>Next Article:</strong> Real-Time Systems in .NET: SignalR Architecture and Scaling</p>]]></content><author><name>Santosh Kumar Singh</name><email>santoshkumar.singh@aristocrat.com</email><uri>https://www.aristocrat.com/</uri></author><category term="dotnet" /><category term="aspnetcore" /><category term="multi-tenancy" /><category term="architecture" /><category term="advanced" /><summary type="html"><![CDATA[This post covers common multi-tenancy patterns in ASP.NET Core. Multi-tenancy means one application serves multiple customers, organizations, or logical tenants while keeping their data and configuration separated. The hard parts are tenant identification, data isolation, configuration, security, and operations.]]></summary></entry><entry><title type="html">Cloud Patterns for .NET: Azure App Service, Azure Container Apps, AWS ECS, and Fargate</title><link href="https://www.singhsk.com/posts/2026/03/cloud_patterns_dotnet_overview/" rel="alternate" type="text/html" title="Cloud Patterns for .NET: Azure App Service, Azure Container Apps, AWS ECS, and Fargate" /><published>2026-03-31T00:00:00+00:00</published><updated>2026-03-31T00:00:00+00:00</updated><id>https://www.singhsk.com/posts/2026/03/cloud_patterns_dotnet_overview</id><content type="html" xml:base="https://www.singhsk.com/posts/2026/03/cloud_patterns_dotnet_overview/"><![CDATA[<p>This post gives a practical overview of cloud hosting patterns for .NET applications, focusing on <strong>Azure App Service, Azure Container Apps, AWS ECS, and AWS Fargate</strong>. The goal is not to memorize every platform feature. The goal is to understand the deployment shape each option encourages.</p>

<h2 id="start-with-the-hosting-model">Start with the hosting model</h2>
<p>Before choosing a platform, answer:</p>
<ul>
  <li>is the app a web API, worker, or both</li>
  <li>does it need containers</li>
  <li>does it need scale-to-zero</li>
  <li>who manages the runtime and OS</li>
  <li>what observability and secrets tools are available</li>
  <li>how deployments and rollbacks work</li>
</ul>

<p>Cloud choice is architecture. It affects configuration, networking, deployment, and operations.</p>

<h2 id="azure-app-service">Azure App Service</h2>
<p>Azure App Service is a managed platform for web apps and APIs.</p>

<p>Good fit:</p>
<ul>
  <li>straightforward ASP.NET Core APIs</li>
  <li>teams that want minimal infrastructure management</li>
  <li>apps that do not require custom orchestration</li>
  <li>deployments from GitHub Actions or Azure DevOps</li>
</ul>

<p>Benefits:</p>
<ul>
  <li>managed runtime</li>
  <li>deployment slots</li>
  <li>built-in TLS support</li>
  <li>easy custom domains</li>
  <li>integration with Application Insights</li>
</ul>

<p>Tradeoffs:</p>
<ul>
  <li>less control than container orchestration</li>
  <li>some platform behavior is specific to App Service</li>
  <li>workers and background jobs need careful planning</li>
</ul>

<h2 id="azure-container-apps">Azure Container Apps</h2>
<p>Azure Container Apps runs containers on a managed platform with scaling features.</p>

<p>Good fit:</p>
<ul>
  <li>containerized APIs</li>
  <li>worker services</li>
  <li>event-driven scale</li>
  <li>teams that want containers without managing Kubernetes directly</li>
</ul>

<p>Useful capabilities:</p>
<ul>
  <li>revision-based deployments</li>
  <li>scale rules</li>
  <li>managed ingress</li>
  <li>environment variables and secrets</li>
  <li>Dapr integration when needed</li>
</ul>

<p>Container Apps is attractive when you want container packaging but not full cluster ownership.</p>

<h2 id="aws-ecs-and-fargate">AWS ECS and Fargate</h2>
<p>Amazon ECS runs containers. Fargate lets you run ECS tasks without managing EC2 instances.</p>

<p>Good fit:</p>
<ul>
  <li>containerized .NET APIs</li>
  <li>worker services</li>
  <li>teams already on AWS</li>
  <li>services that need VPC-level integration</li>
</ul>

<p>Core concepts:</p>
<ul>
  <li>task definition describes containers</li>
  <li>service keeps tasks running</li>
  <li>cluster groups capacity</li>
  <li>load balancer routes traffic</li>
  <li>CloudWatch collects logs and metrics</li>
</ul>

<p>Fargate reduces infrastructure management by removing the need to manage the underlying servers.</p>

<h2 id="configuration-and-secrets">Configuration and secrets</h2>
<p>Across cloud platforms, keep the same .NET design:</p>
<ul>
  <li>use <code class="language-plaintext highlighter-rouge">appsettings.json</code> for non-sensitive defaults</li>
  <li>override with environment variables</li>
  <li>store secrets in platform secret stores</li>
  <li>validate options at startup</li>
</ul>

<p>Example environment variable:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ConnectionStrings__Default=...
</code></pre></div></div>

<p>.NET configuration providers make this consistent across Azure, AWS, containers, and local development.</p>

<h2 id="health-checks-and-scaling">Health checks and scaling</h2>
<p>Cloud platforms need to know whether the app is healthy.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddHealthChecks</span><span class="p">();</span>

<span class="n">app</span><span class="p">.</span><span class="nf">MapHealthChecks</span><span class="p">(</span><span class="s">"/health"</span><span class="p">);</span>
</code></pre></div></div>

<p>For production, distinguish:</p>
<ul>
  <li>liveness: process is running</li>
  <li>readiness: app can handle traffic</li>
</ul>

<p>Scaling depends on the platform:</p>
<ul>
  <li>App Service scales instances</li>
  <li>Container Apps can scale by HTTP traffic, queue length, or events</li>
  <li>ECS services scale task count based on metrics</li>
</ul>

<h2 id="choosing-pragmatically">Choosing pragmatically</h2>
<p>Use Azure App Service when:</p>
<ul>
  <li>you want a simple managed web app platform</li>
  <li>the app is mostly HTTP</li>
  <li>speed of setup matters</li>
</ul>

<p>Use Azure Container Apps when:</p>
<ul>
  <li>containers are part of your workflow</li>
  <li>you need event-driven scale</li>
  <li>you want less operational overhead than Kubernetes</li>
</ul>

<p>Use ECS/Fargate when:</p>
<ul>
  <li>AWS is the primary cloud</li>
  <li>containers are standard</li>
  <li>VPC networking and AWS service integration matter</li>
</ul>

<h2 id="common-mistakes-to-avoid">Common mistakes to avoid</h2>
<p>Watch for these issues:</p>
<ul>
  <li>choosing Kubernetes-level complexity too early</li>
  <li>storing secrets in images or source control</li>
  <li>missing health checks</li>
  <li>failing to design logging and metrics before production</li>
  <li>assuming local container behavior matches cloud networking exactly</li>
</ul>

<p>Cloud platforms differ, but the application fundamentals remain stable: external configuration, health checks, logs, metrics, secure secrets, and repeatable deployments.</p>

<hr />

<p><strong>Next Article:</strong> Multi-Tenancy Patterns in ASP.NET Core</p>]]></content><author><name>Santosh Kumar Singh</name><email>santoshkumar.singh@aristocrat.com</email><uri>https://www.aristocrat.com/</uri></author><category term="dotnet" /><category term="cloud" /><category term="azure" /><category term="aws" /><category term="containers" /><category term="advanced" /><summary type="html"><![CDATA[This post gives a practical overview of cloud hosting patterns for .NET applications, focusing on Azure App Service, Azure Container Apps, AWS ECS, and AWS Fargate. The goal is not to memorize every platform feature. The goal is to understand the deployment shape each option encourages.]]></summary></entry><entry><title type="html">CI/CD with GitHub Actions for .NET: Build, Test, Publish, Secrets, and Environments</title><link href="https://www.singhsk.com/posts/2026/03/github_actions_cicd_dotnet/" rel="alternate" type="text/html" title="CI/CD with GitHub Actions for .NET: Build, Test, Publish, Secrets, and Environments" /><published>2026-03-30T00:00:00+00:00</published><updated>2026-03-30T00:00:00+00:00</updated><id>https://www.singhsk.com/posts/2026/03/github_actions_cicd_dotnet</id><content type="html" xml:base="https://www.singhsk.com/posts/2026/03/github_actions_cicd_dotnet/"><![CDATA[<p>This post covers a practical CI/CD pipeline for .NET using GitHub Actions. A good pipeline should <strong>restore, build, test, publish artifacts, handle secrets correctly, and separate environments such as development, staging, and production</strong>.</p>

<h2 id="why-cicd-matters">Why CI/CD matters</h2>
<p>CI/CD reduces manual deployment risk. Every change should pass the same repeatable checks before it reaches users.</p>

<p>A baseline pipeline should answer:</p>
<ul>
  <li>does the code restore successfully</li>
  <li>does it compile</li>
  <li>do tests pass</li>
  <li>can the app be packaged</li>
  <li>which environment receives the deployment</li>
</ul>

<h2 id="basic-build-and-test-workflow">Basic build and test workflow</h2>
<p>Create <code class="language-plaintext highlighter-rouge">.github/workflows/dotnet.yml</code>:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">dotnet-ci</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span> <span class="pi">[</span> <span class="nv">main</span> <span class="pi">]</span>
  <span class="na">pull_request</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span> <span class="pi">[</span> <span class="nv">main</span> <span class="pi">]</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">build</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>

    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span>

      <span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/setup-dotnet@v4</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">dotnet-version</span><span class="pi">:</span> <span class="s1">'</span><span class="s">8.0.x'</span>

      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">dotnet restore</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">dotnet build --configuration Release --no-restore</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">dotnet test --configuration Release --no-build</span>
</code></pre></div></div>

<p>This is the minimum useful loop for most .NET repos.</p>

<h2 id="publishing-artifacts">Publishing artifacts</h2>
<p>After tests pass, publish the app:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">dotnet publish src/Store.Api/Store.Api.csproj --configuration Release --output ./publish</span>

      <span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/upload-artifact@v4</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">name</span><span class="pi">:</span> <span class="s">store-api</span>
          <span class="na">path</span><span class="pi">:</span> <span class="s">./publish</span>
</code></pre></div></div>

<p>Artifacts give later jobs a known package to deploy. This is better than rebuilding separately for every environment.</p>

<h2 id="secrets">Secrets</h2>
<p>Never hard-code credentials in workflow files.</p>

<p>Use GitHub Actions secrets:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">env</span><span class="pi">:</span>
  <span class="na">ConnectionStrings__Default</span><span class="pi">:</span> <span class="s">$</span>
</code></pre></div></div>

<p>Rules:</p>
<ul>
  <li>store secrets in GitHub secret stores</li>
  <li>scope secrets by repository, organization, or environment</li>
  <li>do not echo secrets in logs</li>
  <li>rotate credentials when needed</li>
</ul>

<h2 id="environments">Environments</h2>
<p>GitHub environments help control deployments.</p>

<p>Example:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">deploy-staging</span><span class="pi">:</span>
  <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
  <span class="na">environment</span><span class="pi">:</span> <span class="s">staging</span>
  <span class="na">needs</span><span class="pi">:</span> <span class="s">build</span>
</code></pre></div></div>

<p>Production environments can require approvals, protection rules, and separate secrets.</p>

<h2 id="build-once-deploy-many">Build once, deploy many</h2>
<p>A strong pipeline builds once and promotes the same artifact.</p>

<p>Why:</p>
<ul>
  <li>staging and production receive the same compiled output</li>
  <li>fewer “works in staging but not prod” surprises</li>
  <li>deployment becomes a promotion decision</li>
</ul>

<p>For containers, the equivalent is:</p>
<ul>
  <li>build an image once</li>
  <li>tag it with the commit SHA</li>
  <li>promote that image across environments</li>
</ul>

<h2 id="quality-gates">Quality gates</h2>
<p>Useful checks include:</p>
<ul>
  <li>unit tests</li>
  <li>integration tests</li>
  <li>formatting checks</li>
  <li>static analysis</li>
  <li>dependency vulnerability scanning</li>
  <li>container image scanning</li>
</ul>

<p>Do not add gates just to make the pipeline look sophisticated. Add checks that catch real risk for your project.</p>

<h2 id="common-mistakes-to-avoid">Common mistakes to avoid</h2>
<p>Watch for these issues:</p>
<ul>
  <li>deploying from a developer machine manually</li>
  <li>rebuilding different artifacts for each environment</li>
  <li>storing secrets in YAML</li>
  <li>skipping tests on pull requests</li>
  <li>letting production deploys happen with no approval or audit trail</li>
</ul>

<p>CI/CD is not just automation. It is a reliability control that makes releases repeatable and traceable.</p>

<hr />

<p><strong>Next Article:</strong> Cloud Patterns for .NET: Azure App Service, Azure Container Apps, AWS ECS, and Fargate</p>]]></content><author><name>Santosh Kumar Singh</name><email>santoshkumar.singh@aristocrat.com</email><uri>https://www.aristocrat.com/</uri></author><category term="dotnet" /><category term="github-actions" /><category term="cicd" /><category term="devops" /><category term="advanced" /><summary type="html"><![CDATA[This post covers a practical CI/CD pipeline for .NET using GitHub Actions. A good pipeline should restore, build, test, publish artifacts, handle secrets correctly, and separate environments such as development, staging, and production.]]></summary></entry><entry><title type="html">Deploying ASP.NET Core Apps: Docker, Linux Hosting, Nginx, and Health Checks</title><link href="https://www.singhsk.com/posts/2026/03/deploying_aspnetcore_apps/" rel="alternate" type="text/html" title="Deploying ASP.NET Core Apps: Docker, Linux Hosting, Nginx, and Health Checks" /><published>2026-03-29T00:00:00+00:00</published><updated>2026-03-29T00:00:00+00:00</updated><id>https://www.singhsk.com/posts/2026/03/deploying_aspnetcore_apps</id><content type="html" xml:base="https://www.singhsk.com/posts/2026/03/deploying_aspnetcore_apps/"><![CDATA[<p>This post covers practical deployment patterns for ASP.NET Core apps: <strong>Docker images, Linux hosting, reverse proxies such as Nginx, and health checks</strong>. Deployment is part of application design. An app that cannot start, stop, report health, and receive traffic cleanly is not production-ready.</p>

<h2 id="publishing-the-app">Publishing the app</h2>
<p>The basic publish command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet publish src/Store.Api/Store.Api.csproj <span class="nt">-c</span> Release <span class="nt">-o</span> publish
</code></pre></div></div>

<p>This creates deployable output with compiled assemblies, dependencies, and configuration files.</p>

<p>Use Release builds for deployment:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet publish <span class="nt">-c</span> Release
</code></pre></div></div>

<p>Debug builds are for local development.</p>

<h2 id="dockerfile">Dockerfile</h2>
<p>A typical multi-stage Dockerfile:</p>

<div class="language-dockerfile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">FROM</span><span class="w"> </span><span class="s">mcr.microsoft.com/dotnet/sdk:8.0</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="s">build</span>
<span class="k">WORKDIR</span><span class="s"> /src</span>
<span class="k">COPY</span><span class="s"> . .</span>
<span class="k">RUN </span>dotnet publish src/Store.Api/Store.Api.csproj <span class="nt">-c</span> Release <span class="nt">-o</span> /app/publish

<span class="k">FROM</span><span class="w"> </span><span class="s">mcr.microsoft.com/dotnet/aspnet:8.0</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="s">runtime</span>
<span class="k">WORKDIR</span><span class="s"> /app</span>
<span class="k">COPY</span><span class="s"> --from=build /app/publish .</span>
<span class="k">ENTRYPOINT</span><span class="s"> ["dotnet", "Store.Api.dll"]</span>
</code></pre></div></div>

<p>Build and run:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build <span class="nt">-t</span> store-api <span class="nb">.</span>
docker run <span class="nt">-p</span> 8080:8080 store-api
</code></pre></div></div>

<p>In containers, configuration usually comes from environment variables or mounted secrets, not edited files inside the image.</p>

<h2 id="linux-hosting">Linux hosting</h2>
<p>ASP.NET Core runs well on Linux. Common hosting options:</p>
<ul>
  <li>systemd service on a VM</li>
  <li>Docker container</li>
  <li>Kubernetes</li>
  <li>platform services such as Azure App Service or AWS ECS</li>
</ul>

<p>For systemd, your service file usually starts the published app and restarts it on failure.</p>

<h2 id="reverse-proxy-with-nginx">Reverse proxy with Nginx</h2>
<p>In many Linux deployments, Nginx sits in front of Kestrel.</p>

<p>Nginx handles:</p>
<ul>
  <li>TLS termination</li>
  <li>public ports</li>
  <li>request forwarding</li>
  <li>compression</li>
  <li>buffering</li>
  <li>static assets in some setups</li>
</ul>

<p>Basic reverse proxy shape:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">api.example.com</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:5000</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-For</span> <span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-Proto</span> <span class="nv">$scheme</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>In ASP.NET Core, enable forwarded headers when running behind a proxy:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">app</span><span class="p">.</span><span class="nf">UseForwardedHeaders</span><span class="p">();</span>
</code></pre></div></div>

<h2 id="health-checks">Health checks</h2>
<p>Health checks let platforms know whether the app is alive and ready.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddHealthChecks</span><span class="p">();</span>

<span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span>

<span class="n">app</span><span class="p">.</span><span class="nf">MapHealthChecks</span><span class="p">(</span><span class="s">"/health"</span><span class="p">);</span>
</code></pre></div></div>

<p>For production, consider separate endpoints:</p>
<ul>
  <li>liveness: process is running</li>
  <li>readiness: app can serve traffic</li>
</ul>

<p>Readiness may include database, cache, or message broker checks, but be careful not to make health checks too expensive.</p>

<h2 id="deployment-checklist">Deployment checklist</h2>
<p>Use this baseline:</p>
<ul>
  <li>publish Release builds</li>
  <li>externalize configuration</li>
  <li>expose a health endpoint</li>
  <li>log to stdout in containers</li>
  <li>set resource limits</li>
  <li>validate reverse proxy headers</li>
  <li>automate deployment through CI/CD</li>
</ul>

<h2 id="common-mistakes-to-avoid">Common mistakes to avoid</h2>
<p>Watch for these issues:</p>
<ul>
  <li>building Docker images with secrets baked in</li>
  <li>running Debug builds in production</li>
  <li>missing health checks</li>
  <li>ignoring graceful shutdown</li>
  <li>forgetting forwarded headers behind Nginx or load balancers</li>
</ul>

<p>Deployment quality affects reliability directly. Treat startup, shutdown, logs, configuration, and health checks as part of the app contract.</p>

<hr />

<p><strong>Next Article:</strong> CI/CD with GitHub Actions for .NET: Build, Test, Publish, Secrets, and Environments</p>]]></content><author><name>Santosh Kumar Singh</name><email>santoshkumar.singh@aristocrat.com</email><uri>https://www.aristocrat.com/</uri></author><category term="dotnet" /><category term="aspnetcore" /><category term="docker" /><category term="linux" /><category term="deployment" /><category term="advanced" /><summary type="html"><![CDATA[This post covers practical deployment patterns for ASP.NET Core apps: Docker images, Linux hosting, reverse proxies such as Nginx, and health checks. Deployment is part of application design. An app that cannot start, stop, report health, and receive traffic cleanly is not production-ready.]]></summary></entry><entry><title type="html">gRPC in .NET: Contracts, Streaming, and Interop</title><link href="https://www.singhsk.com/posts/2026/03/grpc_in_dotnet/" rel="alternate" type="text/html" title="gRPC in .NET: Contracts, Streaming, and Interop" /><published>2026-03-28T00:00:00+00:00</published><updated>2026-03-28T00:00:00+00:00</updated><id>https://www.singhsk.com/posts/2026/03/grpc_in_dotnet</id><content type="html" xml:base="https://www.singhsk.com/posts/2026/03/grpc_in_dotnet/"><![CDATA[<p>This post introduces gRPC in .NET: <strong>contract-first service definitions, generated clients, streaming calls, and interop considerations</strong>. REST and JSON are still excellent for many APIs, but gRPC is useful when strongly typed contracts and efficient service-to-service communication matter.</p>

<h2 id="what-grpc-is">What gRPC is</h2>
<p>gRPC is a remote procedure call framework that commonly uses:</p>
<ul>
  <li>Protocol Buffers for contracts and serialization</li>
  <li>HTTP/2 as the transport</li>
  <li>generated clients and server base classes</li>
  <li>unary and streaming communication patterns</li>
</ul>

<p>It is a good fit for:</p>
<ul>
  <li>internal service-to-service calls</li>
  <li>low-latency APIs</li>
  <li>strongly typed contracts</li>
  <li>streaming scenarios</li>
</ul>

<p>It is not always the best fit for public browser APIs unless you use gRPC-Web and account for ecosystem constraints.</p>

<h2 id="defining-a-contract">Defining a contract</h2>
<p>Contracts live in <code class="language-plaintext highlighter-rouge">.proto</code> files.</p>

<div class="language-proto highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">syntax</span> <span class="o">=</span> <span class="s">"proto3"</span><span class="p">;</span>

<span class="k">option</span> <span class="na">csharp_namespace</span> <span class="o">=</span> <span class="s">"Store.Grpc"</span><span class="p">;</span>

<span class="kd">service</span> <span class="n">ProductCatalog</span> <span class="p">{</span>
  <span class="k">rpc</span> <span class="n">GetProduct</span> <span class="p">(</span><span class="n">GetProductRequest</span><span class="p">)</span> <span class="k">returns</span> <span class="p">(</span><span class="n">ProductReply</span><span class="p">);</span>
<span class="p">}</span>

<span class="kd">message</span> <span class="nc">GetProductRequest</span> <span class="p">{</span>
  <span class="kt">int32</span> <span class="na">id</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">message</span> <span class="nc">ProductReply</span> <span class="p">{</span>
  <span class="kt">int32</span> <span class="na">id</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
  <span class="kt">string</span> <span class="na">name</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
  <span class="kt">double</span> <span class="na">price</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The field numbers are part of the wire contract. Do not reuse them casually.</p>

<h2 id="server-implementation">Server implementation</h2>
<p>.NET generates a base class from the <code class="language-plaintext highlighter-rouge">.proto</code> file.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">ProductCatalogService</span> <span class="p">:</span> <span class="n">ProductCatalog</span><span class="p">.</span><span class="n">ProductCatalogBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">ProductReply</span><span class="p">&gt;</span> <span class="nf">GetProduct</span><span class="p">(</span>
        <span class="n">GetProductRequest</span> <span class="n">request</span><span class="p">,</span>
        <span class="n">ServerCallContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">Task</span><span class="p">.</span><span class="nf">FromResult</span><span class="p">(</span><span class="k">new</span> <span class="n">ProductReply</span>
        <span class="p">{</span>
            <span class="n">Id</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span>
            <span class="n">Name</span> <span class="p">=</span> <span class="s">"Mechanical Keyboard"</span><span class="p">,</span>
            <span class="n">Price</span> <span class="p">=</span> <span class="m">129.00</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Register gRPC:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddGrpc</span><span class="p">();</span>

<span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span>

<span class="n">app</span><span class="p">.</span><span class="n">MapGrpcService</span><span class="p">&lt;</span><span class="n">ProductCatalogService</span><span class="p">&gt;();</span>
</code></pre></div></div>

<h2 id="client-usage">Client usage</h2>
<p>Generated clients make calls strongly typed.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">channel</span> <span class="p">=</span> <span class="n">GrpcChannel</span><span class="p">.</span><span class="nf">ForAddress</span><span class="p">(</span><span class="s">"https://localhost:5001"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">client</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ProductCatalog</span><span class="p">.</span><span class="nf">ProductCatalogClient</span><span class="p">(</span><span class="n">channel</span><span class="p">);</span>

<span class="kt">var</span> <span class="n">product</span> <span class="p">=</span> <span class="k">await</span> <span class="n">client</span><span class="p">.</span><span class="nf">GetProductAsync</span><span class="p">(</span><span class="k">new</span> <span class="n">GetProductRequest</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">42</span> <span class="p">});</span>
</code></pre></div></div>

<p>In real applications, configure gRPC clients through DI rather than constructing channels everywhere.</p>

<h2 id="streaming">Streaming</h2>
<p>gRPC supports:</p>
<ul>
  <li>unary calls</li>
  <li>server streaming</li>
  <li>client streaming</li>
  <li>bidirectional streaming</li>
</ul>

<p>Server streaming example:</p>

<div class="language-proto highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">rpc</span> <span class="n">StreamProducts</span> <span class="p">(</span><span class="n">StreamProductsRequest</span><span class="p">)</span> <span class="k">returns</span> <span class="p">(</span><span class="n">stream</span> <span class="n">ProductReply</span><span class="p">);</span>
</code></pre></div></div>

<p>Implementation concept:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">StreamProducts</span><span class="p">(</span>
    <span class="n">StreamProductsRequest</span> <span class="n">request</span><span class="p">,</span>
    <span class="n">IServerStreamWriter</span><span class="p">&lt;</span><span class="n">ProductReply</span><span class="p">&gt;</span> <span class="n">responseStream</span><span class="p">,</span>
    <span class="n">ServerCallContext</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">await</span> <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">product</span> <span class="k">in</span> <span class="n">productService</span><span class="p">.</span><span class="nf">GetProductsAsync</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">CancellationToken</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">await</span> <span class="n">responseStream</span><span class="p">.</span><span class="nf">WriteAsync</span><span class="p">(</span><span class="k">new</span> <span class="n">ProductReply</span>
        <span class="p">{</span>
            <span class="n">Id</span> <span class="p">=</span> <span class="n">product</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span>
            <span class="n">Name</span> <span class="p">=</span> <span class="n">product</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
            <span class="n">Price</span> <span class="p">=</span> <span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="n">product</span><span class="p">.</span><span class="n">Price</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Streaming is useful when data arrives over time or when a response is too large to buffer comfortably.</p>

<h2 id="interop-considerations">Interop considerations</h2>
<p>Think about:</p>
<ul>
  <li>HTTP/2 support in hosting infrastructure</li>
  <li>load balancer and reverse proxy configuration</li>
  <li>gRPC-Web for browser clients</li>
  <li>versioning <code class="language-plaintext highlighter-rouge">.proto</code> files carefully</li>
  <li>deadlines and cancellation</li>
</ul>

<h2 id="common-mistakes-to-avoid">Common mistakes to avoid</h2>
<p>Watch for these issues:</p>
<ul>
  <li>using gRPC for public APIs when simple REST would be easier</li>
  <li>changing field numbers in <code class="language-plaintext highlighter-rouge">.proto</code> files</li>
  <li>ignoring deadlines and cancellation</li>
  <li>exposing internal domain models directly as generated contracts</li>
  <li>forgetting infrastructure requirements for HTTP/2</li>
</ul>

<p>gRPC is a strong tool for typed service communication. Use it when its contract and streaming model simplify the system, not just because it is faster on paper.</p>

<hr />

<p><strong>Next Article:</strong> Deploying ASP.NET Core Apps: Docker, Linux Hosting, Nginx, and Health Checks</p>]]></content><author><name>Santosh Kumar Singh</name><email>santoshkumar.singh@aristocrat.com</email><uri>https://www.aristocrat.com/</uri></author><category term="dotnet" /><category term="grpc" /><category term="aspnetcore" /><category term="api" /><category term="advanced" /><summary type="html"><![CDATA[This post introduces gRPC in .NET: contract-first service definitions, generated clients, streaming calls, and interop considerations. REST and JSON are still excellent for many APIs, but gRPC is useful when strongly typed contracts and efficient service-to-service communication matter.]]></summary></entry><entry><title type="html">Security Deep Dive for .NET APIs: OWASP, Rate Limiting, Headers, and CORS</title><link href="https://www.singhsk.com/posts/2026/03/security_deep_dive_dotnet_apis/" rel="alternate" type="text/html" title="Security Deep Dive for .NET APIs: OWASP, Rate Limiting, Headers, and CORS" /><published>2026-03-27T00:00:00+00:00</published><updated>2026-03-27T00:00:00+00:00</updated><id>https://www.singhsk.com/posts/2026/03/security_deep_dive_dotnet_apis</id><content type="html" xml:base="https://www.singhsk.com/posts/2026/03/security_deep_dive_dotnet_apis/"><![CDATA[<p>This post covers practical security controls for ASP.NET Core APIs: <strong>OWASP API risks, rate limiting, security headers, CORS, authentication, authorization, and input handling</strong>. Security is not one feature. It is a set of controls that reduce the chance and impact of abuse.</p>

<h2 id="owasp-api-risks">OWASP API risks</h2>
<p>The OWASP API Security Top 10 highlights common API failure modes. Examples include:</p>
<ul>
  <li>broken object-level authorization</li>
  <li>broken authentication</li>
  <li>excessive data exposure</li>
  <li>unrestricted resource consumption</li>
  <li>broken function-level authorization</li>
  <li>unsafe consumption of third-party APIs</li>
</ul>

<p>For .NET APIs, the practical response is:</p>
<ul>
  <li>authorize access to each resource</li>
  <li>validate inputs</li>
  <li>avoid exposing entity models directly</li>
  <li>limit request sizes and rates</li>
  <li>log security-relevant failures</li>
  <li>keep dependencies updated</li>
</ul>

<h2 id="object-level-authorization">Object-level authorization</h2>
<p>A common bug is checking that a user is authenticated but not checking that they can access the specific record.</p>

<p>Bad:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">Authorize</span><span class="p">]</span>
<span class="p">[</span><span class="nf">HttpGet</span><span class="p">(</span><span class="s">"orders/{id:int}"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">IActionResult</span><span class="p">&gt;</span> <span class="nf">GetOrder</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="nf">Ok</span><span class="p">(</span><span class="k">await</span> <span class="n">repository</span><span class="p">.</span><span class="nf">GetByIdAsync</span><span class="p">(</span><span class="n">id</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Better:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">order</span> <span class="p">=</span> <span class="k">await</span> <span class="n">repository</span><span class="p">.</span><span class="nf">GetByIdAsync</span><span class="p">(</span><span class="n">id</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">order</span> <span class="k">is</span> <span class="k">null</span><span class="p">)</span>
    <span class="k">return</span> <span class="nf">NotFound</span><span class="p">();</span>

<span class="k">if</span> <span class="p">(</span><span class="n">order</span><span class="p">.</span><span class="n">CustomerId</span> <span class="p">!=</span> <span class="n">currentUser</span><span class="p">.</span><span class="n">CustomerId</span><span class="p">)</span>
    <span class="k">return</span> <span class="nf">Forbid</span><span class="p">();</span>

<span class="k">return</span> <span class="nf">Ok</span><span class="p">(</span><span class="n">order</span><span class="p">);</span>
</code></pre></div></div>

<p>Authentication is not enough. Resource access must be checked.</p>

<h2 id="rate-limiting">Rate limiting</h2>
<p>Rate limiting protects APIs from abusive or accidental high-volume traffic.</p>

<p>Example:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddRateLimiter</span><span class="p">(</span><span class="n">options</span> <span class="p">=&gt;</span>
<span class="p">{</span>
    <span class="n">options</span><span class="p">.</span><span class="nf">AddFixedWindowLimiter</span><span class="p">(</span><span class="s">"api"</span><span class="p">,</span> <span class="n">limiter</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">limiter</span><span class="p">.</span><span class="n">PermitLimit</span> <span class="p">=</span> <span class="m">100</span><span class="p">;</span>
        <span class="n">limiter</span><span class="p">.</span><span class="n">Window</span> <span class="p">=</span> <span class="n">TimeSpan</span><span class="p">.</span><span class="nf">FromMinutes</span><span class="p">(</span><span class="m">1</span><span class="p">);</span>
    <span class="p">});</span>
<span class="p">});</span>

<span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span>

<span class="n">app</span><span class="p">.</span><span class="nf">UseRateLimiter</span><span class="p">();</span>

<span class="n">app</span><span class="p">.</span><span class="nf">MapGet</span><span class="p">(</span><span class="s">"/api/products"</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="n">Results</span><span class="p">.</span><span class="nf">Ok</span><span class="p">())</span>
   <span class="p">.</span><span class="nf">RequireRateLimiting</span><span class="p">(</span><span class="s">"api"</span><span class="p">);</span>
</code></pre></div></div>

<p>Rate limiting is especially important for:</p>
<ul>
  <li>login endpoints</li>
  <li>expensive search endpoints</li>
  <li>public APIs</li>
  <li>endpoints that trigger external calls</li>
</ul>

<h2 id="cors">CORS</h2>
<p>CORS controls which browser origins can call your API. It is not an authentication system.</p>

<p>Example:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddCors</span><span class="p">(</span><span class="n">options</span> <span class="p">=&gt;</span>
<span class="p">{</span>
    <span class="n">options</span><span class="p">.</span><span class="nf">AddPolicy</span><span class="p">(</span><span class="s">"frontend"</span><span class="p">,</span> <span class="n">policy</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">policy</span>
            <span class="p">.</span><span class="nf">WithOrigins</span><span class="p">(</span><span class="s">"https://app.example.com"</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">AllowAnyHeader</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">AllowAnyMethod</span><span class="p">();</span>
    <span class="p">});</span>
<span class="p">});</span>

<span class="n">app</span><span class="p">.</span><span class="nf">UseCors</span><span class="p">(</span><span class="s">"frontend"</span><span class="p">);</span>
</code></pre></div></div>

<p>Avoid:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">.</span><span class="nf">AllowAnyOrigin</span><span class="p">()</span>
<span class="p">.</span><span class="nf">AllowAnyHeader</span><span class="p">()</span>
<span class="p">.</span><span class="nf">AllowAnyMethod</span><span class="p">()</span>
</code></pre></div></div>

<p>That may be acceptable for a local prototype, but it is usually too broad for production.</p>

<h2 id="security-headers">Security headers</h2>
<p>APIs and web apps benefit from security headers.</p>

<p>Common headers:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">Strict-Transport-Security</code></li>
  <li><code class="language-plaintext highlighter-rouge">X-Content-Type-Options</code></li>
  <li><code class="language-plaintext highlighter-rouge">Content-Security-Policy</code></li>
  <li><code class="language-plaintext highlighter-rouge">Referrer-Policy</code></li>
</ul>

<p>Example middleware:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">app</span><span class="p">.</span><span class="nf">Use</span><span class="p">(</span><span class="k">async</span> <span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">next</span><span class="p">)</span> <span class="p">=&gt;</span>
<span class="p">{</span>
    <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">Headers</span><span class="p">[</span><span class="s">"X-Content-Type-Options"</span><span class="p">]</span> <span class="p">=</span> <span class="s">"nosniff"</span><span class="p">;</span>
    <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">Headers</span><span class="p">[</span><span class="s">"Referrer-Policy"</span><span class="p">]</span> <span class="p">=</span> <span class="s">"no-referrer"</span><span class="p">;</span>
    <span class="k">await</span> <span class="nf">next</span><span class="p">();</span>
<span class="p">});</span>
</code></pre></div></div>

<p>For browser-facing apps, Content Security Policy deserves careful design and testing.</p>

<h2 id="input-and-output-safety">Input and output safety</h2>
<p>Use request DTOs and response DTOs. Avoid binding directly to EF Core entities.</p>

<p>Why:</p>
<ul>
  <li>prevents over-posting</li>
  <li>prevents leaking internal fields</li>
  <li>keeps public contracts stable</li>
  <li>makes validation explicit</li>
</ul>

<p>Example:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">record</span> <span class="nc">UpdateUserRequest</span><span class="p">(</span><span class="kt">string</span> <span class="n">DisplayName</span><span class="p">);</span>
<span class="k">public</span> <span class="k">sealed</span> <span class="k">record</span> <span class="nc">UserResponse</span><span class="p">(</span><span class="kt">int</span> <span class="n">Id</span><span class="p">,</span> <span class="kt">string</span> <span class="n">DisplayName</span><span class="p">);</span>
</code></pre></div></div>

<h2 id="common-mistakes-to-avoid">Common mistakes to avoid</h2>
<p>Watch for these issues:</p>
<ul>
  <li>trusting client-side validation</li>
  <li>using CORS as a security boundary</li>
  <li>authorizing by role only when resource ownership matters</li>
  <li>logging tokens or passwords</li>
  <li>exposing internal entity fields in API responses</li>
  <li>leaving expensive endpoints without limits</li>
</ul>

<p>API security is a set of repeated habits. Authentication gets users in the door, but authorization, validation, limits, and observability keep the system defensible.</p>

<hr />

<p><strong>Next Article:</strong> gRPC in .NET: Contracts, Streaming, and Interop</p>]]></content><author><name>Santosh Kumar Singh</name><email>santoshkumar.singh@aristocrat.com</email><uri>https://www.aristocrat.com/</uri></author><category term="dotnet" /><category term="aspnetcore" /><category term="security" /><category term="owasp" /><category term="advanced" /><summary type="html"><![CDATA[This post covers practical security controls for ASP.NET Core APIs: OWASP API risks, rate limiting, security headers, CORS, authentication, authorization, and input handling. Security is not one feature. It is a set of controls that reduce the chance and impact of abuse.]]></summary></entry><entry><title type="html">Performance Tuning in .NET: Kestrel, GC, Allocations, and BenchmarkDotNet</title><link href="https://www.singhsk.com/posts/2026/03/performance_tuning_dotnet/" rel="alternate" type="text/html" title="Performance Tuning in .NET: Kestrel, GC, Allocations, and BenchmarkDotNet" /><published>2026-03-26T00:00:00+00:00</published><updated>2026-03-26T00:00:00+00:00</updated><id>https://www.singhsk.com/posts/2026/03/performance_tuning_dotnet</id><content type="html" xml:base="https://www.singhsk.com/posts/2026/03/performance_tuning_dotnet/"><![CDATA[<p>This post covers practical performance tuning in .NET: <strong>Kestrel configuration, garbage collection, allocation reduction, and benchmarking with BenchmarkDotNet</strong>. Performance work should start with measurement. Guessing usually leads to busy code that is not actually faster.</p>

<h2 id="start-with-measurement">Start with measurement</h2>
<p>Before changing code, answer:</p>
<ul>
  <li>which endpoint is slow</li>
  <li>what latency percentile matters</li>
  <li>whether CPU, memory, I/O, or locking is the bottleneck</li>
  <li>whether the database or a downstream service dominates time</li>
</ul>

<p>Useful tools:</p>
<ul>
  <li>application metrics</li>
  <li>OpenTelemetry traces</li>
  <li><code class="language-plaintext highlighter-rouge">dotnet-counters</code></li>
  <li><code class="language-plaintext highlighter-rouge">dotnet-trace</code></li>
  <li>load testing tools</li>
  <li>BenchmarkDotNet for isolated code paths</li>
</ul>

<p>Do not optimize a method because it looks inefficient. Optimize because evidence shows it matters.</p>

<h2 id="kestrel-basics">Kestrel basics</h2>
<p>Kestrel is the cross-platform web server used by ASP.NET Core.</p>

<p>Example configuration:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">builder</span><span class="p">.</span><span class="n">WebHost</span><span class="p">.</span><span class="nf">ConfigureKestrel</span><span class="p">(</span><span class="n">options</span> <span class="p">=&gt;</span>
<span class="p">{</span>
    <span class="n">options</span><span class="p">.</span><span class="n">Limits</span><span class="p">.</span><span class="n">MaxRequestBodySize</span> <span class="p">=</span> <span class="m">10</span> <span class="p">*</span> <span class="m">1024</span> <span class="p">*</span> <span class="m">1024</span><span class="p">;</span>
    <span class="n">options</span><span class="p">.</span><span class="n">Limits</span><span class="p">.</span><span class="n">KeepAliveTimeout</span> <span class="p">=</span> <span class="n">TimeSpan</span><span class="p">.</span><span class="nf">FromMinutes</span><span class="p">(</span><span class="m">2</span><span class="p">);</span>
    <span class="n">options</span><span class="p">.</span><span class="n">Limits</span><span class="p">.</span><span class="n">RequestHeadersTimeout</span> <span class="p">=</span> <span class="n">TimeSpan</span><span class="p">.</span><span class="nf">FromSeconds</span><span class="p">(</span><span class="m">30</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div></div>

<p>Tune Kestrel when:</p>
<ul>
  <li>request sizes need strict limits</li>
  <li>slow clients are tying up resources</li>
  <li>reverse proxy behavior requires alignment</li>
  <li>you need explicit endpoint configuration</li>
</ul>

<p>Many apps should keep default Kestrel settings until measurements justify changes.</p>

<h2 id="garbage-collection">Garbage collection</h2>
<p>.NET has a highly optimized garbage collector, but allocation-heavy code still creates pressure.</p>

<p>Signs of allocation problems:</p>
<ul>
  <li>high Gen 0/Gen 1 collection rate</li>
  <li>large object heap growth</li>
  <li>memory spikes during load</li>
  <li>CPU spent in GC</li>
</ul>

<p>Use <code class="language-plaintext highlighter-rouge">dotnet-counters</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet-counters monitor <span class="nt">--process-id</span> 12345 System.Runtime
</code></pre></div></div>

<p>Watch counters such as:</p>
<ul>
  <li>GC heap size</li>
  <li>allocation rate</li>
  <li>Gen 0/1/2 collection counts</li>
  <li>thread pool queue length</li>
</ul>

<h2 id="reducing-allocations">Reducing allocations</h2>
<p>Allocation reduction is most useful in hot paths.</p>

<p>Common improvements:</p>
<ul>
  <li>avoid repeated string concatenation in loops</li>
  <li>use streaming instead of buffering large payloads</li>
  <li>project only needed data from EF Core</li>
  <li>avoid unnecessary LINQ in extremely hot loops</li>
  <li>reuse expensive objects where safe</li>
</ul>

<p>Example:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StringBuilder</span><span class="p">();</span>

<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">item</span> <span class="k">in</span> <span class="n">items</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">builder</span><span class="p">.</span><span class="nf">Append</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">Code</span><span class="p">);</span>
    <span class="n">builder</span><span class="p">.</span><span class="nf">Append</span><span class="p">(</span><span class="sc">','</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">ToString</span><span class="p">();</span>
</code></pre></div></div>

<p>Do not make code unreadable to avoid tiny allocations that do not matter. Keep optimization proportional to the measured cost.</p>

<h2 id="benchmarkdotnet">BenchmarkDotNet</h2>
<p>BenchmarkDotNet is the standard .NET library for microbenchmarks.</p>

<p>Install:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet add package BenchmarkDotNet
</code></pre></div></div>

<p>Benchmark:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">MemoryDiagnoser</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SlugBenchmarks</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="kt">string</span> <span class="n">_title</span> <span class="p">=</span> <span class="s">"Performance Tuning in .NET"</span><span class="p">;</span>

    <span class="p">[</span><span class="n">Benchmark</span><span class="p">]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="nf">ReplaceSpaces</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_title</span><span class="p">.</span><span class="nf">ToLowerInvariant</span><span class="p">().</span><span class="nf">Replace</span><span class="p">(</span><span class="s">" "</span><span class="p">,</span> <span class="s">"-"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Run:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">BenchmarkRunner</span><span class="p">.</span><span class="n">Run</span><span class="p">&lt;</span><span class="n">SlugBenchmarks</span><span class="p">&gt;();</span>
</code></pre></div></div>

<p>Use BenchmarkDotNet for isolated algorithms and utility code. It does not replace end-to-end load tests.</p>

<h2 id="performance-checklist-for-apis">Performance checklist for APIs</h2>
<p>A practical API tuning checklist:</p>
<ul>
  <li>use pagination for lists</li>
  <li>avoid over-fetching data</li>
  <li>use <code class="language-plaintext highlighter-rouge">AsNoTracking</code> for read-only EF Core queries</li>
  <li>set downstream timeouts</li>
  <li>compress responses where appropriate</li>
  <li>cache expensive read models carefully</li>
  <li>measure p95 and p99 latency, not just averages</li>
</ul>

<h2 id="common-mistakes-to-avoid">Common mistakes to avoid</h2>
<p>Watch for these issues:</p>
<ul>
  <li>optimizing without production-like data</li>
  <li>using microbenchmarks to make claims about whole-system performance</li>
  <li>ignoring database indexes</li>
  <li>returning unbounded result sets</li>
  <li>treating GC as the problem before checking allocation behavior</li>
</ul>

<p>Performance tuning is disciplined measurement followed by focused changes. The best optimization is often changing what work the app does, not making unnecessary work slightly faster.</p>

<hr />

<p><strong>Next Article:</strong> Security Deep Dive for .NET APIs: OWASP, Rate Limiting, Headers, and CORS</p>]]></content><author><name>Santosh Kumar Singh</name><email>santoshkumar.singh@aristocrat.com</email><uri>https://www.aristocrat.com/</uri></author><category term="dotnet" /><category term="performance" /><category term="kestrel" /><category term="benchmarkdotnet" /><category term="advanced" /><summary type="html"><![CDATA[This post covers practical performance tuning in .NET: Kestrel configuration, garbage collection, allocation reduction, and benchmarking with BenchmarkDotNet. Performance work should start with measurement. Guessing usually leads to busy code that is not actually faster.]]></summary></entry></feed>