<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
<channel>
<title><![CDATA[ Exception Not Found ]]></title>
<description><![CDATA[ C#, .NET, Web Tech, The Catch Block, Blazor, MVC, and more! ]]></description>
<link>https://exceptionnotfound.net</link>
<image>
    <url>https://exceptionnotfound.net/favicon.png</url>
    <title>Exception Not Found</title>
    <link>https://exceptionnotfound.net</link>
</image>
<lastBuildDate>Tue, 14 Apr 2026 15:07:32 -0700</lastBuildDate>
<atom:link href="https://exceptionnotfound.net" rel="self" type="application/rss+xml"/>
<ttl>60</ttl>

    <item>
        <title><![CDATA[ Re-thinking the Visitor Pattern with the Double-Dispatch Approach ]]></title>
        <description><![CDATA[ This article will help you have another point of view with the Visitor Pattern by thinking it with the Double-Dispatch Approach. This article will also show you a practical use case of how this pattern is applied in .NET. ]]></description>
        <link>https://exceptionnotfound.net/rethinking-the-visitor-pattern-with-the-double-dispatch-approach/</link>
        <guid isPermaLink="false">63f0339b65db5003c8aeb562</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Huy Luong ]]></dc:creator>
        <pubDate>Wed, 22 Feb 2023 08:00:45 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1574417837609-53a862369529?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGRvdWJsZXxlbnwwfHx8fDE2NzY5OTY0OTQ&amp;ixlib&#x3D;rb-4.0.3&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ <p><em>EDITOR'S NOTE: Hi y'all! Please welcome <a href="https://www.linkedin.com/in/vanhuy1995/">Huy Lương Vạn</a> to the <a href="https://exceptionnotfound.net/guest-writer-program/"><a href="https://exceptionnotfound.net/guest-posts/">guest writer program</a></a>! He is a first-time blogger and his article is below. Be nice! Comments are open at the end of the post. -Matthew</em></p><p>Have you ever heard about the Visitor Pattern – one of the Gang of Four Patterns? Have you tried researching it on the internet but still don’t know which problems it’s solving and which use cases should be applied in the real world. In this tutorial, I will show you a different approach called “Double Dispatch” to understand the Visitor pattern easier and how it is used in the .NET Library.</p><h2 id="the-problem">The Problem</h2><p>When searching on the internet, I usually see this common definition:</p><p><em>“The Visitor pattern lets you define a new operation to a collection of objects without changing the objects themselves.”</em></p><p>I would like to say that it’s hard for</p>... <a href="https://exceptionnotfound.net/rethinking-the-visitor-pattern-with-the-double-dispatch-approach/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ A Rant on the Occasional Inhumanity of Tech ]]></title>
        <description><![CDATA[ A cell phone causes me more pain. ]]></description>
        <link>https://exceptionnotfound.net/a-rant-on-the-occasional-inhumanity-of-tech/</link>
        <guid isPermaLink="false">6320ad21e9dee3cb6b93df3e</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Tue, 13 Sep 2022 09:47:49 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1532356884227-66d7c0e9e4c2?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDIxfHxjZWxsJTIwcGhvbmV8ZW58MHx8fHwxNjYzMDg2OTg1&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ <p>As you know from my last post, my younger brother Aaron died of cancer around three months ago. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://exceptionnotfound.net/aaron-memoriam/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Aaron</div><div class="kg-bookmark-description">Aaron is gone now. I miss him.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://exceptionnotfound.net/content/images/size/w256h256/2021/06/enf_favi2_tiny-1.png" alt=""><span class="kg-bookmark-author">Exception Not Found</span><span class="kg-bookmark-publisher">Matthew Jones</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://exceptionnotfound.net/content/images/2022/07/DSC-0313.JPG" alt=""></div></a></figure><p>I don't want to rehash that whole thing here. Rather, this post is a rant about a comparatively minor thing that totally ruined my day, a thing where tech and grief intersect and make my life just that much more difficult. Part of my grieving process, you might say.</p><p>Aaron had a phone, a very nice Samsung s20 FE, and since he is gone we no longer have any use for it. Frankly, I want it out of my house; it's sat in my drawer as an ugly reminder of my loss for weeks now. </p><p>My sister-in-law (we'll call her T) needed a phone, so, with the permission of our parents, we are working on giving Aaron's phone to</p>... <a href="https://exceptionnotfound.net/a-rant-on-the-occasional-inhumanity-of-tech/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ Aaron ]]></title>
        <description><![CDATA[ Aaron is gone now. I miss him. ]]></description>
        <link>https://exceptionnotfound.net/aaron-memoriam/</link>
        <guid isPermaLink="false">62d6e259e9dee3cb6b93cdeb</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Tue, 19 Jul 2022 11:40:27 -0700</pubDate>
        <media:content url="https://exceptionnotfound.net/content/images/2022/07/DSC-0313.JPG" medium="image"/>
        <content:encoded>
            <![CDATA[ <p>My younger brother Aaron died last month of pancreatic cancer. He was 33. </p><figure class="kg-card kg-image-card"><img src="https://exceptionnotfound.net/content/images/2022/07/058.JPG" class="kg-image" alt loading="lazy" width="1537" height="2049" srcset="https://exceptionnotfound.net/content/images/size/w600/2022/07/058.JPG 600w, https://exceptionnotfound.net/content/images/size/w1000/2022/07/058.JPG 1000w, https://exceptionnotfound.net/content/images/2022/07/058.JPG 1537w" sizes="(min-width: 720px) 720px"></figure><p>I'm writing this post for two reasons: one, so the world can help me remember him, and two, because I won't be able to write anything else ever if I can't get this out first.</p><p>I first want to re-publish <a href="https://exceptionnotfound.net/the-catch-block-93-separation-cancer-and-guilt/">something I wrote back in February</a>, because it summarizes the feelings I had at the time that I don't think I can replicate, now that the end has already come.</p><hr><p><em>My younger brother Aaron, my only sibling, is going to die of pancreatic cancer. This will most likely happen soon, within a year. He's only 33. And it's so goddamn unfair.</em></p><p><em>He was diagnosed last August, and it was a complete surprise. He went to the emergency room for abdominal pain, and after two days of tests, the doctors discovered an aggressive stage-4 pancreatic cancer that nobody</em></p>... <a href="https://exceptionnotfound.net/aaron-memoriam/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ The Catch Block #104 - Thank You, Signing Off ]]></title>
        <description><![CDATA[ This will be the last issue of The Catch Block. It's time for me to do something else. ]]></description>
        <link>https://exceptionnotfound.net/the-catch-block-104-thank-you-signing-off/</link>
        <guid isPermaLink="false">627154da126af8f60dd1a6b2</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Wed, 04 May 2022 07:00:00 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1610337673044-720471f83677?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDR8fHN0YXRpY3xlbnwwfHx8fDE2NTE1OTY0Mjk&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ <p>Dear Readers, it's time for me to do something else.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1501139083538-0139583c060f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHRpbWV8ZW58MHx8fHwxNjUxNTk2MDQy&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" class="kg-image" alt="Eventually everything hits the bottom, and all you have to do is wait until someone comes along, and turns it back again. ⌛️" loading="lazy" width="6000" height="4000" srcset="https://images.unsplash.com/photo-1501139083538-0139583c060f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHRpbWV8ZW58MHx8fHwxNjUxNTk2MDQy&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=600 600w, https://images.unsplash.com/photo-1501139083538-0139583c060f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHRpbWV8ZW58MHx8fHwxNjUxNTk2MDQy&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1000 1000w, https://images.unsplash.com/photo-1501139083538-0139583c060f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHRpbWV8ZW58MHx8fHwxNjUxNTk2MDQy&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1600 1600w, https://images.unsplash.com/photo-1501139083538-0139583c060f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHRpbWV8ZW58MHx8fHwxNjUxNTk2MDQy&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2400 2400w" sizes="(min-width: 720px) 720px"><figcaption>Photo by <a href="https://unsplash.com/@aronvisuals?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">Aron Visuals</a> / <a href="https://unsplash.com/?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">Unsplash</a></figcaption></figure><p>I have come to the difficult decision to cancel the publication of The Catch Block. This will be the last issue.</p><p>This was a hard decision to make, no doubt about it. I've been struggling with it for weeks. It was spurred on by two major life events, one <a href="https://exceptionnotfound.net/the-catch-block-93-separation-cancer-and-guilt/">you know about</a>, and one I'll be writing about in the near future. Suffice to say, I have a lot happening all at once, though not all of it is bad.</p><p>At this moment, though, I don't feel that I can commit the energy and time to this publication that it deserves. You probably noticed that the last few issues haven't really been up to my normal standards. And I don't want to publish things that aren't up to my standards. I don't want to be</p>... <a href="https://exceptionnotfound.net/the-catch-block-104-thank-you-signing-off/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ The Catch Block #103 - The Return of the Cool Read Extravaganza! ]]></title>
        <description><![CDATA[ Lots of cool reads! Plus a new .NET MAUI release candidate; F# for C# devs; aggregate roots; logical boundaries; and the Twitter sale. ]]></description>
        <link>https://exceptionnotfound.net/the-catch-block-103-the-return-of-the-cool-read-extravaganza/</link>
        <guid isPermaLink="false">62671013126af8f60dd13eb5</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Wed, 27 Apr 2022 08:54:26 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1623031345438-387dd3c45e9f?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDZ8fHJlYWR8ZW58MHx8fHwxNjUxMDc0NTI2&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ <p>Welcome to the 103rd edition of The Catch Block!</p><p>In this edition: there were a LOT of good reads this week, so let's check them out! </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1535930749574-1399327ce78f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDV8fHJlYWR8ZW58MHx8fHwxNjUxMDc0NTI1&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" class="kg-image" alt="A golden retriever wearing glasses looks at the camera, while a book open to a page with a picture of a dog sits in front of him." loading="lazy" width="3586" height="4781" srcset="https://images.unsplash.com/photo-1535930749574-1399327ce78f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDV8fHJlYWR8ZW58MHx8fHwxNjUxMDc0NTI1&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=600 600w, https://images.unsplash.com/photo-1535930749574-1399327ce78f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDV8fHJlYWR8ZW58MHx8fHwxNjUxMDc0NTI1&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1000 1000w, https://images.unsplash.com/photo-1535930749574-1399327ce78f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDV8fHJlYWR8ZW58MHx8fHwxNjUxMDc0NTI1&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1600 1600w, https://images.unsplash.com/photo-1535930749574-1399327ce78f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDV8fHJlYWR8ZW58MHx8fHwxNjUxMDc0NTI1&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2400 2400w" sizes="(min-width: 720px) 720px"><figcaption>I'm not above using a cute dog in a photo. Photo by <a href="https://unsplash.com/@jamie452?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Jamie Street</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></figcaption></figure><p>Plus: a new .NET MAUI release candidate; F# for C# devs; aggregate roots; logical boundaries; and the Twitter sale. Let's go!</p>
<aside class="gh-post-upgrade-cta">
    <div class="gh-post-upgrade-cta-content" style="background-color: #662A7A">
            <h2>This post is for paying subscribers only</h2>
            <a class="gh-btn" data-portal="signup" style="color:#662A7A">Subscribe now</a>
            <p><small>Already have an account? <a data-portal="signin">Sign in</a></small></p>
    </div>
</aside>
... <a href="https://exceptionnotfound.net/the-catch-block-103-the-return-of-the-cool-read-extravaganza/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ The Catch Block #102 - Microsoft Preview-palooza! ]]></title>
        <description><![CDATA[ Microsoft releases a bunch of previews! Plus: ASP.NET Core interview questions and answers, an AutoMapper programming horror, and is there a good computer job? ]]></description>
        <link>https://exceptionnotfound.net/the-catch-block-102-microsoft-preview-palooza/</link>
        <guid isPermaLink="false">625dad45126af8f60dd0dd0a</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Wed, 20 Apr 2022 08:47:14 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1640763502425-7668dc1e4023?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDh8fG1pY3Jvc29mdHxlbnwwfHx8fDE2NTA0NjkyMzQ&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ 
<aside class="gh-post-upgrade-cta">
    <div class="gh-post-upgrade-cta-content" style="background-color: #662A7A">
            <h2>This post is for paying subscribers only</h2>
            <a class="gh-btn" data-portal="signup" style="color:#662A7A">Subscribe now</a>
            <p><small>Already have an account? <a data-portal="signin">Sign in</a></small></p>
    </div>
</aside>
... <a href="https://exceptionnotfound.net/the-catch-block-102-microsoft-preview-palooza/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ The Catch Block #101 - On Feeling Stuck ]]></title>
        <description><![CDATA[ I'm feeling pretty stuck with my team's current application, and am wondering what to do about it.
Plus: pattern matching; unit tests; "Being Agile"; and better breadcrumbs. ]]></description>
        <link>https://exceptionnotfound.net/the-catch-block-101-on-feeling-stuck/</link>
        <guid isPermaLink="false">62546dc4126af8f60dd0820f</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Wed, 13 Apr 2022 07:00:00 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1554863838-764b29f1ad1b?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDV8fHN0dWNrfGVufDB8fHx8MTY0OTc4Nzg3MA&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ <p>Welcome to the 101st edition of The Catch Block!</p><p>In this edition: I'm feeling pretty stuck with my team's current application. What to do?</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1520462551646-bf2f6a00423b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDd8fHN0dWNrfGVufDB8fHx8MTY0OTc4Nzg3MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" class="kg-image" alt="Survivor" loading="lazy" width="4288" height="2848" srcset="https://images.unsplash.com/photo-1520462551646-bf2f6a00423b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDd8fHN0dWNrfGVufDB8fHx8MTY0OTc4Nzg3MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=600 600w, https://images.unsplash.com/photo-1520462551646-bf2f6a00423b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDd8fHN0dWNrfGVufDB8fHx8MTY0OTc4Nzg3MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1000 1000w, https://images.unsplash.com/photo-1520462551646-bf2f6a00423b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDd8fHN0dWNrfGVufDB8fHx8MTY0OTc4Nzg3MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1600 1600w, https://images.unsplash.com/photo-1520462551646-bf2f6a00423b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDd8fHN0dWNrfGVufDB8fHx8MTY0OTc4Nzg3MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2400 2400w" sizes="(min-width: 720px) 720px"><figcaption>Just squeeze a little more... Photo by <a href="https://unsplash.com/@benhershey?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Ben Hershey</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></figcaption></figure><p>Plus: pattern matching; unit tests; "Being Agile"; and better breadcrumbs.</p><h2 id="stuck-in-the-middle-with-you">Stuck in the Middle with You</h2><p>The application I mentioned at the beginning of the edition is not a single app; it is comprised of a bunch of parts, including an internal web app, two distinct APIs, a public-facing web app, and a collection of smaller applications. One of the APIs is written in .NET Core 3.1, but everything else is .NET 4.8 or earlier. .NET 4.8 is the last version of .NET Framework, so no more upgrades are coming to that platform.</p><p>Obviously, I cannot speak too much about what exactly this application does, but I can say this: this application is critical to our company. It must be working 24/7, and issues in it cause the company to lose money and customers. There are bugs we must fix, as with any app, and the business team which owns it regularly requests improvements and changes. </p><p>These changes and bugs, as frequent as they are, make it difficult for my three-person team to pay down the app's technical debt, which has been accruing for over 10 years, and which we are only now making progress with.</p><p>In other words, my team's application is stuck. Stuck, and time-consuming to improve. I'm getting sick of it.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1554863804-69546eb96737?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHN0dWNrfGVufDB8fHx8MTY0OTc4Nzg3MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" class="kg-image" alt loading="lazy" width="3872" height="2592" srcset="https://images.unsplash.com/photo-1554863804-69546eb96737?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHN0dWNrfGVufDB8fHx8MTY0OTc4Nzg3MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=600 600w, https://images.unsplash.com/photo-1554863804-69546eb96737?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHN0dWNrfGVufDB8fHx8MTY0OTc4Nzg3MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1000 1000w, https://images.unsplash.com/photo-1554863804-69546eb96737?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHN0dWNrfGVufDB8fHx8MTY0OTc4Nzg3MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1600 1600w, https://images.unsplash.com/photo-1554863804-69546eb96737?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHN0dWNrfGVufDB8fHx8MTY0OTc4Nzg3MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2400 2400w" sizes="(min-width: 720px) 720px"><figcaption>Spinning our wheels, making little progress. Photo by <a href="https://unsplash.com/@octoberroses?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Aubrey Odom-Mabey</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></figcaption></figure><p>I've brought up this topic before, with three different bosses. This app needs to be moved to .NET 5 or higher if we're going to keep improving it. And each of my bosses has said the same thing: it sounds like a good idea, but not right now; we'll do it when we have time. And we never get time. Bugs and changes keep coming down the pipeline, and the refactoring needed to get the app ready is very slow going. Progress is progress, I know, but it's not going fast enough.</p><p>I understand the problem, I really do. This app is huge, with a lot of pieces, and the current refactoring work we're doing on it is really the first of many steps necessary to get it to a point where it even <em>can</em> be ported into .NET 5 or higher. The problem is huge, and from the business's perspective, might be a waste of money and time. </p><p>Yet, I'm sick of getting stuck, of being told "we'll do it later" when later never comes. I've been pushing to make certain changes, with moderate success, for a year now. Let's be real: the app is in a much better state than it was even a few months ago. It's much less brittle, meaning it is much easier to modify without causing a bunch of heretofore-unseen bugs.</p><p>Because we're using .NET 4.8, we're also stuck on C# 7.3. We're two major versions of C# behind, and by the end of this year, we will be three versions back. Maybe that doesn't matter in the big picture. But to me, it feels like we're falling behind and can't catch up. I know, logically, that's not the truth of it, but emotionally it feels like we're getting left in the dust.</p>
<aside class="gh-post-upgrade-cta">
    <div class="gh-post-upgrade-cta-content" style="background-color: #662A7A">
            <h2>This post is for paying subscribers only</h2>
            <a class="gh-btn" data-portal="signup" style="color:#662A7A">Subscribe now</a>
            <p><small>Already have an account? <a data-portal="signin">Sign in</a></small></p>
    </div>
</aside>
... <a href="https://exceptionnotfound.net/the-catch-block-101-on-feeling-stuck/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ The Catch Block #100 - Ridiculous Tech Interviewing Stories ]]></title>
        <description><![CDATA[ Bluffing your way into a programming job tends to not go well. Plus: pub/sub, functors, monads, reasons why projects fail, and more! ]]></description>
        <link>https://exceptionnotfound.net/the-catch-block-100-ridiculous-tech-interviewing-stories/</link>
        <guid isPermaLink="false">624b41a7126af8f60dd003e2</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Wed, 06 Apr 2022 08:50:47 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded>
            <![CDATA[ 
<aside class="gh-post-upgrade-cta">
    <div class="gh-post-upgrade-cta-content" style="background-color: #662A7A">
            <h2>This post is for paying subscribers only</h2>
            <a class="gh-btn" data-portal="signup" style="color:#662A7A">Subscribe now</a>
            <p><small>Already have an account? <a data-portal="signin">Sign in</a></small></p>
    </div>
</aside>
... <a href="https://exceptionnotfound.net/the-catch-block-100-ridiculous-tech-interviewing-stories/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ Middleware in ASP.NET 6 - Conditionally Adding Middleware to the Pipeline ]]></title>
        <description><![CDATA[ Let's execute some middleware in our ASP.NET 6 app only under certain conditions, using AppSettings or the request URL and body. ]]></description>
        <link>https://exceptionnotfound.net/middleware-in-dotnet-6-conditionally-adding-middleware-to-the-pipeline/</link>
        <guid isPermaLink="false">62290b0bf8508d63f8a8ea3e</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Mon, 04 Apr 2022 07:00:00 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1605600659873-d808a13e4d2a?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDE3fHxwaXBlbGluZXxlbnwwfHx8fDE2NDY4NTU2MjY&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ <p><em>This is Part 4 of a four-part series. You might want to read <a href="https://exceptionnotfound.net/middleware-in-asp-dotnet-6-intro-and-basics/">Part 1</a>, <a href="https://exceptionnotfound.net/middleware-in-asp-net-6-custom-middleware-classes/">Part 2</a>, and <a href="https://exceptionnotfound.net/middleware-in-dotnet-6-order-of-operations/">Part 3</a> first.</em></p><p>Welcome back! So far in this series, we've covered the basics of Middleware in .NET 6 applications, shown how to create custom Middleware classes, and discussed why the order of operations of the Middleware pipeline is so important.</p><p>In this final part of the series, we will show two ways to conditionally execute middleware in the pipeline: by using settings in the AppSettings.json file to determine whether or not to add the middleware to the pipeline in the first place, or by using the incoming request's data to conditionally execute a middleware piece already in the pipeline.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1607472586893-edb57bdc0e39?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDExfHxwaXBlbGluZXxlbnwwfHx8fDE2NDY4NTU2MjY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" class="kg-image" alt loading="lazy" width="4032" height="3024" srcset="https://images.unsplash.com/photo-1607472586893-edb57bdc0e39?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDExfHxwaXBlbGluZXxlbnwwfHx8fDE2NDY4NTU2MjY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=600 600w, https://images.unsplash.com/photo-1607472586893-edb57bdc0e39?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDExfHxwaXBlbGluZXxlbnwwfHx8fDE2NDY4NTU2MjY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1000 1000w, https://images.unsplash.com/photo-1607472586893-edb57bdc0e39?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDExfHxwaXBlbGluZXxlbnwwfHx8fDE2NDY4NTU2MjY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1600 1600w, https://images.unsplash.com/photo-1607472586893-edb57bdc0e39?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDExfHxwaXBlbGluZXxlbnwwfHx8fDE2NDY4NTU2MjY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2400 2400w" sizes="(min-width: 720px) 720px"><figcaption>This way, or that way? Photo by <a href="https://unsplash.com/@sigmund?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Sigmund</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></figcaption></figure><h2 id="conditional-middleware-based-on-appsettings">Conditional Middleware based on AppSettings</h2><p>Remember the <code>TimeLoggingMiddleware</code> class from Part 3? If you don't, here it is again.</p><pre><code class="language-csharp">using MiddlewareNET6Demo.Logging;</code></pre>... <a href="https://exceptionnotfound.net/middleware-in-dotnet-6-conditionally-adding-middleware-to-the-pipeline/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ The Catch Block #99 - Finishing the Dapper Where Clause Builder ]]></title>
        <description><![CDATA[ Let's complete the DapperWhereClauseBuilder from the previous issue! Plus: .NET 7 Preview 2, code reviews, gotchas, HTML injection, and more! ]]></description>
        <link>https://exceptionnotfound.net/the-catch-block-99-finishing-the-dapper-where-clause-builder/</link>
        <guid isPermaLink="false">623c99d2c818b78ea53bbea4</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Wed, 30 Mar 2022 07:00:00 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1565008447742-97f6f38c985c?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDd8fGNvbnN0cnVjdGlvbnxlbnwwfHx8fDE2NDgxNDI1Nzk&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ <p>Welcome to the 99th edition of The Catch Block!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1554435493-93422e8220c8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDh8fGJ1aWxkaW5nfGVufDB8fHx8MTY0ODE0MjU5NA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" class="kg-image" alt loading="lazy" width="3211" height="4281" srcset="https://images.unsplash.com/photo-1554435493-93422e8220c8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDh8fGJ1aWxkaW5nfGVufDB8fHx8MTY0ODE0MjU5NA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=600 600w, https://images.unsplash.com/photo-1554435493-93422e8220c8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDh8fGJ1aWxkaW5nfGVufDB8fHx8MTY0ODE0MjU5NA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1000 1000w, https://images.unsplash.com/photo-1554435493-93422e8220c8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDh8fGJ1aWxkaW5nfGVufDB8fHx8MTY0ODE0MjU5NA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1600 1600w, https://images.unsplash.com/photo-1554435493-93422e8220c8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDh8fGJ1aWxkaW5nfGVufDB8fHx8MTY0ODE0MjU5NA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2400 2400w" sizes="(min-width: 720px) 720px"><figcaption>Let's put the finishing touches up! Photo by <a href="https://unsplash.com/@rahulbhogal?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Rahul Bhogal</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></figcaption></figure><p>In this edition, we finish up the <code>DapperWhereClauseBuilder</code> that we started building two weeks ago.</p><p>Plus: gotchas; real-world refactoring; unit tests for legacy systems; the code review pyramid; and .NET 7 Preview 2. </p><p>Let's go!</p><h2 id="finishing-the-dapper-where-clause-builder">Finishing the Dapper Where Clause Builder</h2><p>In <a href="https://exceptionnotfound.net/the-catch-block-98-dapper-where-clause-builder/">the previous issue</a>, we talked at length about a class called <code>DapperWhereClauseBuilder</code> that we could use to build complex SQL WHERE clauses. At the end of the previous post, our class looked like this:</p><pre><code class="language-csharp">public class DapperWhereClauseBuilder
{
    private readonly SortedDictionary&lt;string, object&gt; singleValues = new SortedDictionary&lt;string, object&gt;();

    public DapperWhereClauseBuilder AddValue(string parameterName, int? value)
    {
        if (value.HasValue &amp;&amp; !singleValues.ContainsKey(parameterName))
            singleValues.Add(parameterName, value.Value);

        return this;
    }
    
    //Lots of overload AddValue methods, one for each primitive type, including bool, double, string, DateTime, and more.

    public DapperWhereClauseBuilder AddValue(string parameterName, Guid? value)
    {
        if (value.HasValue &amp;&amp; !singleValues.ContainsKey(parameterName))
            singleValues.Add(parameterName, value.Value);

        return this;
    }

    public string WhereClause
    {
        get
        {
            //If no values are submitted, there is effectively no WHERE clause.
            //So, return an empty string.
            if(!singleValues.Any())
                return string.Empty;

            string whereClause = " WHERE ";
            foreach(var item in singleValues)
            {
                whereClause += item.Key + " = @" + item.Key.ToLower() + " AND ";
            }
            whereClause = whereClause.Remove(whereClause.LastIndexOf("AND"));

            return whereClause;
        }
    }

    public DynamicParameters Parameters
    {
        get
        {
            DynamicParameters parameters = new DynamicParameters();
            foreach(var item in singleValues)
            {
                parameters.Add(item.Key.ToLower(), item.Value);
            }
            return parameters;
        }
    }
}</code></pre><p>At this point, this class can only generate WHERE clauses for exact matches on a value. We could end up with "WHERE ColumnName = @Parameter". What we cannot do yet is have more complex matching clauses, such as IS NOT NULL or IS IN. We'll be extending <code>DapperWhereClauseBuilder</code> to permit these kinds of clauses in this issue.</p><h3 id="is-not-null-clauses">IS NOT NULL Clauses</h3><p>Let's deal with IS NOT NULL clauses first. We need a new collection in <code>DapperWhereClauseBuilder</code> to hold the column names that we need to check for NULL on:</p><pre><code class="language-csharp">public class DapperWhereClauseBuilder
{
    private readonly SortedDictionary&lt;string, object&gt; singleValues = new SortedDictionary&lt;string, object&gt;();
    
    //NEW
    private readonly List&lt;string&gt; notNullValues = new List&lt;string&gt;();
    
    //...Rest of implementation
}</code></pre><p>We also need a method by which we can add columns to be checked for NOT NULL:</p><pre><code class="language-csharp">public class DapperWhereClauseBuilder
{
    //...Rest of implementation
    
    public DapperWhereClauseBuilder AddNotNull(string parameterName)
    {
        if (!notNullValues.Contains(parameterName))
            notNullValues.Add(parameterName);

        return this;
    }
    
    //...Rest of implementation
}</code></pre><p>Finally, we need to modify the <code>WhereClause</code> property to includ the output for IS NOT NULL clauses:</p>
<aside class="gh-post-upgrade-cta">
    <div class="gh-post-upgrade-cta-content" style="background-color: #662A7A">
            <h2>This post is for paying subscribers only</h2>
            <a class="gh-btn" data-portal="signup" style="color:#662A7A">Subscribe now</a>
            <p><small>Already have an account? <a data-portal="signin">Sign in</a></small></p>
    </div>
</aside>
... <a href="https://exceptionnotfound.net/the-catch-block-99-finishing-the-dapper-where-clause-builder/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ Middleware in ASP.NET 6 - Order of Operations ]]></title>
        <description><![CDATA[ Let's see how the order of the middleware in the ASP.NET 6 pipeline affects how they function. ]]></description>
        <link>https://exceptionnotfound.net/middleware-in-dotnet-6-order-of-operations/</link>
        <guid isPermaLink="false">62210179f8508d63f8a8996f</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Mon, 28 Mar 2022 07:00:00 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1553159925-02b2e24f471d?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDV8fHBpcGVsaW5lfGVufDB8fHx8MTY0NjMzMzA5Nw&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ <p><em>This post is Part 3 of a four-part series. You might want to read <a href="https://exceptionnotfound.net/middleware-in-asp-dotnet-6-intro-and-basics/">Part 1</a> and <a href="https://exceptionnotfound.net/middleware-in-asp-net-6-custom-middleware-classes/">Part 2</a> first.</em></p><p>Let's continue our series on Middleware in .NET 6 by discussing the pipeline created by Middleware, and specifically why the order in which the middleware are added to the pipeline is very important.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1593583810872-ddee4d6bd55a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDZ8fHBpcGVsaW5lfGVufDB8fHx8MTY0Njg1NTYyNg&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" class="kg-image" alt loading="lazy" width="5760" height="3840" srcset="https://images.unsplash.com/photo-1593583810872-ddee4d6bd55a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDZ8fHBpcGVsaW5lfGVufDB8fHx8MTY0Njg1NTYyNg&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=600 600w, https://images.unsplash.com/photo-1593583810872-ddee4d6bd55a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDZ8fHBpcGVsaW5lfGVufDB8fHx8MTY0Njg1NTYyNg&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1000 1000w, https://images.unsplash.com/photo-1593583810872-ddee4d6bd55a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDZ8fHBpcGVsaW5lfGVufDB8fHx8MTY0Njg1NTYyNg&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1600 1600w, https://images.unsplash.com/photo-1593583810872-ddee4d6bd55a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDZ8fHBpcGVsaW5lfGVufDB8fHx8MTY0Njg1NTYyNg&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2400 2400w" sizes="(min-width: 720px) 720px"><figcaption>You should know the order of things BEFORE this point. Photo by <a href="https://unsplash.com/@selimarda?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">SELİM ARDA ERYILMAZ</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></figcaption></figure><h2 id="the-sample-project">The Sample Project</h2><p>As with all of my <a href="https://exceptionnotfound.net/tag/sampleproject/">code-focused posts</a>, there's a demo project that demonstrates the ideas in this post over on GitHub. You can check it out here:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/exceptionnotfound/MiddlewareNET6Demo"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - exceptionnotfound/MiddlewareNET6Demo</div><div class="kg-bookmark-description">Contribute to exceptionnotfound/MiddlewareNET6Demo development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt=""><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">exceptionnotfound</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/8b96eea7a2a63a0a7d3f1ad5c7ef43b19c4f44d0f3b3913377408df620dd465d/exceptionnotfound/MiddlewareNET6Demo" alt=""></div></a></figure><h2 id="order-of-operations">Order of Operations</h2><p>Recall from Part 1 of this series that middleware forms a pipeline, and the middleware in that pipeline are executed in a certain order, an example of which is shown in</p>... <a href="https://exceptionnotfound.net/middleware-in-dotnet-6-order-of-operations/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ Middleware in ASP.NET 6 - Custom Middleware Classes ]]></title>
        <description><![CDATA[ Let's build custom ASP.NET 6 Middleware classes, including a logger and a simple response middleware. ]]></description>
        <link>https://exceptionnotfound.net/middleware-in-asp-net-6-custom-middleware-classes/</link>
        <guid isPermaLink="false">621ea1dcf8508d63f8a8693d</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Mon, 21 Mar 2022 07:00:00 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1559510981-10719ce4266a?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDF8fHBpcGVsaW5lfGVufDB8fHx8MTY0NjMzMzA5Nw&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ <p><em>This post is part 2 of a four-part series. You might want to <a href="https://exceptionnotfound.net/middleware-in-asp-dotnet-6-intro-and-basics/">read Part 1</a> first.</em></p><p>In the last post, we talked about what Middleware is, what it's for, and simple ways of including it in our ASP.NET 6 app's pipeline. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1635145613344-3e59b1e8afd0?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDh8fHBpcGVsaW5lfGVufDB8fHx8MTY0NjE3NDI1MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" class="kg-image" alt="Hydro-electricity piplines above Tarraleah Power Station, Tarraleah, Tasmania." loading="lazy" width="2656" height="3984" srcset="https://images.unsplash.com/photo-1635145613344-3e59b1e8afd0?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDh8fHBpcGVsaW5lfGVufDB8fHx8MTY0NjE3NDI1MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=600 600w, https://images.unsplash.com/photo-1635145613344-3e59b1e8afd0?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDh8fHBpcGVsaW5lfGVufDB8fHx8MTY0NjE3NDI1MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1000 1000w, https://images.unsplash.com/photo-1635145613344-3e59b1e8afd0?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDh8fHBpcGVsaW5lfGVufDB8fHx8MTY0NjE3NDI1MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1600 1600w, https://images.unsplash.com/photo-1635145613344-3e59b1e8afd0?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDh8fHBpcGVsaW5lfGVufDB8fHx8MTY0NjE3NDI1MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2400 2400w" sizes="(min-width: 720px) 720px"><figcaption>See, now you get why I'm including pictures of pipelines. Photo by <a href="https://unsplash.com/@ceebeesnap?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Christian Bass</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></figcaption></figure><p>In this post, we're going to expand on these fundamentals to build a few custom Middleware classes.</p><h2 id="the-sample-project">The Sample Project</h2><p>Don't forget to check out the sample project over on GitHub:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/exceptionnotfound/MiddlewareNET6Demo"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - exceptionnotfound/MiddlewareNET6Demo</div><div class="kg-bookmark-description">Contribute to exceptionnotfound/MiddlewareNET6Demo development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt=""><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">exceptionnotfound</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/8b96eea7a2a63a0a7d3f1ad5c7ef43b19c4f44d0f3b3913377408df620dd465d/exceptionnotfound/MiddlewareNET6Demo" alt=""></div></a></figure><h2 id="the-standard-middleware-architecture">The Standard Middleware Architecture</h2><p>Unlike what we did in Part 1, most of the time we want to have our Middleware be separate classes, and not just additional lines in our Program.cs file. </p><p>Remember this middleware from Part 1? The one that returned</p>... <a href="https://exceptionnotfound.net/middleware-in-asp-net-6-custom-middleware-classes/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ The Catch Block #98 - Dapper Where Clause Builder ]]></title>
        <description><![CDATA[ Let's write code that generates SQL! Plus: you should deploy more; feature flags; designing better APIs; cancellation; and VS's 25th anniversary! ]]></description>
        <link>https://exceptionnotfound.net/the-catch-block-98-dapper-where-clause-builder/</link>
        <guid isPermaLink="false">622f6df77cdc1959e3e304d4</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Wed, 16 Mar 2022 07:00:00 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1541888946425-d81bb19240f5?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDF8fGNvbnN0cnVjdGlvbnxlbnwwfHx8fDE2NDczNzI0OTI&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ <p>Welcome to the 98th edition of The Catch Block!</p><p>In this edition, we build a class that can generate relatively-complicated SQL WHERE clauses from a group of parameters. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1595844730289-b248c919d6f9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGJ1aWxkZXJ8ZW58MHx8fHwxNjQ3MzcyNDUy&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" class="kg-image" alt="A builder measures out the gap between each beam" loading="lazy" width="6000" height="4000" srcset="https://images.unsplash.com/photo-1595844730289-b248c919d6f9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGJ1aWxkZXJ8ZW58MHx8fHwxNjQ3MzcyNDUy&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=600 600w, https://images.unsplash.com/photo-1595844730289-b248c919d6f9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGJ1aWxkZXJ8ZW58MHx8fHwxNjQ3MzcyNDUy&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1000 1000w, https://images.unsplash.com/photo-1595844730289-b248c919d6f9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGJ1aWxkZXJ8ZW58MHx8fHwxNjQ3MzcyNDUy&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1600 1600w, https://images.unsplash.com/photo-1595844730289-b248c919d6f9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGJ1aWxkZXJ8ZW58MHx8fHwxNjQ3MzcyNDUy&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2400 2400w" sizes="(min-width: 720px) 720px"><figcaption>And we won't even need a tape measure! Photo by <a href="https://unsplash.com/@inkyhills?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Callum Hill</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></figcaption></figure><p>Plus: you should deploy more; feature flags; designing better APIs; cancellation; and VS's 25th anniversary!</p><h2 id="dapper-where-clause-builder">Dapper Where Clause Builder</h2><p>My team and I made the commitment to use Dapper entirely for our major project, and so far it's going pretty well. But occasionally we are running across things like enormously complicated queries, which Entity Framework can do fairly simply but Dapper has a harder time with.</p><p>Queries such as this, from one of our pages that has a bunch of search fields:</p><figure class="kg-card kg-code-card"><pre><code class="language-csharp">public List&lt;LocationDetail&gt; SearchForLocations(LocationSearchVM viewModel)
{
    var resultList 
        = _locationEntities.PickupLocations
          .Where(x =&gt; viewModel.Id == null || x.id == viewModel.Id)
          .Where(x =&gt; viewModel.LocationID == null || x.locationid == viewModel.LocationID)
          .Where(x =&gt; viewModel.LocationName == null || x.locationname == viewModel.LocationName)
          .Where(x =&gt; viewModel.Phone == null || x.phone == viewModel.Phone)
          .Where(x =&gt; viewModel.Address1 == null || x.address1 == viewModel.Address1)
          .Where(x =&gt; viewModel.Address2 == null || x.address2 == viewModel.Address2)
          .Where(x =&gt; viewModel.PostalCode == null || x.postalcode == viewModel.PostalCode)
          .Where(x =&gt; viewModel.Active || !x.active)
          .Take(1000)
          .ToList();
}</code></pre><figcaption>Ignore that this doesn't compile, please.</figcaption></figure><p>Notice that this particular query has to do a null check, and if the property in question is null, the item gets <em>included</em> in the result set. </p><p>This is a terribly complicated query at first glance, but peer a little closer and you start to see the similarities. I decided that it might be possible to create a class which generates the above code as a SQL WHERE clause, and parameters, for Dapper to consumer. Turns out, it IS possible.</p><p>In this post and the next (which will come out in two weeks, see below), we'll show how to build the <code>DapperWhereClauseBuilder</code> class for a few types of queries, and how to use it to replace the above query. Let's go!</p><h3 id="the-internals-of-dapperwhereclausebuilder">The Internals of DapperWhereClauseBuilder</h3><p>The <code>DapperWhereClauseBuilder</code> class needs to do the following things:</p><ol><li>Accept a string parameter name and a value for any given parameter.</li><li>Accept "is not null" parameters.</li><li>Accept "is in this collection" parameters.</li><li>Generate the WHERE clause that results from all the given parameters.</li></ol><p>We're going to do 1 and part of 4 in this post, and we'll do the others in the next one.</p><p>So, let's start with a new <code>DapperWhereClauseBuilder</code> class and an internal collection of parameters, which we will make a <code>SortedDictionary&lt;string, object&gt;</code> type:</p><pre><code class="language-csharp">public class DapperWhereClauseBuilder
{
    private readonly SortedDictionary&lt;string, object&gt; singleValues = new SortedDictionary&lt;string, object&gt;();
}</code></pre><p>We now need accessor methods to add parameters of different types to the where clause builder. Let's start with a simple one, for <code>int</code>:</p><pre><code class="language-csharp">public class DapperWhereClauseBuilder
{
        private readonly SortedDictionary&lt;string, object&gt; singleValues = new SortedDictionary&lt;string, object&gt;();

    public DapperWhereClauseBuilder AddValue(string parameterName, int? value)
    {
        if (value.HasValue &amp;&amp; !singleValues.ContainsKey(parameterName))
            singleValues.Add(parameterName, value.Value);

        return this;
    }
}</code></pre><p>Note that we're doing two kinds of checks on the passed-in value: confirming that the nullable value actually has a value, and confirming that the value <code>parameterName</code> does not already exist in our dictionary of parameters. We also made the method return <code>DapperWhereClauseBuilder</code> so it can be used in a fluent manner.</p><p>We will need quite a few of this basic <code>AddValue()</code> methods; here's two more:</p><pre><code class="language-csharp">public class DapperWhereClauseBuilder
{
    //...Rest of implementation

    public DapperWhereClauseBuilder AddValue(string parameterName, double? value)
    {
        if (value.HasValue &amp;&amp; !singleValues.ContainsKey(parameterName))
            singleValues.Add(parameterName, value.Value);

        return this;
    }

    public DapperWhereClauseBuilder AddValue(string parameterName, long? value)
    {
        if (value.HasValue &amp;&amp; !singleValues.ContainsKey(parameterName))
            singleValues.Add(parameterName, value.Value);

        return this;
    }
}</code></pre><p>For the majority of these methods, the logic is the same even as the type of the second parameter changes: ensure that the value is not <code>null</code>, and ensure that the <code>parameterName</code> does not already exist in the dictionary. The implementation of that logic changes, very slightly, when we get to adding a value of type <code>string</code>:</p>
<aside class="gh-post-upgrade-cta">
    <div class="gh-post-upgrade-cta-content" style="background-color: #662A7A">
            <h2>This post is for paying subscribers only</h2>
            <a class="gh-btn" data-portal="signup" style="color:#662A7A">Subscribe now</a>
            <p><small>Already have an account? <a data-portal="signin">Sign in</a></small></p>
    </div>
</aside>
... <a href="https://exceptionnotfound.net/the-catch-block-98-dapper-where-clause-builder/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ Middleware in ASP.NET 6 - Intro and Basics ]]></title>
        <description><![CDATA[ Let's see what Middleware is in ASP.NET 6, how it forms pipelines, how the Program.cs file is involved, and a simple implementation. ]]></description>
        <link>https://exceptionnotfound.net/middleware-in-asp-dotnet-6-intro-and-basics/</link>
        <guid isPermaLink="false">621e72b9f8508d63f8a865d5</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Mon, 14 Mar 2022 07:00:00 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1507823690283-48b0929e727b?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDR8fHBpcGVsaW5lfGVufDB8fHx8MTY0NjE3NDI1MA&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ <p>Welcome, dear readers, to a brand new series about middleware in .NET 6! </p><p>We're going to talk about what middleware is, what it does, why we use it, and demo several implementations of various kinds of middleware. We'll also talk about the pipeline that middleware exists in, how to create it, and why the order of operations in that pipeline matters. Finally, we'll even show two ways to conditionally execute middleware in the pipeline to give you a finer-grain control of what your app does.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1428585227457-326f25f9cee2?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDEzfHxwaXBlbGluZXxlbnwwfHx8fDE2NDY4NTU2MjY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" class="kg-image" alt="Old rusty waterpipe near Melitopol'" loading="lazy" width="6000" height="4000" srcset="https://images.unsplash.com/photo-1428585227457-326f25f9cee2?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDEzfHxwaXBlbGluZXxlbnwwfHx8fDE2NDY4NTU2MjY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=600 600w, https://images.unsplash.com/photo-1428585227457-326f25f9cee2?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDEzfHxwaXBlbGluZXxlbnwwfHx8fDE2NDY4NTU2MjY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1000 1000w, https://images.unsplash.com/photo-1428585227457-326f25f9cee2?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDEzfHxwaXBlbGluZXxlbnwwfHx8fDE2NDY4NTU2MjY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1600 1600w, https://images.unsplash.com/photo-1428585227457-326f25f9cee2?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDEzfHxwaXBlbGluZXxlbnwwfHx8fDE2NDY4NTU2MjY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2400 2400w" sizes="(min-width: 720px) 720px"><figcaption>Photo by <a href="https://unsplash.com/@frostroomhead?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Rodion Kutsaev</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></figcaption></figure><p>Let's get started!</p><h2 id="the-sample-project">The Sample Project</h2><p>As with all of my code-focused posts, there's a sample project hosted on GitHub that demonstrates the ideas in this post. You can check it out here:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/exceptionnotfound/MiddlewareNET6Demo"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - exceptionnotfound/MiddlewareNET6Demo</div><div class="kg-bookmark-description">Contribute to exceptionnotfound/MiddlewareNET6Demo development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt=""><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">exceptionnotfound</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/8b96eea7a2a63a0a7d3f1ad5c7ef43b19c4f44d0f3b3913377408df620dd465d/exceptionnotfound/MiddlewareNET6Demo" alt=""></div></a></figure><h2 id="middleware-basics">Middleware Basics</h2><p>At its most fundamental, any given interaction using</p>... <a href="https://exceptionnotfound.net/middleware-in-asp-dotnet-6-intro-and-basics/">Read more!</a> ]]>
        </content:encoded>
    </item>
    <item>
        <title><![CDATA[ The Catch Block #97 - The Old, Familiar Comments Trap ]]></title>
        <description><![CDATA[ Comments tell you why. Plus: Finite State Machines, eventual consistency, and cancelling async calls. ]]></description>
        <link>https://exceptionnotfound.net/the-catch-block-97-the-old-familiar-comments-trap/</link>
        <guid isPermaLink="false">622655f8f8508d63f8a8c79e</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ Matthew Jones ]]></dc:creator>
        <pubDate>Wed, 09 Mar 2022 07:00:00 -0700</pubDate>
        <media:content url="https://images.unsplash.com/photo-1463362603537-22059ee1ac77?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDV8fHRyYXBwZWR8ZW58MHx8fHwxNjQ2NzYwMTE3&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" medium="image"/>
        <content:encoded>
            <![CDATA[ 
<aside class="gh-post-upgrade-cta">
    <div class="gh-post-upgrade-cta-content" style="background-color: #662A7A">
            <h2>This post is for paying subscribers only</h2>
            <a class="gh-btn" data-portal="signup" style="color:#662A7A">Subscribe now</a>
            <p><small>Already have an account? <a data-portal="signin">Sign in</a></small></p>
    </div>
</aside>
... <a href="https://exceptionnotfound.net/the-catch-block-97-the-old-familiar-comments-trap/">Read more!</a> ]]>
        </content:encoded>
    </item>

</channel>
</rss>