Home > Software engineering >  .Net - services.Configure bind to already instanciated entity
.Net - services.Configure bind to already instanciated entity

Time:01-11

I've created the following extension to simplify the app configurations in our many projects

public static TAppSettings AddAppSettings<TAppSettings>(this IServiceCollection services,
    IConfiguration configuration, string sectionName = BaseAppSettings.DefaultSectionName,
    ServiceLifetime lifetime = ServiceLifetime.Scoped)
    where TAppSettings : BaseAppSettings
{
    var appSettingsSection = configuration.GetSection(sectionName);
    var appSettings = appSettingsSection.Get<TAppSettings>();
    if (appSettings == null) throw new NullReferenceException(nameof(appSettings));
    services.Configure<TAppSettings>(appSettingsSection);
    services.Add(new ServiceDescriptor(typeof(TAppSettings),serviceProvider =>appSettings , lifetime));
    return appSettings;
}

Which allows me to call it like

services.AddAppSettings<AppSettings>(context.Configuration);

Is there anyway to bind an already defined object instance,like one with some default values?

I've tried the following code, but any value inside IOptions are empty

public static TAppSettings AddAppSettings<TAppSettings>(this IServiceCollection services, IConfiguration configuration,
    TAppSettings appSettings,
    ServiceLifetime lifetime = ServiceLifetime.Scoped)
    where TAppSettings : BaseAppSettings
{

    if (appSettings == null) throw new NullReferenceException(nameof(appSettings));
    services.Configure<TAppSettings>(options=>options=appSettings);
    return appSettings;
}

Update

I know that is unusual but imagine that i've an application that doesn't uses appsettings.json. I want to set some values to my configurations(I know it's possible to set the default values in the class), but imagine that don't want to set some default values there, because they can change from app to app that doesn't uses appsettings. but i still want to inject IOptions;

Any ideas?

CodePudding user response:

this line

services.Configure<TAppSettings>(options=>options=appSettings);

Won't work

You need to construct an Action like

ConstantExpression val = Expression.Constant(prop.GetValue(appSettings));  
    
MemberExpression memberexpression = Expression.PropertyOrField(paraexpression, prop.Name);                
BinaryExpression assign = Expression.Assign(memberexpression, val);                
Expression<Action<TAppSettings>> exp = Expression.Lambda<Action<TAppSettings>>(assign, new ParameterExpression[] { paraexpression });                
services.Configure<TAppSettings>(exp.Compile());

CodePudding user response:

Given that you want to register an object (representing some settings) as IOptions<T>, you just need to wrap that instance with an IOptions<T>.

Options.Create<T> does that.

public static class Extenions
{
    public static TAppSettings AddAppSettings<TAppSettings>(
        this IServiceCollection services, TAppSettings appSettings,
        ) where TAppSettings : class
    {
        services.AddSingleton(typeof(IOptions<TAppSettings>), Options.Create(appSettings));

        return appSettings;
    }
}

The registration exists of creation an AppSettings instance, setting some properties and calling that extension method.

The lifetime of such an existing instance will always need to be a singleton, since you'll be creating that instance only once.

var appSettings = new AppSettings();
// Set some properties on appSettings.
services.AddAppSettings(appSettings);

Now your other classes can have an IOptions<AppSettings> instance injected.

  • Related