<?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>Csharp on Nicola Iarocci</title>
    <link>https://nicolaiarocci.com/tags/csharp/</link>
    <description>Recent content in Csharp on Nicola Iarocci</description>
    <generator>Hugo -- 0.143.1</generator>
    <language>en</language>
    <copyright>Produced / Written / Maintained by Nicola Iarocci since 2010</copyright>
    <lastBuildDate>Mon, 22 Dec 2025 10:49:22 +0100</lastBuildDate>
    <atom:link href="https://nicolaiarocci.com/tags/csharp/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Rediscovering a 2021 podcast on Python, .NET, and open source</title>
      <link>https://nicolaiarocci.com/rediscovering-a-2021-podcast-on-python-.net-and-open-source/</link>
      <pubDate>Mon, 22 Dec 2025 10:49:22 +0100</pubDate>
      <guid>https://nicolaiarocci.com/rediscovering-a-2021-podcast-on-python-.net-and-open-source/</guid>
      <description>&lt;p&gt;Yesterday, the kids came home for the Christmas holidays. Marco surprised me by telling me that on his flight from Brussels, he discovered and listened to “my podcast” on Spotify. I was stunned. I didn&amp;rsquo;t remember ever recording a podcast, even though I&amp;rsquo;ve given a few interviews here and there over the years.&lt;/p&gt;
&lt;p&gt;During my usual morning walk today, I went to look for it, and &lt;a href=&#34;https://open.spotify.com/episode/1xPawIlPhVKnnXcP4PxtC6?si=b1931340af1048de&#34;&gt;there it was&lt;/a&gt;, an interview I had done in 2021 that I had completely forgotten about. I got over the initial embarrassment (it&amp;rsquo;s always strange to hear your own voice) and resisted the temptation to turn it off, listening to it all the way through. I must admit that it captures that moment in my professional life, and much of the content is still relevant, especially regarding my experience as an open-source author and maintainer and my transition from C# to Python and back.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Yesterday, the kids came home for the Christmas holidays. Marco surprised me by telling me that on his flight from Brussels, he discovered and listened to “my podcast” on Spotify. I was stunned. I didn&rsquo;t remember ever recording a podcast, even though I&rsquo;ve given a few interviews here and there over the years.</p>
<p>During my usual morning walk today, I went to look for it, and <a href="https://open.spotify.com/episode/1xPawIlPhVKnnXcP4PxtC6?si=b1931340af1048de">there it was</a>, an interview I had done in 2021 that I had completely forgotten about. I got over the initial embarrassment (it&rsquo;s always strange to hear your own voice) and resisted the temptation to turn it off, listening to it all the way through. I must admit that it captures that moment in my professional life, and much of the content is still relevant, especially regarding my experience as an open-source author and maintainer and my transition from C# to Python and back.</p>
<p>I found copies of the podcast on many platforms, including a <a href="https://youtu.be/D8chi-YA5Uc?si=tkDKK2gWdAG1vsfU">YouTube video</a> (we actually video recorded it, who knew!), but they are all in Italian. I fed the video to MacWhisper, which transcribed it; I then asked Claude to translate it into English, removing pauses and repetitions; and finally, I ran it through Grammarly for a grammatical check. That’s what AI allows today: half an hour to go from an Italian audio podcast to a full English transcript, and that’s including a manual, pedantic review of Grammarly suggestions.</p>
<p>What follows is the full transcript, in English, of that 2021 interview. We touch on a variety of topics, including Python for .NET Developers, functional programming in Python, F#, and C#, the <a href="https://python-eve.org">Eve</a> REST framework and Flask, <a href="https://invoicetronic.com/en/">electronic invoicing</a>, my open-source experience as an author and maintainer in both ecosystems, cross-platform development, and advice to newcomers.</p>
<p>I don’t really know how or why Marco found this relic of mine on Spotify, and I&rsquo;m not brave enough to ask, but I’m grateful he dug it up. Also, many thanks to Mauro Servienti for hosting the interview.</p>
<h2 id="dotnet-podcast---interview-with-nicola-iarocci-2021">DotNet Podcast - Interview with Nicola Iarocci (2021)</h2>
<p><em>Hello everyone, and welcome to a new episode of DotNet Podcast, the Italian podcast dedicated to Microsoft technologies and more. You can find us on all major social platforms and podcasting services; all links are on our website, dotnetpodcast.com. Today we&rsquo;re talking about Python and Eve (or Pyrrest) and, why not, electronic invoicing for .NET.</em></p>
<p><em>Today I have the pleasure of having Nicola Iaroci with me. I met Nicola at the Italian edition of SoCraTes in Rimini a few years ago. Nicola is the classic jack of all trades: developer, entrepreneur, fitness enthusiast, consultant, open-source lover, Microsoft MVP, MongoDB Master, and probably something else I&rsquo;ve forgotten, because the list is very long. In the open source world, he&rsquo;s known primarily for Eve (we&rsquo;ll have him explain how to pronounce it), a REST framework for Python, and Electronic Invoicing .NET. I almost forgot: if you want to know anything about how Git works, Nicola knows it all.</em></p>
<p><strong>Welcome Nicola! Did I forget anything?</strong></p>
<p>Hi, thanks, welcome everyone. Well, no, I&rsquo;d say probably yes, but I can&rsquo;t tell you what, so I&rsquo;d say the introduction is perfect. Thanks.</p>
<p><strong>This podcast has always been oriented toward the .NET world, though lately we&rsquo;re branching out a bit into various technologies and even topics not necessarily technical. But assuming our listeners are primarily .NET developers, briefly, what is Python, and why should or could a C# .NET developer be interested?</strong></p>
<p>Sure, so first of all, Python fundamentally, let&rsquo;s say from a general point of view, is not that different from the languages we&rsquo;re used to in the .NET world, particularly C#, in the sense that it&rsquo;s still a high-level language, object-oriented from its foundations, let&rsquo;s say, from its roots. The main difference, perhaps, is that it&rsquo;s fundamentally interpreted, so there&rsquo;s an interpreter that executes the language and programs, although it&rsquo;s also possible to do JIT compilation, especially for performance reasons.</p>
<p>I&rsquo;ll add an important note because people generally think that a dynamic language is not strongly typed, which is not true. Python is a strongly typed language, but it has dynamic semantics, so type checking is still possible. I always clarify this because those coming from C-derived languages often think it&rsquo;s very similar to JavaScript, when in reality, there are clear differences.</p>
<p>It&rsquo;s certainly a language designed to be more approachable for a general programmer or even a beginner, and this probably also explains why it&rsquo;s had such success, I&rsquo;d say almost incredible success, for example, in the world of scientific research, numerical computing, in the financial world and for those who need to do numerical analysis. Because, among other things, in that particular area it&rsquo;s a language where performance is excellent, not because Python is a fast language (it&rsquo;s not at all, being interpreted), but a very beautiful thing about Python is that you can write its libraries in C, with bindings that practically allow you to use libraries written in C as if they were Python libraries.</p>
<p>And this is the trick that allowed all these tools for numerical, scientific, and financial analysis to be written in a language that&rsquo;s simple to grasp, even for those who perhaps aren&rsquo;t born developers like us. For example, think of a researcher, a scientist locked in their laboratory who can understand Python, approach programming and immediately have powerful tools available, yet the language remains easily readable and understandable. It&rsquo;s a perfect language, for example, for learning to program in general.</p>
<p>Then what else? Like our .NET languages, it obviously supports modules and packages. There&rsquo;s an equivalent to NuGet: PyPI, where you can now find hundreds of thousands of packages to install.</p>
<p>One thing that personally interested me a lot about Python when I started studying it was the fact that it was cross-platform from the beginning. It was a language that, when I started studying, was already twenty years old, so very mature. The base class library, or something like that, so it comes with a lot of included material, a bit like .NET at this point with .NET Core. Practically, whatever you want to do, there&rsquo;s certainly a standard way that allows you to do it.</p>
<p>The fact that it was cross-platform for me then was very interesting, because I came from the .NET ecosystem, which, when I started looking at Python about 10 years ago, was still absolutely out of the question. Then the world is made to change rapidly; it would also be nice if you let me tell you what happened in those years, but we probably don&rsquo;t have time. But fundamentally, yes, the fact that it was open source from the beginning, 20 years ago, I really liked a lot.</p>
<p>I must admit that in those years we fundamentally had to port our application, desktop applications, standalone, networked applications, and I was a bit frustrated by let&rsquo;s say the old Microsoft world, to be clear, which sounds strange coming from a Microsoft MVP, but this is also to tell why I became a Microsoft MVP after having abandoned Microsoft, I must say also quite disappointed, and I moved to the Python world. Then I was noticed in the Python world by Microsoft people, who sort of recruited me into this part of the MVP world.</p>
<p>Then I actually went back to doing a lot of C#, F#, in short, working in the .NET world. Actually, if I have to be honest, nowadays about 75-80% of my work is in C# and F#, and the remaining 20% is maintenance of my open-source Python packages.</p>
<p>So yes, let&rsquo;s say this: Python, personally, gave me new perspectives to answer your question. You know, when you&rsquo;re always inside, you always drink from the same source, you always drink the same water, and certainly it&rsquo;s excellent water, but you don&rsquo;t know the other flavors, the other tastes.</p>
<p>I&rsquo;ll give you a trivial example: in C#, historically (keep in mind that I&rsquo;m a certain age, so I started writing C# really too many years ago), I remember this episode that always marked me. They had always taught me not to use try-catch if possible because exceptions in .NET were performance problems; it was a bad practice. In the Python world, it&rsquo;s exactly the opposite: you write code without too many guards, you focus on the logic that solves the problem, and you catch and handle errors as needed.</p>
<p>Going back to the C# world, I started using this thing a lot in Python and used it aggressively, even to the dismay of my colleagues who had stayed in the world. And this is simply an example. Then, in the meantime, obviously, in these 10-15 years, try-catch is no longer a problem like it was 15 years ago.</p>
<p>I brought some things from the Zen of Python, a kind of decalogue that Python programmers try to follow, into the C# world. For example, &ldquo;Explicit is better than implicit,&rdquo; which is a classic of the Python world. So, rather than write one more line of code, make your intention exactly clear, rather than hiding things behind too many automagical things.</p>
<p>So, all these little things here. Now, yes, the .NET world has given us a lot, it&rsquo;s not even worth saying. Actually, now they&rsquo;ll do the same thing here, too. When I moved there, and especially there, I think C# was already very mature. So I found myself&hellip; I remember another thing: when, for the first time, I didn&rsquo;t understand how a REST call worked in Python, and I realized I could go to GitHub to see the source code of the framework I was using, which was Flask.</p>
<p>It&rsquo;s a bit like if I, 15 or 10-12 years ago, had been able to look at the ASP.NET source code to understand exactly why things weren&rsquo;t working as I thought they should. That thing for me was, the English would say, paradigmatic. It really opened my heart, and I understood that was the world I wanted to be in. Then you see, many of these arguments are a bit, let&rsquo;s say, weak today because C# and .NET are now fully open source. But better this way, thank God. A lot has changed in recent years.</p>
<p><strong>Nicola has a t-shirt I couldn&rsquo;t see well at first; it has the Superman logo, but it&rsquo;s actually an F with a hashtag, so it&rsquo;s an F# t-shirt. Is there a relationship between the functional world and Python, or is Python a traditional object-oriented world, let&rsquo;s call it that?</strong></p>
<p>Well, that&rsquo;s a good question. Actually, Python was born entirely and purely object-oriented. So anything you use in Python is an object, but it has a strong predisposition also toward functional programming, let&rsquo;s say. I have to be honest: if I want to do good quality functional programming, F# is a thousand times better than Python, but you can certainly do it.</p>
<p>Let&rsquo;s say this is probably interesting as well. I wouldn&rsquo;t have arrived at F# (let&rsquo;s say) if I hadn&rsquo;t gone through Python. Always for the discussions I was telling you about before, the approach in Python is to simplify things, break them down into&hellip; well, these are good practices used in all programming languages. But there&rsquo;s a tendency, let&rsquo;s say, to use functions rather than magic classes that incorporate state, for example.</p>
<p>In Python, it&rsquo;s quite common, even if not everyone does it, because, being a complete object-oriented language, you can perfectly well maintain state inside objects as you would in a C# class, in a classic way. But you will surely have noticed, and I think the listeners too, that the trend in C#, as well as in recent versions, is toward functional programming in a manner I&rsquo;d say is almost impetuous, so records, immutables, many other things like enhanced lambdas, etc., etc.</p>
<p>So, coming back to the .NET world from Python, I became much more curious about F # than I had been 10 years ago. So yes, in Python you can do decent functional programming and organize your code in a functional way, but it&rsquo;s certainly a language that remains object-oriented, let&rsquo;s say, in its orientation.</p>
<p>And it&rsquo;s not even, I have to tell you the truth, compared to C#, which has been adopting so much from F# in the last two or three versions, Python is not making this huge effort to become functional, and in this, I have to say I quite agree. I really like the evolution of C#, especially for me, who also obviously does F#. I think I would really like also like to know how to say, I&rsquo;ve also tried actually in some conferences to do outreach in this sense, to encourage the C# developer to go toward functional, and also to illustrate F#, the principles of F#.</p>
<p>But I also appreciate the fact that in the Python world, they said, &ldquo;ok, Python at its heart is an object-oriented language and its focus is there, let&rsquo;s improve that type of paradigm. There are other languages that do well. And in the .NET world, this is very true: there&rsquo;s C#, and we have the enormous fortune of also having F#.</p>
<p>Now there&rsquo;s been an attempt at hybridization, let&rsquo;s say, or rather to bring into the C# world everything that&rsquo;s beautiful about the functional world, which sure is appreciable. I&rsquo;m happy, I&rsquo;m already using it a lot. But I think it can also create a lot of confusion for a newcomer to the language, who perhaps comes from object-oriented programming and finds themselves with many functional things and doesn&rsquo;t quite understand what to do.</p>
<p>I adore the latest versions of C#, and I&rsquo;m very happy about it, but what is the specific direction of C#?</p>
<p><strong>Yes, I also have a sort of adoration for the latest version of C#, but I realize that having behind me&hellip; I started writing C# code in 1999 with Beta 1 of the .NET Framework. So I&rsquo;ve been through all of them, so for me, the novelties are small things compared to the twenty years that have passed. I realize that the problem might be that, for a new developer who arrives today, they face, fundamentally, an almost insurmountable mountain to climb.</strong></p>
<p>That&rsquo;s exactly what I meant, so adding then also, let&rsquo;s say, this cognitive weight. One could ask oneself why can&rsquo;t I use a class instead of a record, for example, but the same thing, what&rsquo;s the fundamental difference? Yes, there are reasons, but one of the really strong things about Python is its ease of access for those starting in programming.</p>
<p>I&rsquo;ve seen that Microsoft is making huge efforts in this regard, with video series on YouTube and sites to welcome people to C#. And I, in particular, who come from the world, I&rsquo;m let&rsquo;s say with feet in both camps, so I&rsquo;m well known in the Python world too, so much so that I&rsquo;ve also done presentations where I present Python to the C# programmer and C# and .NET to the Python programmer.</p>
<p>Especially now that C# is finally cross-platform and open source, it becomes much more&hellip; before, it was unthinkable to talk to a Python programmer about learning C#, which was only Windows and only .NET Framework, standalone, etc. It was really unthinkable. Now some cracks are opening, I&rsquo;m trying to slip in there, but it&rsquo;s very hard because clearly we have let&rsquo;s say an image, we&rsquo;re known as dotNetters in quotes for enterprise, for PA&hellip; and heavy stuff that&rsquo;s installed on Windows, the GAC, all these problems that existed in the Windows world.</p>
<p>Many times, making people understand &ldquo;look, now you can take a Linux machine and run a web application written in C# with the same ease as you would with Node or Python&rdquo; is really a message that leaves people open-mouthed, and they don&rsquo;t believe it, you have to show them. So the work to be done on our part is really a lot.</p>
<p><strong>You touched on Python at the beginning of the discussion, saying, if I remember correctly, you used Flask as a framework, which I assume is a sort of counterpart to ASP.NET. More or less? What relationship is there between Flask, ASP.NET, Eve and the REST world in general? And why did you feel the need to write a framework for REST for Python?</strong></p>
<p>Well, that&rsquo;s an excellent question. When I came to Python, there was a framework called Django, which was very widely used and very famous, and did the equivalent of a modern ASP.NET, an ASP.NET Core. But it was too complex, it was exactly the classic behemoth in the .NET style, because I&rsquo;m talking about the old way, where you had to take everything that came or what you needed. What I needed was to practically implement the equivalent of a Web API application we have in the .NET world, so the controller&hellip; well, there&rsquo;s no concept of controllers, but it&rsquo;s the classic REST API concept.</p>
<p>So, Flask actually defines itself as a REST API, but it&rsquo;s not a true Web API. It&rsquo;s more of a .NET type framework. When I explain to C# programmers what exactly Eve is, I make this kind of comparison: imagine a Web API .NET, well, Eve gives you that with the addition that there was this attempt to make it very easy to put online when you need an API that&rsquo;s basically a front-end for a database, so not much business logic but CRUD operations and things like that.</p>
<p>So, in this sense natively, Eve, besides providing the REST interface toward clients which by the way is strongly opinionated (that is, keep in mind that when I wrote Eve it actually was born as an internal project for my company, so we knew exactly that a POST would create a record, a PUT would replace, a PATCH would modify), I didn&rsquo;t create a framework that lets you do whatever you want, precise choices were made about how verbs work, how modifications work.</p>
<p>And fundamentally, if that&rsquo;s okay with you, my framework probably lets you work agilely and quickly. If you don&rsquo;t agree, use Flask or another framework, or build your own. And so yes, I&rsquo;d say the relationship is this: Flask could be, let&rsquo;s say, the core of a Web API. Look, it comes to mind now with .NET 6 this new interesting feature, which are the minimal APIs.</p>
<p>If you take the Flask homepage and look at the quick start example, it&rsquo;s maybe ten lines of code, and you take a snippet that Microsoft is publishing on its social media (David Fowler comes to mind on Twitter; every now and then, he posts screenshots of these minimal APIs), they&rsquo;re almost overlapping, it&rsquo;s incredible, right?</p>
<p>And so the work they&rsquo;re doing now in .NET 6 with minimal APIs is to remove from the logic let&rsquo;s say MVC and everything that was behind it, remove the routing and those things from verb management and then put it all in your hands so that you can make a pure API without the behemoth, without having to create a controller and so on.</p>
<p>So, Flask practically gives you that base that we&rsquo;ll now have in .NET 6. So, this, and minimal APIs are something that in my opinion can be very interesting for those who want to start using C# for example to make Web APIs, because when I came from C# I had the whole behemoth world let&rsquo;s say to manage and I found Flask which gave me the building blocks to build what I wanted, it was exactly the reason why I went to use Flask and Python.</p>
<p>So finally in .NET 6 we&rsquo;ll have something very similar and it&rsquo;s really impressive to compare Node code, Python code with Flask and .NET 6 minimal API code and see that the effort is very evident from Microsoft to make it interesting also for those coming from other stacks where all that, sorry if I repeat myself (I call it the behemoth), all that complication&hellip; so you have to have a controller, you have to have a view, you have to make a site, you have to have in short the data layer, all these affairs that certainly come from data user, among these and so on, are being somewhat thinned out to make everything lighter and it will be very interesting in my opinion.</p>
<p><strong>Exactly. One thing I noticed is that, finally, for the first time with .NET 6, the empty project template is truly empty.</strong></p>
<p>Exactly, Flask has been like that for me: you just need a .py file with your four lines of API initialization, and then a nice little function that responds to a GET, and you&rsquo;re done. Now we&rsquo;ll have this in .NET 6 too, which is really interesting to me. Hopefully, then we&rsquo;ll be able to make the rest of the world understand that .NET is no longer what it was 10 or 15 years ago, and here I emphasize this is the big commitment, in my opinion, the real challenge to win: communication.</p>
<p>But I have to say that on this I&rsquo;m optimistic for another reason and that&rsquo;s performance, that is the performance of .NET Core, multi-framework, cross-platform are really interesting and this is the reason why I went back to doing a lot of C# actually, because with .NET Core I have cross-platform and performance that I don&rsquo;t have in Python and now I&rsquo;m also starting to have a language, a stack that&rsquo;s agile and very similar to what I used in Python, what I use in Python or in Node for example. But let&rsquo;s not talk about Node, otherwise we&rsquo;ll have a classic flame war.</p>
<p><strong>Ok, in all of this, how does Electronic Invoicing .NET fit in?</strong></p>
<p>Well, Electronic Invoicing is also here, the result of my Python experience, that is, in Python I embraced open source to the point of becoming the first creator and then maintainer of some open source projects, and I saw the incredible potential that comes with letting&rsquo;s say, the benefits you have from making your code public.</p>
<p>And so going back to work in .NET (we&rsquo;re talking about 2014-2015, because electronic invoicing, it must be said, is something that was imposed by law, I think in 2019, now I don&rsquo;t remember, but actually the technical specifications were already in place for some years for the public administration world). So we had to do this thing internally.</p>
<p>Fundamentally, for those who don&rsquo;t know the product, <a href="https://fatturaelettronicaopensource.org">FatturaElettronica.NET</a> is simply a deserializer and serializer of electronic invoices that puts in your hands an instance of a class that represents the electronic invoice and that, very handily, also forces you to validate it according to the technical specifications. So you can, before submitting your electronic invoice to the Revenue Agency, etc., already know whether it will be accepted, identify any errors, and tell your user how to correct them. This is the version in a nutshell.</p>
<p>And so when we did this and I started working on this project I proposed to colleagues to try to leave it as open source because it was evidently something that would become useful certainly to a niche compared to Eve or <a href="https://python-cerberus.org">Cerberus</a> which is another project I have, but because meanwhile it&rsquo;s only dedicated to the Italian public and not to the whole planet let&rsquo;s say, but also certainly only to those who develop management software etc., etc.</p>
<p>But why not? It seemed to me an interesting little game, also because, I&rsquo;ll tell you the truth, it may seem a bit naive on my part, but it seemed to me the way to show and make .NET developers understand that open source, even from us peons, is perfectly possible. If you have an interesting project that can be useful, you can do it even if you come from the let&rsquo;s call it closed enterprise world, like that of .NET, and it seemed to me a way to give an example and encourage others to take the same step.</p>
<p>In short, at the beginning, it remained quiet for two or three years, and we used it only by us and four other unfortunate souls like us. Gradually it gained traction, it clearly became a very important thing when the law then imposed electronic invoicing and I must say we had the advantage, you see there too, of being a project that by then was already a few years old (it was from 2015 I think I left it open source), it was already mature enough to be adopted by those who were panicking because they found themselves with three months to implement something and so after that contributors arrived.</p>
<p>The thing about the whole Electronic Invoicing project that gives me the most satisfaction is the fact that there are .NET developers and it&rsquo;s evident from how they make pull requests and how they contribute to the code that they&rsquo;ve never done it before, but with enthusiasm and obviously out of necessity they get to work, they throw themselves into it and they&rsquo;ve also contributed pieces of code that have proven very important.</p>
<p>So in my small way, in the .NET world, what usually happens in other worlds I come from, or rather that I return to, so Python, is happening.</p>
<p><strong>This is a fascinating thing that recently happened to me too because I have several open source projects, one recently&hellip; a guy who I later discovered was Australian started opening issues, then a couple of pull requests and then more and now I&rsquo;m evaluating within myself whether to make him a maintainer because he&rsquo;s contributing in a very important way and if the project hadn&rsquo;t originally been open source because it didn&rsquo;t need to be open source, originally there wouldn&rsquo;t have been all the contributions that I honestly had never thought of, they didn&rsquo;t make much sense.</strong></p>
<p>Absolutely, I confirm and my experience too. To give a practical example on Electronic Invoicing, a guy comes to mind who contributed&hellip; I think I implemented serialization in JSON, in addition to XML, for these electronic invoices, but I wasn&rsquo;t at all interested in deserialization. It&rsquo;s a guy&hellip; moreover, it&rsquo;s also the contract, the pull request arrived with this feature completely implemented, and so now I support bidirectional JSON or the famous digital signatures, which are a very complex topic.</p>
<p>Electronic invoices can be sent as pure XML or with a digital signature. Actually the large part of those features was contributed from the outside. They&rsquo;re important features you see that I didn&rsquo;t work on, clearly, then I contributed to quality control, everything you want, but giving me so much value to the project and obviously to the community.</p>
<p>And among these contributors, there are precisely new contributors who, often precisely because of their enthusiasm, are the ones who in the end contribute the most, with also those more interesting features.</p>
<p>If I have a minute to tell another episode that comes to mind, in Eve, there was this guy. I had already been on GitHub for 4-5 years; it was going very well, and it had widespread adoption, which I was very proud of. After which, this pull request from this guy arrives, with, I remember, something like 800 code changes, so a monster pull request. Going to look at them, they were all changes to comments, what in Python are called docstrings, they&rsquo;re practically the inline documentation that you put as a comment that then serves developers to understand your code.</p>
<p>They were full of typos and errors because I&rsquo;m obviously not a native English speaker, so there were grammatical errors, typos, and other issues. It was super embarrassing because I realized that my code with all my errors had been seen by who knows how many tens of thousands of programmers, who knows how many laughs they had at my expense.</p>
<p>But the beautiful thing about this contribution was that he wrote to me, &ldquo;look, I&rsquo;m not an expert programmer, so I thought of contributing in this way. And from that day, the Eve documentation has enormously improved, so that a contribution which is not a code contribution, from an absolute non-expert for me personally, for the whole project, has had and still has an immense value.</p>
<p>So this is also a message, I always tell this episode. There are opportunities to contribute in a significant way for anyone, from the super programmer (the famous &ldquo;10x developer&rdquo; if you also say it in Italian), but also those who have just started can help and indeed, they should be encouraged because they&rsquo;re the ones who have so much enthusiasm, among you who then give them confidence, the problem is that after a while being a maintainer becomes very demanding and you start to delegate to someone who I&rsquo;m not saying replaces you, but maybe even yes.</p>
<p><strong>In fact, the next question is precisely that: if I understood correctly, both open source projects have some relationship with your work, but obviously, the cognitive and managerial load is significantly higher than what your work would generate. So what is your experience in the world of open source governance, and in general, managing projects that start maybe a bit like, I don&rsquo;t know, what we could call a playground, and then explode in your hands, and you say, &ldquo;oh my God, now what do I do?&rdquo;</strong></p>
<p>Yes, it&rsquo;s a gigantic problem actually because with Eve, thank God, we&rsquo;ve now reached a maturity and stability of the framework that allows me to live quite on my laurels, but attention, simply because I chose that the project is mature and stable, and I don&rsquo;t want to take it, say, to a version 2.0. If I were like .NET can be forced every year to make a new major release, it would obviously be my job 24 hours a day.</p>
<p>I also confess that to solve this problem I also tried to make Eve somehow profitable, to have an income from the project itself through donations, like &ldquo;buy me a coffee&rdquo;, but not with the objective of becoming full-time living, but with the objective of being able to pay myself half a day of work per week to dedicate explosively to the project, because if I could have dedicated, say, every Friday 8 hours to open source, you would certainly have a project 10 times more beautiful than what it has now, same thing with Cerberus, same thing with Electronic Invoicing.</p>
<p>As you can imagine, this thing didn&rsquo;t have much success because everyone is very good at installing packages, but when they have to put their hands in their wallets, they&rsquo;re much less good at it. Maybe there was gratitude for receiving this, which is very pleasant, but the long-term strategy is missing&hellip; another topic; we don&rsquo;t want to discuss now how to maintain&hellip;</p>
<p>There comes a moment when the cognitive commitment is really great, you have so much other business and other work types to deal with, and it becomes a problem. The solution, for example, I was lucky because, a bit like what happened to you, one of these contributors, gradually, I really let him, even in a somewhat sly way, I let him take control, but it started with minimal pull requests, then he gained courage, I sort of nurtured him.</p>
<p>In the end when I was certain he knew the codebase very well, he was also an expert, in short fundamentally Cerberus I left in his hands 100%, so I follow it from afar, I receive email notifications, if he has some important modification to make he asks me for advice, but actually he even has the rights to publish updates and so let&rsquo;s say now for me I&rsquo;m simply a father watching from afar the child grow, so to speak.</p>
<p>For Eve, I&rsquo;m still the main maintainer, but as I tell you, the choice of Eve was perhaps made with the idea of being able to continue living and earning, let&rsquo;s say, my salary. It was ok. The product is mature. From now on, we accept pull requests for bug fixes or mature new features that make sense to incorporate, but I don&rsquo;t foresee further development in any direction.</p>
<p>Electronic Invoicing, for me, is strategic because we use it every day in the company; we ultimately make management software, so there I remain the maintainer, and I do it gladly because there&rsquo;s a necessity.</p>
<p>So, in general, hopefully in the .NET world too, we&rsquo;ll arrive at this&hellip; so, many have told me &ldquo;how nice, I&rsquo;ll definitely make a donation, we&rsquo;ll make a donation for Electronic Invoicing because we use it in the company&rdquo;, I think not even one has arrived. So in this certainly the .NET world still has to mature and become aware of the fact that a long-term investment for a product you use every day and that gives you income in the end somehow (otherwise you wouldn&rsquo;t use it), it makes sense to think about contributing to the long life of the project to not risk finding yourself at a certain point with the maintainer who took the motorcycle and went to the Himalayas to climb and you have a critical project maybe that&rsquo;s no longer updated, that has security problems, etc. On this, there&rsquo;s work to do.</p>
<p><strong>Ok, to conclude, last two quick questions. Still staying in the open source world, if you had to give advice to someone who wants to start an open source project and advice to someone who wants to contribute to an open source project.</strong></p>
<p>Yes. So, for those who want to start, I&rsquo;d say don&rsquo;t worry. In the sense that, as you said before, there were projects you had put open source that actually didn&rsquo;t need to be. &ldquo;They didn&rsquo;t need to be open source.&rdquo; This is, the perception is a problem of really, I can&rsquo;t translate it into Italian, but it&rsquo;s a problem of wrong perception, in the sense that actually there&rsquo;s certainly someone on planet earth who has to solve the problem that you have to solve at that moment.</p>
<p>So even projects, if you want trivial small ones that serve little purpose, thanks to potential algorithms and tools, exposure from GitHub, from Google and so on, rest assured that if you&rsquo;re doing a project for electronic invoicing, someone else has that problem. So the first thing is that the history of open source is full of projects born as hobby projects, put on GitHub almost like this for convenience, because this way I have a remote backup, which actually exploded in the hands of maintainers because they were successful.</p>
<p>But even if they weren&rsquo;t successful, it serves you in the meantime to acquire the know-how, which is not small, and to gain experience in doing so and overcoming the shyness of sharing your code and showing it to the public. So, this is the other very important thing. My programming style has evolved a lot, thanks also to seeing what others do.</p>
<p>Sure, it can also be, how to say, sometimes not humiliating, I&rsquo;d say, but certainly it puts you in your place when you see that your code has been refactored in a much more performant or more elegant way by others, but it&rsquo;s there that you learn. It&rsquo;s a bit of the discourse about always drinking water from the same place I was telling you about. So certainly I&rsquo;d say first thing, don&rsquo;t be afraid, throw anything on GitHub even if the code is not the best&hellip; sorry&hellip; don&rsquo;t stay there to refine it, to clean it up, because maybe someone else will do it for you, who will even be grateful to you.</p>
<p>The other thing, probably, is&hellip; for those who want to start contributing instead, as I was saying before, there certainly are projects of the day that you use, even in professional frameworks&hellip; I&rsquo;ll also make here, I&rsquo;d say, another episode. When I was preparing a talk on Python and explaining how to use Python inside Visual Studio, which few people know, you can use all the Visual Studio features you&rsquo;re used to to write Python code. I realized that the official documentation on the Microsoft Visual Studio site had some shortcomings in the pages dedicated to Python. And so what did I do? I made a fork of that documentation, which is now finally all on GitHub. I contributed a fix to this documentation.</p>
<p>And now, I don&rsquo;t know if it&rsquo;s still like this, but two or three years ago, if you went to the official Microsoft documentation for Python, you&rsquo;d find my little face among the contributors. So there you go, I made a contribution even to an official Microsoft project. Free, because it&rsquo;s the tool that I use every day.</p>
<p>I&rsquo;m convinced that a large part of us developers have this experience of noticing a small error, a small problem, or a specification that doesn&rsquo;t necessarily require an extremely complicated algorithm to solve. It can also be, as I was telling you in that other episode, a docstring, a comment with a typo. They&rsquo;re all experiences that add up, that help you gain familiarity with the context, and so don&rsquo;t start maybe by contributing a Fibonacci optimization, because I don&rsquo;t know what.</p>
<p>So, really start from the trivial, from the simple, from what you do every day, because you know it very well and you&rsquo;re already competent. After which, there&rsquo;s time and a way to gain confidence; many of these my contributors, as I was telling you, start like this. Then, gradually, they gained courage and went to examine the deeper code, to solve the more complicated issues that I myself didn&rsquo;t feel like going to look at, because I knew it was a hornet&rsquo;s nest and the willing one arrived who did it in my place, riding the enthusiasm, which maybe I don&rsquo;t have anymore, but they have it, the positive energy to use, to spend.</p>
<p><strong>Good, very interesting, I agree completely. It&rsquo;s one of the most common barriers to entering the open source world, precisely because itis tied to the idea that &ldquo;I have to contribute,&rdquo; and you have in your head that the contribution must be substantial, when, in the end, it&rsquo;s often a small thing.</strong></p>
<p>Exactly. The novice contributor, let&rsquo;s say, is intimidated and thinks they should contribute something fundamental, but it doesn&rsquo;t make sense to contribute. On the other hand you have a maintainer who is literally at the window waiting for those who contribute the small things to arrive, because they&rsquo;re those, many small things that then are small things relatively (it&rsquo;s the perception of the remote developer that it&rsquo;s a small thing), it&rsquo;s all work that you take away from the maintainer and that you take away from the community.</p>
<p>So even the very small thing I can&rsquo;t wait for those more sought-after so-called small things to arrive. Actually, it has great value, as seen in the example of the 800 typos in the Eve documentation.</p>
<p><strong>I thank you for your availability. It&rsquo;s been a very pleasant chat. I hope to have you as a guest again, and as we shared before we started, we discussed an interesting topic that could be fitness for developers.</strong></p>
<p>If you decide to do it, call me. Thanks so much to you and your whole team for what you do with this podcast. You do an excellent job.</p>
<p><strong>Thanks so much, thanks so much and thanks again for your availability. See you next time, hello everyone.</strong></p>
<p>Bye-bye, bye everyone, thanks.</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>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>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>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>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>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>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>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>Making C# and OmniSharp play well with Neovim</title>
      <link>https://nicolaiarocci.com/making-csharp-and-omnisharp-play-well-with-neovim/</link>
      <pubDate>Fri, 03 Mar 2023 08:05:25 +0100</pubDate>
      <guid>https://nicolaiarocci.com/making-csharp-and-omnisharp-play-well-with-neovim/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve recently moved away from my custom Neovim configuration to embrace &lt;a href=&#34;https://www.lazyvim.org/&#34;&gt;LazyVim&lt;/a&gt;. LazyVim is a Neovim setup with sane
default settings for options, autocmds, and keymaps. It boldly aims to transform Neovim into a full-fledged IDE that is
easy to extend and customize. It comes with a wealth of plugins pre-configured and ready to use, and it is also blazing
fast. Elijah Manor has a fantastic introductory video on YouTube; I suggest you take the time to look at it.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve recently moved away from my custom Neovim configuration to embrace <a href="https://www.lazyvim.org/">LazyVim</a>. LazyVim is a Neovim setup with sane
default settings for options, autocmds, and keymaps. It boldly aims to transform Neovim into a full-fledged IDE that is
easy to extend and customize. It comes with a wealth of plugins pre-configured and ready to use, and it is also blazing
fast. Elijah Manor has a fantastic introductory video on YouTube; I suggest you take the time to look at it.</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/N93cTbtLCIM?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 -->
So far I&rsquo;m delighted with the result. In the process, I learned about several useful plugins I now use regularly.</p>
<h3 id="neovim-trouble-with-c-and-omnisharp">Neovim trouble with C# and OmniSharp</h3>
<p>When I upgraded my old-<em>ish</em> Neovim (I am using nightly builds now), I started getting a weird error on every <code>.cs</code> file
I loaded:</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>Error executing vim.schedule lua callbaack: /usr/share/[...]/semantic_tokens.lua:342:E5248: Invalid character in group name.
</span></span></code></pre></div><p>A little investigation revealed that semantic tokens provided by
OmniSharp don&rsquo;t conform to the LSP specification, which triggers the error. I cloned the <em>omnisharp-roslyn</em> repo and dug
into the code hoping I could offer a quick fix. As it turns out, however, the issue is actually with <a href="https://github.com/dotnet/roslyn/blob/3cca4fdc3b125995bfd32b3a02b5d5c2d2b82504/src/Workspaces/Core/Portable/Classification/ClassificationTypeNames.cs#L97">Roslyn
itself</a>, not OmniSharp. There are tickets on both the <a href="https://github.com/neovim/neovim/issues/21391">Neovim</a> and the <a href="https://github.com/OmniSharp/omnisharp-roslyn/issues/2483">OmniSharp</a> repositories, but I fear
they&rsquo;ll stagnate there as non-relevant (<em>note to self</em>: maybe report the problem to the Roslyn folks? Alternatively,
propose a patched semantic provider to the <em>omnisharp-roslyn</em> maintainers.)</p>
<p>Anyway, a quick, hacky, and not future-proof fix is to customize Neovim (LazyVim) configuration 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>-- ~/.config/nvim/lua/plugins/omnisharp.lua (create <span style="font-weight:bold">if</span> needed)
</span></span><span style="display:flex;"><span><span style="font-weight:bold">return</span> {
</span></span><span style="display:flex;"><span>  <span style="font-style:italic">&#34;OmniSharp/omnisharp-vim&#34;</span>,
</span></span><span style="display:flex;"><span>  init = function()
</span></span><span style="display:flex;"><span>    require(<span style="font-style:italic">&#34;lazyvim.util&#34;</span>).on_attach(function(client, _)
</span></span><span style="display:flex;"><span>      <span style="font-weight:bold">if</span> client.name == <span style="font-style:italic">&#34;omnisharp&#34;</span> then
</span></span><span style="display:flex;"><span>        client.server_capabilities.semanticTokensProvider = {
</span></span><span style="display:flex;"><span>          full = vim.empty_dict(),
</span></span><span style="display:flex;"><span>          legend = {
</span></span><span style="display:flex;"><span>            tokenModifiers = { <span style="font-style:italic">&#34;static_symbol&#34;</span> },
</span></span><span style="display:flex;"><span>            tokenTypes = {
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;comment&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;excluded_code&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;identifier&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;keyword&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;keyword_control&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;number&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;operator&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;operator_overloaded&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;preprocessor_keyword&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;string&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;whitespace&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;text&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;static_symbol&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;preprocessor_text&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;punctuation&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;string_verbatim&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;string_escape_character&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;class_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;delegate_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;enum_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;interface_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;module_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;struct_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;type_parameter_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;field_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;enum_member_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;constant_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;local_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;parameter_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;method_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;extension_method_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;property_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;event_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;namespace_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;label_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_doc_comment_attribute_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_doc_comment_attribute_quotes&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_doc_comment_attribute_value&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_doc_comment_cdata_section&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_doc_comment_comment&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_doc_comment_delimiter&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_doc_comment_entity_reference&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_doc_comment_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_doc_comment_processing_instruction&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_doc_comment_text&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_literal_attribute_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_literal_attribute_quotes&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_literal_attribute_value&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_literal_cdata_section&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_literal_comment&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_literal_delimiter&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_literal_embedded_expression&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_literal_entity_reference&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_literal_name&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_literal_processing_instruction&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;xml_literal_text&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;regex_comment&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;regex_character_class&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;regex_anchor&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;regex_quantifier&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;regex_grouping&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;regex_alternation&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;regex_text&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;regex_self_escaped_character&#34;</span>,
</span></span><span style="display:flex;"><span>              <span style="font-style:italic">&#34;regex_other_escape&#34;</span>,
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>          },
</span></span><span style="display:flex;"><span>          range = true,
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>      end
</span></span><span style="display:flex;"><span>    end)
</span></span><span style="display:flex;"><span>  end,
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>It overrides the <code>on_attach</code> event to pass an LSP-digestible list of semantic tokens. And voilà, C# files are now loaded seamlessly.</p>
<p>I&rsquo;m not done yet. I&rsquo;m having another <a href="https://github.com/OmniSharp/omnisharp-roslyn/issues/2510">weird issue</a> with <em>.editorconfig</em> files. I&rsquo;m still triaging it, and will report back when (if) I sort it out.</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>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>
  </channel>
</rss>
