This post is about taking a functional approach to dependency injection using an ASP.NET core application written in F# as an example.
Lets say that we are are building an ASP.NET Core web application that exposes an HTTP API, and we want to automatically test the whole application pipeline.
As we only want to test the application behavior we need to be able to identify and isolate any external dependencies. With that done, we will also be able to replace those with fake implementations when running tests. This way we can focus on testing the application behavior without worrying about any external components.
Next up I will be showing an example of how to use dependency injection and partial application to achieve this.
The application we are building is a service that takes in a URL that points to a text document and shows the contents of that document in uppercase text. The interface to our application is an URL that accepts HTTP GET request and this interface is also used in tests.
The example application source code can be found at https://github.com/vilppu/fun-playground
As previously said we need to first find the dependencies that we need to isolate and as we are using F# it is convenient to model dependencies as functions.
In this case we have only one dependency and it is the outgoing HTTP request. We model this dependency as a function named httpSend
let httpSend : HttpRequestMessage -> Task<HttpResponseMessage>
For the concrete implementation easiest way is to use built-in HttpClient class:
let httpClient = HttpClient() let httpSend = httpClient.Send
We can pass this function to our application by adding it as parameter to function that is used to start up the web server:
let CreateHttpServer httpSend = ...
And then register the function as singleton dependency using dependency injection in SelfHost.fs:
WebHostBuilder().ConfigureServices(fun services -> services.AddSingleton(httpSend) |> ignore)
After that the registered function can be injected to an ASP.NET API controller in Api.fs:
type ApiController httpSend = inherit Controller() ...
In our example the ApiController forms a boundary between object-oriented and functional code and from that on we pass on the dependency function as normal parameter.
Then we can use partial application to handle this dependency in more functionally oriented way. In the Api module we apply the httpSend parameter to Application.GetUppercaseContent function:
let getUppercaseContent = Application.GetUppercaseContent httpSend
Later we can call this partially applied function without worrying about our dependency:
Deep dive to code
The actual code tells more than thousand lines of hand-waving, so if you are still interested I recommend you to check out the example from
git clone https://github.com/vilppu/fun-playground/
and look into the tests in Tests.fs