Abp: IOptions<IdentityOptions> doesn't change value when set by ISettingManager

Created on 15 Nov 2019  ·  7Comments  ·  Source: abpframework/abp

In identity module ,
We have a AbpIdentityOptionsFactory to create IdentityOptions by abp Settings module.
That is easy to store identityOptions base on tenant or other SettingValueProvider...
but when i set value by ISettingManager( setting-management module),
identityOptions doesn't know the value is changed, below code:

  var oldValue = IdentityOptions.Value.Password.RequiredLength;
  await settingManager.SetGlobalAsync(IdentitySettingNames.Password.RequiredLength, newValue);
  var updatedValue = IdentityOptions.Value.Password.RequiredLength;

updatedValue should be newValue but it is oldValue.
@hikalkan :
could you tell me how to enhance AbpIdentityOptionsFactory like IOptionsMonitor do .let it can auto change when database(by settingstore) is change.
or is it now enough that , no need to enhance ?

abp-module-identity normal problem

Most helpful comment

Options are cached by aspnet core. I don't know if there is a way of invalidating the cache. I should check it deeper.

All 7 comments

@maliming
thank for reply.
in that unit test doesn't present this question .
it should be in the same scope to modify value and get value directly like

using (var scope1 = ServiceProvider.CreateScope())
{
    var options = scope1.ServiceProvider.GetRequiredService<IOptions<IdentityOptions>>().Value;
    options.Password.RequiredLength.ShouldBe(6); //Default value
    options.Password.RequiredUniqueChars.ShouldBe(1); //Default value 
    _settingProvider.GetOrNullAsync(IdentitySettingNames.Password.RequiredLength).Returns(Task.FromResult("42"));//====>pretend changed by settingManager
    options.Password.RequiredLength.ShouldBe(42);//=====>error,value is 6
}

in fact
it will be fine if modify value by ISettingManager and get value by(IOptions) is in different scope(different http request).
but you should take care in one request the options value is different with db.
so i hope to enhance it to avoid mistake
and this is my test code

    public class SampleAppService : EpsyAppService, ISampleAppService
    {
        public IOptions<IdentityOptions> IdentityOptions { get; set; }
        public ISettingManager _settingManager { get; set; }
        public Volo.Abp.SettingManagement.ISettingManager settingManager { get; set; }
        public SampleAppService(){}
        public async Task<object> PostIdentity(string newValue)
        {
            var oldValue = IdentityOptions.Value.Password.RequiredLength;
            await settingManager.SetGlobalAsync(IdentitySettingNames.Password.RequiredLength, newValue);
            var updatedValue = IdentityOptions.Value.Password.RequiredLength;
            return Task.FromResult(new { oldValue, newValue, updatedValue });
        }
    }

i use it in SampleController to try it.

This is because IOptions is a singleton. I can't think of any way to enhance it.

i found it ASP.NET Core 2.1 源码学习之 Options[3]:IOptionsMonitor
in this article ,the option can watch file change (appsettings.json).
but i have no idea how to do with abp ISettingManager

@hikalkan What do you think?

Options are cached by aspnet core. I don't know if there is a way of invalidating the cache. I should check it deeper.

Currently, options are cached only for a single request. Normally you update the settings in a separate request, so you can get the new values in the next request.
I am moving this to the next milestone since it is not urgent and there is no problem in most cases.

For now, you may want to set options after changing the setting, so other services can get the latest setting value.

Was this page helpful?
0 / 5 - 0 ratings