Skip to content

Instantly share code, notes, and snippets.

@NinoFloris
Last active November 1, 2018 14:30
Show Gist options
  • Save NinoFloris/b59393193e47a0160c6f42eb6354683b to your computer and use it in GitHub Desktop.
Save NinoFloris/b59393193e47a0160c6f42eb6354683b to your computer and use it in GitHub Desktop.
OptionsFactory with func instead of new()
namespace Configuration
open System
open System.Runtime.CompilerServices
open Microsoft.Extensions.Options
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Configuration
type OptionsFactoryFromFunc<'TOptions when 'TOptions : not struct and 'TOptions : (new : unit -> 'TOptions)>
(factoryFunc: Func<'TOptions>,
setups: IConfigureOptions<'TOptions> seq,
postConfigures: IPostConfigureOptions<'TOptions> seq) =
member __.Create(name) =
let options = factoryFunc.Invoke()
for setup in setups do
match setup with
| :? IConfigureNamedOptions<'TOptions> as namedSetup ->
namedSetup.Configure(name, options)
| _ ->
if name = Options.DefaultName then setup.Configure(options)
for post in postConfigures do
post.PostConfigure(name, options)
options
interface IOptionsFactory<'TOptions> with
member this.Create(name) = this.Create(name)
[<Extension>]
type FSharpOptionsExtensions() =
[<Extension>]
static member Configure<'TOptions when 'TOptions : not struct and 'TOptions : (new : unit -> 'TOptions)>(services: IServiceCollection, optionsFactory: Func<'TOptions>) =
if System.Object.ReferenceEquals(optionsFactory.Invoke(), optionsFactory.Invoke()) then
invalidArg "optionsFactory" "Options factory function is expected to return new instances on invocation, use OptionsWrapper for singletons."
let svc (ctx: IServiceProvider) : IOptionsFactory<'TOptions> =
upcast OptionsFactoryFromFunc<'TOptions>(optionsFactory, ctx.GetService<_>(), ctx.GetService<_>())
services.AddSingleton<IOptionsFactory<'TOptions>>(svc)
module Sample
open Configuration
open Microsoft.Extensions.Configuration
[<CLIMutable>]
type MyClientOptions =
{
Host: string
}
let configureServices (services: IServiceCollection) (config: IConfigurationRoot) =
services.Configure<_>(fun () -> { Host = "127.0.0.1" })
// Or whatever
services.Configure<_>(fun () ->
let host = defaultArg (Option.ofObj(config.GetValue<string>("MyClient:Host"))) "127.0.0.1"
{ Host = host }
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment