webconfig net ioptions iconfiguration asp asp.net-core asp.net-core-mvc .net-core coreclr

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>();