Skip to content

Releases: stratdev3/SimpleW

Release Candidate

09 Mar 00:48
87696c9

Choose a tag to compare

Release Candidate Pre-release
Pre-release

State of the Rewrite

Here we are, the last step : the Release Candidate.

I spent a few days thinking about the kind of logging system I wanted for SimpleW. I follow the rule n°1 that guides me : simplicity.

The logger is basically a simple emit() with a few methods on top. It supports sinks, and you can bridge your own logger on it. There are even two packages available for the most widely used .NET loggers : serilog and log4net.

There is a new SimpleWSServer.ConfigureClientIPResolver() methods that allow you to configure where the real client IP address comes from. It replaced the one in the Firewall package (so this is a breaking change for the SimpleW.Service.Firewall).

Finally, there are a few minor fixes in the HttpSession and a new Bag feature that allows data to be shared between middlewares.

The documentation is up to date !

feature / comparison

Feature / Aspect SimpleW v16 (old) SimpleW v26 (new)
NET runtime NET8 NET8 but should consider NET9/NET10 for better perfs and RAM usage under heady load (e.g: NET8 400Mo, NET9 100Mo, NET10 70Mo)
Core architecture ⚠️ (tied to NetCoreServer) ✅ from scratch (custom, simple, clean)
Code readability ⚠️
Overall design philosophy ⚠️ wrapper ✅ minimal, custom, fast
Long-term maintainability ⚠️ harder ✅ much easier
Performance ✅ (very high) ✅ (very high)
Middleware
Modules
Extensibility ⚠️ (callback, subclass) ✅ middleware, module, callback, subclass
Response Builder ✅(status, contentType, headers, body, cookies) ✅ (status, contentType, contentLength, headers, body, cookies, compression)
Handler (Expression Tree) ✅ sync ❌async ✅ sync ✅ async + RequestAborted
Routing ✅ (minimal, attribute, querystring, regexp, path, wildcard) ✅ (minimal, attribute, querystring, path, wildcard)
Minimal API
Controllers
SSL / HTTPS ✅ (SslContext) ✅ (SslContext, mutual authentication)
WebSocket ✅ (full broadcast) ✅ (smart broadcast using "rooms")
Server-Sent Events (SSE) ✅ (smart broadcast using "rooms")
Basic Auth
JWT auth
Unix socket
Static files ✅ (Cache, FileWatcher) ✅ (Cache, FileWatcher, Last-Modified, Etag)
Cross-Origin Resource Sharing (CORS)
Body parsing (JSON)
Body parsing (form-urlencoded)
Body parsing (multipart/form-data)
Bag ✅ (share data between middleware)
WebUser / Identity
Custom JSON engine
HTTP pipelining
Idle Timeout
Request Protection ✅(malformed)
Observability ✅ (traces) & global to all processes ✅ (traces, metrics, enrich) per SimpleWServer instance
Logging
Documentation simplew.net
Tests ✅ (more tests)
Support Discord
Addons ✅ Chaos, Firewall, Hosting, Latency, OpenID, Razor, Swagger, LetsEncrypt, Templates, Serilog, Log4net

Consolidating Beta

21 Feb 00:46
ddb220b

Choose a tag to compare

Consolidating Beta Pre-release
Pre-release

State of the Rewrite

I’m consolidating and polishing the entire codebase :

  • No API changes, things are boring stable now.
  • I’m focusing on addon development : three new ones have been added: LetsEncrypt, OpenID, and Templates.
  • I’m hardening the HttpRequestParser against malformed requests and well-known attack patterns.
  • I also want to make migration from ASP.NET Core easier by adding helpers and utilities (for example, a Bag to pass data across middleware).
  • Fixed a few minor bugs in HttpSession.
  • Added new methods and events to the SimpleWServer class.
  • Improved documentation
Feature / Aspect SimpleW v16 (current) SimpleW v26 (in progress)
NET runtime NET8 NET8 but should consider NET9/NET10 for better perfs and RAM usage under heady load (e.g: NET8 400Mo, NET9 100Mo, NET10 70Mo)
Core architecture ⚠️ (tied to NetCoreServer) ✅ from scratch (custom, simple, clean)
Code readability ⚠️
Overall design philosophy ⚠️ wrapper ✅ minimal, custom, fast
Long-term maintainability ⚠️ harder ✅ much easier
Performance ✅ (very high) ✅ (very high)
Middleware
Modules
Extensibility ⚠️ (callback, subclass) ✅ midlleware, module, callback, subclass
Response Builder ✅(status, contentType, headers, body, cookies) ✅ (status, contentType, contentLength, headers, body, cookies, compression)
Handler (Expression Tree) ✅ sync ❌async ✅ sync ✅ async + RequestAborted
Routing ✅ (minimal, attribute, querystring, regexp, path, wildcard) ✅ (minimal, attribute, querystring, path, wildcard)
Minimal API
Controllers
SSL / HTTPS ✅ (SslContext) ✅ (SslContext)
WebSocket ✅(full broadcast) ✅ (smart broadcast using "rooms")
Server-Sent Events (SSE) ✅ (smart broadcast using "rooms")
Basic Auth
JWT auth
Unix socket
Static files ✅ (Cache, FileWatcher) ✅ (Cache, FileWatcher, Last-Modified, Etag)
Cross-Origin Resource Sharing (CORS)
Body parsing (JSON)
Body parsing (form-urlencoded)
Body parsing (multipart/form-data)
WebUser / Identity
Custom JSON engine
HTTP pipelining
Idle Timeout
Request Protection ✅(malformed)
Observability ✅ (traces) & global to all processes ✅ (traces, metrics, enrich) per SimpleWServer instance
Documentation simplew.net
Tests ✅ (more tests)
Support Discord
Add-Ons ✅ Chaos, Firewall, Hosting, Latency, LetsEncrypt, OpenID, Razor, Swagger, Templates

Open Beta

08 Feb 23:54
e23ca86

Choose a tag to compare

Open Beta Pre-release
Pre-release

State of the Rewrite

Here we are : the beta is now available !

In the previous thread, I mentioned Add-ons, there are already a few available :

  • Chaos: provides a chaos engineering module.
  • Firewall: IP allow/block lists, rate limiting, and related telemetry.
  • Hosting: if you like the way ASP.NET is initialized as a service, this one is for you.
  • Latency: artificially delays HTTP responses in a controlled and deterministic way.
  • Razor: if you like the Razor template engine, this one is for you.
  • Swagger: provides Swagger / OpenAPI documentation support for the SimpleW web server.

How do you use them ?
I spent a crazy amount of time in writing the documentation, read it!

Feature / Aspect SimpleW v16 (current) SimpleW v26 (in progress)
NET runtime NET8 NET8 but should consider NET9/NET10 for better perfs and RAM usage under heady load (e.g: NET8 400Mo, NET9 100Mo, NET10 70Mo)
Core architecture ⚠️ (tied to NetCoreServer) ✅ from scratch (custom, simple, clean)
Code readability ⚠️
Overall design philosophy ⚠️ wrapper ✅ minimal, custom, fast
Long-term maintainability ⚠️ harder ✅ much easier
Performance ✅ (very high) ✅ (very high)
Middleware
Modules
Extensibility ⚠️ (callback, subclass) ✅ midlleware, module, callback, subclass
Response Builder ✅(status, contentType, headers, body, cookies) ✅ (status, contentType, contentLength, headers, body, cookies, compression)
Handler (Expression Tree) ✅ sync ❌async ✅ sync ✅ async + RequestAborted
Routing ✅ (minimal, attribute, querystring, regexp, path, wildcard) ✅ (minimal, attribute, querystring, path, wildcard)
Minimal API
Controllers
SSL / HTTPS ✅ (SslContext) ✅ (SslContext)
WebSocket ✅(full broadcast) ✅ (smart broadcast using "rooms")
Server-Sent Events (SSE)
Basic Auth
JWT auth
Unix socket
Static files ✅ (Cache, FileWatcher) ✅ (Cache, FileWatcher, Last-Modified, Etag)
Cross-Origin Resource Sharing (CORS)
Body parsing (JSON)
Body parsing (form-urlencoded)
Body parsing (multipart/form-data)
WebUser / Identity
Custom JSON engine
HTTP pipelining
Idle Timeout
Request Protection ✅(malformed)
Observability ✅ (traces) & global to all processes ✅ (traces, metrics, enrich) per SimpleWServer instance
Documentation simplew.net
Tests ✅ (more tests)
Support Discord
Add-Ons ✅ Chaos, Firewall, Hosting, Latency, Razor, Swagger

Last alpha

24 Jan 01:38
aa28fef

Choose a tag to compare

Last alpha Pre-release
Pre-release

State of the Rewrite

I've fixed a few bugs in the StaticFilesModule (invalid response, cache invalidation) and improved its performance. I also fixed some Map() handler issues related to QueryString url decode and optimized the HttpRequest parsing time in some areas.

The WebSocketModule is finally out and its design is not bad :

  • Jwt can be pass through the connect (a small valid hack with the sec-sub-protocol).
  • broadcasts are using the notion of room to target specific clients which is a far away cleaner approach than using Dictionary<Session, Object>.

All of this has been in production in one of my SaaS products for the past three weeks, Beta is coming soon !!

And because a product is more quickly adopt when there is an ecosystem around, this new v26 will introduce something very cool : AddOns 🤫🙂

Feature / Aspect SimpleW v16 (current) SimpleW v26 (in progress)
NET runtime NET8 NET8 but should consider NET9/NET10 for better perfs and RAM usage under heady load (e.g: NET8 400Mo, NET9 100Mo, NET10 70Mo)
Core architecture ⚠️ (tied to NetCoreServer) ✅ from scratch (custom, simple, clean)
Code readability ⚠️
Overall design philosophy ⚠️ wrapper ✅ minimal, custom, fast
Long-term maintainability ⚠️ harder ✅ much easier
Performance ✅ (very high) ✅ (very high)
Middleware
Modules
Extensibility ⚠️ (callback, subclass) ✅ midlleware, module, callback, subclass
Response Builder ✅(status, contentType, headers, body, cookies) ✅ (status, contentType, contentLength, headers, body, cookies, compression)
Handler (Expression Tree) ✅ sync ❌async ✅ sync ✅ async
Routing ✅ (minimal, attribute, querystring, regexp, path, wildcard) ✅ (minimal, attribute, querystring, path, wildcard)
Minimal API
Controllers
SSL / HTTPS ✅ (SslContext) ✅ (SslContext)
WebSocket ✅(full broadcast) ✅ (smart broadcast using "rooms")
Server-Sent Events (SSE)
Basic Auth
JWT auth
Unix socket
Static files ✅ (Cache, FileWatcher) ✅ (Cache, FileWatcher, Last-Modified, Etag)
Cross-Origin Resource Sharing (CORS)
Body parsing (JSON)
Body parsing (form-urlencoded)
Body parsing (multipart/form-data)
WebUser / Identity
Custom JSON engine
HTTP pipelining
Idle Timeout
Request Protection (malformed)✅
Observability ✅ (traces) ✅ (traces, metrics, enrich)
Documentation simplew.net
Tests ✅ (more tests)
Support Discord

Happy New Year

06 Jan 02:37
424979f

Choose a tag to compare

Happy New Year Pre-release
Pre-release

State of the Rewrite

I haven't changed the API for a week, and given the commit rhythm, it's a good indicator that things are stabilizing.
I'm running one of my oldest services on the alpha, finding bugs, fixing them and loop.
WebSockets, the last feature, are still a work in progress and will require more attention and work 🥵.

The documentation of the next version is up to date and running on the new simplew.net domain 😎 !

Feature / Aspect SimpleW v16 (current) SimpleW v26 (in progress)
NET runtime NET8 NET8 but should consider NET9/NET10 for better perfs and RAM usage under heady load (e.g: NET8 400Mo, NET9 100Mo, NET10 70Mo)
Core architecture ⚠️ (tied to NetCoreServer) ✅ from scratch (custom, simple, clean)
Code readability ⚠️
Overall design philosophy ⚠️ wrapper ✅ minimal, custom, fast
Long-term maintainability ⚠️ harder ✅ much easier
Performance ✅ (very high) ✅ (very high)
Extensibility ⚠️ (callback, subclass) ✅ midlleware, module, callback, subclass
Middleware
Modules
Minimal API
Response Builder ✅(status, contentType, headers, body, cookies) ✅ (status, contentType, headers, body, cookies, compression)
Handler (Expression Tree) ✅ sync ❌async ✅ sync ✅ async
Routing ✅ (minimal, attribute, querystring, regexp, path, wildcard) ✅ (minimal, attribute, querystring, path, wildcard)
Controllers
SSL / HTTPS ✅ (SslContext) ✅ (SslContext)
WebSocket ⚠️ WIP
Server-Sent Events (SSE) ⚠️ WIP
Basic Auth
JWT auth
Unix socket
Static files
Cross-Origin Resource Sharing (CORS)
Body parsing (JSON)
Body parsing (form-urlencoded)
Body parsing (multipart/form-data)
WebUser / Identity
Custom JSON engine
HTTP pipelining
Idle Timeout
Observability ✅ (traces) ✅ (traces, metrics, enrich)
Documentation simplew.net
Support Discord

Winter is coming

21 Dec 21:55
b1d3532

Choose a tag to compare

Winter is coming Pre-release
Pre-release

State of the Rewrite

A lot of progress since last week : the API is stabilizing (SimpleWServer, HttpSession, HttpRequest, HttpResponse, Router), but I still have to find the best approach for modules. There is a full test suite to prevent regressions and the nightly nuget is usable (you need to enable pre-release).

I archived the current version to a v16 folder and the rewrite is now in master.

Feature / Aspect SimpleW v16 (current) SimpleW v26 (in progress)
NET runtime NET8 NET8 but should consider NET9/NET10 for better perfs and RAM usage under heady load (e.g: NET8 400Mo, NET9 100Mo, NET10 70Mo)
Core architecture ⚠️ (tied to NetCoreServer) ✅ from scratch (custom, simple, clean)
Code readability ⚠️
Overall design philosophy ⚠️ wrapper ✅ minimal, custom, fast
Long-term maintainability ⚠️ harder ✅ much easier
Performance ✅ (very high) ✅ (very high)
Extensibility ⚠️ (callback, subclass) ✅ (midlleware, module, callback, subclass)
Middleware
Modules
Minimal API
Response Builder ✅(status, contentType, headers, body, cookies) ✅ (status, contentType, headers, body, cookies, compression)
Handler (Expression Tree) ✅ sync ❌async ✅ sync ✅ async
Routing ✅ (minimal, attribute, querystring, regexp, path, wildcard) ✅ (minimal, attribute, querystring, path, wildcard)
Controllers
SSL / HTTPS ✅ (SslContext) ✅ (SslContext)
WebSocket ⚠️ WIP
Server-Sent Events (SSE) 📅 TODO
JWT auth 📅 TODO
Unix socket
Static files
Cross-Origin Resource Sharing (CORS) ⚠️ WIP
Body parsing (JSON)
Body parsing (form-urlencoded)
Body parsing (multipart/form-data)
WebUser / Identity 📅 TODO
Custom JSON engine
HTTP pipelining
Idle Timeout
Logging 📅 TODO
Observability (logs, traces) 📅 TODO
Documentation ⚠️ WIP

Documentation

There are two documentation flavors (the switch is in the top right corner) :

Teasing

"SimpleW vs Aspnet", coming soon to your theather 🍿🔥

simplew-vs-aspnet

The REWRITE

14 Dec 16:55
6f558db

Choose a tag to compare

State of SimpleW

It has been a while since I started thinking about rewriting SimpleW: the current implementation has reached its limits, and I’m no longer satisfied with its architecture.

Limitations

At the beginning, this project was built around the OnReceivedRequest() method of NetCoreServer. As the project grew, I found myself patching NetCoreServer to fix issues or add entry points, until it became increasingly difficult to make change without breaking something. And I truly appreciate NetCoreServer for what it has provided. That project is AWESOME and I don't want to mess with it.

What I don't like

As mentioned above, SimpleW is heavily tied to NetCoreServer. NetCoreServer was designed to be extended through subclasses and overrides. It’s a well-designed, high-performance, general-purpose network server and it should be used as such.
But for SimpleW’s domain (HTTP), I know I can deliver a better, more suitable API.

Where to go ?

I’m keeping the same core principles :

  1. simple to use and understand, yet easy to hack
  2. performances at their best
  3. minimal footprint
  4. no external dependencies

Now and the Future

State of the Rewrite

I started a full rewrite of the project four weeks ago:

Feature / Aspect SimpleW v16 (current) New Rewrite (in progress)
NET runtime NET8 NET8 but should consider NET9/NET10 for better perfs and RAM usage under heady load (e.g: NET8 400Mo, NET9 100Mo, NET10 70Mo)
Core architecture ⚠️ (tied to NetCoreServer) ✅ from scratch (custom, simple, clean)
Code readability ⚠️
Overall design philosophy ⚠️ wrapper ✅ minimal, custom, fast
Long-term maintainability ⚠️ harder ✅ much easier
Performance ✅ (very high) ✅ (very high)
Extensibility ⚠️ (callback, subclass) ✅ (midlleware, module, callback, subclass)
Middleware
Modules
Minimal API
Response Builder ✅(status, contentType, headers, body, cookies) ✅ (status, contentType, headers, body, cookies)
Handler (Expression Tree) ✅ sync ❌async ✅ sync ✅ async
Routing ✅ (minimal, attribute, querystring, regexp, path, wildcard) ✅ (minimal, attribute, querystring, path, wildcard)
Controllers
SSL / HTTPS ✅ (SslContext) ✅ (SslContext)
WebSocket ⚠️ WIP
Server-Sent Events (SSE) 📅 TODO
JWT auth 📅 TODO
Unix socket
Static files
Cross-Origin Resource Sharing (CORS) ⚠️ WIP
Body parsing (JSON) 📅 TODO
Body parsing (form-urlencoded) 📅 TODO
Body parsing (multipart/form-data) 📅 TODO
WebUser / Identity 📅 TODO
Custom JSON engine 📅 TODO
HTTP pipelining
Idle Timeout
Logging 📅 TODO
Observability (logs, traces) 📅 TODO
Documentation 📅 TODO

I spent nearly two weeks validating the networking architecture, making technical decisions, running benchmarks, and providing feedback.
There’s still a lot to do, but things are now progressing quickly and in the right direction.

Breaking Changes

Some things will break, however the entire Controller feature should remain unchanged !

Schedule

In a few days, I’ll start migrating some of my projects to it. Once these “production tests” 😅 are successful, I’ll publish a beta (two or three weeks) but for now there are also nightly builds.
I will document all the changes, provide a migration guide, and update the documentation and all examples before the production release.

v16.1.0

02 Nov 20:45
37a2a44

Choose a tag to compare

Maintenance, rewritten some parts of the code and documentation for easier use.

breakingChange

  • moved the Controller.MakeAccessResponse() to HttpResponse.MakeAccessResponse() (see example)

feature

  • feature: add headers parameter to HttpResponse.MakeResponse() (#71)
  • feature: add new HttpResponse.MakeResponse(object content) methods (#75)
  • chore: inject Session in Response (#73)
  • feature(test): add unit test for custom headers and compress types (#80)
  • feature: avoid PerformServerUpgrade there is no websocket route defined (#79)
  • refactor: move MakeAccessResponse() into HttpResponse class (#76)

fix

  • fix(NetCoreServer): WebSocket.PerformServerUpgrade() set MakeErrorResponse() when Connection: "keep-alive" (#77)

v16.0.0

20 Oct 22:46
a65f14f

Choose a tag to compare

What's new ?

This major release includes extensive rewrites and significant performance improvements (around +9% req/s)

That has been on the roadmap for a long time, and Newtonsoft.Json is no longer a dependency but it can still be set as the default json engine.

Remember the performances test ?

Node : 9.923.524 req/s
SimpleW: 8.542.876 req/s

Node is untouchable

Not anymore, that gap has narrowed, see performances update
Here's a screenshot of the v16.0.0 responding to bombardier, that's very exiting !

image

Release notes

breakingChange

  • removed the Newtonsoft.Json dependency from the SimpleW nuget package. The default json engine is now System.Text.Json. To switch back, set Newtonsoft as the JsonEngine and install the a new SimpleW.Newtonsoft nuget package to (see example)
  • "X-*" headers are not trusted by default. To allow them, set the TrustXHeaders server property to true (see example).
  • in Controller, all Make*Response() methods have been replaced by Response.Make*Response() (see example)
  • removed Controller.SendResponseAsync()
  • the cache in AddStaticContent() is now disabled by default. Set the timeout parameter to enable caching (see example)

feature

  • feature: add new JsonEngine property in Server and Netcoreserverextension (#49)
  • feature: add new package SimpleW.Newtonsoft to support Newtonsoft.Json as JsonEngine (#50)
  • chore: remove the Newtonsoft.Json dependency from the SimpleW package
  • feature: use JsonEngine for Inline Func return serialization (#58)
  • feature: support Accept-Encoding br (Brotli) on HttpResponse (#51)
  • chore: move all Make*Response from Controller to HttpResponse partial class (#44)
  • feature: support CORS in AddStaticContent() response (#60)
  • feature: AddStaticContent() with no cache (#46)
  • feature: improve overall performances in Router, StaticContent and DynamicContent
  • feature(test): add unit and integration tests.

fix

Documentation

The documentation has been reorganized and updated.

v15.1.0

18 Sep 23:17
e9c6a34

Choose a tag to compare

Maintenance

Feature

  • chore: expose the Server as a property from the Session (#47)
  • feature: support minimal API with new MapGet() and MapPost() methods in server class (#45)

Documentation

Add the new Session.Server property. This enables retrieving the underlying SimpleWServer instance from within a Controller

Example :

using System.Net;
using SimpleW;


namespace example {

    internal class Program {

        static void Main(string[] args) {

            // listen to all IPs port 2015
            var server = new SimpleWServer(IPAddress.Any, 2015);

            server.AddDynamicContent("/api");

            // start non blocking background server
            server.Start();

            Console.WriteLine("server started at http://localhost:2015/");

            // block console for debug
            Console.ReadKey();

        }

    }


    /// <summary>
    /// Test Controller
    /// </summary>
    [Route("/test")]
    public class TestController : Controller {

        [Route("GET", "/hello")]
        public object Hello() {

           // get the current SimpleWServer instance
           var server = Session.Server;

            return new {
                message = $"Hello World !"
            };
        }
    }

}

Add the new MapGet() and MapPost() inline Func. These allow building minimal APIs and work similarly to ASP.NET Core, making them ideal for rapid prototyping.

Example :

using System.Net;
using SimpleW;


namespace example {

    internal class Program {

        static void Main(string[] args) {

            // listen to all IPs port 2015
            var server = new SimpleWServer(IPAddress.Any, 2015);

            // no parameter
            server.MapGet("/api/test", () => {
                return new { message = "Hello World !" };
            });
            // retrieve the underlying Session and Request object
            server.MapGet("/api/test2", (ISimpleWSession Session, HttpRequest Request) => {
                return new { message = "Hello World 2 !" };
            });
            // retrieve the query string parameter "name" and also the Session instance
            server.MapGet("/api/test3", (ISimpleWSession Session, string? name = null) => {
                return new { message = $"Hello World {name} !" };
            });

            // start non blocking background server
            server.Start();

            Console.WriteLine("server started at http://localhost:2015/");

            // block console for debug
            Console.ReadKey();

        }

    }
}

This example shows that the MapGet() Func can take multiple types of parameters :

  • query string parameters
  • special properties like Session and 'Request`, retrieve from the server

There is no required order, just use the correct types - ISimpleWSession for session, HttpRequest for request and any other type for query string parameters - and they will be mapped automatically inside your Func.