F # Host.CreateDefaultBuilder (). ConfigureServices () не имеет HostBuilderContext - PullRequest
0 голосов
/ 26 апреля 2020

Я создаю WorkerService.
Я уверен, что сделаю это с C#, но я борюсь с версией F #.

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
            ) 

Не могу понять, как я могу прочитать Конфигурацию, чтобы настроить некоторые параметры служб, которые мне нужны впрыснуть.

Почему подпись IHostBuilder.ConfigureServices отличается?
C#
IHostBuilder ConfigureServices (Действие configureDelegate);

F #
IHostBuilder ConfigureServices: configureDelegateAction -> IHostBuilder

HostBuilderContext передается .ConfigureContainer () , поэтому я попробовал это:


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
        )

но это не работает, потому что ConfigureContainer () вызывается после ConfigureServices () , и я думаю, что должен быть способ использовать собранную конфигурацию, не сохраняя ее где-либо.

Как это должно работать?

1 Ответ

2 голосов
/ 29 апреля 2020

Это должно сработать:

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