Custom Frameworks

Runs on your machine

Builds a framework of your own on top of the reflection layer.

Shows the layer that webservices, controllers and functional handlers are built on, to write a framework of your own - for example one that offers scripts or database queries as endpoints. The handler describes an operation - a path, its HTTP methods and the C# method to call - and GenHTTP reads the arguments, calls the method and writes the result.

As the operation is one like any other, the Open API definition and Scalar describe it as well. The reflection layer counts as internal, so it may change in a minor version.

Runs on your machine only. It inspects its own methods via reflection, which this website does not allow.

To run it, create a console app (dotnet new console), add GenHTTP (dotnet add package GenHTTP.Full), replace Program.cs with the code below and start it with dotnet run - it answers at http://localhost:8080/.

Program.cs67 lines
using GenHTTP.Engine.Internal;

using GenHTTP.Api.Content;
using GenHTTP.Api.Infrastructure;
using GenHTTP.Api.Protocol;

using GenHTTP.Modules.ApiBrowsing;
using GenHTTP.Modules.Conversion;
using GenHTTP.Modules.Functional.Provider;
using GenHTTP.Modules.Layouting;
using GenHTTP.Modules.OpenApi;
using GenHTTP.Modules.Practices;
using GenHTTP.Modules.Reflection;
using GenHTTP.Modules.Reflection.Operations;

var app = Layout.Create()
                .Add(new CustomFrameworkHandler()) // GET /42
                .AddOpenApi()
                .AddScalar(); // GET /scalar/

await Host.Create()
          .Handler(app)
          .Defaults()
          .RunAsync();

public class CustomFrameworkHandler : IHandler, IServiceMethodProvider
{
    private MethodCollection? _methods;

    public MethodCollection Methods => _methods ?? throw new InvalidOperationException("Handler is not prepared yet");

    public async ValueTask PrepareAsync(IServer server)
    {
        var list = new List<MethodHandler>();

        // the HTTP methods the operation answers
        var supportedMethods = new MethodConfiguration([RequestMethod.Get]);

        // the code to run - a method info or a delegate
        var methodInfo = GetType().GetMethod("ExposedMethod")!;

        // Auto generates code where possible, and uses reflection otherwise
        var executionSettings = new ExecutionSettings(ExecutionMode.Auto);

        // how arguments are deserialized and injected, and results formatted
        var registry = new MethodRegistry(
            Serialization.Default().Build(),
            Injection.Default().Build(),
            Formatting.Default().Build()
        );

        var operation = OperationBuilder.Create(server, ":id", methodInfo, null, executionSettings, supportedMethods, registry);

        // serves the operation, invoking the method on this instance
        list.Add(new MethodHandler(operation, (_) => new(this), registry));

        // routes requests to the operations
        _methods = new MethodCollection(list);

        await _methods.PrepareAsync(server);
    }

    public ValueTask<IResponse?> HandleAsync(IRequest request) => Methods.HandleAsync(request);

    public string ExposedMethod(int id) => id.ToString();

}

Try it

With the sample running on your machine:

  1. Call the exposed method

    curl -i http://localhost:8080/42
  2. Browse the generated API

    PAGE http://localhost:8080/scalar/ Open