<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Dotnet on Nicola Iarocci</title>
    <link>https://nicolaiarocci.com/tags/dotnet/</link>
    <description>Recent content in Dotnet on Nicola Iarocci</description>
    <generator>Hugo -- 0.143.1</generator>
    <language>en</language>
    <copyright>Produced / Written / Maintained by Nicola Iarocci since 2010</copyright>
    <lastBuildDate>Sun, 22 Mar 2026 09:05:32 +0100</lastBuildDate>
    <atom:link href="https://nicolaiarocci.com/tags/dotnet/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Fattura Elettronica 4.0.6</title>
      <link>https://nicolaiarocci.com/fattura-elettronica-4.0.6/</link>
      <pubDate>Sun, 22 Mar 2026 09:05:32 +0100</pubDate>
      <guid>https://nicolaiarocci.com/fattura-elettronica-4.0.6/</guid>
      <description>&lt;p&gt;A couple of days ago I released &lt;a href=&#34;https://www.nuget.org/packages/FatturaElettronica/4.0.6&#34;&gt;FatturaElettronica 4.0.6&lt;/a&gt;. It adds support for legacy &lt;code&gt;windows-1252&lt;/code&gt; encoding to both XML and P7M invoices, a long-standing annoyance that could previously be circumvented via external code.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;windows-1252&lt;/code&gt; encoding in Italian e-invoices has been a persistent headache — it&amp;rsquo;s technically outside the FatturaPA spec (which mandates UTF-8), but it crops up often enough in real-world invoices from older or misconfigured billing systems that users kept running into it. The &lt;a href=&#34;https://invoicetronic.com&#34;&gt;Invoicetronic&lt;/a&gt; stack has been updated accordingly.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>A couple of days ago I released <a href="https://www.nuget.org/packages/FatturaElettronica/4.0.6">FatturaElettronica 4.0.6</a>. It adds support for legacy <code>windows-1252</code> encoding to both XML and P7M invoices, a long-standing annoyance that could previously be circumvented via external code.</p>
<p><code>windows-1252</code> encoding in Italian e-invoices has been a persistent headache — it&rsquo;s technically outside the FatturaPA spec (which mandates UTF-8), but it crops up often enough in real-world invoices from older or misconfigured billing systems that users kept running into it. The <a href="https://invoicetronic.com">Invoicetronic</a> stack has been updated accordingly.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Code from my session at WPC 2025</title>
      <link>https://nicolaiarocci.com/code-from-my-session-at-wpc-2025/</link>
      <pubDate>Fri, 05 Dec 2025 10:07:42 +0100</pubDate>
      <guid>https://nicolaiarocci.com/code-from-my-session-at-wpc-2025/</guid>
      <description>&lt;p&gt;On Wednesday, I held a session  titled &amp;ldquo;Feature Flags and Dynamic Configurations in C#&amp;rdquo; at &lt;a href=&#34;https://www.wpc.education/&#34;&gt;WPC 2025&lt;/a&gt;. It went well, at least judging by the offline questions that came in at the end of the session and which almost made us late for lunch.&lt;/p&gt;
&lt;p&gt;Attending WPC is always exciting. The audience is large, the rooms are big and well-equipped, the energy is just right, and there&amp;rsquo;s always a chance to catch up with friends and colleagues. I especially enjoy seeing fellow Microsoft MVPs and speakers.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>On Wednesday, I held a session  titled &ldquo;Feature Flags and Dynamic Configurations in C#&rdquo; at <a href="https://www.wpc.education/">WPC 2025</a>. It went well, at least judging by the offline questions that came in at the end of the session and which almost made us late for lunch.</p>
<p>Attending WPC is always exciting. The audience is large, the rooms are big and well-equipped, the energy is just right, and there&rsquo;s always a chance to catch up with friends and colleagues. I especially enjoy seeing fellow Microsoft MVPs and speakers.</p>
<p>As promised, here is a <a href="https://github.com/nicolaiarocci/featureflags">link to the repository</a> with the code I demonstrated; just read the README to get your bearings. Oh, and as expected, someone in the audience got nerd-sniped by that <code>cj</code> bash function <a href="/curl-and-jq-go-to-a-conference/">I mentioned</a>.</p>
<figure>
    <img loading="lazy" src="/images/wpc2025.jpeg"
         alt="Snagged this one on LinkedIn. I expect the slides and video to be released soon by the fine folks at WPC."/> <figcaption>
            <p>Snagged this one on LinkedIn. I expect the slides and video to be released soon by the fine folks at WPC.</p>
        </figcaption>
</figure>

]]></content:encoded>
    </item>
    <item>
      <title>My session on MCP servers at .NET Conference Italia 2025</title>
      <link>https://nicolaiarocci.com/my-session-on-mcp-servers-at-dotnet-conference-italia-2025/</link>
      <pubDate>Wed, 26 Nov 2025 16:24:38 +0100</pubDate>
      <guid>https://nicolaiarocci.com/my-session-on-mcp-servers-at-dotnet-conference-italia-2025/</guid>
      <description>&lt;p&gt;I presented a session at the &lt;a href=&#34;https://www.aspitalia.com/eventi/97/.NET-Conference-Italia-2025-Milano.aspx&#34;&gt;.NET Conference Italia 2025&lt;/a&gt; in Milan a couple of weeks ago. The title was &amp;ldquo;Integrating our applications with LLMs and AI via MCP Servers&amp;rdquo;. It was well received; there were good questions throughout the talk and in the hall afterward. Surprisingly, live coding and demos went relatively smoothly.&lt;/p&gt;
&lt;p&gt;The fine guys at ASP Italia just published the &lt;a href=&#34;https://media.aspitalia.com/events/netconf25-LLM-dotNET-AI-MCP.media&#34;&gt;video&lt;/a&gt; in case someone is interested.&lt;/p&gt;
&lt;p&gt;Yeah, it is in Italian. I got a transcript from MacWhisper and then asked Claude to translate and clean it up. It did a pretty good job, so let me know if there&amp;rsquo;s any interest in an English transcript; I might post it here.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I presented a session at the <a href="https://www.aspitalia.com/eventi/97/.NET-Conference-Italia-2025-Milano.aspx">.NET Conference Italia 2025</a> in Milan a couple of weeks ago. The title was &ldquo;Integrating our applications with LLMs and AI via MCP Servers&rdquo;. It was well received; there were good questions throughout the talk and in the hall afterward. Surprisingly, live coding and demos went relatively smoothly.</p>
<p>The fine guys at ASP Italia just published the <a href="https://media.aspitalia.com/events/netconf25-LLM-dotNET-AI-MCP.media">video</a> in case someone is interested.</p>
<p>Yeah, it is in Italian. I got a transcript from MacWhisper and then asked Claude to translate and clean it up. It did a pretty good job, so let me know if there&rsquo;s any interest in an English transcript; I might post it here.</p>
<p>Speaking of English, I&rsquo;ve started submitting to international events again, without any luck so far. The conference landscape has changed quite a bit, especially since the COVID break. I still get invited to local ones, while internationals have been elusive. I suspect my change in technology stack plays a role. It was relatively easy to speak abroad when I was into Python. With .NET, not so much. But again, I was into Python in the pre-COVID era, so it is hard to tell which factors are at play and what their weight is.</p>
]]></content:encoded>
    </item>
    <item>
      <title>What .NET 10 garbage collection changes really mean for developers</title>
      <link>https://nicolaiarocci.com/what-.net-10-garbage-collection-changes-really-mean-for-developers/</link>
      <pubDate>Tue, 07 Oct 2025 10:12:04 +0200</pubDate>
      <guid>https://nicolaiarocci.com/what-.net-10-garbage-collection-changes-really-mean-for-developers/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;For decades, garbage collection in .NET was a background concern. It was mostly invisible to the everyday developer and was regarded as &amp;lsquo;automatic&amp;rsquo; unless (or until) something slowed down the application. However, .NET 10 changes this perspective by making garbage collection (GC) a key component of application performance.&amp;rdquo;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://roxeem.com/2025/09/30/what-net-10-gc-changes-mean-for-developers/&#34;&gt;What .NET 10 GC Changes Mean for Developers&lt;/a&gt; is a good in-depth article that explores the revolutionary garbage collection improvements in .NET 10, which deliver 2- 3x performance gains through seven key enhancements: escape analysis for stack allocation, DATAS enabled by default, flexible region sizing, delegate optimizations, intelligent write barrier elimination, enhanced devirtualization, and refined heap controls for containers.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>&ldquo;For decades, garbage collection in .NET was a background concern. It was mostly invisible to the everyday developer and was regarded as &lsquo;automatic&rsquo; unless (or until) something slowed down the application. However, .NET 10 changes this perspective by making garbage collection (GC) a key component of application performance.&rdquo;</p></blockquote>
<p><a href="https://roxeem.com/2025/09/30/what-net-10-gc-changes-mean-for-developers/">What .NET 10 GC Changes Mean for Developers</a> is a good in-depth article that explores the revolutionary garbage collection improvements in .NET 10, which deliver 2- 3x performance gains through seven key enhancements: escape analysis for stack allocation, DATAS enabled by default, flexible region sizing, delegate optimizations, intelligent write barrier elimination, enhanced devirtualization, and refined heap controls for containers.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Fattura Elettronica v4</title>
      <link>https://nicolaiarocci.com/fattura-elettronica-v4/</link>
      <pubDate>Mon, 16 Jun 2025 15:51:28 +0200</pubDate>
      <guid>https://nicolaiarocci.com/fattura-elettronica-v4/</guid>
      <description>&lt;p&gt;I just released &lt;a href=&#34;https://www.nuget.org/packages/FatturaElettronica/4.0.0&#34;&gt;FatturaElettronica.NET v4&lt;/a&gt;. The major version bump is due to a minor breaking change introduced with this version.&lt;/p&gt;
&lt;p&gt;After removing the BouncyCastle dependency (&lt;a href=&#34;https://fatturaelettronicaopensource.org/docs/changelog.html#v-3416&#34;&gt;v3.4.16&lt;/a&gt;) for signature, content extraction, and encoding purposes, a few minor behavioral changes were introduced in the library.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It was previously possible to extract content from documents with tampered signatures (if signature validation was flagged false)&lt;/li&gt;
&lt;li&gt;Signature exceptions were being misreported as Base64 &lt;code&gt;FormatExceptions&lt;/code&gt; for non-base64 input files&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After a &lt;a href=&#34;https://github.com/FatturaElettronica/FatturaElettronica.NET/issues/431&#34;&gt;lengthy analysis and troubleshooting&lt;/a&gt;, it was determined that System.Cryptography (which now replaces BouncyCastle) cannot support the successful decoding of tampered invoices. However, this is undesirable as a feature in the first place. The result is a breaking change: attempting to read tampered documents will now invariably throw &lt;code&gt;SignatureException&lt;/code&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I just released <a href="https://www.nuget.org/packages/FatturaElettronica/4.0.0">FatturaElettronica.NET v4</a>. The major version bump is due to a minor breaking change introduced with this version.</p>
<p>After removing the BouncyCastle dependency (<a href="https://fatturaelettronicaopensource.org/docs/changelog.html#v-3416">v3.4.16</a>) for signature, content extraction, and encoding purposes, a few minor behavioral changes were introduced in the library.</p>
<ol>
<li>It was previously possible to extract content from documents with tampered signatures (if signature validation was flagged false)</li>
<li>Signature exceptions were being misreported as Base64 <code>FormatExceptions</code> for non-base64 input files</li>
</ol>
<p>After a <a href="https://github.com/FatturaElettronica/FatturaElettronica.NET/issues/431">lengthy analysis and troubleshooting</a>, it was determined that System.Cryptography (which now replaces BouncyCastle) cannot support the successful decoding of tampered invoices. However, this is undesirable as a feature in the first place. The result is a breaking change: attempting to read tampered documents will now invariably throw <code>SignatureException</code>.</p>
<p>Many thanks to Paolo Manili, aka Delta-38, for <a href="https://github.com/FatturaElettronica/FatturaElettronica.NET/pull/434">contributing</a> this remarkable update.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Fattura Elettronica v3.6.3</title>
      <link>https://nicolaiarocci.com/fattura-elettronica-v3.6.3/</link>
      <pubDate>Tue, 06 May 2025 09:49:13 +0200</pubDate>
      <guid>https://nicolaiarocci.com/fattura-elettronica-v3.6.3/</guid>
      <description>&lt;p&gt;I just released &lt;a href=&#34;https://www.nuget.org/packages/FatturaElettronica/3.6.3&#34;&gt;FatturaElettronica .NET v3.6.3&lt;/a&gt;. Since version 3.6.1, the project has added English to the list of supported languages. The latest release improves English support, aligning it with the official translation. Michael Mairegger &lt;a href=&#34;https://github.com/FatturaElettronica/FatturaElettronica.NET/pull/432&#34;&gt;contributed&lt;/a&gt; this improvement.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://fatturaelettronicaopensource.org&#34;&gt;Fattura Elettronica&lt;/a&gt; open-source project allows for the validation and de/serialization of electronic invoices that adhere to the standard defined by the Italian Revenue Agency.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I just released <a href="https://www.nuget.org/packages/FatturaElettronica/3.6.3">FatturaElettronica .NET v3.6.3</a>. Since version 3.6.1, the project has added English to the list of supported languages. The latest release improves English support, aligning it with the official translation. Michael Mairegger <a href="https://github.com/FatturaElettronica/FatturaElettronica.NET/pull/432">contributed</a> this improvement.</p>
<p>The <a href="https://fatturaelettronicaopensource.org">Fattura Elettronica</a> open-source project allows for the validation and de/serialization of electronic invoices that adhere to the standard defined by the Italian Revenue Agency.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Fattura Elettronica v3.5.2</title>
      <link>https://nicolaiarocci.com/fattura-elettronica-v3.5.2/</link>
      <pubDate>Tue, 07 Jan 2025 11:38:52 +0100</pubDate>
      <guid>https://nicolaiarocci.com/fattura-elettronica-v3.5.2/</guid>
      <description>&lt;p&gt;I just released &lt;a href=&#34;https://www.nuget.org/packages/FatturaElettronica/3.5.2&#34;&gt;FatturaElettronica .NET v3.5.2&lt;/a&gt;. It gets around a &lt;a href=&#34;https://github.com/advisories/GHSA-hh2w-p6rv-4g7w&#34;&gt;known CVE&lt;/a&gt; so you may want to update ASAP. The Fattura Elettronica open-source project allows for the validation and de/serialization of electronic invoices that adhere to the standard defined by the Italian Revenue Agency.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I just released <a href="https://www.nuget.org/packages/FatturaElettronica/3.5.2">FatturaElettronica .NET v3.5.2</a>. It gets around a <a href="https://github.com/advisories/GHSA-hh2w-p6rv-4g7w">known CVE</a> so you may want to update ASAP. The Fattura Elettronica open-source project allows for the validation and de/serialization of electronic invoices that adhere to the standard defined by the Italian Revenue Agency.</p>
]]></content:encoded>
    </item>
    <item>
      <title>On C# and .NET quick release cycle</title>
      <link>https://nicolaiarocci.com/on-csharp-and-dotnet-quick-release-cycle/</link>
      <pubDate>Mon, 09 Dec 2024 17:31:18 +0100</pubDate>
      <guid>https://nicolaiarocci.com/on-csharp-and-dotnet-quick-release-cycle/</guid>
      <description>&lt;p&gt;&lt;em&gt;I sat to jot down a quick introduction to my &lt;a href=&#34;https://nicolaiarocci.com/speaking-at-the-dotnet-conference-italia-2024/&#34;&gt;C# 13 What&amp;rsquo;s New and Interesting&lt;/a&gt; session next week, and what I ended up with instead is a long rant or, should I dare, stream of consciousness that is certainly inappropriate for a five-minute introduction. I&amp;rsquo;ll have to cut most of it down, especially on the personal story part, but my site might be a good place to host it in all its completeness. I may reference this post at the start of the session on Monday for those few poor souls who might be interested.&lt;/em&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><em>I sat to jot down a quick introduction to my <a href="/speaking-at-the-dotnet-conference-italia-2024/">C# 13 What&rsquo;s New and Interesting</a> session next week, and what I ended up with instead is a long rant or, should I dare, stream of consciousness that is certainly inappropriate for a five-minute introduction. I&rsquo;ll have to cut most of it down, especially on the personal story part, but my site might be a good place to host it in all its completeness. I may reference this post at the start of the session on Monday for those few poor souls who might be interested.</em></p>
<p>Exactly one year ago we were here, in this same room, at the same conference, presenting C# 12. Some of you in the audience were present back then. If so, please raise your hands. Twelve months later, here we are again, looking at a new version of C#. It&rsquo;s the new normal; this has been happening, give or take, since the advent of .NET Core and C# 8 in 2019. Previously, C# had a new release every 2–3 years, so the release rate has doubled or even tripled recently. Is this good news? If you&rsquo;ve followed forums or social media, you might have noticed some controversy about the topic. The main complaint is that the language is changing too quickly, &ldquo;chasing trends,&rdquo; with no valuable addition to its core.</p>
<p>Most of these complaints come from old-timers around my age (maybe even ten years younger because I&rsquo;m seasoned) and have been in the .NET environment for many, perhaps too many years. There&rsquo;s always a certain inertia, a form of resistance to change, especially when it&rsquo;s rapid. But I&rsquo;m seasoned enough to remember when complaints went in the opposite direction: back then, the .NET Framework (the historical, monolithic, Windows-only version) moved like a dinosaur while the world was racing ahead. New languages were blooming. Old competitors were evolving at double or triple the speed, constantly innovating, and—this is key—attracting hordes of developers. There was a critical moment when this attraction became so intense that more and more developers set aside .NET and C# to explore new directions. I know because I was one of them.</p>
<p>Around 2010–11, I was set to create a new, rather complex platform of REST services, and instead of reaching out for my usual .NET toolchain, I chose Python. That marked the beginning of an adventure that lasted years and included the unexpected release of some reasonably successful open-source Python projects. The reasons I decided to abandon .NET and C# were several—not least the frustration with the lack of transparency and a clear path for the .NET ecosystem, its languages, with oh-so-many frameworks enthusiastically presented and then abandoned, changes of direction, and above all, in my case, it all being closed source, which didn&rsquo;t allow me to dig deeper and understand why certain things didn&rsquo;t work as expected. I clearly remember when I was writing my first REST service in Python and realized that in this new ecosystem if I didn&rsquo;t understand what was happening behind the scenes (in my case, with the Flask framework), I could quickly look at what was going on because the entire Flask source code, like Python&rsquo;s for that matter, was available not only for consumption but it was also open to contribution. Coming from the enterprise closed-source world, it was an empowering sensation.</p>
<p>The discovery of Flask was an absolute revelation, not for its intrinsic features (which were great) but because it was just one of the many options. In Python space, there were dozens of web frameworks at varying stages of maturity. There was a choice and often many different approaches to solve the same problem. I could experiment freely and decide what was best for my use case. Not only was I facing a vast and diverse world, but I could also use the operating system I wanted. Linux was much less demanding, let alone less expensive, for deployment than Windows, and behold! I could use a Mac for development. Open-source, cross-platform, with a vast community not only adopting the language and the standard library but constantly forging new solutions, making them available to the same community, almost always for free. It was the way forward.</p>
<p>I envied that such a thing was unthinkable in my world. But unbeknownst to many, Microsoft was watching and taking notes. To the best of my knowledge, it was mainly the developers inside the corp —the dev team—who, glancing out of the ivory tower, began a campaign of internal lobbying, initially scattered and disorganized and later increasingly coordinated, which in turn led to endless meetings, discussions at coffee machines, and gradually, slowly and then more rapidly, to the advent of the .NET Core project. The metaphor of a snowball slowly rolling down a slope until it becomes an unstoppable avalanche perfectly applies here.</p>
<p>So, years after my departure (not an actual departure—I still worked in .NET for our legacy products), a new and unexpected .NET appeared on the scene. It was open-source, cross-platform, and open to external contributions. We could and perhaps should have a lengthy discussion on the openness to external contributions, but we can all agree that a revolution occurred and was historic in scale. At the same time, Microsoft opened up to other stacks, mainly because of Azure. I was shocked when I was proposed for a Microsoft MVP Award for my work on Python, not C#, at a time when Python had little to nothing to do with Microsoft. It made sense, as there was an urgent need to speak to developers outside its ecosystem—and perhaps even more so to those like me who had left: <em>Hey, look, we&rsquo;re back, we&rsquo;re on track, and we&rsquo;re not evil anymore</em>.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> </p>
<p>And there I was, finding my old stack (which I secretly, I admit, considered only museum-worthy) back to relevance, competing on equal footing with the rest of the scene. The delay was costly, though. Even today, I meet colleagues who think modern .NET is just a new version, if not a simple rebranding of the Windows framework of old, and C# is more or less the same, way behind the new kids on the block. It&rsquo;s a shame, and there are responsibilities. Some choices could have been bolder and more disruptive, starting with naming the new framework—but that&rsquo;s another story.</p>
<p>Today, I create REST services with Minimal APIs on my Mac and deploy them on Linux via Docker at zero or near-zero cost, just as I would with Python, JavaScript, Rust, Go, or any other stack. The performance is far better than Python&rsquo;s (C# REST services make circles around Python&rsquo;s), and the toolchain is rich and powerful, especially around the command line, while many think .NET is still a GUI/Windows thing. Quick release cycles are essential to compensate for lost time (and there was lots of it) and stay on the cutting edge, sending a continuous signal that the platform is alive, thriving, and constantly expanding.</p>
<p>Aldus Manutius, the renowned Venetian printer and publisher of the Renaissance, adopted the Latin motto <em>Festina lente</em>, which translates to <em>Make haste slowly</em> or <em>Hasten slowly</em>. This paradoxical phrase encapsulates achieving careful, deliberate progress quickly and precisely, balancing urgency with caution. I feel that, consciously or not, the .NET team is on track with Manuzio&rsquo;s goal: they iterate rapidly to achieve progress, balancing urgency with caution.</p>
<p>Nowadays, both .NET and C# focus on performance and while there&rsquo;s room for growth, the current achievements are extraordinary. We&rsquo;re competitive with most stacks, if not significantly ahead of them. Frequent, more minor C# releases allow for quick adjustments. Attentive developers adopt them continuously. Meanwhile, those who aren&rsquo;t in a rush (probably most of Microsoft&rsquo;s long-time customers, slow-moving conglomerates and the like) benefit from performance gains and technological advantages (multi-platform deployment!) at a low cost because, while the framework and language evolve, great effort is put into preserving backward compatibility. In most cases, migrating to .NET Core and newer versions of C# requires minimal effort.</p>
<p>C# 12 introduced two significant features: primary constructors and collection expressions, with the latter being predominant in terms of syntactic, semantic, and performance importance. They weren&rsquo;t the only new features but certainly the key ones. C# 13 innovates further but subtly—there&rsquo;s less syntax and more semantics, building on last year&rsquo;s new features. The improvements may be less flashy but guide developers in the right direction, often ensuring better performance at zero cost, sometimes even without us having to do anything. As we shall see, it happens because in recent releases—let&rsquo;s say the last two or three— features were introduced primarily to improve the framework, which is also written in C#. Our higher-level applications benefit from all of this. It is a pattern we&rsquo;ll observe repeatedly throughout this presentation.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>If you think we&rsquo;re talking about the same company that had its CEO infamously pronounce the &ldquo;Linux is a cancer&rdquo; quote, please consider that it happened on <a href="https://www.theregister.com/2001/06/02/ballmer_linux_is_a_cancer/">June 1, 2001</a>. That was 23 (twenty-three!) years ago at the time of this writing. Take your time to process that. That happened like a couple of technological eras ago. I know it&rsquo;s a distant past because I was there. Things have moved forward. Get over it. Of course, one must stay vigilant; things can change, but this is where we are now, and it is a good position to be in.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Speaking at the .NET Conference Italia 2024</title>
      <link>https://nicolaiarocci.com/speaking-at-the-dotnet-conference-italia-2024/</link>
      <pubDate>Sat, 07 Dec 2024 08:36:26 +0100</pubDate>
      <guid>https://nicolaiarocci.com/speaking-at-the-dotnet-conference-italia-2024/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m speaking at the &lt;a href=&#34;https://www.dotnetconference.it&#34;&gt;.NET Conference Italia 2024&lt;/a&gt; on Dec 16th in Milan at the Microsoft House. My session is titled &lt;a href=&#34;https://www.dotnetconference.it/e/sessione/3589/C-13-e-NET-9-cosa-c%E2%80%99e-di-nuovo-e-interessante&#34;&gt;C# 13 What&amp;rsquo;s New and Interesting&lt;/a&gt; and will be on the latest iteration of the C# language. We&amp;rsquo;ll also briefly touch on .NET 9, which was also just released. Hope to see you there (make sure to come to me to say Hi!)&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I&rsquo;m speaking at the <a href="https://www.dotnetconference.it">.NET Conference Italia 2024</a> on Dec 16th in Milan at the Microsoft House. My session is titled <a href="https://www.dotnetconference.it/e/sessione/3589/C-13-e-NET-9-cosa-c%E2%80%99e-di-nuovo-e-interessante">C# 13 What&rsquo;s New and Interesting</a> and will be on the latest iteration of the C# language. We&rsquo;ll also briefly touch on .NET 9, which was also just released. Hope to see you there (make sure to come to me to say Hi!)</p>
]]></content:encoded>
    </item>
    <item>
      <title>Fattura Elettronica v3.5</title>
      <link>https://nicolaiarocci.com/fattura-elettronica-v3.5/</link>
      <pubDate>Mon, 30 Sep 2024 09:39:20 +0200</pubDate>
      <guid>https://nicolaiarocci.com/fattura-elettronica-v3.5/</guid>
      <description>&lt;p&gt;I just released &lt;a href=&#34;https://www.nuget.org/packages/FatturaElettronica&#34;&gt;FatturaElettronica .NET v3.5.0&lt;/a&gt;. This version adds multi-language support, all thanks to the excellent work done by &lt;a href=&#34;https://michaelmairegger.it&#34;&gt;Michael Mairegger&lt;/a&gt;. We currently support Italian and German and are ready to accept contributions for other languages. The Fattura Elettronica open-source project allows for the validation and de/serialization of electronic invoices that adhere to the standard defined by the Italian Revenue Agency.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I just released <a href="https://www.nuget.org/packages/FatturaElettronica">FatturaElettronica .NET v3.5.0</a>. This version adds multi-language support, all thanks to the excellent work done by <a href="https://michaelmairegger.it">Michael Mairegger</a>. We currently support Italian and German and are ready to accept contributions for other languages. The Fattura Elettronica open-source project allows for the validation and de/serialization of electronic invoices that adhere to the standard defined by the Italian Revenue Agency.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Under ASP.NET 8, NGINX returns 502 Bad Gateway after authentication by IdentityServer</title>
      <link>https://nicolaiarocci.com/under-aspnet-8-nginx-returns-502-bad-gateway-after-authentication-by-identityserver/</link>
      <pubDate>Thu, 12 Sep 2024 16:17:58 +0200</pubDate>
      <guid>https://nicolaiarocci.com/under-aspnet-8-nginx-returns-502-bad-gateway-after-authentication-by-identityserver/</guid>
      <description>Today, I learned the hard way that NGINX has default buffer sizes, which can cause trouble in specific scenarios like mine.</description>
      <content:encoded><![CDATA[<p>Today, I learned the hard way that NGINX has small buffer sizes, which can cause trouble in specific scenarios like mine.</p>
<p>We have two ASP.NET 8 applications behind NGINX; one is a regular web app, and the other is an auth server built with Duende Identity Server. When the user attempts to log in to the web app, they are sent to the auth server; once logged in, they are sent back to the app, and that&rsquo;s when NGINX returns a weird 502 Bad Gateway. Upon inspecting the NGINX logs, I found the following error:</p>
<pre><code>upstream sent too big header while reading response header from upstream
</code></pre>
<p>Some digging revealed that NGINX has a pretty small default buffer size, and proxying auth requests (with their typically above-average-size headers) back and forth is prone to breaking that limit.</p>
<p>The fix is straightforward: raise those buffer sizes. Most blogs suggest doing that globally, but that seems overkill, as NGINX buffering can be configured per server and location blocks. You may want to keep the global defaults and only raise them (along with memory consumption) for locations that need it.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>  location {
</span></span><span style="display:flex;"><span>    ...
</span></span><span style="display:flex;"><span>    proxy_buffers 4 256k;
</span></span><span style="display:flex;"><span>    proxy_buffer_size 128k;
</span></span><span style="display:flex;"><span>    proxy_busy_buffers_size 256k;
</span></span><span style="display:flex;"><span>    ...
</span></span><span style="display:flex;"><span>  }
</span></span></code></pre></div><p>Mind you, the above values (that I found in almost every blog dealing with this problem) are likely too big and should be trimmed down. That&rsquo;s my next task, using <a href="https://www.getpagespeed.com/server-setup/nginx/tuning-proxy_buffer_size-in-nginx">this</a> excellent article for guidance.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Microsoft MVP</title>
      <link>https://nicolaiarocci.com/microsoft-mvp-ninth-time/</link>
      <pubDate>Thu, 11 Jul 2024 15:11:50 +0200</pubDate>
      <guid>https://nicolaiarocci.com/microsoft-mvp-ninth-time/</guid>
      <description>&lt;p&gt;Last night, I was at an outdoor theatre with Serena, watching Anatomy of a Fall (an excellent film). Outdoor theatres are becoming rare, which is a pity, and &lt;a href=&#34;https://maps.app.goo.gl/j7t3SigtkPtKnB22A&#34;&gt;Arena del Sole&lt;/a&gt; is lovely with its strong vintage, 80s vibe. There&amp;rsquo;s little as pleasant as watching a film under the stars with your loved one on a quiet summer evening.&lt;/p&gt;
&lt;p&gt;Anyway, in the pause, I glanced at my e-mails and discovered I had been again granted the &lt;a href=&#34;https://mvp.microsoft.com/en-US/mvp/profile/a6892d61-aea0-e511-8114-c4346bac0abc&#34;&gt;Microsoft MVP Award&lt;/a&gt;. It is the ninth consecutive year, and I&amp;rsquo;m grateful and happy the journey continues. At this point, I should put in some extra effort to reach the 10-year milestone next year.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Last night, I was at an outdoor theatre with Serena, watching Anatomy of a Fall (an excellent film). Outdoor theatres are becoming rare, which is a pity, and <a href="https://maps.app.goo.gl/j7t3SigtkPtKnB22A">Arena del Sole</a> is lovely with its strong vintage, 80s vibe. There&rsquo;s little as pleasant as watching a film under the stars with your loved one on a quiet summer evening.</p>
<p>Anyway, in the pause, I glanced at my e-mails and discovered I had been again granted the <a href="https://mvp.microsoft.com/en-US/mvp/profile/a6892d61-aea0-e511-8114-c4346bac0abc">Microsoft MVP Award</a>. It is the ninth consecutive year, and I&rsquo;m grateful and happy the journey continues. At this point, I should put in some extra effort to reach the 10-year milestone next year.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to handle custom claims in an Open ID Connect-authenticated ASP.NET Core app</title>
      <link>https://nicolaiarocci.com/how-to-handle-custom-claims-in-an-oidc-authenticated-aspnet-core-app/</link>
      <pubDate>Fri, 31 May 2024 15:53:30 +0200</pubDate>
      <guid>https://nicolaiarocci.com/how-to-handle-custom-claims-in-an-oidc-authenticated-aspnet-core-app/</guid>
      <description>&lt;p&gt;Today, I learned how to handle custom claims in an Open ID Connect authenticated ASP.NET Core app.&lt;/p&gt;
&lt;p&gt;The scenario goes like this. I have an ASP.NET Core app that authenticates with Open Id Connect. It receives a bearer token from the authentication server. Besides OIDC claims, this token has been forged with additional custom claims for use in the app. However, only ODIC claims exist when I parse &lt;code&gt;HttpContext.User.Identity.Claims&lt;/code&gt; in my middleware. If I retrieve the token with &lt;code&gt;HttpContext.GetTokenAsync&lt;/code&gt; and decode it, I confirm it contains all the claims I need. Where have my custom claims gone? Or, how can I get &lt;code&gt;User.Identity&lt;/code&gt; to provide them along with the OIDC ones?&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today, I learned how to handle custom claims in an Open ID Connect authenticated ASP.NET Core app.</p>
<p>The scenario goes like this. I have an ASP.NET Core app that authenticates with Open Id Connect. It receives a bearer token from the authentication server. Besides OIDC claims, this token has been forged with additional custom claims for use in the app. However, only ODIC claims exist when I parse <code>HttpContext.User.Identity.Claims</code> in my middleware. If I retrieve the token with <code>HttpContext.GetTokenAsync</code> and decode it, I confirm it contains all the claims I need. Where have my custom claims gone? Or, how can I get <code>User.Identity</code> to provide them along with the OIDC ones?</p>
<p>As it turns out, one must hack them into the <code>User.Identity.Claims</code> collection by hand. That&rsquo;s done by leveraging the <code>OnTokenValidated</code> event handler like this:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span>authenticationBuilder.AddOpenIdConnect(<span style="font-style:italic">&#34;oidc&#34;</span>, options =&gt;
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    options.Authority = <span style="font-style:italic">&#34;authority&#34;</span>;
</span></span><span style="display:flex;"><span>    options.ClientId = <span style="font-style:italic">&#34;client_id&#34;</span>;
</span></span><span style="display:flex;"><span>    options.ClientSecret = <span style="font-style:italic">&#34;secret&#34;</span>;
</span></span><span style="display:flex;"><span>    options.ResponseType = <span style="font-style:italic">&#34;code&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    ...
</span></span><span style="display:flex;"><span>    options.GetClaimsFromUserInfoEndpoint = <span style="font-weight:bold">true</span>;
</span></span><span style="display:flex;"><span>    options.SaveTokens = <span style="font-weight:bold">true</span>;
</span></span><span style="display:flex;"><span>    options.Events = <span style="font-weight:bold">new</span>()
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        OnTokenValidated = context =&gt;
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="font-style:italic">// adds custom claims from the token into Principal.Identity</span>
</span></span><span style="display:flex;"><span>            <span style="font-weight:bold">if</span> (context.Principal?.Identity <span style="font-weight:bold">is</span> not ClaimsIdentity claimsIdentity) <span style="font-weight:bold">return</span> Task.CompletedTask;
</span></span><span style="display:flex;"><span>            
</span></span><span style="display:flex;"><span>            <span style="">var</span> accessToken = context.TokenEndpointResponse?.AccessToken;
</span></span><span style="display:flex;"><span>            <span style="font-weight:bold">if</span> (<span style="">string</span>.IsNullOrEmpty(accessToken)) <span style="font-weight:bold">return</span> Task.CompletedTask;
</span></span><span style="display:flex;"><span>            
</span></span><span style="display:flex;"><span>            <span style="">var</span> handler = <span style="font-weight:bold">new</span> JwtSecurityTokenHandler();
</span></span><span style="display:flex;"><span>            <span style="font-weight:bold">if</span> (handler.ReadToken(accessToken) <span style="font-weight:bold">is</span> not JwtSecurityToken jsonToken) <span style="font-weight:bold">return</span> Task.CompletedTask;
</span></span><span style="display:flex;"><span>            
</span></span><span style="display:flex;"><span>            <span style="font-weight:bold">foreach</span> (<span style="">var</span> claim <span style="font-weight:bold">in</span> jsonToken.Claims)
</span></span><span style="display:flex;"><span>                <span style="font-weight:bold">if</span> (claimsIdentity.Claims.All(c =&gt; c.Type != claim.Type))
</span></span><span style="display:flex;"><span>                    claimsIdentity.AddClaim(claim);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="font-weight:bold">return</span> Task.CompletedTask;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>Is there a better and less hacky way to achieve the same result? Please let me know.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Fattura Elettronica for .NET v3.4.15</title>
      <link>https://nicolaiarocci.com/fattura-elettronica-for-.net-v3.4.15/</link>
      <pubDate>Fri, 24 May 2024 11:02:31 +0200</pubDate>
      <guid>https://nicolaiarocci.com/fattura-elettronica-for-.net-v3.4.15/</guid>
      <description>&lt;p&gt;Today I released &lt;a href=&#34;https://fatturaelettronicaopensource.org/docs&#34;&gt;Fattura Elettronica for .NET&lt;/a&gt; v3.4.15. The Fattura
Elettronica project allows for the validation and de/serialization of electronic
invoices that adhere to the standard defined by Italian Revenue Agency
(&lt;a href=&#34;https://www.agenziaentrate.gov.it/portale/web/guest/specifiche-tecniche-versione-1.8&#34;&gt;Agenzia Entrate&lt;/a&gt;). See the &lt;a href=&#34;https://fatturaelettronicaopensource.org/docs/changelog.html#v-3415&#34;&gt;changelog&lt;/a&gt; for details (Italian).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today I released <a href="https://fatturaelettronicaopensource.org/docs">Fattura Elettronica for .NET</a> v3.4.15. The Fattura
Elettronica project allows for the validation and de/serialization of electronic
invoices that adhere to the standard defined by Italian Revenue Agency
(<a href="https://www.agenziaentrate.gov.it/portale/web/guest/specifiche-tecniche-versione-1.8">Agenzia Entrate</a>). See the <a href="https://fatturaelettronicaopensource.org/docs/changelog.html#v-3415">changelog</a> for details (Italian).</p>
]]></content:encoded>
    </item>
    <item>
      <title>The video of my OAuth2 session at WebDay 2024 is online</title>
      <link>https://nicolaiarocci.com/the-video-of-my-oauth2-session-at-webday-2024-is-online/</link>
      <pubDate>Thu, 23 May 2024 09:30:54 +0200</pubDate>
      <guid>https://nicolaiarocci.com/the-video-of-my-oauth2-session-at-webday-2024-is-online/</guid>
      <description>&lt;p&gt;The video my OAuth2 and OpenID Connect session at WebDay 2024 Milan is
&lt;a href=&#34;https://www.improove.tech/videos/3376/Oauth2-e-Open-ID-Connect-con-ASP-NET-Core-8&#34;&gt;available
online&lt;/a&gt;.
It is in Italian, and you need to login or register in order to see it (sorry, I
don’t have control over it.)&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The video my OAuth2 and OpenID Connect session at WebDay 2024 Milan is
<a href="https://www.improove.tech/videos/3376/Oauth2-e-Open-ID-Connect-con-ASP-NET-Core-8">available
online</a>.
It is in Italian, and you need to login or register in order to see it (sorry, I
don’t have control over it.)</p>
]]></content:encoded>
    </item>
    <item>
      <title>C# 12 Collection Expressions</title>
      <link>https://nicolaiarocci.com/csharp-collection-expressions/</link>
      <pubDate>Fri, 10 May 2024 17:39:02 +0200</pubDate>
      <guid>https://nicolaiarocci.com/csharp-collection-expressions/</guid>
      <description>&lt;p&gt;This is a follow-up post to &lt;a href=&#34;https://nicolaiarocci.com/csharp-primary-constructors&#34;&gt;C# 12 Primary
Constructors&lt;/a&gt;. Like that article, this one
originates from the preparation notes for my presentation at the &lt;a href=&#34;https://abp.io/conference/2024&#34;&gt;ABP Dotnet
Conference 2024&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I love collection expressions. Like primary constructors, collection
expressions will see a significant adoption in the long run.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Collection expressions introduce a new way to initialize common collection
values in a terse, unified syntax.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This is how we initialize collections today:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cs&#34; data-lang=&#34;cs&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;var&lt;/span&gt; x1 = &lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;&#34;&gt;int&lt;/span&gt;[] { 1, 2, 3, 4 };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;var&lt;/span&gt; x2 = Array.Empty&amp;lt;&lt;span style=&#34;&#34;&gt;int&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WriteByteArray(&lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt;[] { (&lt;span style=&#34;&#34;&gt;byte&lt;/span&gt;)1, (&lt;span style=&#34;&#34;&gt;byte&lt;/span&gt;)2, (&lt;span style=&#34;&#34;&gt;byte&lt;/span&gt;)3 });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;List&amp;lt;&lt;span style=&#34;&#34;&gt;int&lt;/span&gt;&amp;gt; x3 = &lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt;() { 1, 2, 3, 4 };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Span&amp;lt;DateTime&amp;gt; dates = &lt;span style=&#34;font-weight:bold&#34;&gt;stackalloc&lt;/span&gt; DateTime[] { GetDate(0), GetDate(1) };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WriteByteSpan(&lt;span style=&#34;font-weight:bold&#34;&gt;stackalloc&lt;/span&gt;[] { (&lt;span style=&#34;&#34;&gt;byte&lt;/span&gt;)1, (&lt;span style=&#34;&#34;&gt;byte&lt;/span&gt;)2, (&lt;span style=&#34;&#34;&gt;byte&lt;/span&gt;)3 });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice how the code is diverse depending on the type and the context. It is also
verbose. Look at how we initialize an empty &lt;code&gt;int&lt;/code&gt; array (second line); it&amp;rsquo;s
lengthy and starkly contrasts with the previous line, where we initialize the
same type with some actual values.  In many situations, casting is needed;
again, take a look at the &lt;code&gt;WriteByteArray&lt;/code&gt; and &lt;code&gt;WriteByteSpan&lt;/code&gt; calls.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>This is a follow-up post to <a href="/csharp-primary-constructors">C# 12 Primary
Constructors</a>. Like that article, this one
originates from the preparation notes for my presentation at the <a href="https://abp.io/conference/2024">ABP Dotnet
Conference 2024</a>.</p>
<ul>
<li>
<p>I love collection expressions. Like primary constructors, collection
expressions will see a significant adoption in the long run.</p>
</li>
<li>
<p>Collection expressions introduce a new way to initialize common collection
values in a terse, unified syntax.</p>
</li>
<li>
<p>This is how we initialize collections today:</p>
</li>
</ul>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span><span style="">var</span> x1 = <span style="font-weight:bold">new</span> <span style="">int</span>[] { 1, 2, 3, 4 };
</span></span><span style="display:flex;"><span><span style="">var</span> x2 = Array.Empty&lt;<span style="">int</span>&gt;();
</span></span><span style="display:flex;"><span>WriteByteArray(<span style="font-weight:bold">new</span>[] { (<span style="">byte</span>)1, (<span style="">byte</span>)2, (<span style="">byte</span>)3 });
</span></span><span style="display:flex;"><span>List&lt;<span style="">int</span>&gt; x3 = <span style="font-weight:bold">new</span>() { 1, 2, 3, 4 };
</span></span><span style="display:flex;"><span>Span&lt;DateTime&gt; dates = <span style="font-weight:bold">stackalloc</span> DateTime[] { GetDate(0), GetDate(1) };
</span></span><span style="display:flex;"><span>WriteByteSpan(<span style="font-weight:bold">stackalloc</span>[] { (<span style="">byte</span>)1, (<span style="">byte</span>)2, (<span style="">byte</span>)3 });
</span></span></code></pre></div><p>Notice how the code is diverse depending on the type and the context. It is also
verbose. Look at how we initialize an empty <code>int</code> array (second line); it&rsquo;s
lengthy and starkly contrasts with the previous line, where we initialize the
same type with some actual values.  In many situations, casting is needed;
again, take a look at the <code>WriteByteArray</code> and <code>WriteByteSpan</code> calls.</p>
<ul>
<li>With collection expressions, it becomes like this:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span><span style="">int</span>[] x4 = [1, 2, 3, 4];
</span></span><span style="display:flex;"><span><span style="">int</span>[] x5 = [];
</span></span><span style="display:flex;"><span>WriteByteArray([1, 2, 3]);
</span></span><span style="display:flex;"><span>List&lt;<span style="">int</span>&gt; x6 = [1, 2, 3, 4];
</span></span><span style="display:flex;"><span>Span&lt;DateTime&gt; dates1 = [GetDate(0), GetDate(1)];
</span></span><span style="display:flex;"><span>WriteByteSpan([1, 2, 3]);
</span></span></code></pre></div><p>We enclose items within square brackets, and that&rsquo;s all. An empty collection is
empty brackets. We can, of course, call functions or use variables.</p>
<ul>
<li>
<p>In many scenarios, the compiler will perform several optimizations. It can
allocate the correct capacity or avoid copying data when unnecessary. The
compiler can do that because the supported collection types are well-known and
have been for a long time. We get these performance boosts for free when we switch to
collection expressions.</p>
</li>
<li>
<p>Let&rsquo;s look at that <code>WriteByteArray</code> call. Let&rsquo;s say that at some
point, maybe months or years after it&rsquo;s been used in many places, we decide to
refactor the method and change the argument type from <code>byte[]</code> to <code>int[].</code> We&rsquo;d
have to refactor the old-style caller to eliminate the casting, which is now an
error. We don&rsquo;t need to do any fix with collection expressions as they come with
enhanced inference that will resolve the casting for us.</p>
</li>
<li>
<p>On the first line, we&rsquo;re initializing a new array (we aren&rsquo;t calling a method
with a signature), so with collection expressions, if we try to use <code>var,</code> it
won&rsquo;t work. In that case, we need to be explicit about the type.</p>
</li>
<li>
<p>The spread operator allows us to insert variables and constants and to sort of
&ldquo;unroll&rdquo; another collection within the new one, and it does so with optimal
performance.</p>
</li>
</ul>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span><span style="">int</span>[] numbers1 = [1, 2, 3];
</span></span><span style="display:flex;"><span><span style="">int</span>[] numbers2 = [4, 5, 6];
</span></span><span style="display:flex;"><span><span style="">int</span>[] moreNumbers = [.. numbers1, .. numbers2, 7, 8, 9];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="font-weight:bold">foreach</span>(<span style="">var</span> number <span style="font-weight:bold">in</span> moreNumbers)
</span></span><span style="display:flex;"><span>    Console.WriteLine(number);
</span></span></code></pre></div><p>It would be nice if lambdas were allowed in collection expressions,
like in other languages (Python), but that&rsquo;s not yet an option.</p>
<ul>
<li>What about custom collections? But let&rsquo;s imagine I have built a <code>LineBuffer</code>
class that inherits from <code>IEnumrable&lt;chrar&gt;</code>; it offers some custom features
over its base class. I get an error if I try to use collection expression syntax
on it. It is not a common .NET type, and the compiler doesn&rsquo;t know how to go
around it.</li>
</ul>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span><span style="font-weight:bold">public</span> <span style="font-weight:bold">class</span> <span style="font-weight:bold">LineBuffer</span> : IEnumerable&lt;<span style="">char</span>&gt;
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">private</span> <span style="font-weight:bold">readonly</span> <span style="">char</span>[] _buffer = <span style="font-weight:bold">new</span> <span style="">char</span>[80];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">public</span> LineBuffer(ReadOnlySpan&lt;<span style="">char</span>&gt; buffer)
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="">int</span> number = (_buffer.Length &lt; buffer.Length) ? _buffer.Length : buffer.Length;
</span></span><span style="display:flex;"><span>        <span style="font-weight:bold">for</span> (<span style="">int</span> i = 0; i &lt; number; i++)
</span></span><span style="display:flex;"><span>            _buffer[i] = buffer[i];
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">public</span> IEnumerator&lt;<span style="">char</span>&gt; GetEnumerator() =&gt; _buffer.AsEnumerable&lt;<span style="">char</span>&gt;().GetEnumerator();
</span></span><span style="display:flex;"><span>    IEnumerator IEnumerable.GetEnumerator() =&gt; _buffer.GetEnumerator();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="font-style:italic">// etc</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="font-style:italic">// this causes a compile error</span>
</span></span><span style="display:flex;"><span>LineBuffer line = [<span style="font-style:italic">&#39;H&#39;</span>, <span style="font-style:italic">&#39;e&#39;</span>, <span style="font-style:italic">&#39;l&#39;</span>, <span style="font-style:italic">&#39;l&#39;</span>, <span style="font-style:italic">&#39;o&#39;</span>, <span style="font-style:italic">&#39; &#39;</span>, <span style="font-style:italic">&#39;W&#39;</span>, <span style="font-style:italic">&#39;o&#39;</span>, <span style="font-style:italic">&#39;r&#39;</span>, <span style="font-style:italic">&#39;l&#39;</span>, <span style="font-style:italic">&#39;d&#39;</span>, <span style="font-style:italic">&#39;!&#39;</span>];
</span></span></code></pre></div><ul>
<li>We can support collection expressions in our custom types, though. It&rsquo;s a
two-step process. First, we implement a builder method, then decorate the class
(or struct) with a <code>CollectionBuilderAttribute.</code> The attribute maps our type to
the builder method.</li>
</ul>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span>[CollectionBuilder(typeof(LineBuffer), nameof(Create))]
</span></span><span style="display:flex;"><span><span style="font-weight:bold">public</span> <span style="font-weight:bold">class</span> <span style="font-weight:bold">LineBuffer</span> : IEnumerable&lt;<span style="">char</span>&gt;
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">private</span> <span style="font-weight:bold">readonly</span> <span style="">char</span>[] _buffer = <span style="font-weight:bold">new</span> <span style="">char</span>[80];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">public</span> LineBuffer(ReadOnlySpan&lt;<span style="">char</span>&gt; buffer)
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="">int</span> number = (_buffer.Length &lt; buffer.Length) ? _buffer.Length : buffer.Length;
</span></span><span style="display:flex;"><span>        <span style="font-weight:bold">for</span> (<span style="">int</span> i = 0; i &lt; number; i++)
</span></span><span style="display:flex;"><span>            _buffer[i] = buffer[i];
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">public</span> IEnumerator&lt;<span style="">char</span>&gt; GetEnumerator() =&gt; _buffer.AsEnumerable&lt;<span style="">char</span>&gt;().GetEnumerator();
</span></span><span style="display:flex;"><span>    IEnumerator IEnumerable.GetEnumerator() =&gt; _buffer.GetEnumerator();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">internal</span> <span style="font-weight:bold">static</span> LineBuffer Create(ReadOnlySpan&lt;<span style="">char</span>&gt; values) =&gt; <span style="font-weight:bold">new</span> LineBuffer(values);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The official documentation says the builder must be named &ldquo;Create,&rdquo; but that&rsquo;s
false. We can name it however we want as long as it matches the attribute (it&rsquo;s
probably still worth adhering to the suggested practice.)</p>
<ul>
<li>
<p>Adding collection expression support to custom types is helpful in your
codebase, even more so if you&rsquo;re a library author.</p>
</li>
<li>
<p>The syntax of collection expressions is symmetric with that of slicing and
pattern matching, a nice touch that keeps the language tidy and coherent. Take a
look at this pattern matching switch:</p>
</li>
</ul>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span><span style="font-weight:bold">public</span> Grade GPA =&gt; Grades <span style="font-weight:bold">switch</span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    [] =&gt; 4.0m,
</span></span><span style="display:flex;"><span>    [var grade] =&gt; grade,
</span></span><span style="display:flex;"><span>    [.. var all] =&gt; all.Average()
</span></span><span style="display:flex;"><span>};
</span></span></code></pre></div><ul>
<li>
<p>Visual Studio, VS Code, JetBrains Rider and most other IDEs offer full support
for refactoring old-style collection initializations to collection expressions.</p>
</li>
<li>
<p>What about dictionary expressions? They are common in other languages (again,
Python). When asked, Kathrine Dollard of the C# design team answered that
they&rsquo;re thinking about it, mostly trying to understand the best design, so
there&rsquo;s a chance that we&rsquo;ll see dictionary expressions in the language in the
future.</p>
</li>
</ul>
<p>Also see: <a href="/csharp-primary-constructors/">C# 12 Primary Constructors</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>C# 12 Primary Constructors</title>
      <link>https://nicolaiarocci.com/csharp-primary-constructors/</link>
      <pubDate>Thu, 09 May 2024 18:04:39 +0200</pubDate>
      <guid>https://nicolaiarocci.com/csharp-primary-constructors/</guid>
      <description>&lt;p&gt;I wrapped up my C# 12 session at the &lt;a href=&#34;https://abp.io/conference/2024&#34;&gt;ABP Dotnet Conference 2024&lt;/a&gt;, and I wanted to share the take-home points, at least about the most relevant features in this language version. Posting the slides made no sense as they were minimal; all the content was packed in the live demo.&lt;/p&gt;
&lt;p&gt;In a follow-up post, I plan to address Collection Expressions (&lt;a href=&#34;https://nicolaiarocci.com/csharp-collection-expressions&#34;&gt;done&lt;/a&gt;) and maybe &amp;ldquo;type any aliases&amp;rdquo;; this is about Primary Constructors.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I wrapped up my C# 12 session at the <a href="https://abp.io/conference/2024">ABP Dotnet Conference 2024</a>, and I wanted to share the take-home points, at least about the most relevant features in this language version. Posting the slides made no sense as they were minimal; all the content was packed in the live demo.</p>
<p>In a follow-up post, I plan to address Collection Expressions (<a href="/csharp-collection-expressions">done</a>) and maybe &ldquo;type any aliases&rdquo;; this is about Primary Constructors.</p>
<ul>
<li>
<p>We can now add a list of parameters to a struct or class declaration. This way, we avoid writing an explicit constructor method, sparing us some boilerplate code.</p>
</li>
<li>
<p>What I refer to as &lsquo;primary parameters&rsquo; are unique in that they are in scope throughout the type definition; this means they can be used anywhere within the type.</p>
</li>
</ul>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span><span style="font-weight:bold">public</span> <span style="font-weight:bold">readonly</span> <span style="font-weight:bold">struct</span> <span style="font-weight:bold">Distance</span>(<span style="">double</span> dx, <span style="">double</span> dy)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">public</span> <span style="font-weight:bold">readonly</span> <span style="">double</span> Magnitude { <span style="font-weight:bold">get</span>; } = Math.Sqrt(dx * dx + dy * dy);
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">public</span> <span style="font-weight:bold">readonly</span> <span style="">double</span> Direction { <span style="font-weight:bold">get</span>; } = Math.Atan2(dy, dx);
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">public</span> <span style="font-weight:bold">override</span> <span style="">string</span> ToString() =&gt; <span style="font-style:italic">$&#34;{nameof(Magnitude)}: {Magnitude}, {nameof(Direction)}: {Direction}&#34;</span>;
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">public</span> <span style="">double</span> Dx { <span style="font-weight:bold">get</span>; } = dx;
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">public</span> <span style="">double</span> Dy { <span style="font-weight:bold">get</span>; } = dy;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ul>
<li>
<p>It&rsquo;s important to note that primary constructor parameters are not class members; therefore, <code>this.</code> cannot be used on them. They can be considered static values, but unlike typical static values, they can also be used in non-static methods, offering a unique advantage (some black magic happens behind the scenes.)</p>
</li>
<li>
<p>We no longer need to define and assign a type-level field; the compiler will do that behind the scenes when needed; if a behind-the-scenes backing field is unnecessary, it won&rsquo;t be created.</p>
</li>
<li>
<p>Primary constructor parameters don&rsquo;t become properties and are inaccessible outside the instance. We can create properties to expose their values if needed. Record types are an exception. Constructor parameters become properties with records, and it makes sense because records are generally used as DTOs, whereas we want the option with class and structs.</p>
</li>
<li>
<p>Secondary and parameterless constructors can be added to a primary constructor. They must invoke the primary, passing its values along.</p>
</li>
</ul>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span><span style="font-weight:bold">public</span> Distance() : <span style="font-weight:bold">this</span>(0, 0) { }
</span></span></code></pre></div><ul>
<li>With primary constructors, we do not have a method body; how do we handle argument validation? One pattern is to perform validation at property assignation.</li>
</ul>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span><span style="font-weight:bold">public</span> <span style="">string</span> AccountID { <span style="font-weight:bold">get</span>; } = ValidAccountNumber(accountID)
</span></span><span style="display:flex;"><span>    ? accountID
</span></span><span style="display:flex;"><span>    : <span style="font-weight:bold">throw</span> <span style="font-weight:bold">new</span> ArgumentException(<span style="font-style:italic">&#34;Invalid account number&#34;</span>, nameof(accountID));
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="font-weight:bold">public</span> <span style="font-weight:bold">static</span> <span style="">bool</span> ValidAccountNumber(<span style="">string</span> accountID) =&gt; accountID?.Length == 10 &amp;&amp; accountID.All(c =&gt; <span style="">char</span>.IsDigit(c));
</span></span></code></pre></div><ul>
<li>
<p>I like this pattern because it brings property declaration and validation close to each other, making it easier to process and reason about the domain logic. When we perform argument validation in an old-style constructor method, we tend to separate validation and declaration, making it difficult to reconcile the two aspects, especially when we have hundreds of lines between constructor code and property declaration.</p>
</li>
<li>
<p>Derived types can have a primary constructor, too; it must invoke the base class&rsquo; primary constructor.</p>
</li>
</ul>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span><span style="font-weight:bold">public</span> <span style="font-weight:bold">class</span> <span style="font-weight:bold">CheckingAccount</span>(<span style="">string</span> accountID, <span style="">string</span> owner, <span style="">decimal</span> overdraftLimit = 0) : BankAccount(accountID, owner)
</span></span></code></pre></div><ul>
<li>
<p>Old-style derived types can still derive from a primary constructor type; a regular constructor will invoke the base primary, as we&rsquo;ve always been doing.</p>
</li>
<li>
<p>Regarding inheritance, we can mix and match primary constructor types with old-style types, making it easy to refactor our libraries to use primary constructors. We know that adopters will have no problem deriving from our refactored types.</p>
</li>
<li>
<p>Watch out for &ldquo;nested captures&rdquo; of primary parameter values in derived types. If both the derived and the base type capture them, and one (or both) change their captured values, we may end up with non-aligned instance values. Roslyn&rsquo;s analyzer will raise a warning so we can fix our code or mute the alert with a pragma.</p>
</li>
<li>
<p>Visual Studio and Visual Studio code offer built-in support for primary constructors (refactorings, etc.) That&rsquo;s true for JetBrains Rider or any other IDEs leveraging Roslyn.</p>
</li>
<li>
<p>The primary constructor&rsquo;s original implementation dates back to C# 6 in 2015. It was publicly available in one of those version previews for a short period. Then, it was taken back to the drawing board, only to resurface with record types in C# 9 (?) and custom types in C# 12.</p>
</li>
</ul>
<p>Also see: <a href="/csharp-collection-expressions/">C# 12 Collection Expressions</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>I am speaking at ABP Dotnet Conf&#39;24</title>
      <link>https://nicolaiarocci.com/i-am-speaking-at-abp-dotnet-conf24.md/</link>
      <pubDate>Mon, 15 Apr 2024 15:01:12 +0200</pubDate>
      <guid>https://nicolaiarocci.com/i-am-speaking-at-abp-dotnet-conf24.md/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;Nicola Iarocci: C#12 What&amp;rsquo;s new and Interesting session at ABP Dotnet Conf&#39;24&#34; loading=&#34;lazy&#34; src=&#34;https://nicolaiarocci.com/images/abp-dotnet-conf24.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;I am thrilled to have the opportunity to present at an international conference once again. On May 9th, I will speak at the &lt;a href=&#34;https://abp.io/conference/2024&#34;&gt;ABP Donet Conf&#39;24&lt;/a&gt;. My session, titled C #12: What&amp;rsquo;s New and Interesting, is on a topic I&amp;rsquo;m passionate about.&lt;/p&gt;
&lt;p&gt;With the alignment of C# and Dotnet Core release cycles, the C# release cadence has increased (we&amp;rsquo;re on a yearly cycle now), while feature quantity has reduced for individual releases, which is good. The faster, smaller iterations allow for quicker course corrections, and introducing fewer new features makes it easier to embrace the changes.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><img alt="Nicola Iarocci: C#12 What&rsquo;s new and Interesting session at ABP Dotnet Conf'24" loading="lazy" src="/images/abp-dotnet-conf24.png"></p>
<p>I am thrilled to have the opportunity to present at an international conference once again. On May 9th, I will speak at the <a href="https://abp.io/conference/2024">ABP Donet Conf'24</a>. My session, titled C #12: What&rsquo;s New and Interesting, is on a topic I&rsquo;m passionate about.</p>
<p>With the alignment of C# and Dotnet Core release cycles, the C# release cadence has increased (we&rsquo;re on a yearly cycle now), while feature quantity has reduced for individual releases, which is good. The faster, smaller iterations allow for quicker course corrections, and introducing fewer new features makes it easier to embrace the changes.</p>
<p>The ABP Dotnet Conf'24<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> will be held online on 8-9th May; the <a href="https://abp.io/conference/2024#agenda">lineup and agenda</a> look great, so reserve a ticket before they are sold out, and see you there!</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>I love what the conference organizers are doing with the subtle product name change. Did you catch that? #dropthedot&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>I am presenting on OAuth2 at two conferences this month</title>
      <link>https://nicolaiarocci.com/i-am-presenting-on-oauth2-at-two-conferences-this-month/</link>
      <pubDate>Tue, 05 Mar 2024 10:36:21 +0100</pubDate>
      <guid>https://nicolaiarocci.com/i-am-presenting-on-oauth2-at-two-conferences-this-month/</guid>
      <description>&lt;p&gt;I am speaking about OAuth2 and Open ID Connect with ASP.NET Core 8 at &lt;a href=&#34;https://www.dotnetconf.it&#34;&gt;Rome .NET
Conference 2024&lt;/a&gt; on March 22 and then, less than a
week later, at &lt;a href=&#34;https://www.webdayconf.it&#34;&gt;WebDay 2024&lt;/a&gt; in Milan.&lt;/p&gt;
&lt;p&gt;I am always particularly excited when I can present the stuff I&amp;rsquo;m currently
working on. Being forced to share as I learn encourages me to go deeper into the
topic to reinforce my comprehension and better explain it to the audience—a
win-win situation.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I am speaking about OAuth2 and Open ID Connect with ASP.NET Core 8 at <a href="https://www.dotnetconf.it">Rome .NET
Conference 2024</a> on March 22 and then, less than a
week later, at <a href="https://www.webdayconf.it">WebDay 2024</a> in Milan.</p>
<p>I am always particularly excited when I can present the stuff I&rsquo;m currently
working on. Being forced to share as I learn encourages me to go deeper into the
topic to reinforce my comprehension and better explain it to the audience—a
win-win situation.</p>
<p>While the Rome conference is free, if you are considering <a href="https://www.webdayconf.it">WebDay in
Milan</a> (you should), feel free to use my speaker
coupon P-SPEAKER10 for a 20% discount.  If you come to any, don&rsquo;t be shy and
come to say Hi!</p>
<p><img loading="lazy" src="/images/dotnet-conference-rome-2024.jpeg"></p>
]]></content:encoded>
    </item>
    <item>
      <title>Default ASP NET Core 8 port changed from 80 to 8080</title>
      <link>https://nicolaiarocci.com/default-asp-net-core-8-port-changed-from-80-to-8080/</link>
      <pubDate>Tue, 20 Feb 2024 11:48:42 +0100</pubDate>
      <guid>https://nicolaiarocci.com/default-asp-net-core-8-port-changed-from-80-to-8080/</guid>
      <description>&lt;p&gt;Today, I learned the hard way that the default port for ASP.NET Core 8 container
images has been updated from port 80 to 8080, quite a remarkable breaking
change.&lt;/p&gt;
&lt;p&gt;We upgraded our web application from .NET 7 and let the CI pipeline do its work.
Finally, we checked the application in the browser to ensure everything was
okay, but unfortunately, we got a 502 Bad Gateway error. The Nginx logs revealed
that the app was rejecting connections, which was unexpected because we didn&amp;rsquo;t
make any changes there. Further investigation showed that the web app listened
on port 8080 while Nginx was reverse-proxied to 80. So that was the problem. But
why did the port change?&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today, I learned the hard way that the default port for ASP.NET Core 8 container
images has been updated from port 80 to 8080, quite a remarkable breaking
change.</p>
<p>We upgraded our web application from .NET 7 and let the CI pipeline do its work.
Finally, we checked the application in the browser to ensure everything was
okay, but unfortunately, we got a 502 Bad Gateway error. The Nginx logs revealed
that the app was rejecting connections, which was unexpected because we didn&rsquo;t
make any changes there. Further investigation showed that the web app listened
on port 8080 while Nginx was reverse-proxied to 80. So that was the problem. But
why did the port change?</p>
<blockquote>
<p>The change to the port number was made because of the need to provide a good
usability experience when switching to a non-root user. Running as a non-root
user requires the use of a non-privileged port in some environments. Since port
80, the previous default port, is a privileged port, the default was updated to
port 8080, which is a non-privileged port <em>(<a href="https://learn.microsoft.com/en-us/dotnet/core/compatibility/containers/8.0/aspnet-port#reason-for-change">source</a>)</em></p></blockquote>
<p>It all makes sense now. In hindsight, it was our mistake. We should have
explicitly declared the port in our launch settings anyway. As the <a href="https://en.wikipedia.org/wiki/Zen_of_Python">Python
Zen</a> says, &ldquo;Explicit is better than
implicit.&rdquo;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Video of my C# 12 session at .NET Conference Italia 2023</title>
      <link>https://nicolaiarocci.com/video-of-my-csharp-12-session-at-dotnet-conference-italia-2023/</link>
      <pubDate>Fri, 26 Jan 2024 15:39:31 +0100</pubDate>
      <guid>https://nicolaiarocci.com/video-of-my-csharp-12-session-at-dotnet-conference-italia-2023/</guid>
      <description>&lt;p&gt;The video and slides of my C# 12 session at .NET Conference Italia 2023 is
finally &lt;a href=&#34;https://www.ugidotnet.org/e/sessione/3295/C-12-Cosa-c-e-di-nuovo-e-interessante&#34;&gt;available
online&lt;/a&gt;.
Unfortunately it&amp;rsquo;s just my voice and my laptop screen, and that&amp;rsquo;s too bad
because the location was as cool as it can get, and the room was packed.&lt;/p&gt;
&lt;p&gt;It is in Italian&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; and you need to login in order to see it (sorry, I
don&amp;rsquo;t have control over it.)&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I also submitted to several international conferences; let&amp;rsquo;s see what
happens. Since the COVID hiatus, I&amp;rsquo;ve had no luck with international events.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The video and slides of my C# 12 session at .NET Conference Italia 2023 is
finally <a href="https://www.ugidotnet.org/e/sessione/3295/C-12-Cosa-c-e-di-nuovo-e-interessante">available
online</a>.
Unfortunately it&rsquo;s just my voice and my laptop screen, and that&rsquo;s too bad
because the location was as cool as it can get, and the room was packed.</p>
<p>It is in Italian<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> and you need to login in order to see it (sorry, I
don&rsquo;t have control over it.)</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>I also submitted to several international conferences; let&rsquo;s see what
happens. Since the COVID hiatus, I&rsquo;ve had no luck with international events.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Fixing the &#34;Failed to create CoreCLR error 0x80070008&#34; error when starting a .NET 8 docker container</title>
      <link>https://nicolaiarocci.com/fixing-the-failed-to-create-coreclr-error-0x80070008-error-when-starting-a-dotnet-docker-container/</link>
      <pubDate>Fri, 26 Jan 2024 09:31:47 +0100</pubDate>
      <guid>https://nicolaiarocci.com/fixing-the-failed-to-create-coreclr-error-0x80070008-error-when-starting-a-dotnet-docker-container/</guid>
      <description>&lt;p&gt;Another day, another unexpected problem. Launching a .NET 8 app from a docker
container, I got this error: &lt;code&gt;Failed to create CoreCLR, HRESULT: 0x80070008&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I was puzzled as the same container ran smoothly in our test environment but not
in production. I ruled out resource problems (memory or disk full, maybe?) but
then compared the Docker Engine versions we run in test and production. Both
were old (20. xx when 25 is available), but interestingly, the production
version was older. I searched online and found a two years-old
&lt;a href=&#34;https://github.com/PowerShell/PowerShell/issues/17624&#34;&gt;ticket&lt;/a&gt; hinting at some
problems between .NET 8 and older Docker versions.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Another day, another unexpected problem. Launching a .NET 8 app from a docker
container, I got this error: <code>Failed to create CoreCLR, HRESULT: 0x80070008</code>.</p>
<p>I was puzzled as the same container ran smoothly in our test environment but not
in production. I ruled out resource problems (memory or disk full, maybe?) but
then compared the Docker Engine versions we run in test and production. Both
were old (20. xx when 25 is available), but interestingly, the production
version was older. I searched online and found a two years-old
<a href="https://github.com/PowerShell/PowerShell/issues/17624">ticket</a> hinting at some
problems between .NET 8 and older Docker versions.</p>
<p>I
<a href="https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository">updated</a>
the Docker Engine to the latest version, and guess what? The .NET 8 container
now starts without making a dent.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to implement a PKCE code challenge in C#</title>
      <link>https://nicolaiarocci.com/how-to-implement-pkce-code-challenge-in-csharp/</link>
      <pubDate>Wed, 17 Jan 2024 18:28:14 +0100</pubDate>
      <guid>https://nicolaiarocci.com/how-to-implement-pkce-code-challenge-in-csharp/</guid>
      <description>&lt;p&gt;Today&amp;rsquo;s fun was implementing OAuth2&amp;rsquo;s &lt;a href=&#34;http://tools.ietf.org/html/rfc7636&#34;&gt;RFC
7636&lt;/a&gt;&amp;rsquo;s PKCE (Proof Key for Code Exchange)
in C#. It&amp;rsquo;s relatively straightforward, but I decided to share my implementation
should it be helpful to someone else out there.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;PKCE  is an extension to the Authorization Code flow to prevent CSRF and
authorization code injection attacks. [..] It was originally designed to protect
the authorization code flow in mobile apps, but its ability to prevent
authorization code injection makes it useful for every type of OAuth client,
even web apps that use client authentication
(&lt;a href=&#34;https://oauth.net/2/pkce/&#34;&gt;source&lt;/a&gt;).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today&rsquo;s fun was implementing OAuth2&rsquo;s <a href="http://tools.ietf.org/html/rfc7636">RFC
7636</a>&rsquo;s PKCE (Proof Key for Code Exchange)
in C#. It&rsquo;s relatively straightforward, but I decided to share my implementation
should it be helpful to someone else out there.</p>
<blockquote>
<p>PKCE  is an extension to the Authorization Code flow to prevent CSRF and
authorization code injection attacks. [..] It was originally designed to protect
the authorization code flow in mobile apps, but its ability to prevent
authorization code injection makes it useful for every type of OAuth client,
even web apps that use client authentication
(<a href="https://oauth.net/2/pkce/">source</a>).</p></blockquote>
<p>In a nutshell:</p>
<ol>
<li>The client requests a single-use authorization code to an authorization server. In doing that, it includes a <code>code_challenge</code> with the request.</li>
<li>The server responds with the authorization code if the client is recognized and authorized.</li>
<li>The client requests an access token in exchange for the authorization code. It includes the <code>code_verifier</code> used to generate the original <code>code_challenge</code>;</li>
<li>The server confirms that the verifier is the same one used to generate the code challenge; hence, the client is the same.</li>
</ol>
<p>Plenty of excellent documentation is online (like
<a href="https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-proof-key-for-code-exchange-pkce">here</a>.)</p>
<p>I was interested in <code>code_verifier</code> and <code>code_challenge</code> generation. Here&rsquo;s my implementation:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span><span style="font-style:italic">/// &lt;summary&gt;</span>
</span></span><span style="display:flex;"><span><span style="font-style:italic">/// Provides a randomly generating PKCE code verifier and it&#39;s corresponding code challenge.</span>
</span></span><span style="display:flex;"><span><span style="font-style:italic">/// &lt;/summary&gt;</span>
</span></span><span style="display:flex;"><span><span style="font-weight:bold">public</span> <span style="font-weight:bold">static</span> <span style="font-weight:bold">class</span> <span style="font-weight:bold">Pkce</span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="font-style:italic">/// &lt;summary&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="font-style:italic">/// Generates a code_verifier and the corresponding code_challenge, as specified in the rfc-7636.</span>
</span></span><span style="display:flex;"><span>    <span style="font-style:italic">/// &lt;/summary&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="font-style:italic">/// &lt;remarks&gt;See https://datatracker.ietf.org/doc/html/rfc7636#section-4.1 and https://datatracker.ietf.org/doc/html/rfc7636#section-4.2&lt;/remarks&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">public</span> <span style="font-weight:bold">static</span> (<span style="">string</span> code_challenge, <span style="">string</span> verifier) Generate(<span style="">int</span> size = 32)
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="font-weight:bold">using</span> <span style="font-weight:bold">var</span> rng = RandomNumberGenerator.Create();
</span></span><span style="display:flex;"><span>        <span style="">var</span> randomBytes = <span style="font-weight:bold">new</span> <span style="">byte</span>[size];
</span></span><span style="display:flex;"><span>        rng.GetBytes(randomBytes);
</span></span><span style="display:flex;"><span>        <span style="">var</span> verifier = Base64UrlEncode(randomBytes);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="">var</span> buffer = Encoding.UTF8.GetBytes(verifier);
</span></span><span style="display:flex;"><span>        <span style="">var</span> hash = SHA256.Create().ComputeHash(buffer);
</span></span><span style="display:flex;"><span>        <span style="">var</span> challenge = Base64UrlEncode(hash);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="font-weight:bold">return</span> (challenge, verifier);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">private</span> <span style="font-weight:bold">static</span> <span style="">string</span> Base64UrlEncode(<span style="">byte</span>[] data) =&gt;
</span></span><span style="display:flex;"><span>        Convert.ToBase64String(data)
</span></span><span style="display:flex;"><span>            .Replace(<span style="font-style:italic">&#34;+&#34;</span>, <span style="font-style:italic">&#34;-&#34;</span>)
</span></span><span style="display:flex;"><span>            .Replace(<span style="font-style:italic">&#34;/&#34;</span>, <span style="font-style:italic">&#34;_&#34;</span>)
</span></span><span style="display:flex;"><span>            .TrimEnd(<span style="font-style:italic">&#39;=&#39;</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Usage is as simple as:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cs" data-lang="cs"><span style="display:flex;"><span><span style="">var</span> (challenge, verifier) = Pkce.Generate();
</span></span></code></pre></div><p>In ASP.NET Core you don&rsquo;t usually need to mess with PKCE as the framework
supports it very transparently, but the project I&rsquo;m working on right now is bare
and to the bones, with no ASP.NET Core in sight, so I had to bring my own
implementation. Fun stuff.</p>
]]></content:encoded>
    </item>
    <item>
      <title>FatturaElettronica for .NET v3.4.13</title>
      <link>https://nicolaiarocci.com/fatturaelettronica-for-.net-v3.4.13/</link>
      <pubDate>Mon, 08 Jan 2024 14:57:59 +0100</pubDate>
      <guid>https://nicolaiarocci.com/fatturaelettronica-for-.net-v3.4.13/</guid>
      <description>&lt;p&gt;Today I released &lt;a href=&#34;https://fatturaelettronicaopensource.org/docs&#34;&gt;Fattura Elettronica for .NET&lt;/a&gt; v3.4.13. The Fattura
Elettronica project allows for the validation and de/serialization of electronic
invoices that adhere to the standard defined by Italian Revenue Agency
(&lt;a href=&#34;https://www.agenziaentrate.gov.it/portale/web/guest/specifiche-tecniche-versione-1.8&#34;&gt;Agenzia Entrate&lt;/a&gt;). See the &lt;a href=&#34;https://fatturaelettronicaopensource.org/docs/changelog.html#v-3413&#34;&gt;changelog&lt;/a&gt; for details (Italian).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today I released <a href="https://fatturaelettronicaopensource.org/docs">Fattura Elettronica for .NET</a> v3.4.13. The Fattura
Elettronica project allows for the validation and de/serialization of electronic
invoices that adhere to the standard defined by Italian Revenue Agency
(<a href="https://www.agenziaentrate.gov.it/portale/web/guest/specifiche-tecniche-versione-1.8">Agenzia Entrate</a>). See the <a href="https://fatturaelettronicaopensource.org/docs/changelog.html#v-3413">changelog</a> for details (Italian).</p>
]]></content:encoded>
    </item>
    <item>
      <title>I am speaking at the .NET Conference Italia 2023</title>
      <link>https://nicolaiarocci.com/i-am-speaking-at-the-dotnet-conference-italia-2023/</link>
      <pubDate>Thu, 23 Nov 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/i-am-speaking-at-the-dotnet-conference-italia-2023/</guid>
      <description>&lt;p&gt;In a few days, on Monday, December 4, at 10 a.m., I will present at the .NET Conference Italia 2023, which will be held
at the Microsoft House in Milan. My session is titled &amp;ldquo;C#12 What&amp;rsquo;s new and interesting&amp;rdquo; and is part of a &lt;a href=&#34;https://dotnetconference.it/e/3281/dotNET-Conference-Italia-2023&#34;&gt;rich agenda&lt;/a&gt;
focused on the recent release of .NET 8.&lt;/p&gt;
&lt;p&gt;I presented on the same subject at a &lt;a href=&#34;https://www.meetup.com/it-IT/devromagna/&#34;&gt;DevRomagna&lt;/a&gt; meetup a few months ago when C# 12 was in preview and still had
several moving parts. Now that the final release is out, it will be interesting to return to the topic to consolidate my
knowledge. I suspect that of the many reasons I challenge myself to speak publicly, enriching my knowledge is prevalent.
As the adage goes, for learning a subject, nothing beats explaining it in front of a knowledgeable audience.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In a few days, on Monday, December 4, at 10 a.m., I will present at the .NET Conference Italia 2023, which will be held
at the Microsoft House in Milan. My session is titled &ldquo;C#12 What&rsquo;s new and interesting&rdquo; and is part of a <a href="https://dotnetconference.it/e/3281/dotNET-Conference-Italia-2023">rich agenda</a>
focused on the recent release of .NET 8.</p>
<p>I presented on the same subject at a <a href="https://www.meetup.com/it-IT/devromagna/">DevRomagna</a> meetup a few months ago when C# 12 was in preview and still had
several moving parts. Now that the final release is out, it will be interesting to return to the topic to consolidate my
knowledge. I suspect that of the many reasons I challenge myself to speak publicly, enriching my knowledge is prevalent.
As the adage goes, for learning a subject, nothing beats explaining it in front of a knowledgeable audience.</p>
<p>If you will attend the conference (you should!), remember to meet me and say hi!</p>
<p><em>Update:</em> the session is now <a href="/video-of-my-csharp-12-session-at-dotnet-conference-italia-2023/">available online</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to use XmlWriter along with StringWriter to properly serialize a UTF-8 string</title>
      <link>https://nicolaiarocci.com/how-to-use-xmlwriter-along-with-stringwriter-to-properly-serialize-a-utf-8-string/</link>
      <pubDate>Thu, 09 Nov 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/how-to-use-xmlwriter-along-with-stringwriter-to-properly-serialize-a-utf-8-string/</guid>
      <description>&lt;p&gt;Today, I (re)learned how to serialize an XML to a UTF-8 string. Like all the other times I did this, I got backstabbed
by StringWriter, which only supports UTF-16. A simple code snippet like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    await using &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; sw = new StringWriter();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    await using &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; w = XmlWriter.Create(sw, new() { Async = true });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    await w.FlushAsync();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; sw.ToString();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Will emit this output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;utf-16&amp;#34;?&amp;gt;&amp;lt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s nothing inherently wrong with UTF-16, but XML is usually UTF-8, so one must do something about it. StringWriter
exposes an &lt;code&gt;Encoding&lt;/code&gt; property, but it is read-only for unknown reasons. One might think that given that the XmlWriter
allows setting its own &lt;code&gt;Encoding&lt;/code&gt; value, something like this would work:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today, I (re)learned how to serialize an XML to a UTF-8 string. Like all the other times I did this, I got backstabbed
by StringWriter, which only supports UTF-16. A simple code snippet like this:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>    await using <span style="font-weight:bold">var</span> sw = new StringWriter();
</span></span><span style="display:flex;"><span>    await using <span style="font-weight:bold">var</span> w = XmlWriter.Create(sw, new() { Async = true });
</span></span><span style="display:flex;"><span>    ...
</span></span><span style="display:flex;"><span>    await w.FlushAsync();
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">return</span> sw.ToString();
</span></span></code></pre></div><p>Will emit this output:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>    &lt;?xml version=&#34;1.0&#34; encoding=&#34;utf-16&#34;?&gt;&lt;...
</span></span></code></pre></div><p>There&rsquo;s nothing inherently wrong with UTF-16, but XML is usually UTF-8, so one must do something about it. StringWriter
exposes an <code>Encoding</code> property, but it is read-only for unknown reasons. One might think that given that the XmlWriter
allows setting its own <code>Encoding</code> value, something like this would work:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>    await using <span style="font-weight:bold">var</span> sw = new StringWriter();
</span></span><span style="display:flex;"><span>    await using <span style="font-weight:bold">var</span> w = XmlWriter.Create(sw, 
</span></span><span style="display:flex;"><span>        new() { Async = true , Encoding = Encoding.UTF8});
</span></span><span style="display:flex;"><span>    ...
</span></span><span style="display:flex;"><span>    await w.FlushAsync();
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">return</span> sw.ToString();
</span></span></code></pre></div><p>But it doesn’t. Over time, I’ve seen a few different ways to get out of this dead end, some more performant and or less
verbose than others, but my favorite is resorting to a custom StringWriter:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>    public class Utf8StringWriter : StringWriter
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        public override Encoding Encoding =&gt; Encoding.UTF8;
</span></span><span style="display:flex;"><span>    }
</span></span></code></pre></div><p>Armed with this, it is trivial, as it should have been from the get-go, to obtain the desired output:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>    await using <span style="font-weight:bold">var</span> sw = new Utf8StringWriter();
</span></span><span style="display:flex;"><span>    await using <span style="font-weight:bold">var</span> w = XmlWriter.Create(sw, new() { Async = true });
</span></span><span style="display:flex;"><span>    ...
</span></span><span style="display:flex;"><span>    await w.FlushAsync();
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">return</span> sw.ToString();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    // returns  &lt;<span style="">?</span>xml version=<span style="font-style:italic">&#34;1.0&#34;</span> encoding=<span style="font-style:italic">&#34;utf-8&#34;</span><span style="">?</span>&gt;&lt;...
</span></span></code></pre></div><p>The whole .NET framework has seen fantastic performance improvements, top-class multi-platform support, and remarkable
streamlining, but some baffling pitfalls are still hidden in some of its less obvious parts. StringWriter not supporting
UTF-8 out-of-the-box is one of them.</p>
]]></content:encoded>
    </item>
    <item>
      <title>FatturaElettronica for .NET v3.4.11</title>
      <link>https://nicolaiarocci.com/fatturaelettronica-for-.net-v3.4.11/</link>
      <pubDate>Fri, 27 Oct 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/fatturaelettronica-for-.net-v3.4.11/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://fatturaelettronicaopensource.org/docs&#34;&gt;Fattura Elettronica&lt;/a&gt; for .NET v3.4.11 was released on NuGet today. The Fattura Elettronica project allows for the
fixes a missing validation point. See the &lt;a href=&#34;https://fatturaelettronicaopensource.org/docs/changelog.html#v-3411&#34;&gt;changelog&lt;/a&gt; for details (Italian). validation and de/serialization of
electronic invoices following the Italian Revenue Agency standards.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://fatturaelettronicaopensource.org/docs">Fattura Elettronica</a> for .NET v3.4.11 was released on NuGet today. The Fattura Elettronica project allows for the
fixes a missing validation point. See the <a href="https://fatturaelettronicaopensource.org/docs/changelog.html#v-3411">changelog</a> for details (Italian). validation and de/serialization of
electronic invoices following the Italian Revenue Agency standards.</p>
]]></content:encoded>
    </item>
    <item>
      <title>LINQ DistinctBy on a property for .NET Standard and older .NET versions</title>
      <link>https://nicolaiarocci.com/linq-distinctby-on-a-property-for-dotnet-standard-and-old-dotnet-versions/</link>
      <pubDate>Wed, 25 Oct 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/linq-distinctby-on-a-property-for-dotnet-standard-and-old-dotnet-versions/</guid>
      <description>&lt;p&gt;Today I learned how to implement a custom &lt;code&gt;Enumerable.DistinctBy&lt;/code&gt; extension method that returns distinct elements from a
sequence according to a specified key selector function.&lt;/p&gt;
&lt;p&gt;.NET 6 and its successors have the method &lt;a href=&#34;https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinctby?view=net-6.0&#34;&gt;built in&lt;/a&gt; within LINQ, but I needed it in a .NET Standard 2.0 class
library, so I was out of luck. My implementation is simple, not different from &lt;a href=&#34;https://stackoverflow.com/a/489421/323269&#34;&gt;others&lt;/a&gt; I found online, and should
also work fine with old .NET releases. Here it is:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today I learned how to implement a custom <code>Enumerable.DistinctBy</code> extension method that returns distinct elements from a
sequence according to a specified key selector function.</p>
<p>.NET 6 and its successors have the method <a href="https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinctby?view=net-6.0">built in</a> within LINQ, but I needed it in a .NET Standard 2.0 class
library, so I was out of luck. My implementation is simple, not different from <a href="https://stackoverflow.com/a/489421/323269">others</a> I found online, and should
also work fine with old .NET releases. Here it is:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>    public <span style="font-weight:bold">static</span> IEnumerable&lt;TSource&gt; DistinctBy&lt;TSource, TKey&gt;(this IEnumerable&lt;TSource&gt; source, Func&lt;TSource, TKey&gt; keySelector)
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="font-weight:bold">var</span> keys = new HashSet&lt;TKey&gt;();
</span></span><span style="display:flex;"><span>        foreach (<span style="font-weight:bold">var</span> element <span style="font-weight:bold">in</span> source)
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="font-weight:bold">if</span> (keys.Contains(keySelector(element))) <span style="font-weight:bold">continue</span>;
</span></span><span style="display:flex;"><span>            keys.Add(keySelector(element));
</span></span><span style="display:flex;"><span>            yield <span style="font-weight:bold">return</span> element;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span></code></pre></div><p>In the following usage example, I will get back all unique objects from the original sequence, distinct by their Name
property:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>    <span style="font-weight:bold">var</span> uniques = mySequenceOfObjects.DistinctBy(x =&gt; x.Name);
</span></span></code></pre></div><p>I later went to check the <a href="https://github.com/dotnet/runtime/blob/e0409d44bd8d1fd0be1d66fbb52bd609be18f388/src/libraries/System.Linq/src/System/Linq/Distinct.cs#L62">official .NET 6+ implementation</a>. They support an optional equality comparer , which I
don&rsquo;t need, but their base implementation is similar to mine (they use deferred execution as well).</p>
<p>By the way, years after its open-sourcing, I still get thrills when I realize I can always look at, let alone contribute
to, the .NET source code.</p>
]]></content:encoded>
    </item>
    <item>
      <title>FatturaElettronica for .NET v3.4.10</title>
      <link>https://nicolaiarocci.com/fattura-elettronica-for-dotnet-v3.4.10/</link>
      <pubDate>Thu, 03 Aug 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/fattura-elettronica-for-dotnet-v3.4.10/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://fatturaelettronicaopensource.org/docs&#34;&gt;Fattura Elettronica&lt;/a&gt; for .NET v3.4.10 was released on NuGet today. The Fattura Elettronica project allows for the
validation and de/serialization of electronic invoices following the Italian Revenue Agency standards. This release
adds a missing validation point. See the &lt;a href=&#34;https://fatturaelettronicaopensource.org/docs/changelog.html#v-3410&#34;&gt;changelog&lt;/a&gt; for details (Italian).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://fatturaelettronicaopensource.org/docs">Fattura Elettronica</a> for .NET v3.4.10 was released on NuGet today. The Fattura Elettronica project allows for the
validation and de/serialization of electronic invoices following the Italian Revenue Agency standards. This release
adds a missing validation point. See the <a href="https://fatturaelettronicaopensource.org/docs/changelog.html#v-3410">changelog</a> for details (Italian).</p>
]]></content:encoded>
    </item>
    <item>
      <title>I won the Microsoft MVP Award</title>
      <link>https://nicolaiarocci.com/i-won-the-microsoft-mvp-award/</link>
      <pubDate>Thu, 06 Jul 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/i-won-the-microsoft-mvp-award/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve just received news that I&amp;rsquo;ve been awarded the Microsoft Most Valuable Professional (MVP) Award in the Software
Development category. It is an honor and a pleasure to be renewed for the eighth time. Being a Microsoft MVP means a lot
to me; I remember how intimidated I felt when I met MVPs at various events and how totally out of reach the title seemed
for someone like me. Besides my everyday work, I kept doing the things I loved:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve just received news that I&rsquo;ve been awarded the Microsoft Most Valuable Professional (MVP) Award in the Software
Development category. It is an honor and a pleasure to be renewed for the eighth time. Being a Microsoft MVP means a lot
to me; I remember how intimidated I felt when I met MVPs at various events and how totally out of reach the title seemed
for someone like me. Besides my everyday work, I kept doing the things I loved:</p>
<ul>
<li>Work on my open-source projects</li>
<li>Present at conferences and local meetups</li>
<li>Write some articles here and there</li>
<li>Blog as usual</li>
</ul>
<p>Then, one day, someone nominated me for the award. I was surprised, baffled and thankful, and I did not expect to pass
the selection process. I was genuinely shocked when I received the first award. Being in the MVP program has been a
happy and rewarding ride, and I&rsquo;m glad the journey continues for another year.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Homebrew and docfx don&#39;t like each other too</title>
      <link>https://nicolaiarocci.com/homebrew-and-docfx-dont-like-each-other-too/</link>
      <pubDate>Tue, 20 Jun 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/homebrew-and-docfx-dont-like-each-other-too/</guid>
      <description>&lt;p&gt;Another day another Homebrew incompatibility emerges, this time with &lt;a href=&#34;https://dotnet.github.io/docfx/index.html&#34;&gt;docfx&lt;/a&gt;, the technical documentation building
tool of reference in .NET space. I&amp;rsquo;ve been using docfx for years to build the &lt;a href=&#34;https://fatturaelettronicaopensource.org&#34;&gt;FatturaElettronica.NET&lt;/a&gt; website, and it&amp;rsquo;s
always been working without a glitch. Lately, however, my builds have been failing with strange errors I was too lazy to
diagnose until today when I decided to grasp the nettle and sort the whole thing out.&lt;/p&gt;
&lt;p&gt;It took me an embarrassing time to realize that, while successful, my docfx updates (&lt;code&gt;dotnet tool update -g docfx&lt;/code&gt;) were
being ignored. An old, Homebrew-installed version of docfx was being executed at my launches —a simple &lt;code&gt;which docfx&lt;/code&gt;
revealed the issue. &lt;code&gt;brew uninstall docfx&lt;/code&gt; finally set the updated, dotnet-installed version free of its chains, and it
is now merrily churning websites.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Another day another Homebrew incompatibility emerges, this time with <a href="https://dotnet.github.io/docfx/index.html">docfx</a>, the technical documentation building
tool of reference in .NET space. I&rsquo;ve been using docfx for years to build the <a href="https://fatturaelettronicaopensource.org">FatturaElettronica.NET</a> website, and it&rsquo;s
always been working without a glitch. Lately, however, my builds have been failing with strange errors I was too lazy to
diagnose until today when I decided to grasp the nettle and sort the whole thing out.</p>
<p>It took me an embarrassing time to realize that, while successful, my docfx updates (<code>dotnet tool update -g docfx</code>) were
being ignored. An old, Homebrew-installed version of docfx was being executed at my launches —a simple <code>which docfx</code>
revealed the issue. <code>brew uninstall docfx</code> finally set the updated, dotnet-installed version free of its chains, and it
is now merrily churning websites.</p>
<p>A similar issue emerged <a href="/homebrew-and-dotnet-8-preview-dont-like-each-other/">between Homebrew and .NET 8 Preview</a> only a few days ago. Lesson learned I&rsquo;m not installing
dotnet tools via Homebrew anymore. Or maybe, I might stay clear of Homebrew altogether.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Homebrew and .NET 8 Preview don&#39;t like each other</title>
      <link>https://nicolaiarocci.com/homebrew-and-dotnet-8-preview-dont-like-each-other/</link>
      <pubDate>Tue, 13 Jun 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/homebrew-and-dotnet-8-preview-dont-like-each-other/</guid>
      <description>&lt;p&gt;Today I learned that .NET 8 Preview could play better with Homebrew (or vice-versa). I&amp;rsquo;m working on a &lt;a href=&#34;https://www.meetup.com/it-IT/devromagna/events/293340671/&#34;&gt;C# 12 presentation
for our local developer meetup&lt;/a&gt;, and for that, I wanted .NET 8 Preview to run side by side with version 7 on my Mac. As
version 7 was initially installed with Homebrew, I also wanted to install version 8 Preview with Homebrew, but that
recipe was unavailable. Not perfectly happy with that, I fell back to the stand-alone installer, expecting
problems.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today I learned that .NET 8 Preview could play better with Homebrew (or vice-versa). I&rsquo;m working on a <a href="https://www.meetup.com/it-IT/devromagna/events/293340671/">C# 12 presentation
for our local developer meetup</a>, and for that, I wanted .NET 8 Preview to run side by side with version 7 on my Mac. As
version 7 was initially installed with Homebrew, I also wanted to install version 8 Preview with Homebrew, but that
recipe was unavailable. Not perfectly happy with that, I fell back to the stand-alone installer, expecting
problems.</p>
<p>Installation went well, but then I turned to the command line only to find that <code>dotnet --list-sdks</code> was still and only
showing version 7. Yet, the 8 Preview was sitting there at its canonical location at <code>/usr/local/share/dotnet/sdk</code>,
where the v7 was also listed.</p>
<p>Puzzled, I tried a few things, but the quick fix was to simply <code>brew uninstall --ignore-dependencies dotnet</code> and, boom,
both versions 8 Preview and 7 became immediately available. I suspect that <code>brew uninstall</code> only removed the symlink
from .NET canonical location to the Homebrew cellar, which magically solved the SDK visibility problem.</p>
<p>TL; DR. Homebrew recipes don&rsquo;t play nicely with .NET canonical installer. To make all my SDK versions visible to .NET,
I had to forego the Homebrew installation, which did not uninstall the SDK itself, but simply unlinked it.</p>
]]></content:encoded>
    </item>
    <item>
      <title>A new modern MSBuild terminal logger is coming with .NET 8</title>
      <link>https://nicolaiarocci.com/a-new-modern-msbuild-terminal-logger-is-coming-with-dotnet-8/</link>
      <pubDate>Sat, 20 May 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/a-new-modern-msbuild-terminal-logger-is-coming-with-dotnet-8/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-preview-4/&#34;&gt;latest .NET 8 Preview&lt;/a&gt; is out, and I love that they&amp;rsquo;re finally changing how MSBuild logs are printed to the terminal.
The new Terminal Logger ditches the infamous &amp;ldquo;wall of text&amp;rdquo; that is a nightmare to parse in favor of a cleaner, leaner,
and more organized output.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Once enabled, the new logger shows you the restore phase, followed by the build phase. During each phase, the
currently-building projects are at the bottom of the terminal, and each building project tells you both the MSBuild
Target currently being built, as well as the amount of time spent on that target.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The <a href="https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-preview-4/">latest .NET 8 Preview</a> is out, and I love that they&rsquo;re finally changing how MSBuild logs are printed to the terminal.
The new Terminal Logger ditches the infamous &ldquo;wall of text&rdquo; that is a nightmare to parse in favor of a cleaner, leaner,
and more organized output.</p>
<blockquote>
<p>Once enabled, the new logger shows you the restore phase, followed by the build phase. During each phase, the
currently-building projects are at the bottom of the terminal, and each building project tells you both the MSBuild
Target currently being built, as well as the amount of time spent on that target.</p></blockquote>
<p>The new MSBuild terminal logger is not the default. It must be opted-in with the <code>tl</code> option of the <code>dotnet build</code>
command. Here&rsquo;s what it looks like for a complex, multi-project and multi-target solution:</p>
<p><img alt="MSBuild Terminal Logger output" loading="lazy" src="/images/modernbuildoutput.gif"></p>
<p>Now, if you&rsquo;re doing .NET programming within an IDE like Rider of Visual Studio, this all might seem of little
importance to you, but rest assured as soon as you have to look at CI logs or if you use the command line in your
workflow a lot as I do, this is pure bliss.</p>
<p>Interestingly, this marks only the first step in a series of upcoming MSBuild UX improvements: <em>&ldquo;We hope to use this
logger as the foundation for a new batch of UX improvements for MSBuild, including aspects like progress reporting and
structured errors in the future.&rdquo;</em> Color me excited.</p>
]]></content:encoded>
    </item>
    <item>
      <title>FatturaElettronica for .NET v3.4.8</title>
      <link>https://nicolaiarocci.com/fatturaelettronica-for-.net-v3.4.8/</link>
      <pubDate>Tue, 02 May 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/fatturaelettronica-for-.net-v3.4.8/</guid>
      <description>&lt;p&gt;Fattura Elettronica for .NET v3.4.8 was &lt;a href=&#34;https://www.nuget.org/packages/FatturaElettronica/3.4.8&#34;&gt;released&lt;/a&gt; on NuGet today. The &lt;a href=&#34;https://fatturaelettronicaopensource.org/&#34;&gt;Fattura Elettronica&lt;/a&gt; project allows for the
validation and de/serialization of electronic invoices following the Italian Revenue Agency standards. As with the
previous one, this release also addresses a small undocumented behavior in validating the invoice. See the &lt;a href=&#34;https://github.com/FatturaElettronica/FatturaElettronica.NET/issues/396&#34;&gt;relevant
ticket&lt;/a&gt; for the details.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Fattura Elettronica for .NET v3.4.8 was <a href="https://www.nuget.org/packages/FatturaElettronica/3.4.8">released</a> on NuGet today. The <a href="https://fatturaelettronicaopensource.org/">Fattura Elettronica</a> project allows for the
validation and de/serialization of electronic invoices following the Italian Revenue Agency standards. As with the
previous one, this release also addresses a small undocumented behavior in validating the invoice. See the <a href="https://github.com/FatturaElettronica/FatturaElettronica.NET/issues/396">relevant
ticket</a> for the details.</p>
]]></content:encoded>
    </item>
    <item>
      <title>FatturaElettronica for .NET v3.4.7</title>
      <link>https://nicolaiarocci.com/fatturaelettronica-for-.net-v3.4.7/</link>
      <pubDate>Wed, 05 Apr 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/fatturaelettronica-for-.net-v3.4.7/</guid>
      <description>&lt;p&gt;Fattura Elettronica for .NET v3.4.7 was &lt;a href=&#34;https://www.nuget.org/packages/FatturaElettronica/3.4.7&#34;&gt;released&lt;/a&gt; on NuGet today. The &lt;a href=&#34;https://fatturaelettronicaopensource.org&#34;&gt;Fattura Elettronica project&lt;/a&gt; allows for
the validation and de/serialization of electronic invoices adhering to the canon defined by the Italian Revenue Agency.&lt;/p&gt;
&lt;p&gt;This release refines how the one-cent tolerance is accounted for in validation checks of types 00421 and 00423. As is
often the case, there are subtle differences between the theoretical implementation defined in the official specs and
the actual validation implemented by the same Agency that released said specs. See the &lt;a href=&#34;https://github.com/FatturaElettronica/FatturaElettronica.NET/issues/394&#34;&gt;relevant ticket&lt;/a&gt; for the
details.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Fattura Elettronica for .NET v3.4.7 was <a href="https://www.nuget.org/packages/FatturaElettronica/3.4.7">released</a> on NuGet today. The <a href="https://fatturaelettronicaopensource.org">Fattura Elettronica project</a> allows for
the validation and de/serialization of electronic invoices adhering to the canon defined by the Italian Revenue Agency.</p>
<p>This release refines how the one-cent tolerance is accounted for in validation checks of types 00421 and 00423. As is
often the case, there are subtle differences between the theoretical implementation defined in the official specs and
the actual validation implemented by the same Agency that released said specs. See the <a href="https://github.com/FatturaElettronica/FatturaElettronica.NET/issues/394">relevant ticket</a> for the
details.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Running .NET code in an isolated sandbox</title>
      <link>https://nicolaiarocci.com/running-dotnet-code-in-an-isolated-sandbox/</link>
      <pubDate>Thu, 23 Mar 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/running-dotnet-code-in-an-isolated-sandbox/</guid>
      <description>&lt;p&gt;Steve Sanderson is experimenting &lt;a href=&#34;https://nicolaiarocci.com/a-quick-preview-of-the-blazor-united-prototype-for-.net8/&#34;&gt;again&lt;/a&gt;, and when Steve plays with his toys, I pay attention. In a new video on his
YouTube channel, Steve introduces an experimental new .NET package that allows the creation of isolated instances of the
.NET runtime that will safely run code in a sandbox.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;!-- raw HTML omitted --&gt;</description>
      <content:encoded><![CDATA[<p>Steve Sanderson is experimenting <a href="/a-quick-preview-of-the-blazor-united-prototype-for-.net8/">again</a>, and when Steve plays with his toys, I pay attention. In a new video on his
YouTube channel, Steve introduces an experimental new .NET package that allows the creation of isolated instances of the
.NET runtime that will safely run code in a sandbox.</p>
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
]]></content:encoded>
    </item>
    <item>
      <title>Making the latest C# language features available in older .NET versions</title>
      <link>https://nicolaiarocci.com/making-the-latest-csharp-language-features-available-in-older-dotnet-versions/</link>
      <pubDate>Sat, 04 Feb 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/making-the-latest-csharp-language-features-available-in-older-dotnet-versions/</guid>
      <description>&lt;p&gt;In a C# library I&amp;rsquo;ve been working on, I wanted to use C# 9.0&amp;rsquo;s &lt;code&gt;init&lt;/code&gt; keyword.
Quoting the &lt;a href=&#34;https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/init&#34;&gt;documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The init keyword defines an accessor method in a property or indexer. An
init-only setter assigns a value to the property or the indexer element
&lt;strong&gt;only&lt;/strong&gt; during object construction. This enforces immutability so that once
the object is initialized, it can&amp;rsquo;t be changed again.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Consider the following class:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    public class Person
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        public string FirstName { get; init; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can initialize it like this:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In a C# library I&rsquo;ve been working on, I wanted to use C# 9.0&rsquo;s <code>init</code> keyword.
Quoting the <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/init">documentation</a>:</p>
<blockquote>
<p>The init keyword defines an accessor method in a property or indexer. An
init-only setter assigns a value to the property or the indexer element
<strong>only</strong> during object construction. This enforces immutability so that once
the object is initialized, it can&rsquo;t be changed again.</p></blockquote>
<p>Consider the following class:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>    public class Person
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        public string FirstName { get; init; }
</span></span><span style="display:flex;"><span>    }
</span></span></code></pre></div><p>You can initialize it like this:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>    <span style="font-weight:bold">var</span> person = new Person { FirstName = <span style="font-style:italic">&#34;John&#34;</span> };
</span></span></code></pre></div><p>But this will fail:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>    <span style="font-weight:bold">var</span> person = new Person();
</span></span><span style="display:flex;"><span>    person.FirstName = <span style="font-style:italic">&#34;John&#34;</span>;  //Not allowed
</span></span></code></pre></div><p>For my project, which is a .NET Standard 2.0 library, I thought this approach
might be preferable to a parameter-enforced class constructor alternative.</p>
<p>To my surprise, however, when I tried the above, I got the following error:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>The predefined type &#39;System.Runtime.CompilerServices.IsExternalInit&#39; must be
</span></span><span style="display:flex;"><span>defined or imported in order to declare init-only setter
</span></span></code></pre></div><p>As it <a href="https://developercommunity.visualstudio.com/t/error-cs0518-predefined-type-systemruntimecompiler/1244809#TPIN-N1249582">turns out</a>, The <code>IsExternalInit</code> type is only included in the net5.0
(and subsequent) target frameworks, so one cannot use it right away in a
NetStandard 2.0 (or 2.1, for that matter) library.</p>
<p>In the dotnet world, when I encounter <em>&ldquo;type is not defined in version X&rdquo;</em>
scenario, I know I can get around the issue by making up the type on my own. A
quick lookup confirmed that this was the case, and the workaround is to add
the following somewhere in my source code:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>    namespace System.Runtime.CompilerServices
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        internal static class IsExternalInit {}
</span></span><span style="display:flex;"><span>    }
</span></span></code></pre></div><p>And presto, the <code>init</code> keyword is now fully available to my library.</p>
<p>While researching this matter, I stumbled into <a href="https://github.com/Sergio0694/PolySharp">PolySharp</a>,  a lovely
package that takes this workaround approach to new heights. What is it?</p>
<blockquote>
<p>PolySharp provides generated, source-only polyfills for C# language features,
to easily use all runtime-agnostic features downlevel. The package is
distributed as a source generator, so that it will automatically detect which
polyfills are needed depending on the target framework and project in use:
just add a reference to PolySharp, set your C# language version to latest,
and have fun!</p></blockquote>
<p>And it works! Just add a PolySharp reference, and almost all modern C# language
features become automagically available to your project, with no tricks around
polluting your code. What&rsquo;s also nice about PolySharp, is that it isn&rsquo;t a
dependency for your library; it only needs to be there at compile time.</p>
<p>Do you know what&rsquo;s funny? After all, I took a different route; no <code>init</code>
keyword is used anymore in my library, but that&rsquo;s for another story.</p>
]]></content:encoded>
    </item>
    <item>
      <title>A quick preview of the Blazor United prototype for .NET8</title>
      <link>https://nicolaiarocci.com/a-quick-preview-of-the-blazor-united-prototype-for-.net8/</link>
      <pubDate>Sat, 28 Jan 2023 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/a-quick-preview-of-the-blazor-united-prototype-for-.net8/</guid>
      <description>&lt;p&gt;Steve Sanderson, the original creator of Blazor, recently posted a quick peek
at some of the new Blazor prototypes they are experimenting with for .NET 8.&lt;/p&gt;
&lt;p&gt;&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen=&#34;allowfullscreen&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/48G_CEGXZZM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;!-- raw HTML omitted --&gt;
I think this looks great. Mixing client and server is a brilliant concept.
Essentially one would be served with server-side Blazor on the first landing.
While using the app, a background task would download the client-side stuff,
ready to be consumed at any subsequent access.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Steve Sanderson, the original creator of Blazor, recently posted a quick peek
at some of the new Blazor prototypes they are experimenting with for .NET 8.</p>
<p><div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/48G_CEGXZZM?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<!-- raw HTML omitted -->
I think this looks great. Mixing client and server is a brilliant concept.
Essentially one would be served with server-side Blazor on the first landing.
While using the app, a background task would download the client-side stuff,
ready to be consumed at any subsequent access.</p>
<p>Blazor United is all experimental at the moment, but I&rsquo;m confident it will land
in one form or another, either in .NET 8 or later. I remember a few years ago
at a Microsoft MVP Summit in Redmond when Steve first introduced Blazor as &ldquo;an
experiment&rdquo;. If he puts in the effort to present his experiments to the public,
he&rsquo;s got approval for that, which means the project is a little more than just
an experiment at this point.</p>
<p>Blazor weakness so far has been more with the tooling than the features. Should
Blazor United come with some solid tooling, it will be a huge hit.</p>
]]></content:encoded>
    </item>
    <item>
      <title>On implementing the ASP.NET Core 7 rate-limiting middleware</title>
      <link>https://nicolaiarocci.com/on-implementing-the-asp.net-core-7-rate-limiting-middleware/</link>
      <pubDate>Fri, 23 Dec 2022 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/on-implementing-the-asp.net-core-7-rate-limiting-middleware/</guid>
      <description>&lt;p&gt;Today, my last self-assigned duty before the Christmas break was to migrate
our in-house rate-limiting implementation (based on the
&lt;a href=&#34;https://github.com/stefanprodan/AspNetCoreRateLimit&#34;&gt;AspNetCoreRateLimiting&lt;/a&gt; third-party package) to the new, shiny
&lt;a href=&#34;https://devblogs.microsoft.com/dotnet/announcing-rate-limiting-for-dotnet/&#34;&gt;rate-limiting middleware&lt;/a&gt; introduced by ASP.NET Core 7. While the process
was relatively straightforward, I stumbled upon a few quirks I want to annotate
here.&lt;/p&gt;
&lt;p&gt;Our use case is simple. We use what the ASP.NET Core 7 documentation defines as
a &amp;ldquo;fixed window limiter.&amp;rdquo; It uses a specified time window to limit requests.
When the time window expires, a new time window starts, and the request limit
is reset. Consider the following code (for convenience, I&amp;rsquo;m using an extension
method):&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today, my last self-assigned duty before the Christmas break was to migrate
our in-house rate-limiting implementation (based on the
<a href="https://github.com/stefanprodan/AspNetCoreRateLimit">AspNetCoreRateLimiting</a> third-party package) to the new, shiny
<a href="https://devblogs.microsoft.com/dotnet/announcing-rate-limiting-for-dotnet/">rate-limiting middleware</a> introduced by ASP.NET Core 7. While the process
was relatively straightforward, I stumbled upon a few quirks I want to annotate
here.</p>
<p>Our use case is simple. We use what the ASP.NET Core 7 documentation defines as
a &ldquo;fixed window limiter.&rdquo; It uses a specified time window to limit requests.
When the time window expires, a new time window starts, and the request limit
is reset. Consider the following code (for convenience, I&rsquo;m using an extension
method):</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>public static void ConfigureRateLimit(this IServiceCollection services)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    services.AddRateLimiter(x =&gt; 
</span></span><span style="display:flex;"><span>        x.AddFixedWindowLimiter(
</span></span><span style="display:flex;"><span>                policyName: &#34;fixed&#34;, options =&gt;
</span></span><span style="display:flex;"><span>                {
</span></span><span style="display:flex;"><span>                    options.PermitLimit 1;
</span></span><span style="display:flex;"><span>                    options.Window = TimeSpan.FromSeconds(10);
</span></span><span style="display:flex;"><span>                    options.QueueLimit 1;
</span></span><span style="display:flex;"><span>                }));
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>It sets a window of 10 seconds. Within that window, a maximum of one request is
allowed. Exceeding requests will be queued and served at window reset. Notice
that we defined &ldquo;fixed&rdquo; as the policy name.</p>
<p>Once our policy is configured, we must instrument the app instance to use the
rate limiter, then we call <code>RequireRateLimiting</code> on our endpoints:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>app.UseRouting();  // I&#39;m mentioning this line for good reason, see below
</span></span><span style="display:flex;"><span>app.UseRateLimiter();
</span></span><span style="display:flex;"><span>app.UseEndpoints(endpoints =&gt; { endpoints.MapControllers()
</span></span><span style="display:flex;"><span>    .RequireRateLimiting(&#34;fixed&#34;); });
</span></span></code></pre></div><p>Nothing else is needed, really, for such a simple scenario. We could be more
sophisticated. We could opt for more advanced options, like a &ldquo;sliding windows
limiter&rdquo; or a &ldquo;bucket token limiter&rdquo;; we could apply rate limiting only to
specific endpoints or controllers or mix and match these options. I chose to
ditch hard-coded settings and read them from the configuration file. My
<em>appsettings.json</em> contains the following (with different vaues):</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>  &#34;RateLimiter&#34;: {
</span></span><span style="display:flex;"><span>    &#34;PermitLimit&#34;: 1
</span></span><span style="display:flex;"><span>    &#34;Window&#34;: 10,
</span></span><span style="display:flex;"><span>    &#34;QueueLimit&#34;: 1
</span></span><span style="display:flex;"><span>  }
</span></span></code></pre></div><p>The <code>RateLimiter</code> class maps the json structure:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>public class RateLimiter
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    public int PermitLimit { get; set; }
</span></span><span style="display:flex;"><span>    public int Window { get; set; }
</span></span><span style="display:flex;"><span>    public int QueueLimit { get; set; }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The updated code looks like this:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>public <span style="font-weight:bold">static</span> void ConfigureRateLimit(this IServiceCollection services, 
</span></span><span style="display:flex;"><span>    IConfiguration configuration)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="font-weight:bold">var</span> rateLimiter = new RateLimiter();
</span></span><span style="display:flex;"><span>    configuration.GetSection(<span style="font-style:italic">&#34;RateLimiter&#34;</span>).Bind(rateLimiter);
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    services.AddRateLimiter(x =&gt; 
</span></span><span style="display:flex;"><span>        x.AddFixedWindowLimiter(
</span></span><span style="display:flex;"><span>                policyName: <span style="font-style:italic">&#34;fixed&#34;</span>, options =&gt;
</span></span><span style="display:flex;"><span>                {
</span></span><span style="display:flex;"><span>                    options.PermitLimit = rateLimiter.PermitLimit;
</span></span><span style="display:flex;"><span>                    options.Window = TimeSpan.FromSeconds(rateLimiter.Window);
</span></span><span style="display:flex;"><span>                    options.QueueLimit = rateLimiter.QueueLimit;
</span></span><span style="display:flex;"><span>                }));
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>I wish I could say it all worked splendidly on the first try. The API was
running fine, but it was not rate-limited. It looked like the middleware was
not being invoked, or it somehow failed miserably and silently. After an
embarrassingly long time, I figured out the problem: <code>UseRateLimiter</code>
<em>must</em> be called after <code>UseRouting</code>.</p>
<p>Before:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>app.UseRateLimiter();
</span></span><span style="display:flex;"><span>app.UseRouting();
</span></span><span style="display:flex;"><span>app.UseEndpoints(endpoints =&gt; { endpoints
</span></span><span style="display:flex;"><span>    .MapControllers().RequireRateLimiting(&#34;fixed&#34;); });
</span></span></code></pre></div><p>After:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>app.UseRouting();
</span></span><span style="display:flex;"><span>app.UseRateLimiter();
</span></span><span style="display:flex;"><span>app.UseEndpoints(endpoints =&gt; { endpoints.MapControllers()
</span></span><span style="display:flex;"><span>    .RequireRateLimiting(&#34;fixed&#34;); });
</span></span></code></pre></div><p>Simply switching two lines saved the day. I looked high and low but could not
find any reference to this requirement. If intended, it should be mentioned in
the documentation. If it is a bug, it should be fixed (and I should
probably open at ticket about it.)</p>
<p>Anyways, now the API is rate-limited via the new middleware. The first request
sent via Postman goes through. The second, rapid-fired one is queued and served
at window reset, as expected. A third request within the same window is bounced
back.</p>
<p>However:</p>
<ol>
<li>You get a <code>503 Service Unavailable</code> response. I&rsquo;m not in favor of 500
replies for this case. Five-hundreds should be reserved for server errors,
and that&rsquo;s not what we are dealing with here. My previous implementation
served a more appropriate <code>429 Too Many Requests</code>.</li>
<li>No <code>Retry-After</code> header is included with the response. I think it&rsquo;s
mandatory to instruct clients on what to do next.</li>
</ol>
<p>Luckily, the rate-limiting middleware allows for ample customization. On
defining our policy, we can attach a custom function to the <code>OnRejected</code> event.
The code below is updated to address both issues above:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>public <span style="font-weight:bold">static</span> <span style="font-weight:bold">class</span> ServicesConfiguration
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    public <span style="font-weight:bold">static</span> void ConfigureRateLimit(this IServiceCollection services, 
</span></span><span style="display:flex;"><span>        IConfiguration configuration) {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="font-weight:bold">var</span> rateLimiter = new RateLimiter();
</span></span><span style="display:flex;"><span>        configuration.GetSection(<span style="font-style:italic">&#34;RateLimiter&#34;</span>).Bind(rateLimiter);
</span></span><span style="display:flex;"><span>        
</span></span><span style="display:flex;"><span>        services.AddRateLimiter(x =&gt; 
</span></span><span style="display:flex;"><span>            x.AddFixedWindowLimiter(
</span></span><span style="display:flex;"><span>                    policyName: <span style="font-style:italic">&#34;fixed&#34;</span>, options =&gt; {
</span></span><span style="display:flex;"><span>                        options.PermitLimit = rateLimiter.PermitLimit;
</span></span><span style="display:flex;"><span>                        options.Window = TimeSpan.FromSeconds(rateLimiter.Window);
</span></span><span style="display:flex;"><span>                        options.QueueLimit = rateLimiter.QueueLimit;
</span></span><span style="display:flex;"><span>                    })
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>                // new code here:
</span></span><span style="display:flex;"><span>                .OnRejected = (context, _) =&gt; {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>                // inject Retry-After header (too much line wrapping, I know)
</span></span><span style="display:flex;"><span>                <span style="font-weight:bold">if</span> (context.Lease.TryGetMetadata(MetadataName.RetryAfter, 
</span></span><span style="display:flex;"><span>                    out <span style="font-weight:bold">var</span> retryAfter)) {
</span></span><span style="display:flex;"><span>                    context.HttpContext.Response.Headers.RetryAfter =
</span></span><span style="display:flex;"><span>                        ((<span style="font-weight:bold">int</span>) retryAfter.TotalSeconds).ToString();
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>                // <span style="font-weight:bold">return</span> a different status code
</span></span><span style="display:flex;"><span>                context.HttpContext.Response.StatusCode = 
</span></span><span style="display:flex;"><span>                    StatusCodes.Status429TooManyRequests;
</span></span><span style="display:flex;"><span>                <span style="font-weight:bold">return</span> new();
</span></span><span style="display:flex;"><span>            });
</span></span><span style="display:flex;"><span>    }
</span></span></code></pre></div><p>And that&rsquo;s all there is to it. I dropped the AspNetCoreRateLimiting dependency.
That is one great piece of software, and I am grateful to its author Stefan
Prodan and his contributors. As mentioned in <a href="/my-top-7-new-features-in-.net-7/">My Top 7 New Features in .NET
7</a>, they recently released a package that allows using Redis as a
rate-limiting backend. I might adopt it in the future.</p>
<p>Complete documentation for ASP.NET Core 7 rate-limiting middleware is available
<a href="https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit?view=aspnetcore-7.0">here</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>First impressions on JetBrains Rider 2022.3 update</title>
      <link>https://nicolaiarocci.com/first-impressions-on-jetbrains-rider-2022.3-update/</link>
      <pubDate>Mon, 12 Dec 2022 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/first-impressions-on-jetbrains-rider-2022.3-update/</guid>
      <description>&lt;p&gt;Today I upgraded to JetBrains&amp;rsquo; Rider 2022.3. Startup speed has been
enhanced, and full .NET 7 and C# 11 support is included. So far,  my favorite
feature is the conversion of regular and verbatim strings into their raw
counterparts (it&amp;rsquo;s often the small, simple things.)&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://nicolaiarocci.com/images/cs-to-raw-strings.gif&#34;&gt;&lt;/p&gt;
&lt;p&gt;My second best is the fulls upport for WSL2  remote development. This one took a
good while to come out of the trenches, but better late than never, I&amp;rsquo;d say.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today I upgraded to JetBrains&rsquo; Rider 2022.3. Startup speed has been
enhanced, and full .NET 7 and C# 11 support is included. So far,  my favorite
feature is the conversion of regular and verbatim strings into their raw
counterparts (it&rsquo;s often the small, simple things.)</p>
<p><img loading="lazy" src="/images/cs-to-raw-strings.gif"></p>
<p>My second best is the fulls upport for WSL2  remote development. This one took a
good while to come out of the trenches, but better late than never, I&rsquo;d say.</p>
<p>And the new experimental UI? That&rsquo;s neat too.</p>
<p><img loading="lazy" src="/images/uiux-newui-thumb.png"></p>
<p>The full list of updates is available on their <a href="https://www.jetbrains.com/rider/whatsnew/2022-3/">What&rsquo;s New</a> page.</p>
]]></content:encoded>
    </item>
    <item>
      <title>My Top 7 New Features in .NET 7</title>
      <link>https://nicolaiarocci.com/my-top-7-new-features-in-.net-7/</link>
      <pubDate>Sun, 04 Dec 2022 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/my-top-7-new-features-in-.net-7/</guid>
      <description>&lt;p&gt;The other day we did a &lt;a href=&#34;https://www.meetup.com/it-IT/devromagna/events/289709131/&#34;&gt;.NET 7 Spotlight&lt;/a&gt; event at this month&amp;rsquo;s
&lt;a href=&#34;https://www.meetup.com/it-IT/devromagna/&#34;&gt;DevRomagna&lt;/a&gt; meetup. The speakers were &lt;a href=&#34;https://twitter.com/imperugo&#34;&gt;Ugo Lattanzi&lt;/a&gt; and me. In my
session, I chose to talk about my top 7 new features in .NET 7 (pun intended.)
What follows is a mix of my preparation notes and what I ended up really
saying&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&#34;1-performance&#34;&gt;1. Performance&lt;/h2&gt;
&lt;p&gt;Since the initial release of &amp;ldquo;new dotnet&amp;rdquo; (.NET Core), performance has always
been a critical goal for the .NET team. Starting with .NET 5, performance gains
have been skyrocketing. .NET 6 was &lt;em&gt;a lot&lt;/em&gt; faster than 5, and now, well, I&amp;rsquo;m
surprised by the remarkable performance improvements in .NET 7. Stephen Toub
posted a remarkably long (255 printed pages!) &lt;a href=&#34;https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7&#34;&gt;in-depth analysis of the
performance improvements in .NET 7&lt;/a&gt;. one That was followed by articles
dedicated to &lt;a href=&#34;https://devblogs.microsoft.com/dotnet/performance-improvements-in-aspnet-core-7/&#34;&gt;ASP.NET Core 7&lt;/a&gt; and &lt;a href=&#34;https://devblogs.microsoft.com/dotnet/dotnet-7-performance-improvements-in-dotnet-maui/&#34;&gt;MAUI 7&lt;/a&gt; performance gains. At .NETConf
2022, a particular slide caught everyone&amp;rsquo;s attention.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The other day we did a <a href="https://www.meetup.com/it-IT/devromagna/events/289709131/">.NET 7 Spotlight</a> event at this month&rsquo;s
<a href="https://www.meetup.com/it-IT/devromagna/">DevRomagna</a> meetup. The speakers were <a href="https://twitter.com/imperugo">Ugo Lattanzi</a> and me. In my
session, I chose to talk about my top 7 new features in .NET 7 (pun intended.)
What follows is a mix of my preparation notes and what I ended up really
saying<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<h2 id="1-performance">1. Performance</h2>
<p>Since the initial release of &ldquo;new dotnet&rdquo; (.NET Core), performance has always
been a critical goal for the .NET team. Starting with .NET 5, performance gains
have been skyrocketing. .NET 6 was <em>a lot</em> faster than 5, and now, well, I&rsquo;m
surprised by the remarkable performance improvements in .NET 7. Stephen Toub
posted a remarkably long (255 printed pages!) <a href="https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7">in-depth analysis of the
performance improvements in .NET 7</a>. one That was followed by articles
dedicated to <a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-aspnet-core-7/">ASP.NET Core 7</a> and <a href="https://devblogs.microsoft.com/dotnet/dotnet-7-performance-improvements-in-dotnet-maui/">MAUI 7</a> performance gains. At .NETConf
2022, a particular slide caught everyone&rsquo;s attention.</p>
<p><img loading="lazy" src="/images/dotnetconf22.png"></p>
<p>I recall seeing the same slide at the .NET 5 release, so this one is must be
updated version. I&rsquo;m more impressed with the gRPC graph than the big &ldquo;11x
faster than Node&rdquo; one. Being faster than Node doesn&rsquo;t break the news these days,
but being quicker than Go, C++ and Rust? That&rsquo;s one bold statement you have
right there.</p>
<p>An <a href="https://dusted.codes/how-fast-is-really-aspnet-core">exciting article</a> surfaced a while ago on this specific topic. In it,
Dustin Moris Gorski presents an in-depth analysis of the ASP.NET Core 7 code
used for the TechEmpower Framework Benchmark referenced in the above slide. The
results are&hellip; fascinating. That code is undoubtedly <em>not</em> what mere mortals
tend to run in their production systems. It is super-performance-optimized,
often ditching canonical, built-in, and wildly adopted features in favor of
low-level, high-performance and precisely hand-crafted alternatives. Dustin&rsquo;s
article is a masterpiece for several reasons; I suggest you invest your time
<a href="https://dusted.codes/how-fast-is-really-aspnet-core">reading it</a>.</p>
<p>But yeah, despite this glitch, the takeaway is that .NET 7 is speedy, faster
than previous versions, and on par with, if not (far?) superior to, most stacks
and frameworks. The <a href="https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7">Stephen Toub&rsquo;s article</a> is a testament to the massive
work done and the achievements obtained.</p>
<p>Most importantely, we get most of these speed benefits for free, just by
upgrading to .NET 7. And the good new is, the upgrade is as easy as changing
the framework moniker from, say, <code>net6.0</code> to <code>net7.0</code> and upgrading the
Microsoft dependencies to v7.0.0.</p>
<h2 id="2-c-11-required-modifier">2. C# 11 <code>required</code> modifier</h2>
<p>As a consequence of the C# release cycle alignment to that of.NET itself (which
is much faster), recent versions of C# see fewer features announcements than in
the past. A good thing in my opinion. Of the several appreciable new features
coming with C# 11, a remarkable one is the <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/required"><code>required</code> modifier</a>.</p>
<p>When you enable nullable checks in a project, non-nullable string properties
are flagged with warning that they should be initialized with a non-null value
when exiting the constructor:</p>
<p><img loading="lazy" src="/images/required-keyword1.png"></p>
<p>A common workaround has been these properties them with a <code>null!</code> value. That
is like telling the compiler that we know they should be initialized with a
non-nullable, but well, let&rsquo;s initialize them with a null value first, just in
case. It&rsquo;ll all be sorted later in the code. Somewhat awkward and prone to
errors. Also, battling the compiler like that is a tedious task.</p>
<p>Enter the <code>required</code> keyword. When you flag a property with <code>required,</code> the
IntelliSense engine will report an error if the property value is not set <em>at
initialization</em>, not at declaration.</p>
<p><img loading="lazy" src="/images/required-keyword2.png"></p>
<p>When someone initializes our class instance, he/she&rsquo;s <em>required</em> to set an
explicit value for our property. Notice how we went from a warning (which
will compile) to an error (which won&rsquo;t compile). Once you start using this
feature, it feels so obvious and natural that you wonder why it wasn&rsquo;t there
right from start.</p>
<h2 id="3-c-11-raw-string-literals">3. C# 11 raw string literals</h2>
<p>In C# 11, wrapping a string with triple-double-quotes makes it a <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-11.0/raw-string-literal">raw
literal</a>. Its main benefits are that no escaping of double-quotes is
necessary, and newlines are allowed within the string.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span><span style="font-weight:bold">var</span> xml = <span style="font-style:italic">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">          &lt;element attr=&#34;content&#34;&gt;
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">            &lt;body&gt;
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">            &lt;/body&gt;
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">          &lt;/element&gt;
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">          &#34;&#34;&#34;</span>;
</span></span></code></pre></div><p>The code looks natural, and no runtime costs for specialized string
manipulation are required. One caveat is that string literals naturally remove
the indentation when producing the final literal value. The snippet above
prints as:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>&lt;element attr=&#34;content&#34;&gt;
</span></span><span style="display:flex;"><span>  &lt;body&gt;
</span></span><span style="display:flex;"><span>  &lt;/body&gt;
</span></span><span style="display:flex;"><span>&lt;/element&gt;
</span></span></code></pre></div><p>We can disable indentation removal like so:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span><span style="font-weight:bold">var</span> xml = <span style="font-style:italic">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">          &lt;element attr=&#34;content&#34;&gt;
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">            &lt;body&gt;
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">            &lt;/body&gt;
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">          &lt;/element&gt;
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">&#34;&#34;&#34;</span>;
</span></span></code></pre></div><p>String interpolation is also supported:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span><span style="font-weight:bold">var</span> json = $$<span style="font-style:italic">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">             {
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">                &#34;summary&#34;: &#34;text&#34;,
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">                &#34;length&#34; : {{value.Length}},
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">             };
</span></span></span><span style="display:flex;"><span><span style="font-style:italic">             &#34;&#34;&#34;</span>
</span></span></code></pre></div><p>In hindsight, like the <code>required</code> modifier, raw string literals appear as
obvious.</p>
<h2 id="4-built-in-container-support">4. Built-in container support</h2>
<p>.NET 7 has <a href="https://devblogs.microsoft.com/dotnet/announcing-builtin-container-support-for-the-dotnet-sdk/">built-in container support</a>, meaning that <code>dotnet publish</code> can
now output to a container image instead of a directory. We control image names,
tags, and other settings (like the base image) via dedicated <code>.csproj</code> tags. Two
requirements:</p>
<ul>
<li>Docker must be running when we issue the <code>publish</code> command;</li>
<li>The <code>Microsoft.NET.Build.Containers</code> package must be added to the project as
a package reference.</li>
</ul>
<p>In my demo, I had a small console application that I published to a docker
image by simply issuing the following command:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>$ dotnet publish --os linux --arch x64 /t:PublishContainer -c Release
</span></span></code></pre></div><p>I did not mention a Dockerfile, and that&rsquo;s because it is not needed anymore.
All my projects deploy to docker containers and are already migrated to .NET 7.
I&rsquo;m currently using Dockerfiles, but I&rsquo;ll be experimenting with this
alternative in the coming weeks, both with builds and remote CI builds.</p>
<h2 id="5-native-aot">5. Native AOT</h2>
<p><a href="https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/">Native AOT</a> produces a standalone executable in the target platform&rsquo;s file
format, with no external dependencies. It&rsquo;s native, with no IL or JIT involved,
and provides fast startup time and a small, self-contained deployment.</p>
<p>In my demo, I just needed to add a <code>&lt;PublishAot&gt;true&lt;/PublishAot&gt;</code> tag to the
<code>.csproj</code>, and then the <code>dotnet publish -c Release</code> command produced a
single-file, macOS native executable. You can set the destination platform at
build-time like so:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>$ dotnet publish -r win-x64 -c Release
</span></span></code></pre></div><p>Native AOT will be determinant in a number of use cases, like
multi-cloud-deployments, lambda functions, and, in general, hyper-scale
services. ASP.NET Core is currently not supported, so we&rsquo;re limited to console
apps.</p>
<h2 id="6-and-7-rate-limiting-and-output-caching">6 and 7. Rate-limiting and output caching</h2>
<p>Ok, these are two, not one. Luckily, my pal Ugo, who was demoing ASP.NET Core 7
parts after me, took charge of showing these.</p>
<p>I briefly mentioned that rate-limiting and output caching are key features in
mature production systems. Until today, we had to bake them in-house or rely on
third-party packages. I&rsquo;ve been using LazyCache and AspNetCoreRateLimit myself.
The latter <a href="https://github.com/stefanprodan/AspNetCoreRateLimit/issues/382">recently acknowledged</a> the arrival of rate-limiting in .NET 7 and
embraced it in a new package that offers Redis as a rate-limiting backend.
<a href="https://devblogs.microsoft.com/dotnet/announcing-rate-limiting-for-dotnet/">Rate-limiting</a> and <a href="https://learn.microsoft.com/en-us/aspnet/core/performance/caching/output?view=aspnetcore-7.0">output caching</a> are now part of the ASP.NET Core
framework, and that&rsquo;s where they belong.</p>
<h2 id="8-minimal-apis-group-routes">8. Minimal APIs group routes</h2>
<p>I know I said 7. I don&rsquo;t use minimal APIs in production yet, but <a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-7.0#route-groups">group
routing</a> is beautiful and something I&rsquo;ll be employing on the first
occasion. During the meetup, an interesting (and much-expected) discussion
ensued on the usefulness of minimal APIs. Veterans of many battles don&rsquo;t deem
them necessary, especially in real-world use cases, which is actually accurate:
one can keep relying on the canonical MVC approach. The sentiment was that
Minimal APIs are mostly targeted to newcomers, which is probably true<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. As
someone coming from the Python REST ecosystem, I dig them a lot. They evolve
rapidly and I&rsquo;m sure we&rsquo;ll soon see them in action in complex, real scenarios.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>To Caesar what is Caesar&rsquo;s, short on time, I recycled both the idea and the materials from James Montemagno&rsquo;s <a href="https://www.youtube.com/watch?v=0BvCzZ9P7UY">excellent video</a> on the same the topic.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Back when Minimal APIs were about to debut, I wrote <em><a href="https://nicolaiarocci.com/will-.net-6-minimal-apis-turn-heads?">Will .NET 6 Minimal APIs turn heads?</a></em>, with some musings on their effectiveness and target audience.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>FatturaElettronica v3.4 released</title>
      <link>https://nicolaiarocci.com/fatturaelettronica-v3.4-released/</link>
      <pubDate>Fri, 09 Sep 2022 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/fatturaelettronica-v3.4-released/</guid>
      <description>&lt;p&gt;Today I released v3.4 of &lt;a href=&#34;https://fatturaelettronicaopensource.org/&#34;&gt;FatturaElettronica&lt;/a&gt;, a .NET open source project
that allows validation and de/serialization of electronic invoices adhering to
the standard defined by the Italian &amp;ldquo;Agenzia delle Entrate&amp;rdquo;. It&amp;rsquo;s doing very
well for such a niche project, with downloads now well beyond the one hundred
thousand mark.&lt;/p&gt;
&lt;p&gt;Be aware that this release anticipates support for &lt;a href=&#34;https://www.agenziaentrate.gov.it/portale/web/guest/specifiche-tecniche-versione-1.7.1&#34;&gt;v1.7.1&lt;/a&gt; of the
specification going into effect on October 1, 2022. For more information, see
the appropriate &lt;a href=&#34;https://github.com/FatturaElettronica/FatturaElettronica.NET/issues/376&#34;&gt;ticket&lt;/a&gt; and the &lt;a href=&#34;https://fatturaelettronicaopensource.org/docs/changelog.html#v-34&#34;&gt;changelog&lt;/a&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today I released v3.4 of <a href="https://fatturaelettronicaopensource.org/">FatturaElettronica</a>, a .NET open source project
that allows validation and de/serialization of electronic invoices adhering to
the standard defined by the Italian &ldquo;Agenzia delle Entrate&rdquo;. It&rsquo;s doing very
well for such a niche project, with downloads now well beyond the one hundred
thousand mark.</p>
<p>Be aware that this release anticipates support for <a href="https://www.agenziaentrate.gov.it/portale/web/guest/specifiche-tecniche-versione-1.7.1">v1.7.1</a> of the
specification going into effect on October 1, 2022. For more information, see
the appropriate <a href="https://github.com/FatturaElettronica/FatturaElettronica.NET/issues/376">ticket</a> and the <a href="https://fatturaelettronicaopensource.org/docs/changelog.html#v-34">changelog</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>I&#39;m a Microsoft MVP once again</title>
      <link>https://nicolaiarocci.com/im-a-microsoft-mvp-once-again/</link>
      <pubDate>Wed, 27 Jul 2022 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/im-a-microsoft-mvp-once-again/</guid>
      <description>&lt;p&gt;I am happy and humbled to have been awarded the Microsoft MVP Award for the
seventh consecutive year. July 1, the award assignation day, always comes with
curiosity and a bit of trepidation.&lt;/p&gt;
&lt;p&gt;Being a member of the MVP community has been a very positive experience for me,
especially in the years before COVID, when the MVP Summit, the main MVP event,
was held in person in Seattle at the Microsoft HQ. That assembly of experienced
developers from all over the world is an exhilarating experience. Smart guys
and gals from different cultures gather to meet the people responsible for
their daily drivers&amp;rsquo; tools and technologies. There are countless networking
possibilities, both with fellow MVPs and Microsoft personnel.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I am happy and humbled to have been awarded the Microsoft MVP Award for the
seventh consecutive year. July 1, the award assignation day, always comes with
curiosity and a bit of trepidation.</p>
<p>Being a member of the MVP community has been a very positive experience for me,
especially in the years before COVID, when the MVP Summit, the main MVP event,
was held in person in Seattle at the Microsoft HQ. That assembly of experienced
developers from all over the world is an exhilarating experience. Smart guys
and gals from different cultures gather to meet the people responsible for
their daily drivers&rsquo; tools and technologies. There are countless networking
possibilities, both with fellow MVPs and Microsoft personnel.</p>
<p>For the last two years, the Summit has been an online event. I admit I&rsquo;ve had
a hard time following the sessions as work and family tended to get in the way.
The networking was, of course, next to zero. I miss the original MVP Summit. In
the absence of it, even just meeting the Italian MVPs has been a rare
occurrence. Hopefully, things will return to normal this year, although I&rsquo;m
doubtful.</p>
]]></content:encoded>
    </item>
    <item>
      <title>My Playwright session at WebDay 2022</title>
      <link>https://nicolaiarocci.com/my-playwright-session-at-webday-2022/</link>
      <pubDate>Fri, 01 Apr 2022 06:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/my-playwright-session-at-webday-2022/</guid>
      <description>&lt;p&gt;If you understand Italian, the recording of my Playwright session at
UGIdotNET&amp;rsquo;s &lt;a href=&#34;https://www.ugidotnet.org/e/2840/Web-Day-2022&#34;&gt;WebDay 2022&lt;/a&gt; is now available on YouTube&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. Playwright is
a phenomenal cross-browser, cross-platform, cross-language, single-API,
mobile-friendly front-end testing tool.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m looking forward to giving the same session in English sooner or later, but
I should first win my laziness and start looking for exciting events with open
CFPs. If you happen to know one, please let me know.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen=&#34;allowfullscreen&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/BaY9WIHUwFc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;A couple weeks later I also presented at &lt;a href=&#34;https://www.meetup.com/it-IT/DevRomagna/events/284626987/&#34;&gt;DevRomagna&lt;/a&gt;, the local meetup I run.
[rss]: &lt;a href=&#34;https://nicolaiarocci.com/index.xml&#34;&gt;https://nicolaiarocci.com/index.xml&lt;/a&gt;
[tw]: &lt;a href=&#34;http://twitter.com/nicolaiarocci&#34;&gt;http://twitter.com/nicolaiarocci&lt;/a&gt;
[nl]: &lt;a href=&#34;https://buttondown.email/nicolaiarocci&#34;&gt;https://buttondown.email/nicolaiarocci&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>If you understand Italian, the recording of my Playwright session at
UGIdotNET&rsquo;s <a href="https://www.ugidotnet.org/e/2840/Web-Day-2022">WebDay 2022</a> is now available on YouTube<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. Playwright is
a phenomenal cross-browser, cross-platform, cross-language, single-API,
mobile-friendly front-end testing tool.</p>
<p>I&rsquo;m looking forward to giving the same session in English sooner or later, but
I should first win my laziness and start looking for exciting events with open
CFPs. If you happen to know one, please let me know.</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/BaY9WIHUwFc?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>A couple weeks later I also presented at <a href="https://www.meetup.com/it-IT/DevRomagna/events/284626987/">DevRomagna</a>, the local meetup I run.
[rss]: <a href="https://nicolaiarocci.com/index.xml">https://nicolaiarocci.com/index.xml</a>
[tw]: <a href="http://twitter.com/nicolaiarocci">http://twitter.com/nicolaiarocci</a>
[nl]: <a href="https://buttondown.email/nicolaiarocci">https://buttondown.email/nicolaiarocci</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Parameter null-checking added to C# 11 Preview</title>
      <link>https://nicolaiarocci.com/paramter-null-checking-added-to-csharp-11-preview/</link>
      <pubDate>Sun, 27 Feb 2022 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/paramter-null-checking-added-to-csharp-11-preview/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/&#34;&gt;first preview&lt;/a&gt; of C# 11 is out, and well, I think I like what I see.
I dig the new &lt;a href=&#34;https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/#c-11-preview-list-patterns&#34;&gt;List patterns&lt;/a&gt; and am a fan of &lt;a href=&#34;https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/#c-11-preview-allow-newlines-in-the-holes-of-interpolated-strings&#34;&gt;allowing newlines in the
&amp;ldquo;holes&amp;rdquo; of interpolated strings&lt;/a&gt;. &lt;a href=&#34;https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/#c-11-preview-parameter-null-checking&#34;&gt;Parameter null-checking&lt;/a&gt; is a bit
contentious, and it&amp;rsquo;s good that they are releasing it in preview one and asking
for feedback.&lt;/p&gt;
&lt;p&gt;In a nutshell, they want to spare us a lot of boilerplate. Code like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static void M(string s)
{
    if (s is null)
    {
        throw new ArgumentNullException(nameof(s));
    }
    // Body of the method
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Would be abbreviated by adding &lt;code&gt;!!&lt;/code&gt; to the parameter name:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The <a href="https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/">first preview</a> of C# 11 is out, and well, I think I like what I see.
I dig the new <a href="https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/#c-11-preview-list-patterns">List patterns</a> and am a fan of <a href="https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/#c-11-preview-allow-newlines-in-the-holes-of-interpolated-strings">allowing newlines in the
&ldquo;holes&rdquo; of interpolated strings</a>. <a href="https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/#c-11-preview-parameter-null-checking">Parameter null-checking</a> is a bit
contentious, and it&rsquo;s good that they are releasing it in preview one and asking
for feedback.</p>
<p>In a nutshell, they want to spare us a lot of boilerplate. Code like this:</p>
<pre><code>public static void M(string s)
{
    if (s is null)
    {
        throw new ArgumentNullException(nameof(s));
    }
    // Body of the method
}
</code></pre>
<p>Would be abbreviated by adding <code>!!</code> to the parameter name:</p>
<pre><code>public static void M(string s!!)
{
    // Body of the method
}
</code></pre>
<blockquote>
<p>Code will be generated to perform the null check. The generated null check
will execute before any of the code within the method. For constructors, the
null check occurs before field initialization, calls to base constructors,
and calls to this constructors.</p></blockquote>
<p>My initial reaction was, we don&rsquo;t need this; we got Nullable Reference Types.
NRTs however help at design time, to know whether a null is possible, while
parameter null-checking is meant for runtime.</p>
<p>According to Kathleen Dollard, the .NET Runtime itself removed nearly 20,000
lines of code using this new null-check syntax. That&rsquo;s one heck of a lot of
boilerplate removed.</p>
<p>I don&rsquo;t think I like the syntax, though. It&rsquo;s super concise, which is good, and
I appreciate putting the <code>!!</code> on the parameter rather than the type since
the parameter&rsquo;s value is being checked. Still, the two-punctuation character
seems a bit clumsy. Someone suggested adopting <code>notnull</code> instead:</p>
<pre><code>public void M(string s notnull) { // code }
</code></pre>
<p>I like this suggestion. I wouldn&rsquo;t want <code>notnull</code> on the left of the parameter
name. To the right? Count me in.</p>
]]></content:encoded>
    </item>
    <item>
      <title>My ASP.NET 5 migration to .NET 6</title>
      <link>https://nicolaiarocci.com/my-asp.net-5-migration-to-.net-6/</link>
      <pubDate>Sun, 14 Nov 2021 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/my-asp.net-5-migration-to-.net-6/</guid>
      <description>&lt;p&gt;I spent the last few days migrating our ASP.NET REST services, MVC web
applications and Blazor server apps to .NET 6. Overall the process was pretty
straightforward. The few issues I went through were easy to solve and well
documented. Things got more involved with the EF Core 6 transition, especially
with the Npgsql Entity Framework Core Provider.&lt;/p&gt;
&lt;p&gt;The official &lt;a href=&#34;https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60&#34;&gt;ASP.NET Core 5.0 to 6.0 migration guide&lt;/a&gt; was my first stop. It
offers the perfect entry point, rich with in-depth links. At this stage, I am
not interested in switching to the new .NET 6 minimal hosting model (aka
Minimal APIs). I think it&amp;rsquo;s a significant improvement, and we will likely adopt
it for new projects, but our production projects aren&amp;rsquo;t going to be refactored
right away. Should minimal APIs also prove to be remarkably performant, we&amp;rsquo;ll
reconsider them&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I spent the last few days migrating our ASP.NET REST services, MVC web
applications and Blazor server apps to .NET 6. Overall the process was pretty
straightforward. The few issues I went through were easy to solve and well
documented. Things got more involved with the EF Core 6 transition, especially
with the Npgsql Entity Framework Core Provider.</p>
<p>The official <a href="https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60">ASP.NET Core 5.0 to 6.0 migration guide</a> was my first stop. It
offers the perfect entry point, rich with in-depth links. At this stage, I am
not interested in switching to the new .NET 6 minimal hosting model (aka
Minimal APIs). I think it&rsquo;s a significant improvement, and we will likely adopt
it for new projects, but our production projects aren&rsquo;t going to be refactored
right away. Should minimal APIs also prove to be remarkably performant, we&rsquo;ll
reconsider them<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>The first step was updating the target framework moniker to <code>net6.0</code>.</p>
<pre><code>&lt;Project Sdk=&quot;Microsoft.NET.Sdk.Web&quot;&gt;
  &lt;PropertyGroup&gt;
    &lt;TargetFramework&gt;net6.0&lt;/TargetFramework&gt;
  &lt;/PropertyGroup&gt;
&lt;/Project&gt;
</code></pre>
<p>Then, I updated all <code>Microsoft.AspNetCore.*</code> and <code>Microsoft.Extensions.*</code> package
references to version 6.0.0.</p>
<pre><code>&lt;ItemGroup&gt;
  &lt;PackageReference Include=&quot;Microsoft.AspNetCore.JsonPatch&quot; Version=&quot;6.0.0&quot; /&gt;
  &lt;PackageReference Include=&quot;Microsoft.Extensions.Caching.[...]&quot; Version=&quot;6.0.0&quot; /&gt;
&lt;/ItemGroup&gt;
</code></pre>
<p>That&rsquo;s all I needed to do to update the MVC application. The only other thing
left for me was to update Dockerfile&rsquo;s <code>FROM</code> statements to pull the new .NET
6 image:</p>
<pre><code># build stage
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /build
[..]
# final stage/image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
[..]
</code></pre>
<p>Migrating the WebApi/REST services required more work. I got a few errors and
warnings, either at compile or runtime. Let&rsquo;s go through them one by one.</p>
<h3 id="new-jsonserializer-source-generator-overloads">New <code>JsonSerializer</code> source generator overloads</h3>
<blockquote>
<p>The call is ambiguous between the following methods or properties:
&lsquo;JsonSerializer.Serialize(TValue, JsonSerializerOptions?)&rsquo; and
&lsquo;JsonSerializer.Serialize(TValue, JsonTypeInfo)&rsquo;&quot;</p></blockquote>
<p>In .NET 6, the <code>Sytem.Text.Json.JsonSerializer</code> <a href="https://docs.microsoft.com/en-us/dotnet/core/compatibility/serialization/6.0/jsonserializer-source-generator-overloads">acquired two new overloads</a> that
support pre-generated type information via source-generators. Previously, you
could write code that passed <code>null</code> (or <code>default</code>) as the value for the
<code>JsonSeralizerOptions</code> parameter:</p>
<pre><code>entity.Property(e =&gt; e.Value)
    .HasConversion(
        v =&gt; JsonSerializer.Serialize(v, null),
        v =&gt; JsonSerializer.Deserialize(v, null));
</code></pre>
<p>However, the new source-generator-enabled overloads will cause ambiguity if you
pass <code>null</code>. The solution was to add simply an explicit cast to the intended
target:</p>
<pre><code>entity.Property(e =&gt; e.Value)
    .HasConversion(
        v =&gt; JsonSerializer.Serialize(v, (JsonSerializerOptions)null), 
        v =&gt; JsonSerializer.Deserialize(v, (JsonSerializerOptions)null));
</code></pre>
<h3 id="the-rngcryptoserviceprovider-is-now-obsolete">The <code>RNGCryptoServiceProvider</code> is now obsolete</h3>
<blockquote>
<p>SYSLIB0023: RNGCryptoServiceProvider is obsolete</p></blockquote>
<p>As it turns out, <code>RNGCryptoServiceProvider</code> is <a href="https://docs.microsoft.com/en-us/dotnet/fundamentals/syslib-diagnostics/syslib0023">marked as obsolete in .NET 6</a>. The
new preferred way to generate a random number is using one of the
<code>RandomNunmberGenerator</code> static methods.</p>
<pre><code>  // old
  using var rng = new RNGCryptoServiceProvider();
  var uintBuffer = new byte[sizeof(uint)];
  rng.GetBytes(uintBuffer);
  var num = BitConverter.ToUInt32(uintBuffer, 0);

  // new
  using var rng = RandomNumberGenerator.Create();
  var uintBuffer = new byte[sizeof(uint)];
  rng.GetBytes(uintBuffer);
  var num = BitConverter.ToUInt32(uintBuffer, 0);
</code></pre>
<p>The two issues above are essentially the only ones I met with .NET 6 itself. As
mentioned, I also encountered a few EF Core 6 annoyances. They are listed
below.</p>
<h3 id="new-imodelcachekeyfactorycreate-overload">New <code>IModelCacheKeyFactory.Create()</code> overload</h3>
<blockquote>
<p>The requested configuration is not stored in the read-optimized model, please
use DbContext.GetService&lt;IDesignTimeModel&gt;().Model.</p></blockquote>
<p>If, like me, you happen to have a custom <code>IModelCacheKeyFactory</code>
implementation, you will likely get this error at runtime. Starting with EF
Core 6, <a href="https://github.com/dotnet/EntityFramework.Docs/pull/3305/files">you must implement</a> the new overload of the <code>Create</code> method that
handles design-time model caching.</p>
<pre><code>// old
public class DynamicModelCacheKeyFactoryDesignTimeSupport : IModelCacheKeyFactory
{
   public object Create(DbContext context) =&gt; 
     context is DynamicContext dynamicContext
       ? (context.GetType(), dynamicContext.UseIntProperty)
       : (object)context.GetType();

    public object Create(DbContext context) =&gt; Create(context, false);
}

// new
public class DynamicModelCacheKeyFactoryDesignTimeSupport : IModelCacheKeyFactory
{
   public object Create(DbContext context, bool designTime) =&gt; 
     context is DynamicContext dynamicContext
       ? (context.GetType(), dynamicContext.UseIntProperty, designTime)
       : (object)context.GetType();

    public object Create(DbContext context) =&gt; Create(context, false);
}
</code></pre>
<h3 id="nested-optional-dependents-with-no-required-properties">Nested optional dependents with no required properties</h3>
<blockquote>
<p>Entity type &lsquo;[EntityType]&rsquo; is an optional dependent using table sharing and
containing other dependents without any required non shared property to
identify whether the entity exists. If all nullable properties contain a null
value in database then an object instance won&rsquo;t be created in the query
causing nested dependent&rsquo;s values to be lost. Add a required property to
create instances with null values for other properties or mark the incoming
navigation as required to always create an instance.</p></blockquote>
<p>The message above is a consequence of a <a href="https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-6.0/breaking-changes#high-impact-changes">high-impact breaking change</a> introduced
in EF Core 6.0. In the past, you could have models with nested optional dependents
sharing the same table, each with no required properties. In such
circumstances, data loss could occur (see the <a href="https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-6.0/breaking-changes#high-impact-changes">documentation</a> for details
and examples). My solution was to mark at least one property of dependent
models with the <code>RequiredAttribute</code> (which, in every single case, was the right
thing to do anyway)</p>
<h3 id="the-efcorenamingconventions-package-is-missing-a-method">The <code>EFCore.NamingConventions</code> package is missing a method</h3>
<blockquote>
<p>Method &lsquo;GetServiceProviderHashCode&rsquo; in type &lsquo;ExtensionInfo&rsquo; from assembly
&lsquo;EFCore.NamingConventions&quot;</p></blockquote>
<p>The message says it all: there&rsquo;s currently a missing method in the latest
stable version of the <code>EFCore.NamingConventions</code> package. At the time of this
writing, <code>v6.0</code> of the package has not been released, but there is a pre-release
available that includes the missing implementation. Switch to <code>v6.0.0-rc.1</code> and
you&rsquo;ll be fine (ticket is <a href="https://github.com/efcore/EFCore.NamingConventions/issues/108">here</a>). I&rsquo;m sure the new stable release will be
out by the time you read this.</p>
<p><em>Update: EFCore.NamingConventions v6 has now been released.</em></p>
<h3 id="the-npgsql-timestamps-breaking-change">The Npgsql timestamps breaking change</h3>
<p>While the above situations were quick to fix, the new, updated Npgsql provider
offers a different threat level. There&rsquo;s <a href="https://www.npgsql.org/efcore/release-notes/6.0.html#major-changes-to-timestamp-mapping">one significant breaking change</a>
that impacts <code>DateTime</code> fields (timestamps). As the documentation suggests, it is
possible to opt out of this change to preserve backward compatibility, but
I decided to take the plunge and embrace it. The short version is that
Postgres&rsquo;s <code>timestamp</code> fields (&rsquo;timestamps without timezone&rsquo;) are changed to
<code>timestampz</code> (&rsquo;timestamps with time zones&rsquo;). In the application, when dealing
with Npgsql, <code>DateTime</code> properties must be treated as UTC by setting the <code>Kind</code>
property to <code>DateTimeKind.UTC</code>. When you run the migration tool, a migration is
created to accomodate the change, which can impact existing data. Make sure you
read the <a href="https://www.npgsql.org/efcore/release-notes/6.0.html#migrating-columns-from-timestamp-to-timestamptz">detailed notes</a> to assess the impact on your data. I let the
migration run, then updated models configuration by setting a custom
<code>DateTimeUtcValueConverter</code> for DateTime properties:</p>
<pre><code>// custom DateTime converter
protected readonly ValueConverter DateTimeToUtcConverter = 
  new ValueConverter&lt;DateTime, DateTime&gt;(
    v =&gt; DateTime.SpecifyKind(v, DateTimeKind.Utc),
    v =&gt; v);

// Entity configuration 
internal class MyEntityConfiguratin : IEntityTypeConfiguration&lt;MyEntity&gt; 
{
  public override void Configure(EntityTypeBuilder&lt;MyEntity&gt; builder)
  {
    builder.Property(o =&gt; o.Date).HasConversion(DateTimeToUtcConverter);
  }
}
</code></pre>
<p>Now Postgres timestamps are stored as &rsquo;timestamp with timezone (timestampz).
Actual values are UTC as before. A custom converter is attached to the <code>Date</code>
property at the application level to ensure that values are correctly handled.</p>
<p>Our stack is now fully running on .NET 6. Upgrading a standard ASP.NET
5 project to .NET 6 revealed to be relatively straightforward. The EF Core
6.0 migration can be more involved, while the Npgsql 6 migration requires some
attention but, remember, you can always opt-out of the delicate timestamps
change. Was the upgrade worth it? I think so for a few reasons. First, .NET
6 is LTS, while .NET 5 will be out of support in six months. Second, .<a href="https://devblogs.microsoft.com/dotnet/announcing-net-6">NET 6 is
the fastest yet</a>, with a remarkable margin (EF Core 6 alone is <a href="https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-6.0/whatsnew#improved-performance-on-techempower-fortunes">70%
faster</a>.) While the primary migration is done, there are a lot of changes
and new features that are worth considering for our codebase, which is
something we will be doing in the upcoming weeks.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>My initial ramblings on Minimal APIs are available <a href="/will-.net-6-minimal-apis-turn-heads/">here</a>.
[rss]: <a href="https://nicolaiarocci.com/index.xml">https://nicolaiarocci.com/index.xml</a>
[tw]: <a href="http://twitter.com/nicolaiarocci">http://twitter.com/nicolaiarocci</a>
[nl]: <a href="https://buttondown.email/nicolaiarocci">https://buttondown.email/nicolaiarocci</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Drama going on at the .NET Foundation</title>
      <link>https://nicolaiarocci.com/drama-going-on-at-the-.net-foundation/</link>
      <pubDate>Thu, 07 Oct 2021 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/drama-going-on-at-the-.net-foundation/</guid>
      <description>&lt;p&gt;A few months after I released my first &lt;a href=&#34;https://fatturaelettronicaopensource.org/&#34;&gt;.NET open source project&lt;/a&gt; (a niche
one targeting the Italian fintech world), I was contacted by a representative
of Team Digitale, the digital innovation branch of the Italian Public
Administration. He suggested joining the Developers Italia initiative and
moving my project to the their organization on GitHub &amp;ldquo;to enjoy
enhanced visibility and broaden the audience&amp;rdquo;. I politely refused. I did not
doubt my counterpart&amp;rsquo;s good faith. At the same time, I was concerned about the
possible long-term consequences of a seemingly easy move. Moving a GitHub
project away from your profile or an organization you control means ceding
control over it. I was assured I would keep control of the project. But what
happens if sometime in the future, when people in charge might even have
changed, they revoke my access rights? As long as I am involved with my
project, I should be in control. Also, I was not convinced that the move would
help promote the project. We live in the search-engine age; people search for
solutions to their problems. I was, and still am, confident that if I did my
due diligence and my project is any good, people will find it&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>A few months after I released my first <a href="https://fatturaelettronicaopensource.org/">.NET open source project</a> (a niche
one targeting the Italian fintech world), I was contacted by a representative
of Team Digitale, the digital innovation branch of the Italian Public
Administration. He suggested joining the Developers Italia initiative and
moving my project to the their organization on GitHub &ldquo;to enjoy
enhanced visibility and broaden the audience&rdquo;. I politely refused. I did not
doubt my counterpart&rsquo;s good faith. At the same time, I was concerned about the
possible long-term consequences of a seemingly easy move. Moving a GitHub
project away from your profile or an organization you control means ceding
control over it. I was assured I would keep control of the project. But what
happens if sometime in the future, when people in charge might even have
changed, they revoke my access rights? As long as I am involved with my
project, I should be in control. Also, I was not convinced that the move would
help promote the project. We live in the search-engine age; people search for
solutions to their problems. I was, and still am, confident that if I did my
due diligence and my project is any good, people will find it<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>Unfortunately, the worst-case scenario pictured above, or worse, appears to
be happening these days, not to me, but to the many open-source maintainers
who, in recent years, agreed to move their projects under the .NET Foundation
umbrella.  The drama is unfolding in these very same hours, and it is
painful. On my Twitter feed, I first noticed <a href="https://twitter.com/eric_sink/status/1445096990153613323">Eric Sink&rsquo;s note</a> on the issue.
The next day, a <a href="https://www.theregister.com/2021/10/05/microsoft_net_foundation_under_fire/">detailed article</a> surfaces on The Register. Then, just
yesterday, the Executive Director of the DNF posted an <a href="https://github.com/dotnet-foundation/Home/discussions/39">I am Sorry</a> message on
GitHub, which most maintainers consider disappointing, to say the least.
Maintainers see the ownership of their projects being moved over to DNF. Some
projects are transferred to GitHub Enterprise for no apparent reason. DNF
Executive Director opened a Pull Request, which was closed by the maintainers
and then reopened (twice!) by the Director (who also happens to be a former
maintainer). You can get all the details at the links above. The I am Sorry
thread is especially worth reading.</p>
<p>I think the foundation is well-intentioned. I question whether independent
open-source projects should belong there, though—maybe very few major and
commercially inclined ones. To offer legal protection, DNF needs some control
over its projects, and that&rsquo;s something not every maintainer is willing to give
away. On the other hand, maintainers might have underestimated the consequences
of moving their projects to DNF. I can feel their pain.</p>
<p>Overall, this is all concerning. As someone <a href="https://news.ycombinator.com/item?id=28759630">commented</a> on Hacker News, with the
.NET ecosystem, Microsoft has made so many surprisingly good moves in recent
years that there is room for a couple of fuck-ups, but this is a big one.
Besides, most maintainers involved in this drama are highly influential and
very well respected individuals in the .NET world. The DNF needs to get its
acts together and react immediately, at the risk of losing all of its credibility.</p>
<p><em>Update:</em> Executive director [has resigned][7]. Updates from DNF are due as
earsly as next week.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>One year later, someone from the same team got in touch and proposed the move again. I refused for the same reasons. The story is actually longer than that. A few months later, I was also invited to join Team Digitale. I even had a brief video call with their recruiter. I chukled when he realized I was a grey beard, not the typical just-out-of-college boy or girl they usually head-hunt.
[7]: <a href="https://github.com/dotnet-foundation/Home/discussions/40">https://github.com/dotnet-foundation/Home/discussions/40</a>
[rss]: <a href="https://nicolaiarocci.com/index.xml">https://nicolaiarocci.com/index.xml</a>
[tw]: <a href="http://twitter.com/nicolaiarocci">http://twitter.com/nicolaiarocci</a>
[nl]: <a href="https://buttondown.email/nicolaiarocci">https://buttondown.email/nicolaiarocci</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>ASP.NET 6 Migration Cheatsheet and FAQ</title>
      <link>https://nicolaiarocci.com/asp.net-6-migration-cheatsheet-and-faq/</link>
      <pubDate>Thu, 23 Sep 2021 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/asp.net-6-migration-cheatsheet-and-faq/</guid>
      <description>&lt;p&gt;David Fowler has a very informative gist up on GitHub. It&amp;rsquo;s titled [Migration
to ASP.NET Core. NET6][3] and it&amp;rsquo;s filled with details, recipes and FAQs on
migrating an ASP.NET Core 5 web app to ASP.NET Core 6&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. The focus is on the
new, streamlined hosting model, also known as Minimal APIs&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. To be clear,
You don&amp;rsquo;t &lt;em&gt;have&lt;/em&gt; to move to the new model. As the FAQ section emphasizes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Do I have to migrate to the new hosting model&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>David Fowler has a very informative gist up on GitHub. It&rsquo;s titled [Migration
to ASP.NET Core. NET6][3] and it&rsquo;s filled with details, recipes and FAQs on
migrating an ASP.NET Core 5 web app to ASP.NET Core 6<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. The focus is on the
new, streamlined hosting model, also known as Minimal APIs<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. To be clear,
You don&rsquo;t <em>have</em> to move to the new model. As the FAQ section emphasizes:</p>
<blockquote>
<p>Do I have to migrate to the new hosting model</p>
<p>No, you don&rsquo;t have to. It&rsquo;s the preferred way to host ASP.NET Core
applications from .NET 6 and onwards but you aren&rsquo;t forced to change your
project layout. This means you can upgrade from .NET 5 to .NET 6.0 by
changing the target framework in your project file from net5.0 to net6.0.</p></blockquote>
<p>.NET6 Release Candidate is out, so the guide is unlikely to receive updates,
but I&rsquo;m sure that David will be ready to do so if required.</p>
<p>We are about to release several brand new web services in the coming weeks.
They are all ASP.NET 5, currently in beta, but before release we&rsquo;re likely to
upgrade them to NET6. NET6 is LTS, NET5 isn&rsquo;t, and offers significant
advantages, remarkable [performance gains][2] included.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>The Core tag was dropped in NET5, and it was a good move. The reason why the insist on using it with ASP.NET eludes me.
[rss]: <a href="https://nicolaiarocci.com/index.xml">https://nicolaiarocci.com/index.xml</a>
[tw]: <a href="http://twitter.com/nicolaiarocci">http://twitter.com/nicolaiarocci</a>
[nl]: <a href="https://buttondown.email/nicolaiarocci">https://buttondown.email/nicolaiarocci</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://nicolaiarocci.com/will-.net-6-minimal-apis-turn-heads/">Will .NET 6 Mininal APIs turn heads?</a> collects my thoughts on the subject.
[2]: <a href="https://nicolaiarocci.com/performance-improvements-in-.net6/">https://nicolaiarocci.com/performance-improvements-in-.net6/</a>
[3]: <a href="https://gist.github.com/davidfowl/0e0372c3c1d895c3ce195ba983b1e03d">https://gist.github.com/davidfowl/0e0372c3c1d895c3ce195ba983b1e03d</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Performance improvements in .NET6</title>
      <link>https://nicolaiarocci.com/performance-improvements-in-.net6/</link>
      <pubDate>Fri, 03 Sep 2021 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/performance-improvements-in-.net6/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m pretty psyched about the upcoming .NET6 release. I&amp;rsquo;ve already &lt;a href=&#34;https://nicolaiarocci.com/will-.net-6-minimal-apis-turn-heads/&#34;&gt;touched&lt;/a&gt;
on ASP.NET 6 Minimal APIs. Continuing on the long-established tradition, the
team has also worked hard on the performance side of things. File IO, for
example, is seeing &lt;a href=&#34;https://devblogs.microsoft.com/dotnet/file-io-improvements-in-dotnet-6/&#34;&gt;impressive gains&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For .NET 6, we have made FileStream much faster and more reliable, thanks to
an almost entire re-write. For same cases, the async implementation is now
a few times faster! We also recognized the need of having more
high-performance file IO features: concurrent reads and writes,
scatter/gather IO and introduced new APIs for them. TL;DR File I/O is better,
stronger, faster!&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I&rsquo;m pretty psyched about the upcoming .NET6 release. I&rsquo;ve already <a href="https://nicolaiarocci.com/will-.net-6-minimal-apis-turn-heads/">touched</a>
on ASP.NET 6 Minimal APIs. Continuing on the long-established tradition, the
team has also worked hard on the performance side of things. File IO, for
example, is seeing <a href="https://devblogs.microsoft.com/dotnet/file-io-improvements-in-dotnet-6/">impressive gains</a>:</p>
<blockquote>
<p>For .NET 6, we have made FileStream much faster and more reliable, thanks to
an almost entire re-write. For same cases, the async implementation is now
a few times faster! We also recognized the need of having more
high-performance file IO features: concurrent reads and writes,
scatter/gather IO and introduced new APIs for them. TL;DR File I/O is better,
stronger, faster!</p></blockquote>
<p>If you have the time, make sure you read the whole blog post. Learning about
the low-level details on how they achieved such (pretty phenomenal) results is
fascinating. They&rsquo;re not stopping at file IO either. In another <a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/#is-that-all">lengthy blog
post</a>, they had to add a table of contents, or we would get lost in the myriad
of improvements.</p>
<blockquote>
<p>Don’t worry, I don’t cover all of them here, but grab a large mug of your
favorite hot beverage, and settle in: this post takes a rip-roarin’ tour
through ~400 PRs that, all together, significantly improve .NET performance
for .NET 6.</p></blockquote>
<p>There are <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-7/">a</a> <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-6/">ton</a> <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-5/">of</a> <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-4/">new</a> <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-3/">things</a> <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-2/">coming</a> <a href="https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-1/">up</a>,
too, of course.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to read Windows-1252 encoded files with .NETCore and .NET5&#43;</title>
      <link>https://nicolaiarocci.com/how-to-read-windows-1252-encoded-files-with-.netcore-and-.net5-/</link>
      <pubDate>Fri, 27 Aug 2021 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/how-to-read-windows-1252-encoded-files-with-.netcore-and-.net5-/</guid>
      <description>&lt;p&gt;Another day, another lesson learned: modern .NET does not support the
Windows-1252 encoding out of the box. Today my colleague was happily porting
a legacy NET4+ app to NET6. As usual, the port was super-easy; it would compile
and run just fine, so he was surprised when the app crashed reading a few
specific XML files. That&amp;rsquo;s when I was called in. A closer inspection revealed
a pattern: all those crashing files were Windows 1252-encoded (the rest, a vast
majority, were UTF-8.)&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Another day, another lesson learned: modern .NET does not support the
Windows-1252 encoding out of the box. Today my colleague was happily porting
a legacy NET4+ app to NET6. As usual, the port was super-easy; it would compile
and run just fine, so he was surprised when the app crashed reading a few
specific XML files. That&rsquo;s when I was called in. A closer inspection revealed
a pattern: all those crashing files were Windows 1252-encoded (the rest, a vast
majority, were UTF-8.)</p>
<p>It turns out that under NETCore/NET5+, to read Windows-1252 encoded files, we
first need to take a dependency on <code>System.Text.Encoding.CodePages</code>:</p>
<pre><code>dotnet add package System.Text.Encoding.CodePages
</code></pre>
<p>Then, we register a <code>CodePagesEncodingProvider</code> instance from the package:</p>
<pre><code>Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
</code></pre>
<p>Finally, on creating the XmlReader instance, we can set the encoding. To do
that, we need to pass an <code>XmlParserContext</code> instance, which allows us to
specify custom encoding:</p>
<pre><code># Create the parser context and set the encoding
var context = new XmlParserContext(null, null, null, XmlSpace.None)
context.Encoding = Encoding.GetEncoding(1252);

# Use the custom parser when reading the Xml
using (var r = XmlReader.Create(fileName, null, context))
{
    ...
}
</code></pre>
<p>And sure enough, all those troublesome XML files are no problem anymore. It
works on all platforms: Linux, macOS, and Windows.  That&rsquo;s a lot of tinkering
for a small task that required no effort in the past. However, it makes sense
as .NET is now cross-platform, and we want to reduce the app&rsquo;s footprint as
much as possible.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Will .NET 6 Minimal APIs turn heads?</title>
      <link>https://nicolaiarocci.com/will-.net-6-minimal-apis-turn-heads/</link>
      <pubDate>Wed, 14 Jul 2021 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/will-.net-6-minimal-apis-turn-heads/</guid>
      <description>&lt;p&gt;I am pretty excited about the [Minimal APIs][3] feature that is coming with
.NET 6. Three lines of code will be enough to build a fully functional REST
microservice&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var app = WebApplication.Create(args);
app.MapGet(&amp;quot;/&amp;quot;, () =&amp;gt; &amp;quot;Hello World!&amp;quot;);
await app.RunAsync();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&amp;rsquo;re a seasoned ASP.NET MVC/WebApi developer, the snippet caught your
attention because, pre-.NET 6, achieving the same result will have you messing
with a lot of extra cruft&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. I suspect, however, that this feature is not
primarily targeted at existing .NET developers. Developers new and old looking
at .NET for the first time, or those like me returning after a long break;
these are, I think, the designated audience.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I am pretty excited about the [Minimal APIs][3] feature that is coming with
.NET 6. Three lines of code will be enough to build a fully functional REST
microservice<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>:</p>
<pre><code>var app = WebApplication.Create(args);
app.MapGet(&quot;/&quot;, () =&gt; &quot;Hello World!&quot;);
await app.RunAsync();
</code></pre>
<p>If you&rsquo;re a seasoned ASP.NET MVC/WebApi developer, the snippet caught your
attention because, pre-.NET 6, achieving the same result will have you messing
with a lot of extra cruft<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. I suspect, however, that this feature is not
primarily targeted at existing .NET developers. Developers new and old looking
at .NET for the first time, or those like me returning after a long break;
these are, I think, the designated audience.</p>
<p>A long time ago, I left C# and .NET behind <em>precisely</em> because I had to write
REST APIs, and back then, the options available in .NET were, to put it mildly,
cumbersome. Admittedly, there were other reasons for switching, like .NET not
being cross-platform - I wanted to run my APIs on Linux - and general
dissatisfaction with the Microsoft ecosystem. Long story short, I went with
Python. Check out this snippet from Flask&rsquo;s renowned <a href="https://flask.palletsprojects.com/en/2.0.x/quickstart/#a-minimal-application">Quickstart</a>:</p>
<pre><code>app = Flask(__name__)

@app.route(&quot;/&quot;)
def hello_world():
    return &quot;&lt;p&gt;Hello, World!&lt;/p&gt;&quot;
</code></pre>
<p>Launched with the compelling motto &lsquo;web development, one drop at a time&rsquo; and
presented as a &lsquo;micro&rsquo; web framework, Flask immediately caught my attention<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.
Cruft-free and elegant APIs are not a Flask (or Python, for the matter)
exclusive. A Node code snippet for a REST API would be similar. Now, with NET
6 Minimal APIs, we&rsquo;re finally matching the industry standard for code clarity
and simplicity. Moreover, .NET has better performance<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> and strongly typed
languages that offer excellent type inference (F# reigns supreme there, with C#
catching up nicely.) I&rsquo;d dare to say that the C# snippet is a winner. I mean,
look at that inline lambda, with no casts!</p>
<p>Minimal APIs typical use-case is everyone&rsquo;s favourite, microservices. I do not
doubt the delivery<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup><sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>. The challenge, I think, is the actual adoption rate.
Whether veterans will adopt them or not (over time, they will) is relatively
significant, I guess. The critical question is, will Minimal APIs succeed in
attracting new developers to .NET?</p>
<p>That will mainly depend on communication. Will evangelism be robust, persistent
and persuasive enough? That&rsquo;s the tricky part. Every time I speak to the Python
or JavaScript crowd, I  am amazed that the majority don&rsquo;t even know that .NET
is now open-source, cross-platform, and blazingly performant. Most, if not all,
are tied to the old idea of a Windows-only, cumbersome, black-boxed,
enterprise-oriented offering. That&rsquo;s not the case anymore. .NET is on par with
the other cool stacks or is getting there very rapidly. I am afraid it&rsquo;s just
a little bit too late for the vast majority of the web development crowd to
take notice. It will take an enormous, coordinated effort to bring the message
across.</p>
<p>With the platform now ready, effective communication, branding, and evangelism
will eventually change the tide. Tutorials, getting-started guides, conference
talks, YouTube videos, and workshops should all be explicitly conceived for new
developers. The process started already. The observant can see the numerous
efforts being made in this area. Will it be enough to attract new crowds? It is
a hard bet, but I sure hope so because C# and F# are great languages, and NET
6 is modern, robust,  feature-rich, and powerful enough to go at war, and with
no fear.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>You will still be able to scale up to (or start right away with) a fully-functional WebApi/MVC application, with all its classes and controllers.
[3]: <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#introducing-minimal-apis">https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#introducing-minimal-apis</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Mind you. The dev team isn&rsquo;t just adding a layer of abstraction on top of the existing code. Quoting fellow MVP <a href="https://www.telerik.com/blogs/low-ceremony-high-value-tour-minimal-apis-dotnet-6">Dave Brock</a> &ldquo;With minimal APIs, the goal is to move out core API-building capabilities—the ones that only exist in MVC today—and allow them to be used outside of MVC. When extracting these components away to a new paradigm, you can rely on middleware-like performance.&rdquo;&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Long story short, besides lazily maintaining my Python open source <a href="/opensource">projects</a>, I am mostly back to C# these days.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Sure, all benchmarks should be taken with a grain of salt, but <a href="https://www.techempower.com/benchmarks/#section=data-r20&amp;hw=ph&amp;test=plaintext">check this out</a>. ASPCORE ranks at #2; Flask and Node #338 and #173 respectively. And NET 6 is expected to still improve on performance.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>For examples of real-life-scenarios, see Damian Edwards&rsquo; <a href="https://github.com/DamianEdwards/MinimalApiPlayground/blob/main/src/MinimalApiPlayground/Program.cs">Minimal APIs playground</a>.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Cool. As I am writing this, NET 6 Preview 6 is released, which adds <a href="https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-6/#configure-swagger-ui-with-minimal-apis">OpenAPI (Swagger UI) support</a> to Minimal APIs.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>My DotNetPodcast interview</title>
      <link>https://nicolaiarocci.com/my-dotnetpodcast-interview/</link>
      <pubDate>Tue, 06 Jul 2021 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/my-dotnetpodcast-interview/</guid>
      <description>&lt;p&gt;Today I was interviewed by &lt;a href=&#34;https://twitter.com/mauroservienti&#34;&gt;Mauro Servienti&lt;/a&gt; on the &lt;a href=&#34;https://www.spreaker.com/show/dotnetpodcast&#34;&gt;DotNetPodcast&lt;/a&gt;. The
theme was my experience as an open-source maintainer on both the Python and C#
stacks. We also discussed the ongoing evolution of the dotNET ecosystem,
touching on a few tangent topics.&lt;/p&gt;
&lt;p&gt;The recording is in Italian and is available below here.&lt;/p&gt;
&lt;p&gt;&lt;!-- raw HTML omitted --&gt;Listen to &amp;ldquo;Python, Eve, open source
e fattura elettronica. Con Nicola Iarocci&amp;rdquo; on Spreaker.&lt;!-- raw HTML omitted --&gt;&lt;!-- raw HTML omitted --&gt;&lt;!-- raw HTML omitted --&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today I was interviewed by <a href="https://twitter.com/mauroservienti">Mauro Servienti</a> on the <a href="https://www.spreaker.com/show/dotnetpodcast">DotNetPodcast</a>. The
theme was my experience as an open-source maintainer on both the Python and C#
stacks. We also discussed the ongoing evolution of the dotNET ecosystem,
touching on a few tangent topics.</p>
<p>The recording is in Italian and is available below here.</p>
<p><!-- raw HTML omitted -->Listen to &ldquo;Python, Eve, open source
e fattura elettronica. Con Nicola Iarocci&rdquo; on Spreaker.<!-- raw HTML omitted --><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
]]></content:encoded>
    </item>
    <item>
      <title>Custom default values for not existing dictionary items (and a lesson learned)</title>
      <link>https://nicolaiarocci.com/custom-default-values-for-not-existing-dictionary-items-and-a-lesson-learned/</link>
      <pubDate>Fri, 11 Jun 2021 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/custom-default-values-for-not-existing-dictionary-items-and-a-lesson-learned/</guid>
      <description>&lt;p&gt;When dealing with dictionaries, a typical problem is when an operation attempts
to retrieve an element using a key that does not exist in the dictionary. In
.NET, a &lt;code&gt;KeyNotFoundException&lt;/code&gt; is raised, and that&amp;rsquo;s the desired behaviour in
most circumstances. Sometimes, however, you know that your program will
frequently try to retrieve keys that do not exist. In such cases, it is more
efficient to use the &lt;code&gt;TryGetValue&lt;/code&gt; method:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This method returns the value associated with the specified key, if the key
is found; otherwise, the default value for the type of the value parameter is
returned (&lt;a href=&#34;https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.trygetvalue?view=net-5.0&#34;&gt;source&lt;/a&gt;)&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>When dealing with dictionaries, a typical problem is when an operation attempts
to retrieve an element using a key that does not exist in the dictionary. In
.NET, a <code>KeyNotFoundException</code> is raised, and that&rsquo;s the desired behaviour in
most circumstances. Sometimes, however, you know that your program will
frequently try to retrieve keys that do not exist. In such cases, it is more
efficient to use the <code>TryGetValue</code> method:</p>
<blockquote>
<p>This method returns the value associated with the specified key, if the key
is found; otherwise, the default value for the type of the value parameter is
returned (<a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.trygetvalue?view=net-5.0">source</a>)</p></blockquote>
<p>The devil hides in details. <code>TryGetValue</code> returns the default value for the
type of the <code>value</code> parameter. So, if you use <code>TryGetValue</code> to look into
a dictionary of strings, <code>null</code> is returned on a missing key. That is probably
ok in most cases. Howewer, if your logic requires a custom default value
instead, then you are out of luck. You have to set it yourself on <code>TryGetValue</code>
failure. A typical implementation would be:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>    <span style="font-weight:bold">var</span> result = MyDictionary.TryGetValue(<span style="font-style:italic">&#34;key&#34;</span>, <span style="font-weight:bold">var</span> out value) 
</span></span><span style="display:flex;"><span>        <span style="">?</span> value
</span></span><span style="display:flex;"><span>        : <span style="font-style:italic">&#34;not found&#34;</span>;
</span></span></code></pre></div><p>It is a minor annoyance but still a hassle. Our solution has always been
a homemade <code>GetValueOrDefault</code> extension method, something like this:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>    public <span style="font-weight:bold">static</span> TValue GetValueOrDefault&lt;TKey, TValue&gt; 
</span></span><span style="display:flex;"><span>        (this IDictionary&lt;TKey, TValue&gt; dictionary, TKey key, TValue defaultValue)
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="font-weight:bold">return</span> dictionary.TryGetValue(key, <span style="font-weight:bold">var</span> out value) 
</span></span><span style="display:flex;"><span>            <span style="">?</span> value
</span></span><span style="display:flex;"><span>            : defaultValue;
</span></span><span style="display:flex;"><span>    }
</span></span></code></pre></div><p>Usage:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>    <span style="font-weight:bold">var</span> result = MyDictionary.GetValueOrDefault(<span style="font-style:italic">&#34;key&#34;</span>, <span style="font-style:italic">&#34;not found&#34;</span>);
</span></span></code></pre></div><p>We&rsquo;ve been using it since forever, and we are still using it even in recent
projects.</p>
<p>Today, as I was looking at something only tangentially related, I learned that
our extension method is obsolete, and it&rsquo;s been for a while. NetStandard
2.1 and NetCore 2 added a new extension method to the official API. It&rsquo;s
called, you guessed it, <a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.collectionextensions.getvalueordefault?view=net-5.0"><code>GetValueOrDefault</code></a>. It extends
<code>ÌReadOnlyDictionary&lt;TKey, TValue&gt;</code>, so it applies to all generic dictionaries,
which is cool.</p>
<p>We could continue with our extension method. It has the advantage of working
across all .NET platforms, not just recent ones. Implementations are likely
similar, and there’s probably little (if any) performance difference (I am too
lazy to compare). With NETCore (now NET5), APIs have not only acquired
cross-platform compatibility and improved performance but they have also been
expanded and amended, something often not very apparent. Not to me, at least.</p>
<p>The point I want to make here, I think, is that nothing is set in stone. Today&rsquo;s
little event shows how my knowledge becomes stagnant over time. Setting apart
the time to learn new things is good, but acquired ones need sharping too.</p>
]]></content:encoded>
    </item>
    <item>
      <title>dotnet SmtpClient should not be used</title>
      <link>https://nicolaiarocci.com/dotnet-smtpclient-should-not-be-used/</link>
      <pubDate>Tue, 04 May 2021 07:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/dotnet-smtpclient-should-not-be-used/</guid>
      <description>&lt;p&gt;I am very late to the party, but today I learned that the good old dotnet
&lt;code&gt;SmptClient&lt;/code&gt; is considered obsolete and should not be used. Quoting the
documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We don&amp;rsquo;t recommend using the SmtpClient class for new development because
SmtpClient doesn&amp;rsquo;t support many modern protocols. Use MailKit or other
libraries instead. (&lt;a href=&#34;https://docs.microsoft.com/en-us/dotnet/api/system.net.mail.smtpclient?view=net-5.0&amp;amp;viewFallbackFrom=netcore-5.0#remarks&#34;&gt;source&lt;/a&gt;)&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Interestingly, Microsoft is recommending a third-party open-source library as an
alternative. I hope we&amp;rsquo;ll see more of that in the future.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I am very late to the party, but today I learned that the good old dotnet
<code>SmptClient</code> is considered obsolete and should not be used. Quoting the
documentation:</p>
<blockquote>
<p>We don&rsquo;t recommend using the SmtpClient class for new development because
SmtpClient doesn&rsquo;t support many modern protocols. Use MailKit or other
libraries instead. (<a href="https://docs.microsoft.com/en-us/dotnet/api/system.net.mail.smtpclient?view=net-5.0&amp;viewFallbackFrom=netcore-5.0#remarks">source</a>)</p></blockquote>
<p>Interestingly, Microsoft is recommending a third-party open-source library as an
alternative. I hope we&rsquo;ll see more of that in the future.</p>
<p>I just finished integrating <a href="https://github.com/jstedfast/MailKit">MailKit</a> in our backend. I must say that I&rsquo;m
pleasantly surprised by its rich feature-set and the elegant and
straightforward design, which makes getting on-board super easy. It&rsquo;s built on
top of the excellent MimeKit, after all, and authored by the very same author
Jeffrey Stedfast.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
