Update for .NET 8.
This commit is contained in:
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -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}"
|
||||
}
|
||||
,]
|
||||
}
|
||||
}
|
||||
|
||||
4
.vscode/tasks.json
vendored
4
.vscode/tasks.json
vendored
@@ -7,9 +7,9 @@
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/kestrel.csproj"
|
||||
"${workspaceFolder}/StandaloneKestrel.csproj"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
31
Program.cs
31
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<Context>
|
||||
@@ -58,16 +53,25 @@ class Application : IHttpApplication<Context>
|
||||
await socket.SendAsync(new ArraySegment<byte>(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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
===
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PublishAot>true</PublishAot>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
<ItemGroup>
|
||||
<TrimmerRootDescriptor Include="TrimmerRoots.xml" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
5
TrimmerRoots.xml
Normal file
5
TrimmerRoots.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<linker>
|
||||
<assembly fullname="Microsoft.AspNetCore.Server.Kestrel.Core">
|
||||
<type fullname="Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.KestrelMetrics" preserve="all" />
|
||||
</assembly>
|
||||
</linker>
|
||||
Reference in New Issue
Block a user