.NET 8 is on the way! Discover its new Features🚀
Tags: dotnet, csharp, news, beginners
Published: 2023-03-15 10:45:49

Can you believe it? It feels like just yesterday that we were geeking out over .NET 7, and here we are already talking about .NET 8! Time flies when you’re coding up a storm.

But fear not, Microsoft is hard at work bringing us the latest and greatest features that we’ll be exploring in this article.

So sit back, relax, and let’s dive into all the exciting new updates that .NET 8 has in store for us.

## dotnet publish and dotnet pack

Microsoft just released an awesome new feature for the `dotnet publish` and `dotnet pack` commands that makes it even easier to produce production-ready code.

Before this update, these commands produced `Debug` assets by default, which could be a bit of a hassle if you wanted to produce production-ready code. But now, with the new update, `dotnet publish` and `dotnet pack` **produce** `Release` **assets by default**, which means you can easily produce production-ready code without any extra steps.

But don’t worry, if you still need to produce `Debug` assets for any reason, **it's still possible to do** so by setting the in `false` the `PublishRelease` property.

### How dotnet publish and dotnet pack works?

First, let’s create a new console application using the `dotnet new console` command. Then, let's build the project using `dotnet build` and take a look at the output. In this case, the output will be in `Debug` mode, since that's the default behavior of `dotnet build`.

Next, let’s run the `dotnet publish` command to produce production-ready code. With the new update, this command will now produce `Release` assets by default, which is exactly what we want for production code. We can see the `Release` assets in the `/app/bin/Release/net8.0` directory.

Finally, let’s say we need to produce `Debug` assets for some reason. We can do that by running the `dotnet publish` command again, but this time we'll set the `PublishRelease` property to `false`. This will produce `Debug` assets instead of `Release` assets, which we can see in the `/app/bin/Debug/net8.0` directory.

And that’s it! With this new feature, it’s now easier than ever to produce production-ready code using the `dotnet publish` and `dotnet pack` commands.

📚**Check:** [dotnet publish and dotnet pack](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#dotnet-publish-and-dotnet-pack)

---

## Improvements in System.Text.Json serialization

`System.Text.Json` is a built-in .NET library that provides JSON serialization and deserialization functionality. It allows developers to convert .NET objects to JSON data and vice versa.

Now, `System.Text.Json` [serialization](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#systemtextjson-serialization) and deserialization functionality has been **improved in various ways for .NET 8**.

Another series of improvements included in this preview are in the source generator when used with ASP.NET Core in Native AOT apps, making it more reliable and faster.

Additionally, the source generator will support in .NET 8 serializing types with `required` and `init properties`, which were already supported in reflection-based serialization.

Moreover, customization of serialization for members that aren’t present in the JSON payload is now possible.

Lastly, properties from interface hierarchies can now be serialized, including those from both the immediately implemented interface and its base interface. Let’s check this example:

```csharp
IDerived value = new DerivedImplement { Base = 0, Derived =1 };
JsonSerializer.Serialize(value); // {"Base":0,"Derived":1}

public interface IBase
{
    public int Base { get; set; }
}
public interface IDerived : IBase
{
    public int Derived { get; set; }
}
public class DerivedImplement : IDerived
{
    public int Base { get; set; }
    public int Derived { get; set; }
}
```

Now, the `JsonNamingPolicy` has been expanded to include naming policies for `snake_case` (with an underscore) and `kebab-case` (with a hyphen) property name conversions. These new policies can be utilized in the same way as the `JsonNamingPolicy.CamelCase` policy.

```csharp
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower };
JsonSerializer.Serialize(new { PropertyName = "value" }, options); // { "property_name" : "value" }}
```

The `JsonSerializerOptions.MakeReadOnly()` method gives you explicit control over when a `JsonSerializerOptions` instance is frozen. You can also check whether it's read-only with the `IsReadOnly` property.

📚**Check:** [System.Text.Json serialization](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#systemtextjson-serialization)

---

## GetItems<T>()

The `GetItems<T>()` [method](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#getitemst) is a new feature in .NET 8 that allows you to randomly select a specific number of items from a given set of elements.

This can be useful in games, simulations, and other applications where randomness is desired. The method is available in both `System.Random` and `System.Security.Cryptography.RandomNumberGenerator`.

In this example, we have an array of `City` objects, and we use the `GetItems<T>()` method to randomly select 3 cities from the array:

```csharp
private static ReadOnlySpan<City> s_allCities = new[] { new City("New York", "USA"), new City("London", "UK"), new City("Paris", "France"), new City("Tokyo", "Japan"), new City("Sydney", "Australia"), };...City[] selectedCities = Random.Shared.GetItems(s_allCities, 3); foreach (City city in selectedCities) { Console.WriteLine(city.Name + ", " + city.Country); } // Output: // Paris, France // Tokyo, Japan // Sydney, Australia
```

We then loop through the selected cities and print their name and country to the console. The output will be different each time we run the program, because the cities are selected randomly.

📚**Check:** [GetItems<T>()](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#getitemst)

---

## Shuffle<T>()

The `Shuffle<T>()` [method](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#shufflet) is another new feature in .NET 8 that allows you to randomize the order of elements in a span.

This is important in machine learning instances when you wish to eliminate training bias by randomizing training data order.

Here’s an example that shows how to use `Shuffle<T>()` with an array of `YourType` objects:

```csharp
YourType[] trainingData = LoadTrainingData(); Random.Shared.Shuffle(trainingData);IDataView sourceData = mlContext.Data.LoadFromEnumerable(trainingData);DataOperationsCatalog.TrainTestData split = mlContext.Data.TrainTestSplit(sourceData); model = chain.Fit(split.TrainSet);IDataView predictions = model.Transform(split.TestSet); // ... 
```

In this example, we load some training data into an array of `YourType` objects and use `Random.Shared` to shuffle the order of the elements.

We then load the shuffled data into an `IDataView` object, split the data into training and test sets, and use the shuffled training data to train a machine learning model. Finally, we use the trained model to make predictions on the test set.

📚**Check:** [Shuffle<T>()](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#shufflet)

---
## Performance Improvements

.NET 8 introduces several [new types that are focused on improving app performance](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#shufflet). These new types are:

-   The `System.Collections.Frozen` namespace includes two collection types, `FrozenDictionary<TKey,TValue>` and `FrozenSet<T>`. These types do not allow any changes to keys and values once a collection is created, which allows for faster read operations such as `TryGetValue()`. They are particularly **useful for collections** that are populated on first use and then persisted for the duration of a long-lived service:

```csharp
private static readonly FrozenDictionary<string, bool> s_configurationData = LoadConfigurationData().ToFrozenDictionary(optimizeForReads: true); // ... if (s_configurationData.TryGetValue(key, out bool setting) && setting) { Process(); }
```

-   The `System.Text.CompositeFormat` type is useful for optimizing format strings that aren't known at compile time. A little extra time is spent up front to do work such as parsing the string, but it saves the work from being done on each use:

```csharp
private static readonly CompositeFormat s_rangeMessage = CompositeFormat.Parse(LoadRangeMessageResource()); // ... static string GetMessage(int min, int max) => string.Format(CultureInfo.InvariantCulture, s_rangeMessage, min, max);
```

The `System.Buffers.IndexOfAnyValues<T>` type is designed to be passed to methods that look for the first occurrence of any value in the passed collection. .NET 8 adds new overloads of methods like `String.IndexOfAny` and `MemoryExtensions.IndexOfAny` that accept an instance of the new type.

📚**Check:** [Performance-focused types](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#performance-focused-types)

---

## Native AOT

.NET 8 brings [improvements to the **native ahead-of-time**](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#shufflet) (AOT) compilation feature that was first introduced in .NET 7. Publishing an application as native AOT generates a self-contained version of the app that doesn’t require a runtime as everything is included in a single file.

In addition to the existing support for various platforms, .NET 8 now includes **support for the x64 and Arm64 architectures on macOS**. This means that developers can now publish their .NET apps as native AOT for macOS systems.

The latest improvements to native AOT apps on Linux systems have resulted in significantly reduced application sizes.

According to recent tests, native AOT apps built with .NET 8 Preview 1 now take up to **50% less space** compared to those built with .NET 7.

You can see in the table below a comparison of the size of a “Hello World” app published with native AOT and including the entire .NET runtime between the two versions:

| Operating System                      | .NET 7  | .NET 8 Preview 1 |
|---------------------------------------|---------|------------------|
| Linux x64 (with -p:StripSymbols=true) | 3.76 MB | 1.84 MB          |
| Windows x64                           | 2.85 MB | 1.77 MB          |

These improvements in native AOT can help .NET developers to create smaller, faster, and more efficient apps that run on a variety of platforms without requiring any external dependencies.

📚**Check:** [Native AOT](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#native-aot)

---
## Code generation

.NET 8 also has some improvements in [**code generation and JIT**](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#code-generation) (Just-In-Time) compilation enhancing performance and efficiency:

-   **Arm64 architecture** performance improvements
-   **SIMD** (Single Instruction Multiple Data) **improvements** for better vectorization and parallelization of operations
-   **Cloud-native improvements** for better performance in containerized environments
-   **Profile-guided optimization** (PGO) **improvements** that enable better optimizations based on application usage patterns
-   **Support for AVX-512 ISA extensions** for more efficient floating-point operations on modern CPUs
-   **JIT** (Just-In-Time) t**hroughput improvements** for faster code generation
-   Loop and general optimizations that improve the performance of frequently used code blocks

These improvements help developers to optimize the performance of their .NET applications and reduce resource utilization in cloud-native environments.

📚**Check:** [Code generation](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#code-generation)

---

## .NET container images

.NET 8 also makes a few changes to the way [.NET container images](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#net-container-images) work. First, Debian 12 (Bookworm) is now the default Linux distribution in the container images.

Additionally, the images include a `non-root` user to make the images `non-root` capable. To run as `non-root`, add the line `USER app` at the end of your Dockerfile or a similar instruction in your Kubernetes manifests.

The **default port has also changed** from `80` to `8080` and a **new environment variable** `ASPNETCORE_HTTP_PORTS` is available to make it **easier to change ports**.

The format for the `ASPNETCORE_HTTP_PORTS` variable is easier compared to the format required by `ASPNETCORE_URLS`, and it accepts a list of ports. If you change the port back to `80` using one of these variables, it won't be possible to run as `non-root`.

To pull the .NET 8 Preview SDK, you can use the following tag which includes the `-preview` suffix in the tag name for preview container images:

```csharp
docker run --rm -it mcr.microsoft.com/dotnet/sdk:8.0-preview
```

The suffix `-preview` will no longer be used for release candidate (RC) releases. In addition, developers can use chiseled Ubuntu images with .NET 8 that offer a smaller attack surface, no package manager or shell, and `non-root` capability. These images are ideal for developers looking for the advantages of appliance-style computing.

📚**Check:** [.NET](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#net-container-images) [c](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#net-container-images)[ontainer images](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#net-container-images)

---

So, are you excited to try out these new features in .NET 8? What do you think will be the most useful addition for your projects? Don’t hesitate to download the preview and explore the possibilities. Happy coding!