Natalie Perret
Natalie Perret

Reputation: 9047

Is there a way to use F# record types to extract the appsettings.json configuration?

Long story short I can extract the appsettings.json to the Configuration type when I use C#-like classes:

type Connection() =
    member val Host = Unchecked.defaultof<string> with get,set
    member val Port = Unchecked.defaultof<int> with get,set
    member val UserName = Unchecked.defaultof<string> with get,set
    member val Password = Unchecked.defaultof<string> with get,set

type Configuration() =
    member val RabbitMQ = Unchecked.defaultof<Connection> with get,set
    member val PostgreSQL = Unchecked.defaultof<Connection> with get,set

let fetchConfiguration =
        let builder = (new ConfigurationBuilder())
                          .SetBasePath(Directory.GetCurrentDirectory())
                          .AddJsonFile("appsettings.json", true, true)
                          .AddEnvironmentVariables(); 
        let configurationRoot = builder.Build();
        let configuration = new Configuration()
        configurationRoot.Bind(configuration)
        configuration

But when using F# record types:


type Connection = {
    Host: string
    Port: int32
    Username: string
    Password: string
}

type Configuration = {
    RabbitMQ: Connection
    PostgreSQL: Connection
}

let fetchConfiguration =
        let builder = (new ConfigurationBuilder())
                          .SetBasePath(Directory.GetCurrentDirectory())
                          .AddJsonFile("appsettings.json", true, true)
                          .AddEnvironmentVariables(); 
        let configurationRoot = builder.Build();
        let configuration = {
            RabbitMQ = {
                Host = Unchecked.defaultof<string>
                Port = Unchecked.defaultof<int>
                Username = Unchecked.defaultof<string>
                Password = Unchecked.defaultof<string>
            }
            PostgreSQL = {
                Host = Unchecked.defaultof<string>
                Port = Unchecked.defaultof<int>
                Username = Unchecked.defaultof<string>
                Password = Unchecked.defaultof<string>
            }
        }
        configurationRoot.Bind(configuration)
        configuration

I end up with configuration that is no different than the value I gave before calling the 'Bind' method (even though I did'nt any exception), basically it's like nothing happened.

Note: I have the same behaviour when I use the defaults below:

let configuration = {
    RabbitMQ = Unchecked.defaultof<Connection>
    PostgreSQL = Unchecked.defaultof<Connection>
}

Upvotes: 10

Views: 2159

Answers (1)

Natalie Perret
Natalie Perret

Reputation: 9047

Thanks to the comments above, the solution was simply to set the [<CLIMutable>] attribute to the F# record types:

[<CLIMutable>]
type Connection = {
    Host: string
    Port: int32
    Username: string
    Password: string
}

[<CLIMutable>]
type Configuration = {
    RabbitMQ: Connection
    PostgreSQL: Connection
}

let fetchConfiguration =
        let builder = (new ConfigurationBuilder())
                          .SetBasePath(Directory.GetCurrentDirectory())
                          .AddJsonFile("appsettings.json", true, true)
                          .AddEnvironmentVariables(); 
        let configurationRoot = builder.Build();
        configurationRoot.Get<Configuration>()

Upvotes: 10

Related Questions