20: The Magnificent 7!
17 Jun 2022We've been hearing that goods things are coming our way in .NET 7 so we thought we spend some time talking about what's coming in ASP.NET Core, C#11 and the Core APIs based on Preview 4.
Random fact
The mathematical symbol for division (÷) is called an obelus. (https://en.wikipedia.org/wiki/Obelus)
An obelus (plural: obeluses or obeli) is a term in typography that refers to a historical mark which has resolved to three modern meanings:
- Division sign ÷
- Dagger † - footnote
- Commercial minus sign ⁒ (limited geographical area of use)
The dagger symbol originated from a variant of the obelus, originally depicted by a plain line − or a line with one or two dots ÷. It represented an iron roasting spit, a dart, or the sharp end of a javelin symbolizing the skewering or cutting out of dubious matter.
Introduction
What’s new in .NET 7!!
.NET 7 preview 4 was released on 10/05/22 and we wanted to take a look at what is coming in C#11 and ASP.NET Core and Core Apis (.Net 7).
ASP.NET Core updates in .NET 7
Here’s a summary of what’s new in this preview release:
HTTP/2 performance improvements
.NET 7 Preview 4 introduces a significant re-architecture of how Kestrel processes HTTP/2 requests. ASP.NET Core apps with busy HTTP/2 connections will experience reduced CPU usage and higher throughput.
HTTP/2 allows up to 100 requests to run on a TCP connection in parallel. This is called multiplexing. It’s a powerful feature but makes HTTP/2 complex to implement. Before Preview 4, HTTP/2 multiplexing in Kestrel relied on C#’s
lock
keyword to control which request could write to the TCP connection. Whilelock
is a simple solution to writing safe multi-threading code, it’s inefficient under high thread contention. Threads fighting over the lock waste CPU resources that could be used for other work.Kestrel profiling and benchmarking showed:
- High thread contention when a connection is busy.
- CPU cycles are wasted by requests fighting over the write lock.
- Idle CPU cores as requests wait for the write lock.
- Kestrel HTTP/2 benchmarks are lower than other servers in busy connection scenarios.
The solution is to rewrite how HTTP/2 requests in Kestrel access the TCP connection. A thread-safe queue replaces the write lock. Instead of fighting over who gets to use the write lock, requests now queue up in an orderly line, and a dedicated consumer processes them. Previously wasted CPU resources are available to the rest of the app.
These improvements are visible in gRPC, a popular RPC framework that uses HTTP/2. Kestrel + gRPC benchmarks show a dramatic improvement:
Typed results for minimal APIs
- In .NET 6 we introduced the
IResult
interface to ASP.NET Core to represent values returned from minimal APIs that don’t utilize the implicit support for JSON serializing the returned object to the HTTP response. The staticResults
class is used to create varyingIResult
objects that represent different types of responses, from simply setting the response status code, to redirecting to another URL.
- In .NET 6 we introduced the
OpenAPI improvements for minimal APIs
- The OpenAPI specification provides a language-agnostic standard for describing RESTful APIs. In .NET 7 Preview 4, we’re introducing support for the new
Microsoft.AspNetCore.OpenApi
package to provide APIs for interacting with the OpenAPI specification in minimal APIs. Package references to the new package are included automatically in minimal API-enabled application that are created from a template with--enable-openapi
. In other cases, the dependency can be added as a package reference.
The package exposes a
WithOpenApi
extension method that generates anOpenApiOperation
derived from a given endpoint’s route handler and metadata.app.MapGet("/todos/{id}", (int id) => ...) .WithOpenApi();
The
WithOpenApi
extension method above generates anOpenApiOperation
associated with aGET
request to the/todos/{id}
endpoint. A secondWithOpenApi
extension method overload can be used to extend and override the generated operation.app.MapGet("/todos/{id}", (int id) => ...) .WithOpenApi(operation => { operation.Summary = "Retrieve a Todo given its ID"; operation.Parameters[0].AllowEmptyValue = false; return operation; });
- The OpenAPI specification provides a language-agnostic standard for describing RESTful APIs. In .NET 7 Preview 4, we’re introducing support for the new
Return multiple results types from minimal APIs
- The new
Results<TResult1, TResult2, TResultN>
generic union types, along with theTypesResults
class, can be used to declare that a route handler returns multipleIResult
-implementing concrete types, and any of those types implementingIEndpointMetadataProvider
will contribute to the endpoint’s metadata, enabling the framework to automatically describe the various HTTP results for an API in OpenAPI/Swagger:
// Declare that the lambda returns multiple IResult types app.MapGet("/todos/{id}", async Results<Ok<Todo>, NotFound> (int id, TodoDb db) { return await db.Todos.FindAsync(id) is Todo todo ? TypedResults.Ok(todo) : TypedResults.NotFound(); });
- The new
Route groups
- .NET 7 Preview 4 introduces the
MapGroup()
extension method, which helps organize groups of endpoints with a common prefix. It allows for customizing entire groups of endpoints with a singe call to methods likeRequireAuthorization()
andWithMetadata()
.
// ... // Was: app.MapTodosApi() app.MapGroup("/public/todos").MapTodosApi(); // Auth configuration is left as an exercise for the reader. More to come in future previews. app.MapGroup("/private/todos").MapTodosApi().RequireAuthorization();
- .NET 7 Preview 4 introduces the
Client results in SignalR
- Previously, when using SignalR, the server could invoke a method on a client but didn’t have the ability to wait for a response. This scenario is now supported with .NET 7 Preview 4. The server uses
ISingleClientProxy.InvokeAsync()
to invoke a client method, and the client returns a result from its.On()
handler.
- Previously, when using SignalR, the server could invoke a method on a client but didn’t have the ability to wait for a response. This scenario is now supported with .NET 7 Preview 4. The server uses
gRPC JSON transcoding
- The first preview of gRPC JSON transcoding is now available with .NET 7 Preview 4. gRPC JSON transcoding allows gRPC services to be called as RESTful APIs. This enables apps to support gRPC and REST without duplication.
- One limitation with gRPC is not every platform can use it. Browsers don't fully support HTTP/2, making REST APIs and JSON the primary way to get data into browser apps. Even with the benefits that gRPC brings, REST APIs and JSON have an important place in modern apps. Building gRPC and JSON Web APIs adds unwanted overhead to app development. (https://docs.microsoft.com/en-gb/aspnet/core/grpc/httpapi)
syntax = "proto3"; import "google/api/annotations.proto"; package greet; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) { option (google.api.http) = { get: "/v1/greeter/{name}" }; } } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
Allows the
SayHello
gRPC method to be invoked as gRPC and as a JSON Web ApiProject template option to use
Program.Main
method instead of top-level statementsIn .NET 6, we updated the ASP.NET Core project templates to use modern C# features from C# 8 through to C# 10. One of these features was top-level statements, a feature from C# 9, which removes the need to explicitly define an application entry-point, typically in the form of a
Main
method declared on aProgram
class (Program.Main
).While many people appreciate the reduced boilerplate code this feature results in, others expressed frustration that this change was made in the project templates without an option to continue using the traditional
Program.Main
structure instead.In this preview, we’ve added a template option that allows the creation of new projects without using top-level statements. If using the .NET CLI, you can specify the
--use-program-main
option like so:> dotnet new web --use-program-main
If creating projects with Visual Studio, you can select the new “Do not use top-level statements” checkbox during project creation:
Rate limiting middleware
- The new rate limiting middleware in .NET 7 Preview 4 provides a convenient way to limit the rate of incoming HTTP requests.
- The following example applies a
ConcurrencyLimiter
globally with a maximum of 1 concurrent lease:
var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.UseRateLimiter(new RateLimiterOptions { Limiter = PartitionedRateLimiter.Create<HttpContext, string>(resource => { return RateLimitPartition.CreateConcurrencyLimiter("MyLimiter", _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); }) }); app.Run();
The
string
passed as the first argument toCreateConcurrencyLimiter
is a key used to distinguish different component limiters in thePartitionedRateLimiter
.
What's new in C# 11
The following features are available in Visual Studio 2022 version 17.3:
-
- Type parameter names and parameter names are now in scope when used in a
nameof
expression in an attribute declaration on that method. This feature means you can use thenameof
operator to specify the name of a method parameter in an attribute on the method or parameter declaration. This feature is most often useful to add attributes for nullable analysis.
- Type parameter names and parameter names are now in scope when used in a
-
- These are a new format for string literals. Raw string literals can contain arbitrary text, including whitespace, new lines, embedded quotes, and other special characters without requiring escape sequences. A raw string literal starts with at least three double-quote (""") characters. It ends with the same number of double-quote characters. Typically, a raw string literal uses three double quotes on a single line to start the string, and three double quotes on a separate line to end the string. The newlines following the opening quote and preceding the closing quote aren't included in the final content:
string longMessage = """ This is a long message. It has several lines. Some are indented more than others. Some should start at the first column. Some have "quoted text" in them. """;
Any whitespace to the left of the closing double quotes will be removed from the string literal. Raw string literals can be combined with string interpolation to include braces in the output text. Multiple
$
characters denote how many consecutive braces start and end the interpolation:var location = $$""" You are at {{{Longitude}}, {{Latitude}}} """;
The preceding example specifies that two braces start and end an interpolation. The third repeated opening and closing brace are included in the output string.
Newlines in string interpolation expressions.
- The text inside the
{
and}
characters for a string interpolation can now span multiple lines. The text between the{
and}
markers is parsed as C#. Any legal C#, including newlines, is allowed. This feature makes it easier to read string interpolations that use longer C# expressions, like pattern matchingswitch
expressions, or LINQ queries.
- The text inside the
-
- List patterns extend pattern matching to match sequences of elements in a list or an array. For example,
sequence is [1, 2, 3]
istrue
when thesequence
is an array or a list of three integers (1, 2, and 3). You can match elements using any pattern, including constant, type, property and relational patterns. The discard pattern (_
) matches any single element, and the new range pattern (..
) matches any sequence of zero or more elements.
- List patterns extend pattern matching to match sequences of elements in a list or an array. For example,
More information can be found via these links https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-7-preview-4/ and https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11
.NET 7 stuff
- Performance improvements, particularly around startup
- Http 3 support
- Added new TAR APIs (
System.Formats.Tar
) that allow reading, writing, archiving, and extracting of Tar archives.
Nullability annotations added to all Microsoft.Extensions
libs
Nullability annotations completed across the Microsoft.Extensions.*
libraries:
Background:
- C# 8 introduced nullability checks features to minimize the likelihood that your code causes the runtime to throw
NullReferenceException
. There are 3 features:- Improved static flow analysis to determine if a variable may be null before dereferencing it
- Variable annotations that devs use to declare the intended null-states for variables
- Attributes to annotate APIs so that flow analysis can determine null-state
.Net 7 has completed adding [MemberNotNull(nameof(Property))]
attributes to all Microsoft.Extensions.*
libraries. Why?
- Adds resilience to the libs
- Validates the Nullability feature itself
- Find null-related bugs in the runtime
Adding Microseconds and Nanoseconds to TimeStamp, DateTime, DateTimeOffset, and TimeOnly
- Prior to Preview 4, the lowest increment of time available in the various date and time structures was the “tick” available in the Ticks property.
- In .NET, a single tick is 100ns. Developers traditionally have had to perform computations on the “tick” value to determine microsecond and nanosecond values.
- Preview 4 addresses that by introducing both microseconds and milliseconds to the date and time implementations
More improvements and new APIs for System.Text.RegularExpressions
For preview 4 we are adding the remaining planned APIs in order to add span support into our Regex library. The changes span several issues:
- Augment Regex extensibility point for better perf and span-based matching
- [API Proposal]: Add Regex.Enumerate(ReadOnlySpan) which is allocation free
- Overhaul Regex’s handling of RegexOptions.IgnoreCase
OS project/utility of the week
Agent ransack (https://www.mythicsoft.com/agentransack/)
Finding files that other search engines miss
Agent Ransack is a free file search tool for finding files on your PC or network drives. It has a Lite mode, which is FREE for both personal and commercial use but also a Professional mode that includes optional pay-for features.
First released in April 2000 the Agent Ransack desktop search app has been helping people find files for over 20 years.