KestrelToolbox.CodeGen
2.0.0
See the version list below for details.
dotnet add package KestrelToolbox.CodeGen --version 2.0.0
NuGet\Install-Package KestrelToolbox.CodeGen -Version 2.0.0
<PackageReference Include="KestrelToolbox.CodeGen" Version="2.0.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="KestrelToolbox.CodeGen" Version="2.0.0" />
<PackageReference Include="KestrelToolbox.CodeGen"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add KestrelToolbox.CodeGen --version 2.0.0
#r "nuget: KestrelToolbox.CodeGen, 2.0.0"
#:package KestrelToolbox.CodeGen@2.0.0
#addin nuget:?package=KestrelToolbox.CodeGen&version=2.0.0
#tool nuget:?package=KestrelToolbox.CodeGen&version=2.0.0
Kestrel Toolbox
Kestrel Toolbox is a collection of tools and utilities for building web services using Kestrel.
Installation
You can install this package using Nuget/KestrelToolbox
dotnet add package KestrelToolbox
Web Host
The core of this package is helping to spin up an IWebHost that will serve requests. These requests lean heavily on Routes attribute for how to service requests. These are similar to Controllers with some differences.
Some additional features:
- Routes can exist on static or instance classes.
- Bodies that are json can be automatically parsed. 400 and 415 can be returned on invalid data or content type.
- Query parameters can be parsed and return 400 when they are invalid.
public static class Routes
{
[JsonSerializable]
public class GetStorageBody
{
[Name("value")]
public string Value { get; set; }
}
// Parse the body as json. Return 400 on invalid body and return 412 when the request body type is not application/json.
[Route("/api/v1/storage/{id:guid}", methods: "POST")]
public static async Task GetStorage(HttpContext context, Guid id, [JsonBody] body)
{
// Do stuff here.
}
}
public static void Main()
{
var configuration = new WebHostBuilderConfiguration { HttpPort = PortNumber };
// Can either use the WebHostBuilderConfiguration or do it manually using the extension method
// IApplicationBuilder.UseRouteInfo(Routes.GetRoutes()).
configuration.AddRoutes(Routes.GetRoutes());
using var server = configuration.CreateWebHost();
await server.RunAsync();
}
Parsing and Serializing
Kestrel Toolbox has several parsing/serializing tools to make it easy to verify data with minimal code before parsing even completes. All of these features can be generated AOT using Roslyn or at runtime using IL code generation.
Supported Types
- Query Parameters - parsing (serialization planned)
- Json - parsing and serialization
- Command Line - parsing
- Enums - parsing and serialization
public enum HttpMethod
{
// Only the first argument to Name will be serialized. Others will be deserialized.
[Name("GET", "get")]
Get,
[Name("PUT", "put")]
Put,
[Name("DELETE", "delete")]
Delete,
}
[CommandLineSerializable]
public partial class CommandLineArgs
{
[Name("-X", "--request")]
[DefaultValue(HttpMethod.Get)]
public HttpMethod HttpMethod { get; set; }
// EmptyArgumentValue means that `--raw` with no trailing argument will become true.
[Name("--raw")]
[EmptyArgumentValue(true)]
public bool Raw { get; set; }
}
public static int Main(string[] args)
{
if (!CommandLineArgs.TryParse(args, out var commandLineArgs, out var errors)
{
Console.Error.WriteLine(errors);
return 1;
}
}
Typedef
Filling out a feature that is missing from other mainstream languages, never again will you accidentally use a type when it shouldn't be.
An example of this would be making sure username and password are never intermingled. This is especially useful for string based types.
[Typedef(typeof(string))]
public partial class Username { }
[Typedef(typeof(string))]
public partial class Password { }
// Will throw if username or password are not the correct type.
public static Task Login(Username username, Password password)
{
await postgres.ExecuteQuery("SELECT * FROM users WHERE username=?", (string)username);
// ...rest of login.
}
[JsonSerializable]
public partial class PerformLoginRequest
{
[Name("username")]
public required Username Username { get; set; }
[Name("password")]
public required Password Password { get; set; }
}
public static async Task PerformLogin(HttpContext context, [JsonBody] PerformLoginRequest body)
{
// Will be a compile error because order of arguments is incorrect.
await Login(body.Password, body.Username);
}
Miscellaneous
There are a bunch of other odds and ends to help out with operating a web service.
UUIDv1
Standard UUIDv1 to compliment Guid (which is UUIDv4).
Miscellaneous
Every web server has a few things that seem to be missing from base library that can help a lot.
Array Pool Rental
Stop having to remember to rent and return from ArrayPool. This class adds the ability to use using statements.
using (var rental = new ArrayPoolRental(1024))
{
stream.Read(rental.Array);
}
IPAddressRange
CIDR addresses are pretty commonly used in web services. This class helps to alleviate building it yourself.
public bool ShouldBlock(IPAddress address)
{
var firewalledRange = IPAddressRange.Parse("192.168.0.0/16");
return firewalledRange.Contains(address);
}
MemoryPoolStream
Similar to MemoryStream except that it allocates memory out of MemoryPool. It does not currently auto expand though.
using var stream = new MemoryPoolStream(4096);
using (var fileStream = File.OpenRead(path))
{
fileStream.CopyTo(stream);
}
MutexSlim
No more having to using SemaphoreSlim and simulating a mutex. This super lightweight mutex depends on an atomic int and will
spin before using a full lock to wait.
MutexSlim mutex;
using (await mutex.LockAsync())
{
// Do stuff under mutex.
}
// Or you can protect a value with it.
MutexSlim<int> mutex;
using (var locker = mutex.LockAsync())
{
var value = locker.Value;
locker.Value = value + 2;
}
ProcessExtended
Setting up a process can be difficult if you want to read the output or interact. This sets everything up and makes sure to wait appropriately. It also allows for async/await pattern while waiting for a process.
var process = new ProcessExtended("cat", new string[] { path1, path2 })
{
WorkingDirectory = localDirectory,
};
var output = new StringBuilder();
process.OnData += e => output.AppendLine(e);
var exitCode = await process.RunAsync();
if (exitCode != 0)
{
throw new Exception(output.ToString());
}
Extensions
There is also a series of extension methods to help out with common web server functionality.
ReadOnlySequence Extensions
- Reader
- Stream
Utilities
PEM
Parsing certificates from openssl into x509 is no longer a chore or requires the entire Bouncy Castle library. This utility will parse these files with minimal amounts of extra code on top of built-in dotnet.
ReadPrivateKey
// Read an RSA private key.
using RSA rsa = PEM.ReadPrivateKey(keyText));
// Generate a self signed certificate for testing.
X509Certificate2 cert = PEM.CreateSelfSignedServerCertificate("Example Company", "example.com", TimeSpan.FromDays(365));
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.CodeAnalysis.Common (>= 4.11.0)
- Microsoft.CodeAnalysis.CSharp (>= 4.11.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.4 | 17,606 | 7/23/2025 |
| 2.0.3 | 6,887 | 3/7/2025 |
| 2.0.2 | 259 | 3/6/2025 |
| 2.0.1 | 255 | 3/5/2025 |
| 2.0.0 | 1,860 | 2/15/2025 |
| 2.0.0-alpha5 | 137 | 11/26/2024 |
| 2.0.0-alpha4 | 5,786 | 11/5/2024 |
| 2.0.0-alpha3 | 196 | 10/17/2024 |
| 2.0.0-alpha2 | 139 | 8/11/2024 |
| 2.0.0-alpha1 | 124 | 8/3/2024 |