From 3a70349e9858fe5ab345b782bd4230835aadb0ee Mon Sep 17 00:00:00 2001 From: Pete Chown Date: Sun, 23 Jun 2024 20:15:04 +0100 Subject: [PATCH] Update for .NET 8. --- .vscode/launch.json | 4 ++-- .vscode/tasks.json | 4 ++-- Program.cs | 31 ++++++++++++++++++++----------- README.md | 8 +++++--- StandaloneKestrel.csproj | 7 +++++-- TrimmerRoots.xml | 5 +++++ 6 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 TrimmerRoots.xml diff --git a/.vscode/launch.json b/.vscode/launch.json index 4a83d94..02088ff 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/bin/Debug/netcoreapp2.1/kestrel.dll", + "program": "${workspaceFolder}/bin/Debug/net8.0/StandaloneKestrel.dll", "args": [], "cwd": "${workspaceFolder}", // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window @@ -25,4 +25,4 @@ "processId": "${command:pickProcess}" } ,] -} \ No newline at end of file +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 845855c..622678f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,9 +7,9 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/kestrel.csproj" + "${workspaceFolder}/StandaloneKestrel.csproj" ], "problemMatcher": "$msCompile" } ] -} \ No newline at end of file +} diff --git a/Program.cs b/Program.cs index 0e44b24..322528b 100644 --- a/Program.cs +++ b/Program.cs @@ -1,4 +1,5 @@ -using System.Net.WebSockets; +using System.Diagnostics.Metrics; +using System.Net.WebSockets; using System.Security.Cryptography.X509Certificates; using System.Text; using Microsoft.AspNetCore.Hosting.Server; @@ -9,18 +10,12 @@ using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets; using Microsoft.AspNetCore.WebSockets; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; -using Microsoft.Extensions.Primitives; namespace Kestrel; -class Context +class Context(IFeatureCollection features) { - public IFeatureCollection features; - - public Context(IFeatureCollection features) - { - this.features = features; - } + public IFeatureCollection features = features; } class Application : IHttpApplication @@ -58,16 +53,25 @@ class Application : IHttpApplication await socket.SendAsync(new ArraySegment(message), WebSocketMessageType.Text, true, CancellationToken.None); - await socket.ReceiveAsync(new byte[4096], CancellationToken.None); + message = new byte[4096]; + var received = await socket.ReceiveAsync(message, CancellationToken.None); + if (received.MessageType == WebSocketMessageType.Text) + Console.WriteLine($"Received: {Encoding.ASCII.GetString(message, 0, received.Count)}"); } else { - httpContext.Response.Headers.Add("Content-Type", new StringValues("text/plain")); + httpContext.Response.Headers.ContentType = "text/plain"; await httpContext.Response.Body.WriteAsync(Encoding.ASCII.GetBytes("hello world\n")); } } } +class MeterFactory : IMeterFactory +{ + public Meter Create(MeterOptions options) => new(options); + public void Dispose() { } +} + class AppServices : IServiceProvider { public object? GetService(Type serviceType) @@ -75,6 +79,11 @@ class AppServices : IServiceProvider if (serviceType == typeof(ILoggerFactory)) return new NullLoggerFactory(); + if (serviceType.FullName == "Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.KestrelMetrics") +#pragma warning disable IL2067 + return Activator.CreateInstance(serviceType, new MeterFactory()); +#pragma warning restore IL2067 + return null; } } diff --git a/README.md b/README.md index 6f42943..0076c3e 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,12 @@ dotnet publish -c Release time ./time-startup ``` -.NET 7 +.NET 8 ====== -I've been maintaining this package on and off since .NET Core 2.1. For most of this time, it has just been an interesting hack, but now it has a potential real-world use. .NET 7 supports [AOT compilation to a single executable](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/), but this is only for simple console applications, not for ASP.NET. Standalone Kestrel, though, works in this mode. You can build it like this: +On .NET 7, the techniques used here were the only way to use Kestrel with native AOT compilation. With .NET 8, the [minimal APIs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/overview?view=aspnetcore-8.0) are supported with native AOT. For most projects, this will be a better option. If you still want to use Kestrel directly, this project may be useful. + +As with .NET 7, you can build an AOT version if that is useful: ``` dotnet publish -r linux-x64 -c Release @@ -23,7 +25,7 @@ dotnet publish -r linux-x64 -c Release (This has only been tested on Linux. If you are not on Linux, you could try building an executable, but you will need to substitute a different runtime identifier in the above command.) -You will see a few warnings during compilation, but as far as I can tell, the resulting executable works well. The executable is about 46M with debug information, 15M stripped. After the process has been invoked (using both HTTP GET and websockets) the resident memory is about 22M, far better than even the simplest ASP.NET application, and similar to Go. +Unfortunately, with .NET 8, `UseHttps` has a dependency on the `KestrelMetrics` class, which is internal. Instances of this class are created by reflection, and there is a `TrimmerRootDescriptor` in the `.csproj` file to ensure that all the necessary code is included in the final executable. This is unsatisfactory because it depends on the internal design of Kestrel. Also, the `dotnet publish` step displays trim warnings for this class even though they are supposed to be turned off; presumably this is a bug in the .NET SDK. If you have a better solution for any of this, please let me know! TLS === diff --git a/StandaloneKestrel.csproj b/StandaloneKestrel.csproj index 7fc3378..c7007e5 100644 --- a/StandaloneKestrel.csproj +++ b/StandaloneKestrel.csproj @@ -1,10 +1,13 @@ - net7.0 + net8.0 enable enable true - \ No newline at end of file + + + + diff --git a/TrimmerRoots.xml b/TrimmerRoots.xml new file mode 100644 index 0000000..f57344d --- /dev/null +++ b/TrimmerRoots.xml @@ -0,0 +1,5 @@ + + + + +