asp.net core - net - ¿Cómo obtener IOptions en el método ConfigureServices?
net core web config (3)
Al usar .NET Core 2 y no tener un proveedor disponible (o querer agregarlo) en ConfigureServices
, opté por usar algo como esto (usando el código OP como ejemplo):
public void ConfigureServices(IServiceCollection services)
{
// secOpts available for use in ConfigureServices
var secOpts = Configuration
.GetSection("SecurityHeaderOptions")
.Get<SecurityHeaderOptions>();
...
}
Tengo la aplicación principal de asp.net. Quiero usar el patrón de IOptions
para inyectar valores desde appsettings.json. Así que tengo una clase SecurityHeaderOptions
, y también tengo una clase objetivo SecurityHeadersBuilder
cuyo constructor toma IOptions<SecurityHeaderOptions>
como parámetro.
Sé que .net core puede crear implícitamente una instancia de SecurityHeadersBuilder
inyectando IOptions<SecurityHeaderOptions>
después de registrar ambos con el contenedor.
Sin embargo, quiero crear explícitamente la instancia de SecurityHeadersBuilder
, llamar a uno de sus métodos y luego registrar la instancia con el contenedor.
public sealed class SecurityHeaderOptions
{
public string FrameOption { get; set; }
public string XssProtection { get; set; }
}
public class SecurityHeadersBuilder
{
private readonly SecurityHeaderOptions _options = null;
public SecurityHeadersBuilder(IOptions<SecurityHeaderOptions> options)
{
_options = options.Value;
}
public SecurityHeadersBuilder AddDefaultPolicy()
{
AddFrameOptions();
AddConetntSecurityPolicy();
return this;
}
}
Método ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
services.Configure<SecurityHeaderOptions>(Configuration.GetSection("SecurityHeaderOptions"));
services.AddScoped<SecurityHeadersBuilder>(provider =>
new SecurityHeadersBuilder(?????).AddDefaultPolicy())
}
Preguntas
1> Si estoy pasando opciones explícitamente al constructor, ¿necesito registrar SecurityHeaderOptions
con el contenedor usando el método service.Configure
?
2> Configuration.GetSection("SecurityHeaderOptions")
no puede devolver la instancia de IOptions<SecurityHeaderOptions>
, en su lugar, devuelve IConfigurationSection
?
3> De cualquier manera, ¿cómo recupero y paso SecurityHeaderOptions
al constructor de SecurityHeadersBuilder
?
Así es como registro las opciones e inyecto en SecurityHeadersBuilder
public void ConfigureServices(IServiceCollection services)
{
services.Configure<SecurityHeaderOptions>(Configuration.GetSection("SecurityHeaderOptions"));
services.AddScoped<SecurityHeadersBuilder>(provider =>
{
var option = provider.GetService<IOptions<SecurityHeaderOptions>>();
return new SecurityHeadersBuilder(option)
.AddDefaultPolicy();
});
}
Con respecto a sus preguntas:
1. Sí, necesita registrar las opciones, pero creo que lo está haciendo de manera incorrecta (al menos por su ejemplo). Debes registrarte así:
services.Configure<SecurityHeaderOptions>(options => Configuration.GetSection("SecurityHeaderOptions").Bind(options));
2. Creo que el registro correcto al que me refiero más arriba devuelve lo que está esperando.
3. Basta con registrarlo y colocarlo en el constructor SecurityHeaderBuilder
es suficiente. No es necesario (tampoco lo hace el contenedor de .NET Core IOC predeterminado) para pasar los parámetros del constructor al registrarlo. Para eso necesitarías usar otros IOC como Autofac.
Pero necesita registrar SecurityHeadersBuilder
para usarlo dentro de otras clases. Solo usa una interfaz para eso.
public interface ISecurityHeadersBuilder
{
SecurityHeadersBuilder AddDefaultPolicy;
}
public class SecurityHeadersBuilder : ISecurityHeadersBuilder
{
private readonly SecurityHeaderOptions _options = null;
public SecurityHeadersBuilder(IOptions<SecurityHeaderOptions> options)
{
_options = options.Value;
}
public SecurityHeadersBuilder AddDefaultPolicy()
{
AddFrameOptions();
AddContentSecurityPolicy();
return this;
}
}
Entonces, simplemente registralo en startup.cs
como esta
services.AddScoped<ISecurityHeadersBuilder, SecurityHeadersBuilder>();