Skip to content

Commit f574d44

Browse files
authored
Merge pull request #353 from SAFE-Stack/dependency-injection
Add DI recipe
2 parents cd2711f + 9929337 commit f574d44

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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)

mkdocs.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ extra:
4242
analytics:
4343
provider: google
4444
property: G-WED2S9FLSL
45-
45+
4646
nav:
4747
- Home: "index.md"
4848
- Introduction: "intro.md"
@@ -107,6 +107,8 @@ nav:
107107
- Migrate to Paket from NuGet: "recipes/package-management/migrate-to-paket.md"
108108
- Migrate to NuGet from Paket: "recipes/package-management/migrate-to-nuget.md"
109109
- Sync NuGet and NPM Packages: "recipes/package-management/sync-nuget-and-npm-packages.md"
110+
- Patterns:
111+
- Use Dependency Injection: "recipes/patterns/add-dependency-injection.md"
110112
- Client / Server:
111113
- Use Giraffe instead of Saturn: "recipes/client-server/saturn-to-giraffe.md"
112114
- Handle server errors on the client: "recipes/client-server/server-errors-on-client.md"

0 commit comments

Comments
 (0)