Open Closed

How to use iOptions with ISettingManager? #1926


User avatar
0
BassaSolutions created
  • ABP Framework version: v4.3.3
  • UI type: Blazor Server
  • DB provider: EF Core

We use iOptions for our settings management throught all application modules (some of which do use the ABP framework).

As ABP provides the ISettingManager, and we want to manage the settings in the UI, we moved all settings to ISettingManager & created UI pages as described in the ABP documentation. Of course we must not have references to the ABP framework in each modules, so for providing the settings we have to stay with iOptions.

Now is there a way to update the iOptions (initialized from appsettings.json) when the ISettingManager is updated? Of course this only applies on restart, as we use iOptions and not iOptionsSnapshot, but we still need to somehow 'merge' these 2.

We saw that the ABP LDAP module does the same (use iOptions combined with ISettingManager), but it seems to have to get the settings values each time when iOptions is read, and not when the settings in ISettingManager change. This is not an option for us.

This is the example similiar to the ABP LDAP application. This does not work, as it has to be called each single time when iOptions is read, and not once when the settings are stored.

Code Snipped:

   public class FhirOptionManager : AbpDynamicOptionsManager<FhirOptions>
    {
        protected ISettingProvider SettingProvider { get; }

        public FhirOptionManager(IOptionsFactory<FhirOptions> factory, ISettingProvider settingProvider)
            : base(factory)
        {
            SettingProvider = settingProvider;
        }

        protected override async Task OverrideOptionsAsync(string name, FhirOptions options)
        {
            options.Endpoint = await GetSettingOrDefaultValue(MySettings.SettingsFhirEndpoint, options.Endpoint);
        }

        protected virtual async Task<string> GetSettingOrDefaultValue(string name, string defaultValue)
        {
            var value = await SettingProvider.GetOrNullAsync(name);
            return value.IsNullOrWhiteSpace() ? defaultValue : value;
        }
    }

Thank you for your time!


11 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi I think you can customize a IOptions implementation, You can refer to OptionsMonitor.

    IOptions<FhirOptions>
    

  • User Avatar
    0
    BassaSolutions created

    What exactly will context.Services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>))); do?

    My question was on how to get the Settings from ISettingManager into IOptions, permanently?

    If i update ISettingManager & restart the app, IOptions is still loaded from the JSON file. How can iOptions be changed to use the ABP settings instead?

    With the line added, iOption is still the values from the json file.

    await _options.SetAsync();, which is calling the AbpDynamicOptionsManager mapping is only updating the current instance of ioptinos, and not the ones injected into the modules.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi BassaSolutions

    Can you share a simple project? liming.ma@volosoft.com

  • User Avatar
    0
    BassaSolutions created

    I will create one and send it to you

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    No problem

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    https://github.com/maliming/abp-ioptions-example/commit/a5ab8b02d793edcd096ff16cb8157be0e3c44fba

  • User Avatar
    0
    BassaSolutions created

    Ok this solutions is not fixing the 2 main issues:

    We do NOT want to have to update the settings when using them in any feature. So in this case, putting OverrideOptionsAsync before getting from the feature:

            {
                await _options2.As<MySpecialSettings2OptionsManager>().OverrideOptionsAsync();
                return _exampleFeature.getSetting();
            }
    

    is doing exactly the same thing as with the previous

     await _mySpecialSettings2Options.SetAsync();
    

    Both update the CURRENT ioptions instance. For this, the created tmp cache stuff was not necessary - ABP aready provides a feature that does this (AbpDynamicOptionsManager<MySpecialSettings2> + ioptions.SetAsync)

    We have 1 place where we update the settings and hundres where we use them - and we of course only want to call the ioptions/abpsettings sync once.

    So what does not work:

    • On startup, the current example still takes the JSON file content
    • When we add 50 more features that access the ioptions, they also do not get the update
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    I did not find other solutions. AbpDynamicOptionsManagery must also call the SetAsync method every time

  • User Avatar
    0
    BassaSolutions created

    So how is the ABP approach to change settings in the UI?

    Do we really have to remove iOptions and add the complete ABP settings module everywhere across the application? This seems like it will cause performance issues (e.g. in each single middlewares that gets started for each call it then has to get the settingsmanager and call the db?)

    Also the biggest issues - there is no more datamodel for the options? Having to get string keys is really bad in contrast to accessing a simple DTO.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    The Setting module uses cache internally. Of course you can design your own optimized performance plan.

  • User Avatar
    0
    BassaSolutions created

    Ok, thank you for your support.

    For anyone else looking for an answer:

    ABP Settings does not really work with IOptions.

    • ABP ISettingsProvider is dirty to use to get settings (as every module would have access to all settings) + missing DTOs make it easy to have errors
    • IOptions pattern is for settings that do not change after initialization

    We went with a hybrid approach that limits ABP to just storing the settings in the DB and created our own small IOptions alternative that is changeable after startup. Actually a very simple approach.

Made with ❤️ on ABP v9.1.0-preview. Updated on November 19, 2024, 12:56