Alex 75
Alex 75

Reputation: 3236

F# Host.CreateDefaultBuilder().ConfigureServices() does not have HostBuilderContext

I'm creating a WorkerService.
I've confidence on doing it with C# but I'm struggling with the F# version.

C# Program.cs

public static IHostBuilder CreateHostBuilder(string[] args) =>
  Host.CreateDefaultBuilder(args)                
    .ConfigureServices((hostContext, services) =>
    {      
        // here I have access to the builded configuration
        // read stuff from configuration
        var interval = TimeSpan.Parse(hostContext.Configuration["Service:Run:interval"]);
        services.AddHostedService<Worker>();
    });

F# Program.fs

let CreateHostBuilder (args) = 
    Host.CreateDefaultBuilder() 
        .ConfigureServices( 
            fun (services:IServiceCollection) -> //hostContext:HostBuilderContext,
            //fun (context:HostBuilderContext, services:IServiceCollection) ->  
                // where is the builded configuration ??? 
                //let configuration = ???
                services.AddHostedService<Worker>() |> ignore
            ) 

I can't figure out how can I read the Configuration to setup some services settings I need to inject.

Why the signature of IHostBuilder.ConfigureServices is different?
C#
IHostBuilder ConfigureServices(Action configureDelegate);

F#
IHostBuilder ConfigureServices: configureDelegateAction -> IHostBuilder

HostBuilderContext is passed to .ConfigureContainer() so I tried this:


open System
open System.Threading
open System.Threading.Tasks

type IMyWorker =
    abstract member Start: unit -> unit

type MyWorker(interval:TimeSpan) =
    inherit BackgroundService()

    override this.ExecuteAsync (step:CancellationToken):Task = Task.CompletedTask

    interface IMyWorker with
        member this.Start() = ()


let CreateHostBuilder (args) = 

    // 1. this is empty
    //let configuration = ConfigurationBuilder().Build()
    //let interval = TimeSpan.Parse(configuration.["Service:Run:interval"])

    let mutable loadedConfiguration:Option<IConfiguration> = None

    Host.CreateDefaultBuilder() 
        .ConfigureHostConfiguration( fun(confBuilder:IConfigurationBuilder) ->
            // it's ok here to read more settings, like "serilog.json" for example ?

            // 2. this is still empty
            //let configuration = confBuilder.Build()
            //let interval = TimeSpan.Parse(configuration.["Service:Run:interval"])
            // where to store the values ?  configuration.[""]
            ()
        )
        .ConfigureContainer( fun (hostContext:HostBuilderContext) -> 

            // 5. this is ok, it is builded properly
            // but ist is called after ConfigureServices()
            loadedConfiguration <- Some(hostContext.Configuration) // :> IConfigurationRoot
            let interval = TimeSpan.Parse(hostContext.Configuration.["Service:Run:interval"])
            ()
        )
        .ConfigureServices(
            fun(services:IServiceCollection) ->

                // 4. this is empty
                //let configuration = ConfigurationBuilder().Build()
                //let interval = TimeSpan.Parse(configuration.["Service:Run:interval"])

                if loadedConfiguration.IsNone then failwith "configuration not loqaded yet"

                let interval = TimeSpan.Parse(loadedConfiguration.Value.["Service:Run:interval"])

                //let interval = TimeSpan.Parse("00:01:00")
                let worker = new MyWorker(interval)
                services.AddSingleton<IMyWorker>(worker) |> ignore
        )

but it does not work because ConfigureContainer() is called after ConfigureServices() and I think there should be a way to use the builded configuration without storing it somewhere.

How is it supposed to work?

Upvotes: 1

Views: 753

Answers (1)

nilekirk
nilekirk

Reputation: 2383

This should do the trick:

let createHostBuilder args =
    Host
        .CreateDefaultBuilder(args)
        .ConfigureServices (fun hostContext services ->
            let interval = TimeSpan.Parse(hostContext.Configuration.["Service:Run:interval"]);
            services.AddHostedService<Worker>() |> ignore
        )

Upvotes: 3

Related Questions