Home > Software engineering >  Dependency Injection Access While Configuring Service Registrations in asp.net Core (3 )
Dependency Injection Access While Configuring Service Registrations in asp.net Core (3 )

Time:10-09

I have cases, where I want to configure services based on objects which are registered in the dependency injection container. For example I have the following registration for WS Federation:

authenticationBuilder.AddWsFederation((options) =>{                
       options.MetadataAddress = "...";
       options.Wtrealm = "...";                
       options.[...]=...
});

My goal in the above case is to use a configuration object, which is available via the DI container to configure the WsFederation-middleware. It looks to me that IPostConfigureOptions<> is the way to go, but until now, I have not found a way to accomplish this.
How can this be done, or is it not possible?

CodePudding user response:

See https://andrewlock.net/simplifying-dependency-injection-for-iconfigureoptions-with-the-configureoptions-helper/ for the I(Post)ConfigureOptions<T> way, but I find that way too cumbersome.

I generally use this pattern:

// Get my custom config section
var fooSettingsSection = configuration.GetSection("Foo");

// Parse it to my custom section's settings class
var fooSettings = fooSettingsSection.Get<FooSettings>() 
    ?? throw new ArgumentException("Foo not configured");

// Register it for services who ask for an IOptions<FooSettings>
services.Configure<FooSettings>(fooSettings);

// Use the settings instance
services.AddSomeOtherService(options => {
    ServiceFoo = fooSettings.ServiceFoo;
})

A little more explicit, but you have all your configuration and DI code in one place.

Of course this bypasses the I(Post)ConfigureOptions<T> entirely, so if there's other code that uses those interfaces to modify the FooSettings afterwards, my code won't notice it as it's reading directly from the configuration file. Given I control FooSettings and its users, that's no problem for me.


This should be the approach if you do want to use that interface:

First, register your custom config section that you want to pull the settings from:

var fooSettingsSection = configuration.GetSection("Foo");
services.Configure<FooSettings>(fooSettingsSection);

Then, create an options configurer:

public class ConfigureWSFedFromFooSettingsOptions 
    : IPostConfigureOptions<Microsoft.AspNetCore.Authentication.WsFederation.WsFederationOptions>
{
    private readonly FooSettings _fooSettings;

    public ConfigureWSFedFromFooSettingsOptions(IOptions<FooSettings> fooSettings)
    {
        _fooSettings = fooSettings.Value;
    }

    public void Configure(WsFederationOptions options)
    {
        options.MetadataAddress = _fooSettings.WsFedMetadataAddress;
        options.Wtrealm = _fooSettings.WsFedWtRealm;
    }
}

And finally link the stuff together:

services.AddTransient<IPostConfigureOptions<WsFederationOptions>, ConfigureWSFedFromFooSettingsOptions>();

The configurer will get your IOptions<FooSettings> injected, instantiated from the appsettings, and then be used to further configure the WsFederationOptions.

  • Related