Buckle up, developers, because Microsoft is back at it again with the release of .NET 8 Preview 3! Hot on the heels of the previous preview 1 and preview 2, this latest iteration promises to deliver even more enhancements and exciting new features to the ever-evolving .NET ecosystem.
In this article, we’ll be diving into the fresh updates and optimizations that Preview 3 has to offer, so grab your favorite coding beverage (coffee in my case☕) and let’s explore the cutting-edge advancements of .NET 8 Preview 3 together.
Simpler Output Path
Building .NET apps can be a wild ride, and over time, Microsoft have all gotten used to that tangled web of output paths for our beloved build artifacts. You know the drill: bin
, obj
, publish
, and all those quirky arrangements. Not to mention the per-project directories! But hey, Microsoft has been listening, and it’s clear that it’s time for a change.
So, buckle up, because the .NET SDK has whipped up a spiffy new option to have an easier output path structure. Here’s the lowdown:
- All build outputs gather ’round in one cozy spot.
- Each project gets its own little corner in that happy place.
- The whole shebang is flattened to a max of three depth levels.
Ready to dive in? Set the UseArtifactsOutput
property in a Directory.Build.props
file, and you’ll be off to the races. Just run dotnet new buildprops
in your repo’s root, tweak the generated Directory.Build.props
file, and add:
<UseArtifactsOutput>true</UseArtifactsOutput>
And there you have it! All your build output will now snuggle up in the .artifacts
directory in your repo’s root. Not a fan of the default? No sweat, just change the ArtifactsPath
property in your Directory.Build.props
file to your heart’s desire.
The new .artifacts
directory will look like this: <ArtifactsPath>\<Type of Output>\<Project Name>\<Pivots>
. So, you’ll have:
- Make order of the compilation outputs. These would be done in different categories. We could find categories such as NuGet packages, publishet applications or binaries.
- A tidy way to sort out build options, like
Configuration
andRuntimeIdentifier
.
They believe this streamlined structure will make your life a whole lot easier and pave the way for future improvements. Plus, it’ll be a breeze for tools to handle build outputs.
Time for Spring Cleaning with dotnet workload clean
Have you ever encountered extra workload packages after updating .NET SDK or Visual Studio? It’s a bumpy ride, and sometimes, things get left behind. But don’t panic – and please, don’t manually delete those directories!
Microsoft is excited to introduce a useful new command that helps clean up the leftover mess:
dotnet workload clean
Got workload woes? Give dotnet workload clean
a whirl to safely tidy up before trying again. This handy helper comes in two flavors:
dotnet workload clean
It is somewhat similar to a garbage collector but also works for workloads that are based on MSI files. The tool is specifically designed to remove any leftover packages that are no longer needed after uninstalling previous versions of .NET SDK
And heads up! On the other hand, we have our friend Visual Studio, which manages the workloads. Dotnet workload clean
will remind you to uninstall them via Visual Studio, not the .NET SDK CLI.
dotnet workload clean --all
This one’s a bit more intense. workload clean --all
not only performs the function that a garbage collector would perform, in this case it is different. All packages that do not match the load facility and/or are not from Visual Studio would be cleaned up.
So, next time you find yourself in workload pack purgatory, give dotnet workload clean
a try and watch your troubles disappear!
Meet the Handy ValidateOptionsResultBuilder
Say hello to the ValidateOptionsResultBuilder, your new best friend for creating a ValidateOptionsResult
object! It makes implementing IValidateOptions.Validate(String, TOptions)
a breeze.
The best part? You will be able to check several problems at the same time as this constructor is able to add several constructors!
Here’s a little taste of how it works:
ValidateOptionsResultBuilder builder = new();
builder.AddError("Error: invalid operation code");
builder.AddResult(ValidateOptionsResult.Fail("Invalid request parameters"));
builder.AddError("Malformed link", "Url");
// Build ValidateOptionsResult object with multiple errors.
ValidateOptionsResult result = builder.Build();
// Reset the builder for a fresh start.
builder.Clear();
Say Hello to the Configuration Binding Source Generator!
ASP.NET Core uses configuration providers to read data (key-value pairs) from sources like appsettings.json, environment variables, and Azure Key Vault.
The heart of this system is ConfigurationBinder
, which maps configuration values to strongly-typed objects with Bind
and Get
methods. However, the current reflection-based approach has its drawbacks.
Fear not! Now, Microsoft adds a generator (which is AOT compliant and creates binding implementations) that is able to generate source code. The generator focuses on Configure
, Bind
, and Get
calls.
Check out the example below to see the binder in action:
// ... (sample code)
public class MyOptions
{
// ... (property declarations)
}
public class MyClass
{
public int SomethingElse { get; set; }
}
To enable the generator, grab the latest preview of Microsoft.Extensions.Configuration.Binder
and tweak your project file like so:
<PropertyGroup>
<EnableMicrosoftExtensionsConfigurationBinderSourceGenerator>true</EnableMicrosoftExtensionsConfigurationBinderSourceGenerator>
</PropertyGroup>
Mix & Match Architectures with .NET Container Images!
With both Arm64 and x64 machines now widely used, Docker supports building multi-platform images that work across different environments. Microsoft has finally managed to develop a new pattern for .NET image architectures just to help!
What if you imagine for a moment that you have a computer with an Apple Mac and what you need is to point to an x64 service that is currently in the azure cloud? No sweat! Just use the --platform
switch:
docker build --pull -t app --platform linux/amd64 .
To make the SDK run faster and more compatibly on your local machine, update one line in your Dockerfile:
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-preview-alpine AS build
Microsoft have also spruced up the SDK to support $TARGETARCH
values and added the -a
argument on restore. Check it out:
RUN dotnet restore -a $TARGETARCH
# copy everything else and build app
COPY aspnetapp/. .
RUN dotnet publish -a $TARGETARCH --self-contained false --no-restore -o /app
This cool method lets you whip up optimized apps that get along swimmingly with Docker. Neat, huh? --platform
values. Take a peek at this sample to see the pattern in action!
A Handy Trick for Non-Root User UID
This time Microsoft has discovered that the runAsNonRoot test requires that the same user that is configuring the container be set by UID. But, Microsoft didn’t want you to memorize a special number for tons of Dockerfiles.
Here you can check this Dockerfile example out how it can be used:
USER $APP_UID
If you want to build a Docker container image with USER
like this, the container metadata shows:
$ docker inspect app | jq .[-1].Config.User
"64198"
Also you can check how the environment variable is defined:
$ docker run --rm -it mcr.microsoft.com/dotnet/runtime bash -c "export | grep APP"
declare -x APP_UID="64198"
$ docker run --rm -it mcr.microsoft.com/dotnet/runtime cat /etc/passwd | tail -n 1
app:x:64198:64198::/home/app:/bin/sh