Reputation: 3236
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
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