skip to content
Relatively General .NET

Challenge

by Oren Eini

posted on: January 04, 2023

Given the following code: This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters Show hidden characters using System; Iterator? it = new Iterator(); while (it.Value.MoveNext()) { Console.WriteLine(it.Value.Current); } public struct Iterator { public int Current; public bool MoveNext() { Current++; return Current < 10; } } view raw what.cs hosted with ❤ by GitHub Can you guess what it will do? Can you explain why?I love that this snippet is under 20 lines of code, but being able to explain it shows a lot more knowledge about C# than you would expect.

A first look behind the scenes of minimal API endpoints

by Andrew Lock

posted on: January 03, 2023

Behind the scenes of minimal APIs - Part 1

C# 11 List Patterns - Create compatible types

by Gérald Barré

posted on: January 03, 2023

C# 11 introduced list patterns. List patterns extend pattern matching to match sequences of elements in a list or an array. The goal of this post is not to explain the syntax but to show how to create a compatible type. If you don't know what list patterns are, I recommend reading the following doc

Adding dark theme to a website

by Gérald Barré

posted on: December 27, 2022

I've recently added a dark theme to this website. The light or dark theme is selected based on the browser / OS settings. In this post, I'll describe how I've added this support!Theme is selected based on browser settings#Step 1: Extracting colors to variablesThe first step is to extract all colors

Delete dotnet bin and obj folders recursively

by Ardalis

posted on: December 20, 2022

Although Visual Studio and the dotnet CLI both offer clean commands, neither one really cleans up bin and obj files generated by the build…Keep Reading →

ASP.NET Core in Action, Version 3 update

by Andrew Lock

posted on: December 20, 2022

In this article I talk a little about my upcoming book, ASP.NET Core in Action, Version 3.…

Generating a dump file when tests hang on a CI machine

by Gérald Barré

posted on: December 19, 2022

I recently investigated an issue where the tests hang on the CI. It's easier to debug when issues happen on your machine as you can easily attach a debugger and see what's going on. But in this case, the tests were hanging on the CI and I couldn't attach a debugger. I had to find an alternative way

Answer

by Oren Eini

posted on: December 15, 2022

I asked the following question, about code that uses AsyncLocal as well as async calls. Here is the code again: This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters Show hidden characters using System; using System.Threading; using System.Threading.Tasks; await new Scenario().Run(); public class Scenario { public AsyncLocal<bool> Active = new(); private async Task Start() { Active.Value = true; } public async Task Run() { Console.WriteLine(Active.Value); await Start(); Console.WriteLine(Active.Value); } } view raw wierd.cs hosted with ❤ by GitHub This code prints False twice, the question is why. I would expect that the AsyncLocal value to remain the same after the call to Start(), since that is obviously the point of AsyncLocal. It turns out that this isn’t the case. AsyncLocal is good if you are trying to pass a value down to child tasks, but it won’t be applicable to other tasks that are called in the same level. In other words, it works for children, not siblings tasks. This is actually even more surprising in the code above, since we don’t do any awaits in the Start() method. The question is why? Looking at the documentation, I couldn’t see any reason for that. Digging deeper into the source code, I figured out what is going on. We can use SharpLab.io to lower the high level C# code to see what is actually going on here, which gives us the following code for the Start() method: This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters Show hidden characters [AsyncStateMachine(typeof(<Start>d__1))] public Task Start() { <Start>d__1 stateMachine = default(<Start>d__1); stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); stateMachine.<>4__this = this; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } view raw lower.cs hosted with ❤ by GitHub Note that we call to AsyncTaskMethodBuilder.Start() method, which ends up in AsyncMethodBuilderCore.Start(). There we have a bunch of interesting code, in particular, we remember the current thread execution context before we execute user code, here. After the code is done running, we restore it if this is needed, as you can see here. That looks fine, but why would the execution context change here? It turns out that one of the few places that interact with it is the AsyncValue itself, which ends up in the ExecutionContext.SetLocalValue. The way it works, each time you set an async local, it creates a new layer in the async stack. And when you exit an async call, it will reset the async stack to the place it was before the async call started. In other words, the local in the name AsyncLocal isn’t a match to ThreadLocal, but is more similar to a local variable, which goes out of scope on function exit. This isn’t a new thing, and there are workarounds, but it was interesting enough that I decided to dig deep and understand what is actually going on.

Add All Projects to Solution with dotnet CLI

by Ardalis

posted on: December 15, 2022

If you need to just create a new solution file with all projects in all subfolders in it, this should work for you. Scenario For whatever…Keep Reading →

Microsoft Account Azure Login Problem Resolved

by Ardalis

posted on: December 15, 2022

In November 2022, I started having problems logging into the Azure portal with my Microsoft Account that I've had for years, and which…Keep Reading →