|
| 1 | +> This recipe is not a detailed discussion of the pros and cons of Dependency Injection (DI) compared to other patterns. It simply illustrates how to use it within a SAFE Stack application! |
| 2 | +
|
| 3 | +1. Create a class that you wish to inject with a dependency (in this example, we use the built-in `IConfiguration` type that is included in ASP .NET): |
| 4 | + |
| 5 | + ```fsharp |
| 6 | + open Microsoft.Extensions.Configuration |
| 7 | +
|
| 8 | + type DatabaseRepository(config:IConfiguration) = |
| 9 | + member _.SaveDataToDb (text:string) = |
| 10 | + let connectionString = config["SqlConnectionString"] |
| 11 | + // Connect to SQL using the above connection string etc. |
| 12 | + Ok 1 |
| 13 | + ``` |
| 14 | +
|
| 15 | + > Instead of functions or modules, DI in .NET and F# only works with classes. |
| 16 | +
|
| 17 | +2. Register your type with ASP .NET during startup within the `application { }` block. |
| 18 | + ```diff |
| 19 | + ++ open Microsoft.Extensions.DependencyInjection |
| 20 | +
|
| 21 | + application { |
| 22 | + //... |
| 23 | + ++ service_config (fun services -> services.AddSingleton<DatabaseRepository>()) |
| 24 | + ``` |
| 25 | +
|
| 26 | + > [This section](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-8.0#lifetime-and-registration-options) of the official ASP .NET Core article explain the distinction between different lifetime registrations, such as Singleton and Transient. |
| 27 | +
|
| 28 | +3. Ensure that your Fable Remoting API can access the `HttpContext` type by using the `fromContext` builder function. |
| 29 | + ```diff |
| 30 | + -- |> Remoting.fromValue createFableRemotingApi |
| 31 | + ++ |> Remoting.fromContext createFableRemotingApi |
| 32 | + ``` |
| 33 | +
|
| 34 | +4. Within your Fable Remoting API, use the supplied `context` to retrieve your dependency: |
| 35 | +
|
| 36 | + ```diff |
| 37 | + ++ open Microsoft.AspNetCore.Http |
| 38 | +
|
| 39 | + let createFableRemotingApi |
| 40 | + ++ (context:HttpContext) = |
| 41 | + ++ let dbRepository = context.GetService<DatabaseRepository>() |
| 42 | + // ... |
| 43 | + // Return the constructed API record value... |
| 44 | + ``` |
| 45 | +
|
| 46 | + > Giraffe provides the `GetService<'T>` extension to allow you to quickly retrieve a dependency from the `HttpContext`. |
| 47 | +
|
| 48 | + This will instruct ASP .NET to get a handle to the `DatabaseRepository` object; ASP .NET will automatically supply the `IConfiguration` object to the constructor. Whether a new `DatabaseRepository` object is constructed on each call depends on the lifetime you have registered it with. |
| 49 | +
|
| 50 | +> You can have your types depend on other types that you create, as long as they are registering into ASP .NET Core's DI container using methods such as `AddSingleton` etc. |
| 51 | +
|
| 52 | +## Further Reading |
| 53 | +* [Official documentation on DI in ASP .NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-8.0) |
| 54 | +* [Archived example PR to update the SAFE Template Todo App to use DI](https://github.com/SAFE-Stack/SAFE-template/pull/466/files) |
0 commit comments