Dependency Injection
Runs on your machineLets the framework construct services and pass their dependencies.
Lets the framework construct the book service and pass it what it depends on - a repository and the clock -
so the service does not need to know how they are made, and tests can pass fakes instead. The services are
registered with Microsoft’s dependency injection, and AddDependencyInjection makes them available to
the server.
AddDependentService creates BookService with the repository passed to its constructor, and Add receives
the TimeProvider as a parameter of the method.
Runs on your machine only. Dependency injection is enabled for the whole server, which this website shares with others.
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/.
using GenHTTP.Engine.Internal;
using GenHTTP.Modules.DependencyInjection;
using GenHTTP.Modules.Layouting;
using GenHTTP.Modules.Practices;
using GenHTTP.Modules.Reflection;
using GenHTTP.Modules.Webservices;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddSingleton<IBookRepository, InMemoryBookRepository>()
.AddSingleton(TimeProvider.System);
var app = Layout.Create()
.AddDependentService<BookService>("books"); // GET /books/
await Host.Create()
.Handler(app)
.AddDependencyInjection(services.BuildServiceProvider())
.Defaults()
.RunAsync();
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 added = book with { Id = _books.Select(b => b.Id).DefaultIfEmpty().Max() + 1 };
_books.Add(added);
return added;
}
}
}
// dependencies are passed to the constructor ...
public class BookService(IBookRepository repository)
{
[ResourceMethod]
public List<Book> List() => repository.GetAll();
// ... or to a method
[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:
List all books
curl -i http://localhost:8080/books/Add a book
curl -i -X PUT -H "Content-Type: application/json" -d '{ "title": "Dune" }' http://localhost:8080/books/