Closed yurotor closed 4 years ago
I agree that it should be possible to provide the current configuration at application CE usage. This is in line with the various lifecycle hooks that aspnetcore provides currently. They typically allow for DI of the IConfiguration type into the Startup type used, and our analogue would be providing a way to extract out the IConfiguration from the current app CE.
I see a couple options:
a new CE operation could be made that would provide access to the IConfiguration
Run
CE method is invoked, so this would be a large refactorcurrent CE operations that could make use of IConfiguration could have overloads added that would provide the IConfiguration
Run
and fed into the user-configured lambdas as necessary.Here is how i finally solved it:
Add a host_config operation to your app CE to read from settings file(s):
host_config (fun (webHost:IWebHostBuilder) = webHost.ConfigureAppConfiguration(fun ctx builder -> builder.AddJsonFile(sprintf "appSettings.%s.json" ctx.HostingEnvironment.EnvironmentName) |> ignore ))
Access the configuration from within any function in the app CE like this:
fun (services:IServiceCollection) = let config = services .BuildServiceProvider() .GetService<IConfiguration>() .GetSection("MySettingsSection") .Get<MySettings>() //do whatever needed with the config
Where the MySettings type is marked with the CLIMutable attribute.
If you need to access the MySettings within HTTP requests, then first register it using the service_config operation in the app CE like this:
service_config (fun (services:IServiceCollection) = let cfg = services .BuildServiceProvider() .GetService<IConfiguration>() .GetSection("MySettingsSection") services.Configure<MySettings>(cfg)
Then, add a pipe_through operation to your router CE like this:
pipe_through (fun _ : HttpHandler = fun next ctx -> let cfg = ctx.RequestServices.GetRequiredService<IOptions<MySettings>>().Value //do something with the config and return an HttpHandler)
Thank you. I ended up using this in a custom ApplicationBuilder method I wrote to handle CAS authentication. This made it so I didn't have to hardcode the settings. It looks like this:
[<CustomOperation("use_cas")>]
member __.UseCasAuthentication(state: ApplicationState, webAuthSettingKey) =
let middleware (app : IApplicationBuilder) =
app.UseAuthentication()
let service (s : IServiceCollection) =
let config = s.BuildServiceProvider()
.GetService<IConfiguration>()
.GetSection(webAuthSettingKey)
let c = s.AddAuthentication(fun cfg ->
cfg.DefaultScheme <- CookieAuthenticationDefaults.AuthenticationScheme
cfg.DefaultChallengeScheme <- "CAS"
)
c.AddCAS(fun o ->
o.CasServerUrlBase <- config.Value //["WebAuth:Url"]
o.SignInScheme <- CookieAuthenticationDefaults.AuthenticationScheme
)
|> ignore
s
{ state with
ServicesConfig = service::state.ServicesConfig
AppConfigs = middleware::state.AppConfigs
}
Suggestions from @yurotor are correct - in Saturn 0.14 we will add some helpers functions to make this user friendly
Currently, if i add a use_config operation to the application CE, i will be able to access the config through HttpContext in any controller. But what if i need the config data in the application itself? For example, when i use the service_config operation to integrate identity server authentication, i need to load the settings from an appSettings.json file. Am i missing something or is it not implemented?