Dependency Injection

Runs on your machine

Lets the framework construct services and pass their dependencies.

This sample runs on your machine only. Dependency injection is enabled for the whole server, which this website shares with others.

Clone GenHTTP, let Playground/Program.cs serve DependencyInjectionSample.Create() and start it with dotnet run - then try the commands below.

DependencyInjectionSample.cs97 lines
using GenHTTP.Api.Content;

using GenHTTP.Modules.DependencyInjection;
using GenHTTP.Modules.Layouting;
using GenHTTP.Modules.Reflection;
using GenHTTP.Modules.Webservices;

using Microsoft.Extensions.DependencyInjection;

public static class DependencyInjectionSample
{

    public static IHandlerBuilder Create()
    {
        /*
         *
         * Lets the framework create services and pass their dependencies, so the
         * services do not need to know how to construct them (and can be tested
         * with fakes).
         *
         * Dependency injection needs to be enabled on the host, see Services() below
         * and Program.cs:
         *
         *   Host.Create()
         *       .AddDependencyInjection(DependencyInjectionSample.Services())
         *
         * See https://genhttp.org/documentation/content/concepts/dependency-injection/
         *
         */

        return Layout.Create()
                     .AddDependentService<BookService>("books"); // GET http://localhost:8080/books/
    }

    public static IServiceProvider Services()
    {
        var services = new ServiceCollection();

        services.AddSingleton<IBookRepository, InMemoryBookRepository>()
                .AddSingleton(TimeProvider.System);

        return services.BuildServiceProvider();
    }

    public record Book(int Id, string Title, DateTimeOffset? Added = null);

    public interface IBookRepository
    {

        List<Book> GetAll();

        Book Add(Book book);

    }

    public class InMemoryBookRepository : IBookRepository
    {
        private readonly List<Book> _books = [new(1, "Lord of the Rings")];

        private readonly Lock _sync = new();

        public List<Book> GetAll()
        {
            lock (_sync)
            {
                return [.._books];
            }
        }

        public Book Add(Book book)
        {
            lock (_sync)
            {
                var toAdd = book with { Id = _books.Select(b => b.Id).DefaultIfEmpty().Max() + 1 };

                _books.Add(toAdd);

                return toAdd;
            }
        }

    }

    // dependencies can be injected via the constructor ...
    public class BookService(IBookRepository repository)
    {

        [ResourceMethod]
        public List<Book> List() => repository.GetAll();

        // ... or as a method parameter
        [ResourceMethod(Method.Put)]
        public Book Add(Book book, TimeProvider time) => repository.Add(book with { Added = time.GetUtcNow() });

    }

}

Try it

With the sample running on your machine:

  1. List all books

    curl -i http://localhost:8080/books/
  2. Add a book

    curl -i -X PUT -H "Content-Type: application/json" -d '{ "title": "Dune" }' http://localhost:8080/books/