Dot-Net-Core

IConfigureOptions<T> 沒有創建範圍選項

  • February 22, 2018

通常Options是單例。但是我正在從數據庫中建構選項,其中一個選項屬性是密碼,每個月都在變化。所以我想創建Scoped選項的實例。我正在使用IConfigureOptions&lt;T&gt;如下方式從數據庫建構選項

public class MyOptions
{
  public string UserID {get;set;}
  public string Password {get;set;
}

public class ConfigureMyOptions : IConfigureOptions&lt;MyOptions&gt;
{
   private readonly IServiceScopeFactory _serviceScopeFactory;
   public ConfigureMyOptions(IServiceScopeFactory serviceScopeFactory)
   {
       _serviceScopeFactory = serviceScopeFactory;
   }

   public void Configure(MyOptions options)
   {
       using (var scope = _serviceScopeFactory.CreateScope())
       {
           var provider = scope.ServiceProvider;
           using (var dbContext = provider.GetRequiredService&lt;MyDBContext&gt;())
           {
               options.Configuration = dbContext.MyOptions
                                       .SingleOrDefault()
                                       .Select(x =&gt; new MyOptions()
                                       {
                                           UserID = x.UserID,
                                           Password = x.Password
                                       });
           }
       }
   }
}

在控制器中使用它

   public class HomeController : BaseController
   {
       private readonly MyOptions _options;
       public HomeController(IOptions&lt;MyOptions&gt; option)
       {
           _options = option.Value;
       }

       [HttpGet]
       [Route("home/getvalue")]
       public string GetValue()
       {
           // do something with _options here
           return "Success";
       }
   }

我想MyOptions為每個新請求創建一個實例,因此將其註冊為Scoped在 startup.cs

services.AddScoped&lt;IConfigureOptions&lt;MyOptions&gt;, ConfigureMyOptions&gt;();

但是,當我將調試器放在 ConfigureMyOptions 的 Configure 方法中時,它只會在第一個請求中被命中一次。對於下一個請求,容器返回相同的實例(如單例)。

如何在此處設置範圍,以便為每個請求創建 MyOptions?

在您的控制器中使用IOptionsSnapshot而不是,IOptions它將根據請求重新創建選項。


為什麼不適用於IOptions

Configuration API 的.AddOptions擴展方法將OptionsManager實例註冊為單例IOptions&lt;&gt;

services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions&lt;&gt;), typeof(OptionsManager&lt;&gt;)));
services.TryAdd(ServiceDescriptor.Scoped(typeof(IOptionsSnapshot&lt;&gt;), typeof(OptionsManager&lt;&gt;)));

OptionsManager在內部使用記憶體

public virtual TOptions Get(string name)
{
    name = name ?? Options.DefaultName;

    // Store the options in our instance cache
    return _cache.GetOrAdd(name, () =&gt; _factory.Create(name));
}

github 上的以下問題有助於在上面找到:OptionsSnapshot 應該始終根據請求重新創建

引用自:https://stackoverflow.com/questions/48914513