Skip to content

Instantly share code, notes, and snippets.

@jhewlett
Last active January 26, 2020 03:25
Show Gist options
  • Save jhewlett/52ebfd6e40a59fb0c66e1abaa8151044 to your computer and use it in GitHub Desktop.
Save jhewlett/52ebfd6e40a59fb0c66e1abaa8151044 to your computer and use it in GitHub Desktop.
Pure DI in F# ASP.NET Core Web API
namespace PureDI
open Microsoft.AspNetCore.Builder
open Microsoft.Extensions.Configuration
open Microsoft.Extensions.DependencyInjection
open Microsoft.AspNetCore.Mvc
open Microsoft.AspNetCore.Mvc.Controllers
open Microsoft.AspNetCore.Hosting
type Person = {
Id : string
Name : string
}
module Person =
let people = [{ Id = "1"; Name = "Person 1" }; { Id = "2"; Name = "Person 2" }]
let getPersonById dbConnection id =
async {
return people |> List.tryFind (fun p -> p.Id = id)
}
let getAllPeople dbConnection =
async {
return people
}
type GetPersonById = string -> Async<Person option>
type GetAllPeople = unit -> Async<Person list>
[<ApiController>]
type PersonController(getPersonById : GetPersonById, getAllPeople : GetAllPeople) =
inherit ControllerBase()
[<HttpGet>]
[<Route("people/{personId}")>]
member _.GetPersonById(personId : string) : Async<IActionResult> =
async {
let! person = getPersonById personId
return
match person with
| Some p -> OkObjectResult(p) :> IActionResult
| None -> NotFoundResult() :> IActionResult
}
[<HttpGet>]
[<Route("people")>]
member _.GetAllPeople() : Async<IActionResult> =
async {
let! people = getAllPeople ()
return OkObjectResult(people) :> IActionResult
}
type CompositionRoot(dbConnection) =
//explicit wire-up of functions via partial application
let getPersonById = Person.getPersonById dbConnection
let getAllPeople () = Person.getAllPeople dbConnection
interface IControllerActivator with
member _.Create(context: ControllerContext): obj =
let controller = context.ActionDescriptor.ControllerTypeInfo.AsType()
if controller = typeof<PersonController> then
PersonController(getPersonById, getAllPeople) :> obj
else
failwith ("Unknown controller " + controller.Name)
member _.Release(context: ControllerContext, controller: obj): unit =
()
type Startup (config : IConfiguration) =
member _.ConfigureServices(services : IServiceCollection) : unit =
services
.AddSingleton<IControllerActivator>(CompositionRoot(config.["dbConnection"]))
.AddControllers()
|> ignore
member _.Configure(app : IApplicationBuilder) : unit =
app.UseRouting () |> ignore
app.UseEndpoints (fun endpoints ->
endpoints.MapControllers () |> ignore
) |> ignore
module Program =
let createHostBuilder args =
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(fun webBuilder ->
webBuilder.UseStartup<Startup>() |> ignore
)
[<EntryPoint>]
let main args =
createHostBuilder(args).Build().Run()
0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment