# Dependency injection

Source: https://docs.sisk-framework.org/docs/features/instancing.html

It is common to dedicate members and instances that last for the lifetime of a request, such as a database connection, an authenticated user, or a session token. One of the possibilities is through the [HttpContext.RequestBag](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpContext.md), which creates a dictionary that lasts for the entire lifetime of a request.

This dictionary can be accessed by [request handlers](https://docs.sisk-framework.org/docs/fundamentals/request-handlers.md) and define variables throughout that request. For example, a request handler that authenticates a user sets this user within the `HttpContext.RequestBag`, and within the request logic, this user can be retrieved with `HttpContext.RequestBag.Get<User>()`.

The objects defined in this dictionary are scoped to the request lifecycle. They are disposed of at the end of the request. Not necessarily does sending a response define the end of the request lifecycle. When [request handlers](https://docs.sisk-framework.org/docs/fundamentals/request-handlers.md) that run after sending a response are executed, the `RequestBag` objects still exist and have not been disposed of.

Here’s an example:

```csharp {title="RequestHandlers/AuthenticateUser.cs"}
public class AuthenticateUser : IRequestHandler
{
    public RequestHandlerExecutionMode ExecutionMode { get; init; } = RequestHandlerExecutionMode.BeforeResponse;
    
    public HttpResponse? Execute(HttpRequest request, HttpContext context)
    {
        User authenticatedUser = AuthenticateUser(request);
        context.RequestBag.Set(authenticatedUser);
        return null; // advance to the next request handler or request logic
    }
}
```

```csharp {title="Controllers/HelloController.cs"}
[RouteGet("/hello")]
[RequestHandler<AuthenticateUser>]
public HttpResponse SayHello(HttpRequest request)
{
    var authenticatedUser = request.Bag.Get<User>();
    return new HttpResponse()
    {
        Content = new StringContent($"Hello {authenticatedUser.Name}!")
    };
}
```

This is a preliminary example of this operation. The instance of `User` was created within the request handler dedicated to authentication, and all routes that use this request handler will have the guarantee that there will be a `User` in their instance of `HttpContext.RequestBag`.

It is possible to define logic to obtain instances when not previously defined in the `RequestBag` through methods like [GetOrAdd](https://docs.sisk-framework.org/api/Sisk.Core.Entity.TypedValueDictionary.GetOrAdd.md) or [GetOrAddAsync](https://docs.sisk-framework.org/api/Sisk.Core.Entity.TypedValueDictionary.GetOrAddAsync.md).

Since version 1.3, the static property [HttpContext.Current](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpContext.Current.md) was introduced, allowing access to the currently executing `HttpContext` of the request context. This enables exposing members of the `HttpContext` outside the current request and defining instances in route objects.

The example below defines a controller that has members commonly accessed by the context of a request.

```csharp {title="Controllers/Controller.cs"}
public abstract class Controller : RouterModule
{
    // Get the existing or create a new database instance for this request
    protected DbContext Database => HttpContext.Current.RequestBag.GetOrAdd(() => new DbContext());

    // Lazy loading repositories is common too
    protected IUserRepository Users => HttpContext.Current.RequestBag.GetOrAdd(() => new UserRepository(Database));
    protected IBlogRepository Blogs => HttpContext.Current.RequestBag.GetOrAdd(() => new BlogRepository(Database));
    protected IBlogPostRepository BlogPosts => HttpContext.Current.RequestBag.GetOrAdd(() => new BlogPostRepository(Database));

    // the following line will throw if the property is accessed when the User is not
    // defined in the request bag
    protected User AuthenticatedUser => => HttpContext.Current.RequestBag.Get<User>();

    // Exposing the HttpRequest instance is supported too
    protected HttpRequest Request => HttpContext.Current.Request
}
```

And define types that inherit from the controller:

```csharp {title="Controllers/PostsController.cs"}
[RoutePrefix("/api/posts/{author}")]
sealed class PostsController : Controller
{
    protected Guid AuthorId => Request.RouteParameters["author"].GetInteger();

    [RouteGet]
    public IAsyncEnumerable<BlogPost> ListPosts()
    {
        return BlogPosts.GetPostsAsync(authorId: AuthorId);
    }

    [RouteGet("<id>")]
    public async Task<BlogPost?> GetPost()
    {
        int postId = Request.RouteParameters["id"].GetInteger();

        Post? post = await BlogPosts
            .FindPostAsync(post => post.Id == postId && post.AuthorId == AuthorId);

        return post;
    }
}
```

For the example above, you will need to configure a [value handler](https://docs.sisk-framework.org/docs/fundamentals/responses.md#implicit-response-types) in your router so that the objects returned by the router are transformed into a valid [HttpResponse](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpResponse.md).

Note that the methods do not have an `HttpRequest request` argument as present in other methods. This is because, since version 1.3, the router supports two types of delegates for routing responses: [RouteAction](https://docs.sisk-framework.org/api/Sisk.Core.Routing.RouteAction.md), which is the default delegate that receives an `HttpRequest` argument, and [ParameterlessRouteAction](https://docs.sisk-framework.org/api/Sisk.Core.Routing.ParameterlessRouteAction.md). The `HttpRequest` object can still be accessed by both delegates through the [Request](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpContext.Request.md) property of the static `HttpContext` on the thread.

In the example above, we defined a disposable object, the `DbContext`, and we need to ensure that all instances created in a `DbContext` are disposed of when the HTTP session ends. For this, we can use two ways to achieve this. One is to create a [request handler](https://docs.sisk-framework.org/docs/fundamentals/request-handlers.md) that is executed after the router's action, and the other way is through a custom [server handler](https://docs.sisk-framework.org/docs/advanced/http-server-handlers.md).

For the first method, we can create the request handler inline directly in the [OnSetup](https://docs.sisk-framework.org/api/Sisk.Core.Routing.RouterModule.OnSetup.md) method inherited from `RouterModule`:

```csharp {title="Controllers/PostsController.cs"}
public abstract class Controller : RouterModule
{
    ...

    protected override void OnSetup(Router parentRouter)
    {
        base.OnSetup(parentRouter);

        HasRequestHandler(RequestHandler.Create(
            execute: (req, ctx) =>
            {
                // get one DbContext defined in the request handler context and
                // dispose it
                ctx.RequestBag.GetOrDefault<DbContext>()?.Dispose();
                return null;
            },
            executionMode: RequestHandlerExecutionMode.AfterResponse));
    }
}
```

> [!TIP]
>
> Since Sisk version 1.4, the property [HttpServerConfiguration.DisposeDisposableContextValues](https://docs.sisk-framework.org/api/Sisk.Core.Http.HttpServerConfiguration.DisposeDisposableContextValues.md) is introduced and enabled by default, which defines whether the HTTP server should dispose all `IDisposable` values in the context bag when an HTTP session is closed.

The method above will ensure that the `DbContext` is disposed of when the HTTP session is finalized. You can do this for more members that need to be disposed of at the end of a response.

For the second method, you can create a custom [server handler](https://docs.sisk-framework.org/docs/advanced/http-server-handlers.md) that will dispose of the `DbContext` when the HTTP session is finalized.

```csharp {title="Server/Handlers/ObjectDisposerHandler.cs"}
public class ObjectDisposerHandler : HttpServerHandler
{
    protected override void OnHttpRequestClose(HttpServerExecutionResult result)
    {
        result.Context.RequestBag.GetOrDefault<DbContext>()?.Dispose();
    }
}
```

And use it in your app builder:

```csharp {title="Program.cs"}
using var host = HttpServer.CreateBuilder()
    .UseHandler<ObjectDisposerHandler>()
    .Build();
```

This is a way to handle code cleanup and keep the dependencies of a request separated by the type of module that will be used, reducing the amount of duplicated code within each action of a router. It is a practice similar to what dependency injection is used for in frameworks like ASP.NET.
