
Our Favorite New Features in .NET 10 and C# 14
See our favorite new C#, ASP.NET, and EF Core features in .NET's latest LTS release
Every fall .NET developers get to experience an early Christmas as the latest versions of C# and .NET leave preview and enter the wild as fully supported long-term support (LTS) or standard-term support (STS) releases.
This fall is an LTS release which should see many organizations switch to it over the coming year as their preferred .NET version.
While there are many helpful articles covering the entire suite of features and improvements being released, this article aims to direct your attention to some of the ones our team is most excited about including:
- New C# Language Features around extension methods and field syntax
- Improvements to minimal APIs and OpenAPI documentation in ASP.NET Core 10
- New features and improvements for Entity Framework Core
- A brand new model for supporting non-LTS releases
Let's dive into some of the highlights.
C# 14 Language Conveniences
While C# 14 has a number of changes, including increased support for Span
and ReadOnlySpan
, a new null-conditional assignment statement (mayBeNull?.Name = "This is only set if mayBeNull is not null"
), partial constructors, and a few other conveniences, I want to highlight a few changes around property support.
The field keyword
C# has had auto-properties since the early days. Auto properties automatically generate backing fields, resulting in more fluent and focused syntax for developer productivity. Properties and auto-properties have continued to evolve and improve over the years, but there are still some cases where you might want to explicitly declare a property.
For example, the following code used to require a manually declared field for validation:
1private string _firstName;
2public string FirstName
3{
4 get => _firstName;
5 set => _firstName = value ?? throw new InvalidOperationException("First name is required");
6}
With the new field
keyword we can remove the explicit field entirely and use field
to refer to the field that .NET generates for us:
1public string FirstName
2{
3 get => field;
4 set => field = value ?? throw new InvalidOperationException("First name is required");
5}
This is a minimal change, but I do like it as it reduces the amount of non-logic code in a file, which helps keep code focused towards behavior, not structure and ceremony.
Extension properties and alternative extension method syntax
Ever since the advent of LINQ we've been able to author extension methods that act like they're new methods bolted on to existing classes, through syntax like this:
1public static class StringExtensions
2{
3 public static string DoOurCustomTransform(this string input)
4 {
5 return input.ToUpperInvariant().Trim();
6 }
7}
This then let you invoke the method in scenarios like this:
1string prompt = Console.ReadLine();
2string cleaned = prompt.DoOurCustomTransform();
You can still do this in C# 14, but we now have alternative syntax for it using the extension
keyword:
1public static class StringExtensions
2{
3 extension(string input)
4 {
5 public string DoOurCustomTransform()
6 {
7 return input.ToUpperInvariant().Trim();
8 }
9 }
10}
Note how the parameter is moved from the method to the extension
block and you drop the static
keyword.
As a former educator, I do think that this syntax is going to be a little more intuitive for new learners, but the biggest thing this syntax gets you is a way of declaring extension members:
1public static class StringExtensions
2{
3 extension(string input)
4 {
5 public string DoOurCustomTransform()
6 {
7 return input.ToUpperInvariant().Trim();
8 }
9
10 public string CleanedString => input.DoOurCustomTransform();
11 }
12}
This block adds a CleanedString
property that uses our existing transform. This makes it possible to write code that calls this property getter on any string using the following syntax:
1string userInput = Console.ReadLine();
2string cleaned = userInput.CleanedString;
This is nice and minimal and helps expand the ways you can introduce new APIs to existing code and distribute your code across different files, should it make sense to organize your code this way.
I expect there will be fewer places where I'll want to use extension properties vs extension methods, but I'm happy to have the option. I also find the new optional syntax to be nicer for new learners and convenient for grouping together related extension methods and properties, so I will likely begin shifting my code to the new syntax when writing new code.
Read the full release notes for C# 14
Minimal API Improvements
Looking over the full release notes for ASP.NET Core 10, there's a lot in there around various aspects of ASP.NET including Blazor, authentication, SignalR, and other areas. However the parts I gravitated to the most were around API management with Minimal APIs and OpenAPI.
When Minimal APIs came about they gave us a nice concise way of defining simple endpoints in regular C# code without needing the ceremony of Controller
classes. These endpoints have been great for simple demonstrations and microservices that don't need to provide a wide variety of different endpoints, but they also lacked some of the full features found in traditional controllers.
In ASP.NET Core 10 we get a number of improvements to Minimal API endpoints including:
- Better handling of empty strings in request bodies
- Support for validation attributes and
IValidatableObject
- Exposing problem details with
IProblemDetailsService
- Server-Sent Event (SSE) support
We also see new improvements with the option of supporting OpenAPI 3.1 and a significant amount of new ways of providing API documentation through minimal API endpoints including:
- More accurate type documentation using OpenAPI 3.1
Description
property forProducesResponseType
annotations- XML Doc support for minimal APIs referencing a named method for handling them
IOpenApiDocumentProvider
dependency injection support for more advanced scenarios- Misc. other documentation improvements around
AsParameters
, JSON Patch scenarios, and more
While none of these improvements stands out on its own, together they tell the story of more professional results using Minimal APIs in production scenarios and better OpenAPI documentation support.
Entity Framework Core 10 Features
There's a lot of new things in EF Core 10, as you can glean from the full release highlights, but there are a few key things that stuck out to me around embeddings, joins, and complex types that expand EF's features to handle more professional use cases.
First of all, EF adds support for Azure SQL and SQL Server embeddings through the SqlVector<float>
column declaration. This allows you to use an embedding generator to calculate text embeddings for an item and store it in that column. Later, you can use the EF.Functions.VectorDistance
convenience function to calculate the distance between the stored embeddings and a search query. This vector support is increasingly more relevant in an AI-powered world where embeddings are critically important for powering retrieval augmentation generation (RAG) capabilities such as those you'd see in a RAG chat application.
Secondly, EF now supports columns with complex properties from JSON data. This allows you to use strongly-typed C# class definitions to represent data that is stored as JSON in your database rows and not need to worry about the complexities of serialization and deserialization. Although I try to avoid JSON data in databases, there are times when you can't avoid it or it makes sense for a specific scenario. In these cases complex properties from JSON data look fantastic to work with.
EF also has a number of interesting other features, such as named query filters you can define and optionally exclude. This helps reduce repetition in your code if you frequently repeat the same checks (such as filtering out deleted records).
I'm also very happy to see query optimization improvements around SQL that increases the odds of hitting a cached query plan when using IN
clauses as this is something I often rely on. Finally, I'm very excited to see the addition of a code analyzer that can flag cases where raw SQL is being executed in such a way where SQL injection attacks are possible as SQL injection attacks remain a common vulnerability for teams, even in late 2025.
Changes to Standard-Term Support (STS)
One of the most impactful changes of this year's LTS release isn't actually with the LTS release, but a change in how long STS releases will be supported.
.NET does LTS releases every other year with STS releases on the off cycle years. This allows .NET to continue to ship new features and improvements but gives organizations stability and longer-term support when they can't upgrade frequently.
However, these STS releases were primarily used in non-production scenarios with their full features getting adopted by organizations as part of the next LTS release. This is because the STS releases expired before the previous LTS release. This means that organizations upgrading from an LTS to the next STS release would see the date of end of support for their application move forward in time when moving to STS releases. As a result, most organizations stayed on LTS releases and would only use STS releases if there was something critical for them to have.
With the new change, STS releases are now supported for 24 months instead of 18, meaning there is effectively no penalty for an organization of moving to an STS release if they wanted to - or starting new projects using that STS release instead of their preferred LTS release.
This change should hopefully make it easier for organizations to adopt STS releases and make sure future STS releases are as exciting as LTS releases.
Final thoughts
I've really only scratched the surface of what's coming with C# 14 and .NET 10, but I hope you're getting a common theme from this: we're not looking at a few major headline features, but a platform that continues to remain relevant and improve each year with new additions for convenience, support for industry trends, performance improvements, and progressive refinement of what's already there.
I'm excited to be working with these tools both in my hobby projects and with my clients and I'm excited to see .NET continuing to innovate and evolve.