Why do I need to specify the .Net version in global.json
In this post, LondonPilot discusses issues with EF Core migrations caused by .NET SDK version mismatches, seeking clarification on the roles of global.json and .csproj target frameworks.
Understanding the Need for global.json
in .NET Projects
Context
LondonPilot describes an issue faced while maintaining a .NET project. Attempting to create an Entity Framework (EF) Core migration resulted in the error:
“The “DiscoverPrecompressedAssets” task failed unexpectedly. System.ArgumentException: An item with the same key has already been added.”
A solution found online largely resolved the problem. However, an additional step—installing the specific SDK version—was needed. Listing installed SDKs revealed only .NET 9 was present, even though the app targeted .NET 8.
Despite all .csproj
files properly listing target frameworks, the app compiled and ran in debug mode with just .NET 9 installed. Running EF Core migrations, however, required:
- Adding a
global.json
specifying the necessary .NET SDK version - Installing the corresponding SDK version
Key Questions
- Why is
global.json
needed for specifying the SDK version when target frameworks appear in.csproj
? - Why can the program compile and run without the relevant SDK, but advanced CLI tools (like EF Core migrations) fail unless it’s installed?
Explanation
Project File (.csproj
) vs. global.json
- The
.csproj
project file defines the target framework for your project (e.g.,net8.0
). This tells the compiler what runtime your code should run against and which APIs are available. global.json
allows you to fix the SDK version used by the CLI (e.g.,dotnet build
,dotnet ef
). Without it, the CLI will use the latest installed SDK (here, .NET 9) that matches (or can interpret) your project.
Why Did it Work Without the Right SDK?
- Many .NET SDKs are backward-compatible: the .NET 9 SDK can often build and debug apps targeting .NET 8, using reference assemblies for .NET 8.
- However, tools like EF Core migrations sometimes rely on specific behaviors or features present only in a matching or older SDK. They may fail, or produce unexpected errors, if the SDK versions diverge.
Why Both Steps Were Needed
- Adding
global.json
: Forces tools to use a specific SDK version (e.g., .NET 8) rather than a later SDK, ensuring command-line tools behave as expected. - Installing the SDK: If the SDK specified in
global.json
isn’t installed, commands will fail to run. Both the SDK andglobal.json
are needed for reproducible builds and consistent dev team behavior.
Summary
For consistent CLI tool behavior—especially across teams or build servers—global.json
pins the SDK version. Relying on just the latest installed SDK can lead to mysterious errors during advanced scenarios like EF Core migrations, even if most build/debug scenarios work.
Practical Recommendations
- Commit a
global.json
with your desired SDK version to source control. - Ensure all contributors/installations have the SDKs in
global.json
. - Use
dotnet --list-sdks
to verify which SDKs are present and troubleshoot issues.
References
This post appeared first on “Reddit CSharp”. Read the entire article here