Errata (15 items)
If you find any mistakes, then please raise an issue in this repository or email me at markjprice (at) gmail.com.
Warning! Avoid copying and pasting links that break over multiple lines and include hyphens or dashes because your PDF reader might remove a hyphen thinking that it being helpful but break the link! Just click on the links and they will work. Or carefully check that your PDF reader has not removed a hyphen after pasting into your web browser address bar. See an example of this issue here.
- Online docs
- Page 12 - Installing other extensions
- Page 70 - Raw string literals
- Page 71 - Raw string literals
- Page 84 - Storing dynamic types
- Page 88 - What does new do?
- Page 103 - Getting key input from the user
- Page 317 - Comparing objects when sorting
- Page 319 - Implicit and explicit interface implementations
- Page 515 - Understanding Entity Framework Core
- Page 521 - Managing the Northwind sample database with SQLiteStudio, Page 628 - Creating the Northwind database
- Page 677 - Using shared layouts with Blazor static SSR pages
- Page 710 - Abstracting a service for a Blazor component
- Page 735 - Creating an ASP.NET Core Minimal API project
- Appendix B - Setting Up Your Development Environment
Thanks to Donald Maisey for raising this issue on January 12, 2026.
The link to an online topic about async/await was moved in the book from Chapter 2 to Chapter 4, but the online files and link were not. These have now been moved to where they should be. Also, some links to online topics were missing from the docs README.md file. These have now been added.
Thanks to Eduardo Almeidabr for raising this issue on April 19, 2026.
Table 1.1 VS Code extensions for .NET development includes a row for Polyglot Notebooks ms-dotnettools.dotnetinteractive-vscode, and Polyglot Notebooks are referenced in two other sections of the book, Explore Polyglot Notebooks on page 38, and C# 101 notebooks on page 169.
However, in February 2026, the .NET Interactive team officially announced the deprecation of this extension:
- The Polyglot Notebooks Extension became deprecated on March 27th, 2026.
- .NET Interactive became deprecated on April 24th, 2026.
The team knows notebooks are very unique and nothing can directly replace a notebook. However, for the use case we are continuing to invest in (a lightweight scratch pad for quick experiments, testing code, trying NuGet packages, etc.) file-based apps will provide that path going forward.
Important notes:
- The Polyglot Notebooks extension will not be disabled or uninstalled from your VS Code.
- You can continue using the extension as is after its deprecation date if you don't uninstall it, but future VS Code updates may eventually break it.
- No new features will be added to Polyglot Notebooks or .NET Interactive.
- Bugs for Polyglot Notebooks or .NET Interactive will not be fixed.
- Any security vulnerabilities reported for both Polyglot Notebooks and .NET Interactive after their respective deprecation dates will not be addressed.
Recommended Action: Uninstall the Polyglot Notebooks extension and/or uninstall .NET Interactive from your machine once you've migrated to another solution.
In the next edition, all references to Polyglot Notebooks will be removed.
Thanks to Paul Marangoni for raising this issue on November 19, 2025.
In the book, the following example is wrong:
It should be:
Thanks to mushobeti for raising this issue on November 29, 2025.
The following code example mistakenly indents the last three-quotes by one space:
string json = $$"""
{
"first_name": "{{person.FirstName}}",
"age": {{person.Age}},
"calculation": "{{ 1 + 2 }}"
}
""";This causes the compiler to give Error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal.
To fix this error, delete the extra space at the start of the last statement, as shown in the following code:
string json = $$"""
{
"first_name": "{{person.FirstName}}",
"age": {{person.Age}},
"calculation": "{{ 1 + 2 }}"
}
""";This code example was correct in earlier editions so must have been accidently introduced during the editing process. I apologize for missing it.
Thanks to iheartdotnet for raising this issue on August 2, 2025 and to Chris Alberty for noticing that I had missed fixing it in the 10th edition.
In the last paragraph of this section, I wrote, "Dynamic types are most useful when interoperating with non-.NET systems. For example, you might need to work with a class library written in F#, Python, or some JavaScript. You might also need to interop with technologies like the Component Object Model (COM), for example, when automating Excel or Word."
I included F# in the list of languages after giving the example of dynamic being useful when interoperating with non-.NET systems. This accidently implies that F# is not a .NET language when it is. In the next edition, I will change "non-.NET systems" to "other .NET languages and non-.NET systems".
Thanks to CalebFord who raised this issue on March 31, 2026.
I wrote, "Consider the following code, which declares some local variables:"
short age; // Allocates 2 bytes of memory on the stack to store a System.Int16 value.Below the code block I wrote, "Note the following about the preceding code:
agehas a value of0and 2 bytes of memory have been allocated in stack memory"
But value-type variables that you have not explicitly set are uninitialized because they do not officially have a value yet, even though internally they will have a value of zero. To protect you from assumptions, the compiler will show an error like Use of unassigned local variable 'age' if you try to access the variable.
In the next edition, I will change the bullet to read:
agehas not been assigned a value (so the compiler with show an error if you attempt to access it) and 2 bytes of memory have been allocated in stack memory
Thanks to mushobeti for raising this issue on November 30, 2025.
In Steps 2 and 4, the output of the Modifiers should be None instead of 0. To output the integer value of the Modifiers enum, we would use arg2: (int)key.Modifiers.
Thanks to Nick Johnston for raising this issue on December 27, 2025.
In Step 5, I wrote, "In Person.cs, after inheriting from object, add a comma and enter IComparable<Person?>,"
Inheriting from object was shown in Chapter 5. I should have written, "In Person.cs, after Person, enter : IComparable<Person?>," and the code highlighting should include the colon.
Thanks to Clint Mayers who emailed me about this issue on May 20, 2026.
In the code example, I wrote comments about explicit interfaces:
// Explicit implementation can be any access modifier.
void IGamePlayer.Lose() // Defaults to private.
{
// Implement losing a game.
WriteLine("Implementation for losing a game.");
}After the code example, I added some notes:
Although the implementation of
IGamePlayer.LoseinHumanisprivate, theIGamePlayer.Losemember itself has an access modifier ofpublic, so if we cast theHumaninstance into the interface type, then thatLoseimplementation is accessible.
Warning! Method access modifiers in an implementation type must match the method definition in the interface. For example, the
Losemethod in the interface ispublic, so the method implementation in the class must also bepublic.
But what I wrote is confusing because you cannot set any modifier on explicit interfaces. As Microsoft say, "An explicit interface implementation doesn't have an access modifier since it isn't accessible as a member of the type it's defined in. Instead, it's only accessible when called through an instance of the interface. If you specify an access modifier for an explicit interface implementation, you get compiler error CS0106." This is what I clumsily tried to say in my first note.
In the next edition, I will rewrite this section, and include a link to the official documentation: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation
On February 10, 2026, the EF Core team published packages for EF Core 11 Preview 1, and a page for what's new: https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-11.0/whatsnew
It includes an important note: "EF11 requires the .NET 11 SDK to build and requires the .NET 11 runtime to run. EF11 will not run on earlier .NET versions, and will not run on .NET Framework."
In my book, I wrote: "EF Core 10 targets .NET 10 or later, and EF Core 11 will also target .NET 10 because the EF Core team wants as many developers as possible to benefit from new features in future releases, even if you must target only long-term support releases of .NET. This means that you can use all the new features of EF Core 11 with either .NET 10 or .NET 11."
In the past, the EF Core team often targeted the latest LTS .NET so you could adopt the new EF Core STS version without moving your whole app runtime. Microsoft’s own “Supported .NET implementations” page even states that as the general approach: “In general, we target the latest LTS release of .NET… There may be exceptions… as runtime features sometimes get added that require us to depend on the latest version of .NET.” From: https://learn.microsoft.com/en-us/ef/core/miscellaneous/platforms
But EF Core 11 is now explicitly saying that it requires the .NET 11 SDK to build and the .NET 11 runtime to run, and it won’t run on earlier .NET versions.
Why? The EF team’s own platform guidance acknowledges that sometimes they must depend on the latest .NET due to runtime features. In practice, “won’t run on earlier .NET” usually means they’re compiling against and taking dependencies on assemblies/APIs that simply are not present (or not the same versions) on earlier runtimes, and the team has decided not to carry the extra compatibility shims or multi-targeting.
Net result: EF Core 11 only running on .NET 11 is the documented requirement. If you want to stay on .NET 10 LTS, EF Core 10 is the ceiling. If you move to .NET 11 (STS), EF Core 11 becomes available.
Page 521 - Managing the Northwind sample database with SQLiteStudio, Page 628 - Creating the Northwind database
Thanks to Amar Jamal for raising this issue on November 4, 2025.
On page 521, in Step 6, I wrote, "You will see the 10 tables..." but there are only 8 tables. For many editions there were 10, but recently I simplified the script to only create 8 tables by removing the unneeded Territories and EmployeeTerritories tables.
On page 628, I wrote, "The script for SQLite is a simplified version that only creates 10 tables..." Again, this should be 8 tables.
Thanks to Amar Jamal for raising this issue on November 19, 2025.
In Step 3, the markup includes the following to link to the Suppliers page:
<NavLink class="nav-link" href="suppliers">
Suppliers
</NavLink>To prevent broken links, it would be better to use a forward-slash / prefix for the href, as shown in the following link:
<NavLink class="nav-link" href="/suppliers">
Suppliers
</NavLink>The same applies when you add a link for the Customers page in Exercise 13.2.
Thanks to Amar Jamal for raising this issue on December 3, 2025.
In Step 6, the existing reference to the data context project starts the path with ..\ when it should be ..\..\, as shown in the following markup:
<ProjectReference Include="..\..\Northwind.DataContext.Sqlite\Northwind.DataContext.Sqlite.csproj" />Thanks to hungvuongvo for raising this issue on February 22, 2026.
In Step 4, I wrote, "Build the Northwind.WebApi project." And then in Step 5, I tell the reader to remove the Version attribute from the package. These steps should be swapped otherwise you will get a compile error on Step 4.
Thanks to José Luis García for emailing me about this on November 16, 2025.
In Step 7, Northwind4SQLServer.sql should be Northwind4SqlServerLocal.sql.

