<?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: Taher Maimoon</title>
    <description>The latest articles on DEV Community by Taher Maimoon (@taherm18).</description>
    <link>https://dev.to/taherm18</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%2F3683876%2Fec1cf27b-f06a-4f8f-ac76-0cd9d3e17944.png</url>
      <title>DEV Community: Taher Maimoon</title>
      <link>https://dev.to/taherm18</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/taherm18"/>
    <language>en</language>
    <item>
      <title>The Blazor Closure Bug That Made All My Time Slots 24:00 🕛 🕛</title>
      <dc:creator>Taher Maimoon</dc:creator>
      <pubDate>Sat, 03 Jan 2026 19:41:38 +0000</pubDate>
      <link>https://dev.to/taherm18/the-blazor-closure-bug-that-made-all-my-time-slots-2400--g7m</link>
      <guid>https://dev.to/taherm18/the-blazor-closure-bug-that-made-all-my-time-slots-2400--g7m</guid>
      <description>&lt;h2&gt;
  
  
  🐛 The Mysterious Bug
&lt;/h2&gt;

&lt;p&gt;I was building a conference room booking system in Blazor when I encountered a bizarre bug. My timeline component showed time slots from 6 AM to 11 PM, but whenever I clicked &lt;strong&gt;any&lt;/strong&gt; time slot, it would always show &lt;strong&gt;24:00&lt;/strong&gt; in the console.&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;// Console output - ALWAYS showed 24!&lt;/span&gt;
&lt;span class="n"&gt;Time&lt;/span&gt; &lt;span class="n"&gt;slot&lt;/span&gt; &lt;span class="n"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;06&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;2026&lt;/span&gt; &lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;End&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;06&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;2026&lt;/span&gt; &lt;span class="m"&gt;01&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The timeline looked correct visually, but every single button was broken. How could &lt;strong&gt;all&lt;/strong&gt; buttons from 6 AM to 11 PM send "24" as the hour?&lt;/p&gt;

&lt;h2&gt;
  
  
  🔍 The Investigation Journey
&lt;/h2&gt;

&lt;p&gt;My first assumptions were all wrong:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Timezone issue?&lt;/strong&gt; - Checked DateTime.Kind, UTC conversions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DateTime parsing bug?&lt;/strong&gt; - Added extensive validation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser datetime-local bug?&lt;/strong&gt; - Tested across browsers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After 3 hours of debugging, I added more logging:&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;private&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;OnTimeSlotClick&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;hour&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;minute&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;$"[DEBUG] Clicked hour: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Always showed 24, regardless of which button!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The maddening part? The loop looked perfectly correct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- This SHOULD create buttons for hours 6-23 --&amp;gt;
@for (int hour = 6; hour &amp;lt; 24; hour++)
{
    &amp;lt;button @onclick="() =&amp;gt; OnTimeSlotClick(hour, 0)"&amp;gt;
        @hour:00 &amp;lt;!-- Shows 6:00, 7:00, 8:00... CORRECT! --&amp;gt;
    &amp;lt;/button&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Buttons displayed: &lt;code&gt;6:00&lt;/code&gt;, &lt;code&gt;7:00&lt;/code&gt;, &lt;code&gt;8:00&lt;/code&gt;... but all called &lt;code&gt;OnTimeSlotClick(24, 0)&lt;/code&gt; when clicked!&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 The Revelation: Closure Capture
&lt;/h2&gt;

&lt;p&gt;The issue was &lt;strong&gt;closure capture&lt;/strong&gt; - a classic C# gotcha that's especially tricky in Blazor!&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;// What's ACTUALLY happening:&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;hour&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;hour&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ❌ Captures the VARIABLE 'hour', not its VALUE!&lt;/span&gt;
    &lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Click&lt;/span&gt; &lt;span class="p"&gt;+=&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;OnTimeSlotClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hour&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="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// When loop finishes: hour = 24&lt;/span&gt;
&lt;span class="c1"&gt;// ALL click handlers now reference hour = 24!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In C#, lambdas capture &lt;strong&gt;variables&lt;/strong&gt;, not &lt;strong&gt;values&lt;/strong&gt;. By the time any button is clicked, the loop has completed, and &lt;code&gt;hour = 24&lt;/code&gt; (the loop exits when &lt;code&gt;hour &amp;lt; 24&lt;/code&gt; is false).&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠️ The Simple Fix That Worked
&lt;/h2&gt;

&lt;p&gt;I changed from &lt;code&gt;for&lt;/code&gt; to &lt;code&gt;foreach&lt;/code&gt; with &lt;code&gt;Enumerable.Range&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- ✅ THIS WORKS! --&amp;gt;
@foreach (var hour in Enumerable.Range(6, 18)) &amp;lt;!-- 6 to 23 --&amp;gt;
{
    &amp;lt;button @onclick="() =&amp;gt; OnTimeSlotClick(hour, 0)"&amp;gt;
        @hour:00
    &amp;lt;/button&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this works:&lt;/strong&gt; Each iteration of &lt;code&gt;foreach&lt;/code&gt; creates a &lt;strong&gt;new variable&lt;/strong&gt; in memory, while &lt;code&gt;for&lt;/code&gt; reuses the &lt;strong&gt;same variable&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔧 Alternative Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Local Copy in Loop&lt;/strong&gt; (Most Common Fix)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@for (int hour = 6; hour &amp;lt; 24; hour++)
{
    var currentHour = hour; // ✅ Local copy
    &amp;lt;button @onclick="() =&amp;gt; OnTimeSlotClick(currentHour, 0)"&amp;gt;
        @currentHour:00
    &amp;lt;/button&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. &lt;strong&gt;Method with Parameter&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@for (int hour = 6; hour &amp;lt; 24; hour++)
{
    &amp;lt;button @onclick="@(() =&amp;gt; HandleHourClick(hour))"&amp;gt;
        @hour:00
    &amp;lt;/button&amp;gt;
}

@code {
    private void HandleHourClick(int hour) // ✅ New parameter each call
    {
        OnTimeSlotClick(hour, 0);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. &lt;strong&gt;Use &lt;a class="mentioned-user" href="https://dev.to/key"&gt;@key&lt;/a&gt; to Force Re-renders&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@for (int hour = 6; hour &amp;lt; 24; hour++)
{
    &amp;lt;div @key="hour"&amp;gt; &amp;lt;!-- ✅ Forces new component instance --&amp;gt;
        &amp;lt;button @onclick="() =&amp;gt; OnTimeSlotClick(hour, 0)"&amp;gt;
            @hour:00
        &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🎯 Why This Happens in Blazor Specifically
&lt;/h2&gt;

&lt;p&gt;Blazor makes this bug more likely because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Event handlers are lambdas&lt;/strong&gt; that execute later&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Component lifecycle&lt;/strong&gt; delays execution until after render&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State changes&lt;/strong&gt; trigger re-renders, changing captured variables&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async nature&lt;/strong&gt; means lambdas execute long after loop completes&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  📚 The Universal Lesson
&lt;/h2&gt;

&lt;p&gt;This isn't just a Blazor problem - it's a &lt;strong&gt;closure capture&lt;/strong&gt; issue that appears in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript&lt;/strong&gt;: Same issue with &lt;code&gt;var&lt;/code&gt; in loops&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C#&lt;/strong&gt;: Any lambda in a loop&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Java&lt;/strong&gt;: Anonymous classes capturing loop variables&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python&lt;/strong&gt;: Similar issues with default arguments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The rule:&lt;/strong&gt; When creating lambdas/events in loops, ensure you're capturing &lt;strong&gt;values&lt;/strong&gt;, not &lt;strong&gt;variables&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 Debugging Tips for Similar Issues
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add immediate logging&lt;/strong&gt; in the lambda&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test with hardcoded values&lt;/strong&gt; to isolate the issue&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check if it's a closure problem&lt;/strong&gt; by creating local copies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remember&lt;/strong&gt;: Loops with lambdas are always suspicious!&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;This bug taught me that sometimes the simplest-looking code can have the most surprising behavior. What looks like a primitive &lt;code&gt;int&lt;/code&gt; in a loop actually becomes a shared reference across all event handlers.&lt;/p&gt;

&lt;p&gt;Have you encountered similar closure bugs? What's your favorite "it can't be that" debugging moment?&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;Have you been bitten by closure capture bugs?&lt;/li&gt;
&lt;li&gt;What other Blazor gotchas have you encountered?&lt;/li&gt;
&lt;li&gt;Share your favorite debugging stories!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>blazor</category>
    </item>
  </channel>
</rss>
