F# Host.CreateDefaultBuilder().ConfigureServices() не имеет HostBuilderContext

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

Программа C#.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(Action 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(), и я думаю, что должен быть способ использовать созданную конфигурацию, не сохраняя ее где-то.

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


person Alex 75    schedule 26.04.2020    source источник


Ответы (1)


Это должно помочь:

let createHostBuilder args =
    Host
        .CreateDefaultBuilder(args)
        .ConfigureServices (fun hostContext services ->
            let interval = TimeSpan.Parse(hostContext.Configuration.["Service:Run:interval"]);
            services.AddHostedService<Worker>() |> ignore
        )
person nilekirk    schedule 29.04.2020
comment
Что за черт! Наконец я понял, я перепробовал весь возможный синтаксис, но всегда с параметрами в неправильном порядке! Спасибо. Что делать, если я хочу указать тип? Я пробовал это: 1. забава (hostContext: IConfigurationBuilder, services: IServiceCollection) -> 2. забава (hostContext: IConfigurationBuilder) (services: IServiceCollection) -> Оба недействительный синтаксис. - person Alex 75; 29.04.2020
comment
Вы можете указать типы, используя fun (hostContext: HostBuilderContext) (services: IServiceCollection) -> ... - person nilekirk; 29.04.2020