<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Supratim Roy</title>
    <description>The latest articles on DEV Community by Supratim Roy (@supratim).</description>
    <link>https://dev.to/supratim</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2950239%2F90667095-a0d8-4cd2-9f72-1a03559a8ccf.png</url>
      <title>DEV Community: Supratim Roy</title>
      <link>https://dev.to/supratim</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/supratim"/>
    <language>en</language>
    <item>
      <title>The One-Time Pad: The Only Truly Unbreakable Encryption</title>
      <dc:creator>Supratim Roy</dc:creator>
      <pubDate>Tue, 25 Mar 2025 19:53:43 +0000</pubDate>
      <link>https://dev.to/supratim/the-one-time-pad-the-only-truly-unbreakable-encryption-40f2</link>
      <guid>https://dev.to/supratim/the-one-time-pad-the-only-truly-unbreakable-encryption-40f2</guid>
      <description>&lt;p&gt;A classical cipher cannot be truly secure unless it uses an extremely large key, but using such a key is impractical. However, the one-time pad is an exception — it is the most secure cipher available. It guarantees perfect secrecy, meaning that even if an attacker has unlimited computing power, they cannot extract any information about the plaintext except its length.&lt;/p&gt;

&lt;p&gt;Although the one-time pad is not practical for everyday use, understanding why it is secure is important. In the 1940s, American mathematician Claude Shannon proved that for a cipher to achieve perfect secrecy, its key must be at least as long as the message. The reasoning behind this is straightforward:&lt;/p&gt;

&lt;p&gt;If an attacker had unlimited computing power, they could try all possible keys. However, a properly used one-time pad ensures that every possible plaintext remains equally likely, making it impossible to determine the original message from the ciphertext. &lt;/p&gt;

&lt;h2&gt;
  
  
  Example:
&lt;/h2&gt;

&lt;p&gt;Plaintext Message: HELLO&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Convert the plaintext to numbers&lt;/strong&gt;&lt;br&gt;
We'll use a simple substitution where A=0, B=1, ..., Z=25. So:&lt;/p&gt;

&lt;p&gt;H = 7&lt;br&gt;
E = 4&lt;br&gt;
L = 11&lt;br&gt;
L = 11&lt;br&gt;
O = 14&lt;br&gt;
Plaintext as numbers: 7, 4, 11, 11, 14&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Generate a random key (one-time pad)&lt;/strong&gt;&lt;br&gt;
The key must be the same length as the message (5 characters in this case) and completely random. Let’s say the key is: KXQWZ&lt;/p&gt;

&lt;p&gt;Convert the key to numbers:&lt;/p&gt;

&lt;p&gt;K = 10&lt;br&gt;
X = 23&lt;br&gt;
Q = 16&lt;br&gt;
W = 22&lt;br&gt;
Z = 25&lt;br&gt;
Key as numbers: 10, 23, 16, 22, 25&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Encrypt the message&lt;/strong&gt;&lt;br&gt;
Encryption is done by adding the plaintext numbers and key numbers modulo 26 (since there are 26 letters in the alphabet):&lt;/p&gt;

&lt;p&gt;H (7) + K (10) = 17 mod 26 = 17 (R)&lt;br&gt;
E (4) + X (23) = 27 mod 26 = 1 (B)&lt;br&gt;
L (11) + Q (16) = 27 mod 26 = 1 (B)&lt;br&gt;
L (11) + W (22) = 33 mod 26 = 7 (H)&lt;br&gt;
O (14) + Z (25) = 39 mod 26 = 13 (N)&lt;br&gt;
Ciphertext as numbers: 17, 1, 1, 7, 13&lt;/p&gt;

&lt;p&gt;Ciphertext as letters: RBBHN&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Decrypt the message&lt;/strong&gt;&lt;br&gt;
To decrypt, the recipient (who also has the one-time pad KXQWZ) subtracts the key numbers from the ciphertext numbers (mod 26):&lt;/p&gt;

&lt;p&gt;R (17) - K (10) = 7 mod 26 = 7 (H)&lt;br&gt;
B (1) - X (23) = -22 mod 26 = 4 (E)&lt;br&gt;
(Note: -22 + 26 = 4)&lt;br&gt;
B (1) - Q (16) = -15 mod 26 = 11 (L)&lt;br&gt;
(Note: -15 + 26 = 11)&lt;br&gt;
H (7) - W (22) = -15 mod 26 = 11 (L)&lt;br&gt;
N (13) - Z (25) = -12 mod 26 = 14 (O)&lt;br&gt;
(Note: -12 + 26 = 14)&lt;br&gt;
Decrypted numbers: 7, 4, 11, 11, 14&lt;/p&gt;

&lt;p&gt;Decrypted message: HELLO&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is it Impossible to Break?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Randomness of the Key:&lt;/strong&gt; The key used in an One-Time Pad must be truly random, as long as the message, and never reused. If the key is random, then every possible plaintext is equally likely, making it impossible for an attacker to determine the actual message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Length Equals Message Length:&lt;/strong&gt; Since the key is the same length as the message, every bit of plaintext is masked by a different bit of the key.
This ensures that no patterns exist in the ciphertext that could reveal information about the plaintext.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unbreakability by Frequency Analysis:&lt;/strong&gt; In conventional ciphers, letter frequencies or patterns can help break encryption. Since One-Time Pad keys are random, the ciphertext has no statistical relationship with the plaintext, making frequency analysis useless.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mathematical Proof of Perfect Secrecy:&lt;/strong&gt; According to Claude Shannon's proof, One-Time Pad satisfies perfect secrecy because:
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;P(Plaintext | Ciphertext) = P(Plaintext)&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;This means knowing the ciphertext does not change the probability of any given plaintext. No amount of computing power can reduce the uncertainty of the plaintext.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resistance to Brute-Force Attacks:&lt;/strong&gt; Trying all possible keys in a brute-force attack yields all possible plaintexts with equal probability.
Since there’s no way to determine which one is correct, the attacker gains zero useful information.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations of One-Time Pad:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Key Management:&lt;/strong&gt; Securely generating, distributing, and storing long, random keys is impractical.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Reuse Weakens Security:&lt;/strong&gt; If a key is reused, an attacker can compare multiple ciphertexts to extract information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;True Randomness:&lt;/strong&gt; Pseudorandom number generators (PRNGs) do not provide the required randomness.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;When used correctly—with truly random, single-use keys—the one-time pad is unbreakable. However, its impractical key management makes it unsuitable for most applications. Since the key must be as long as the message and never reused, encrypting a 1TB drive requires another 1TB drive for the key. Despite this, it has been historically used by British SOE in WWII, Soviet spies, and the NSA, and remains in use for specific purposes today.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building Resilient Apps: Health Checks in ASP.NET Core</title>
      <dc:creator>Supratim Roy</dc:creator>
      <pubDate>Tue, 18 Mar 2025 14:29:05 +0000</pubDate>
      <link>https://dev.to/supratim/building-resilient-apps-health-checks-in-aspnet-core-p5</link>
      <guid>https://dev.to/supratim/building-resilient-apps-health-checks-in-aspnet-core-p5</guid>
      <description>&lt;p&gt;In today’s fast-paced digital world, application reliability is critical. A single failure in a database, external API, or caching service can impact performance and lead to downtime. Health checks in ASP.NET Core help monitor the status of your app and its dependencies, ensuring smooth operation and proactive issue detection. They provide a simple way to check system health, notify monitoring tools, and even help with load balancing in cloud environments.&lt;/p&gt;

&lt;p&gt;In this post, we'll explore how to implement health checks in ASP.NET Core to keep your application running smoothly and resilient against failures.&lt;/p&gt;

&lt;p&gt;In ASP.NET Core, you can implement health checks using the built-in &lt;code&gt;Microsoft.AspNetCore.Diagnostics.HealthChecks&lt;/code&gt; middleware. Health checks help monitor the status of your application and its dependencies (like databases, external APIs, etc.).&lt;/p&gt;

&lt;p&gt;ASP.NET Core has built-in support for health checks, but if you need UI support or database checks, install additional packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package AspNetCore.HealthChecks.UI
dotnet add package AspNetCore.HealthChecks.UI.Client
dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, add the health checks middleware in your &lt;code&gt;Program.cs&lt;/code&gt; (for .NET 6+) or &lt;code&gt;Startup.cs&lt;/code&gt; (older versions):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Program.cs&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Add health checks&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddHealthChecks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;span class="c1"&gt;// Add health check endpoint&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseHealthChecks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/health"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;For a more detailed implementation with specific checks, here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Program.cs&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Add health checks with specific checks&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddHealthChecks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMemoryHealthCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"memory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximumMemoryBytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;104857600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 100MB&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDiskStorageHealthCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDrive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C:\\"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minimumFreeMegabytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// 1GB free&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddUrlGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.example.com"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"external-api-check"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;span class="c1"&gt;// Configure health check endpoint with response&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseHealthChecks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;HealthCheckOptions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ResponseWriter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContentType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;checks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsJsonAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;To add custom health checks, create a class implementing &lt;code&gt;IHealthCheck&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomHealthCheck&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IHealthCheck&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HealthCheckResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CheckHealthAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;HealthCheckContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Your custom health check logic&lt;/span&gt;
        &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isHealthy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;CheckSomeCondition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;isHealthy&lt;/span&gt;
                &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;HealthCheckResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Healthy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"System is healthy"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HealthCheckResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Unhealthy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"System is unhealthy"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;CheckSomeCondition&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Implement your condition checking logic&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Register it in Program.cs&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddHealthChecks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddCheck&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CustomHealthCheck&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"custom_check"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also add health check UI (optional):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add NuGet package: AspNetCore.HealthChecks.UI&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddHealthChecksUI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddInMemoryStorage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseHealthChecksUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UIPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/health-ui"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Access at /health-ui&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Common Health Check Types You Can Add:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.AddSqlServer(connectionString)&lt;/code&gt; - SQL Server check&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.AddRedis(redisConnectionString)&lt;/code&gt; - Redis check&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.AddNpgSql(connectionString)&lt;/code&gt; - PostgreSQL check&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.AddMongoDb(mongodbConnectionString)&lt;/code&gt; - MongoDB check&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Usage Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IHealthCheckService&lt;/span&gt; &lt;span class="n"&gt;_healthCheckService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MyService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IHealthCheckService&lt;/span&gt; &lt;span class="n"&gt;healthCheckService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_healthCheckService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;healthCheckService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;CheckHealthAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_healthCheckService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CheckHealthAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;HealthStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Healthy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Handle healthy state&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Default endpoint is &lt;code&gt;/health&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Returns HTTP 200 for healthy, 503 for unhealthy&lt;/li&gt;
&lt;li&gt;Can be used with load balancers&lt;/li&gt;
&lt;li&gt;Supports dependency injection&lt;/li&gt;
&lt;li&gt;Can be secured with authorization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;To Test:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run your app&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;http://localhost:port/health&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For UI (if added): &lt;code&gt;http://localhost:port/health-ui&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Use Cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application monitoring&lt;/strong&gt;: Check database, cache, and API status.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load balancer health checks&lt;/strong&gt;: Route traffic only to healthy instances.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes readiness and liveness probes&lt;/strong&gt;: Ensure smooth deployments.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aspdotnetcore</category>
      <category>dotnet</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Efficient Thread Synchronization in .NET with SemaphoreSlim</title>
      <dc:creator>Supratim Roy</dc:creator>
      <pubDate>Tue, 18 Mar 2025 11:34:11 +0000</pubDate>
      <link>https://dev.to/supratim/efficient-thread-synchronization-in-net-with-semaphoreslim-1fcg</link>
      <guid>https://dev.to/supratim/efficient-thread-synchronization-in-net-with-semaphoreslim-1fcg</guid>
      <description>&lt;h2&gt;
  
  
  Why Do We Need Semaphores?
&lt;/h2&gt;

&lt;p&gt;Semaphores are used in programming to &lt;strong&gt;control access to shared resources&lt;/strong&gt; in multi-threaded environments. They prevent &lt;strong&gt;race conditions, deadlocks, and excessive resource usage&lt;/strong&gt;, ensuring smooth execution of concurrent processes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Reasons for Using Semaphores
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Preventing Race Conditions&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When multiple threads access a shared resource simultaneously, it can lead to &lt;strong&gt;inconsistent data&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semaphore&lt;/strong&gt; ensures that only a limited number of threads can access the resource at a time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: Multiple threads writing to a shared log file might corrupt the log.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Controlling Concurrent Access&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Semaphores &lt;strong&gt;limit the number of threads&lt;/strong&gt; that can execute a critical section at the same time.
&lt;/li&gt;
&lt;li&gt;Unlike a simple lock (&lt;code&gt;lock&lt;/code&gt; in C#), semaphores allow &lt;strong&gt;multiple&lt;/strong&gt; threads instead of just one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: A &lt;strong&gt;database connection pool&lt;/strong&gt; allowing only 5 concurrent connections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Avoiding Deadlocks&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When multiple threads wait indefinitely for a resource, it causes a &lt;strong&gt;deadlock&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Using a properly configured semaphore prevents such situations by &lt;strong&gt;restricting&lt;/strong&gt; entry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Managing Resource Usage&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some system resources are &lt;strong&gt;expensive&lt;/strong&gt; (like CPU, I/O, or memory).
&lt;/li&gt;
&lt;li&gt;Semaphores help &lt;strong&gt;optimize usage&lt;/strong&gt; by allowing only a few threads to access them at a time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;print server&lt;/strong&gt; that processes only 3 jobs simultaneously.
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;web scraper&lt;/strong&gt; that limits concurrent HTTP requests to avoid server overload.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Supporting Asynchronous Execution&lt;/strong&gt; (With &lt;code&gt;SemaphoreSlim&lt;/code&gt;)  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SemaphoreSlim&lt;/code&gt; is useful in &lt;strong&gt;async programming&lt;/strong&gt; to prevent excessive parallel execution while keeping the application responsive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;API rate limiter&lt;/strong&gt; allowing only 10 requests per second.
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;background task processor&lt;/strong&gt; handling multiple jobs efficiently.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is &lt;code&gt;SemaphoreSlim&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;SemaphoreSlim&lt;/code&gt; is a lightweight, managed version of &lt;code&gt;Semaphore&lt;/code&gt; in .NET that is designed for controlling access to a limited resource by multiple threads. It works similarly to &lt;code&gt;Semaphore&lt;/code&gt; but provides better performance in asynchronous scenarios.&lt;/p&gt;

&lt;p&gt;It is defined in the &lt;code&gt;System.Threading&lt;/code&gt; namespace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is &lt;code&gt;SemaphoreSlim&lt;/code&gt; Useful?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Limits Concurrent Access&lt;/strong&gt;: It ensures that only a fixed number of threads can access a critical section simultaneously. Useful when managing connections, file I/O, or shared resources like database calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimized for Asynchronous Programming&lt;/strong&gt;: Unlike &lt;code&gt;Semaphore&lt;/code&gt;, &lt;code&gt;SemaphoreSlim&lt;/code&gt; supports the &lt;code&gt;await&lt;/code&gt; pattern with &lt;code&gt;WaitAsync()&lt;/code&gt;, making it more efficient for &lt;code&gt;async/await&lt;/code&gt; workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More Lightweight than &lt;code&gt;Semaphore&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;SemaphoreSlim&lt;/code&gt; does not use kernel-mode objects, making it more performant for in-memory scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoids Lock Contention&lt;/strong&gt;: Instead of blocking a thread (like &lt;code&gt;lock&lt;/code&gt; or &lt;code&gt;Monitor&lt;/code&gt;), it allows waiting asynchronously, improving overall system responsiveness.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Example of &lt;code&gt;SemaphoreSlim&lt;/code&gt;:
&lt;/h2&gt;

&lt;p&gt;Here's a practical example showing how to use SemaphoreSlim to limit concurrent access to a resource (simulating 10 tasks trying to access a resource limited to 3 at a time):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Initialize SemaphoreSlim with 3 concurrent access slots&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;SemaphoreSlim&lt;/span&gt; &lt;span class="n"&gt;semaphore&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SemaphoreSlim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Create 10 tasks to simulate concurrent operations&lt;/span&gt;
        &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;taskNumber&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;DoWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;taskNumber&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WhenAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"All tasks completed!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;DoWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Task &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; waiting to enter..."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Wait to acquire the semaphore (blocks if 3 are already in use)&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Task &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; started processing"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="c1"&gt;// Simulate some work with random duration&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Task &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; completed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;finally&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Release the semaphore slot for other waiting tasks&lt;/span&gt;
            &lt;span class="n"&gt;semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;SemaphoreSlim(3)&lt;/code&gt; creates a semaphore allowing 3 concurrent entries&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WaitAsync()&lt;/code&gt; asynchronously waits for an available slot&lt;/li&gt;
&lt;li&gt;When a slot is available, the task enters and does its work&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Release()&lt;/code&gt; frees up the slot when the task is done&lt;/li&gt;
&lt;li&gt;Only 3 tasks can execute simultaneously; others wait their turn&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Sample output might look like:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Task 0 waiting to enter...
Task 1 waiting to enter...
Task 2 waiting to enter...
Task 0 started processing
Task 1 started processing
Task 2 started processing
Task 3 waiting to enter...
Task 4 waiting to enter...
[Task 0 completes]
Task 3 started processing
[Task 1 completes]
Task 4 started processing
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a thread-safe way to manage concurrent access while being more performant than the traditional Semaphore class, especially in async scenarios.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>multithreading</category>
      <category>asynchronousprogramming</category>
    </item>
    <item>
      <title>Modular Monolith: The Best of Both World</title>
      <dc:creator>Supratim Roy</dc:creator>
      <pubDate>Tue, 18 Mar 2025 07:28:21 +0000</pubDate>
      <link>https://dev.to/supratim/modular-monolith-the-best-of-both-world-37hc</link>
      <guid>https://dev.to/supratim/modular-monolith-the-best-of-both-world-37hc</guid>
      <description>&lt;p&gt;A Modular Monolith is an architectural style that blends the advantages of both traditional monolithic architectures and microservices. It structures a software application into distinct, loosely coupled modules, with each module handling a specific business capability. However, unlike microservices, these modules are not deployed independently; instead, they are packaged and deployed together as a single unit, like a monolith.&lt;/p&gt;

&lt;p&gt;The biggest advantage of a Modular Monolith is its ease of management. Unlike microservices, it does not require Kubernetes or other complex orchestration tools to handle multiple moving parts.&lt;/p&gt;

&lt;p&gt;While the application is monolithic in deployment, it is not a tangled "big ball of mud." Instead, it follows a modular structure, where each module functions like a mini-application with a well-defined responsibility. However, all modules are deployed together as a single unit. This approach makes the system both cost-effective and easy to manage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Architecture
&lt;/h2&gt;

&lt;p&gt;In a Modular Monolith architecture, the application is typically deployed as a single unit, which often leads to using a single database shared by all modules as shown in Figure 1. This approach minimizes inter-module communication since all data is centrally available.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhec3cid05lcer85mw5zu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhec3cid05lcer85mw5zu.jpg" alt=" " width="800" height="624"&gt;&lt;/a&gt;&lt;br&gt;
When using a single database, organizing data into separate schemas for each module can help isolate their data, improving maintainability and reducing unintended dependencies between modules.&lt;/p&gt;

&lt;p&gt;However, if the modules are designed to be independent and serve distinct business functions, they can also have separate databases that store only the data relevant to their specific context as shown in Figure 2. Even in this case, the overall architecture remains monolithic because all modules are deployed together as a single unit.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Module Communication
&lt;/h2&gt;

&lt;p&gt;In this architectural style, direct communication between modules is generally discouraged, though it often becomes necessary in practice. Below are two primary approaches to facilitate module communication, each with its own benefits and trade-offs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Peer-to-Peer Communication&lt;/strong&gt;&lt;br&gt;
The simplest approach is peer-to-peer communication, where modules interact directly with one another. Here, a class in one module instantiates a class from another module and calls its methods directly. While this method is straightforward to implement, it has a significant drawback: it tightly couples the modules. Excessive interconnections can erode modularity, leading to a tangled architecture, often leading to the "Big Ball of Mud" antipattern—a system that becomes increasingly difficult to manage and scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aggregator Pattern&lt;/strong&gt;&lt;br&gt;
A more structured alternative is the aggregator pattern, which introduces an aggregator component as an intermediary layer between modules. Rather than communicating directly, modules send requests to the aggregator, which then routes them to the appropriate destination module.&lt;/p&gt;

&lt;p&gt;This approach reduces direct dependencies, enhancing modularity and maintainability. However, while it decouples modules from one another, each module still relies on the aggregator. Although this does not eliminate all coupling, it simplifies the architecture and enforces a controlled, centralized communication structure.&lt;/p&gt;

&lt;p&gt;Importantly, the aggregator—not the dependent modules—should provide an API for accessing functionality in other modules. This design keeps modules loosely coupled and preserves a clear separation of concerns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Here is a typical Modular Monolith example. The solution, named &lt;code&gt;EcommerceApplication&lt;/code&gt;, is organized into distinct directories for clarity and modularity. The Applications directory houses deployable applications, such as the Aggregator project, which includes an API along with its associated &lt;code&gt;API.Contracts&lt;/code&gt; and &lt;code&gt;API.Tests&lt;/code&gt; projects. This directory is designed to accommodate additional deployable applications or user interface, each encapsulated within its own subdirectory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn14e87n4p36n1zdr1sxx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn14e87n4p36n1zdr1sxx.jpg" alt=" " width="651" height="847"&gt;&lt;/a&gt;&lt;br&gt;
The Modules directory contains modular components, each residing in a separate subdirectory. This includes &lt;code&gt;InventoryManagement&lt;/code&gt;, &lt;code&gt;OrderPlacement&lt;/code&gt;, and &lt;code&gt;PaymentProcessing&lt;/code&gt;, each with corresponding C# projects. These modules are further structured with Contracts projects that define API contracts and integration events. Additionally, each module includes a Tests project for unit and integration testing.&lt;/p&gt;

&lt;p&gt;This structure adheres to a traditional .NET convention, enabling the separation of API contracts into dedicated assembly projects. The Contracts projects not only define the API contracts but also house integration events. For a larger application, these could be further separated to enhance maintainability and scalability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Simpler Deployment&lt;/strong&gt;: Since it is a single application, you deploy a single artifact. This avoids the complexity of coordinating multiple services, as you would see in microservices, reducing operational overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier Debugging and Testing&lt;/strong&gt;: With everything in one codebase, tracing issues across modules is straightforward. You can run the entire system locally, making integration testing simpler compared to distributed systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Efficiency&lt;/strong&gt;: Modules communicate in-process (e.g., via function calls) rather than over a network, avoiding latency and serialization costs typical in microservices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared Resources&lt;/strong&gt;: Modules can share a single database, memory, or other resources without needing complex synchronization mechanisms, simplifying data consistency avoiding the need for distributed transactions or eventual consistency models.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gradual Evolution&lt;/strong&gt;: It is a middle ground between a traditional monolith and microservices. You can start with a modular monolith and later extract modules into separate services if needed, offering flexibility as requirements grow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Overhead&lt;/strong&gt;: No need for service discovery, API gateways, or distributed logging setups early on, which lowers initial development and infrastructure costs.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Disadvantages
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scalability Limits&lt;/strong&gt;: Unlike microservices, you cannot scale individual modules independently. The entire application scales as a unit, which can waste resources if only one module is under heavy load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coupling Risk&lt;/strong&gt;: While modules are intended to be loosely coupled, poor design can lead to tight dependencies, eroding modularity and bringing back the pitfalls of a traditional monolith (e.g., spaghetti code).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single Point of Failure&lt;/strong&gt;: If the monolith goes down, the entire system is affected. There is no isolation of failures as you would get with separate services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technology Lock-In&lt;/strong&gt;: All modules typically use the same tech stack. If one module would benefit from a different language or framework, you are constrained unless you refactor significantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment Bottlenecks&lt;/strong&gt;: Changes to one module require redeploying the whole application, which can slow down release cycles and increase the risk of introducing unrelated bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team Coordination&lt;/strong&gt;: As the codebase grows, multiple teams working on different modules can step on each other’s toes, especially if boundaries are not well-defined or enforced.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  When It Works Best
&lt;/h2&gt;

&lt;p&gt;A modular monolith shines for medium-sized applications where you want maintainability without the complexity of a distributed system. It is a pragmatic choice for startups or teams that need to iterate fast but expect growth. If you outgrow it, the modularity makes transitioning to microservices less painful.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>microservices</category>
      <category>monolith</category>
    </item>
  </channel>
</rss>
