Ich habe eine asp.net-Kernanwendung. Ich möchte IOptions
pattern verwenden, um Werte aus appsettings.json einzufügen. Ich habe also eine Klasse SecurityHeaderOptions
und auch eine Zielklasse SecurityHeadersBuilder
, deren Konstruktor IOptions<SecurityHeaderOptions>
als Parameter verwendet.
Ich weiß, dass .net Core die Instanz von SecurityHeadersBuilder
implizit erstellen kann, indem IOptions<SecurityHeaderOptions>
nach der Registrierung beider Container in Container eingefügt wird.
Ich möchte jedoch die Instanz von SecurityHeadersBuilder
explizit erstellen, eine ihrer Methoden aufrufen und dann die Instanz beim Container registrieren.
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;
}
}
ConfigureServices-Methode
public void ConfigureServices(IServiceCollection services)
{
services.Configure<SecurityHeaderOptions>(Configuration.GetSection("SecurityHeaderOptions"));
services.AddScoped<SecurityHeadersBuilder>(provider =>
new SecurityHeadersBuilder(?????).AddDefaultPolicy())
}
Fragen
1> Wenn ich Optionen explizit an Konstruktor übergeben möchte, muss ich SecurityHeaderOptions
mit dem Container mithilfe der service.Configure
-Methode registrieren?
2> Configuration.GetSection("SecurityHeaderOptions")
kann keine Instanz von IOptions<SecurityHeaderOptions>
zurückgeben, stattdessen IConfigurationSection
.
3> Wie kann ich auf jeden Fall SecurityHeaderOptions
abrufen und in den Konstruktor von SecurityHeadersBuilder
übergeben?
Mit .NET Core 2 und nicht mit einem Anbieter in ConfigureServices
(oder mit dem Gedanken, es hinzuzufügen) habe ich mich für Folgendes entschieden (Beispiel: OP-Code)
public void ConfigureServices(IServiceCollection services)
{
// secOpts available for use in ConfigureServices
var secOpts = Configuration
.GetSection("SecurityHeaderOptions")
.Get<SecurityHeaderOptions>();
...
}
So registriere ich Optionen und füge in SecurityHeadersBuilder
ein
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();
});
}
In Bezug auf Ihre Fragen:
1. Ja, Sie müssen die Optionen registrieren, aber ich glaube, dass Sie es falsch machen (zumindest durch Ihr Beispiel). Sie sollten sich wie folgt registrieren:
services.Configure<SecurityHeaderOptions>(options => Configuration.GetSection("SecurityHeaderOptions").Bind(options));
2. Ich glaube, dass die korrekte Registrierung, auf die ich mich bezogen habe, das zurückgibt, was Sie erwarten.
3. Es reicht aus, es zu registrieren und im Konstruktor SecurityHeaderBuilder
abzulegen. Sie müssen (und der Standardcontainer von .NET Core IOC nicht erlaubt) die Konstruktorparameter bei der Registrierung nicht übergeben. Dafür müssten Sie andere IOCs wie Autofac verwenden.
Sie müssen jedoch SecurityHeadersBuilder
registrieren, um sie in anderen Klassen verwenden zu können. Verwenden Sie dazu einfach eine Schnittstelle.
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;
}
}
Dann registrieren Sie es einfach in startup.cs
services.AddScoped<ISecurityHeadersBuilder, SecurityHeadersBuilder>();