KestrelToolbox.CodeGen 2.0.0

There is a newer version of this package available.
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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="KestrelToolbox.CodeGen" Version="2.0.0">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="KestrelToolbox.CodeGen" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="KestrelToolbox.CodeGen">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add KestrelToolbox.CodeGen --version 2.0.0
                    
#r "nuget: KestrelToolbox.CodeGen, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package KestrelToolbox.CodeGen@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=KestrelToolbox.CodeGen&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=KestrelToolbox.CodeGen&version=2.0.0
                    
Install as a Cake Tool

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.

More Info On Web

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
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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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