代码之家  ›  专栏  ›  技术社区  ›  emp

ICredentialProvider与DbContext框架v4结合使用

  •  0
  • emp  · 技术社区  · 6 年前

    我用的是 MultiCredentialProvider 这实现了 Microsoft.Bot.Connector.Authentication.ICredentialProvider 界面它与 static values 但当我试图通过一个使用 DbContext 要检索我的bot凭据,它将失败,并显示以下消息。

    System.InvalidOperationException: An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point. This can happen if a second operation is started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.

    这是因为存储库应该被限定范围,而不仅仅是传递给一个对象以便在以后的阶段使用。存储库在 ConfigureServices 调查方法 Startup

    var sp = services.BuildServiceProvider();
    var repository = sp.GetService<SomeRepository>();
    
    services.AddBot<SomeBot>(options => { 
             options.CredentialProvider = new MultiCredentialProvider(configuration, repository); 
        })
    

    问题是,如何解决按需服务以避免此错误?有没有可能解决整个CredentialProvider,这样我就可以使用构造函数注入?我还缺什么吗?

    --

    更新: 作为一种临时解决方法,我首先从数据库中获取凭据列表,然后构造对象并将凭据传递给 多属性提供者 建造师。唯一的问题是,一切都是在启动时分配的,以后无法更改。仍在寻找更好的解决方案。

    0 回复  |  直到 6 年前
        1
  •  0
  •   emp    5 年前

    我最终编写了一个Func,当需要凭据时会调用它。这些值是缓存的,因此查找成本不高。

    public class MultiCredentialProvider : ICredentialProvider
        {
            private readonly IConfiguration _configuration;
            private readonly Func<Task<List<MultiBotCredential>>> _botCredentialsFunc;
    
            public MultiCredentialProvider(IConfiguration configuration, Func<Task<List<MultiBotCredential>>> botCredentialsFunc)
            {
                _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
                _getBotCredentialsFunc = botCredentialsFunc;
            }
    
            public int BotId => _configuration.GetBotId();
    
            public async Task<bool> IsValidAppIdAsync(string appId)
            {
                var botCredentials = await _botCredentialsFunc.Invoke();
                var credential = botCredentials.FirstOrDefault(x => x.BotId == BotId);
    
                if (credential == null)
                {
                    return false;
                }
    
                return credential.AppId.Equals(appId, StringComparison.InvariantCultureIgnoreCase);
            }
    
            ...
        }
    
        2
  •  0
  •   T.J. McNaboe    3 年前

    在启动时,将凭据提供程序和db上下文添加到服务集合中。将您的凭证提供者创建为作用域服务,并将db上下文添加到其构造函数中,以便可以从DI解析它。一旦提供者从依赖项注入中解析dbcontext,就可以将凭据提供者传递给bot,并在凭据提供者中执行逻辑,从db中检索凭据。
    如果您需要比配置更健壮的东西,您可以选择创建一个botid解析器来解析每个请求的botid。。。也许可以在管道中添加一些查看管线值的内容。

    public void ConfigureServices(IServiceCollection services)
    {
        //OtherServices
        // add your db context to services
        services.AddDbContext<YourDbContext>();
        // setup your credential provider to resolve on every request -scoped
        services.AddScoped<ICredentialProvider, MultiCredentialProvider>();
        // optional create a BotIdResolver that can retrieve the botid at runtime per request for example resolve it from the route
        services.AddScoped<IBotIdResolver, ConfigIdResolver>();
    
    
    }
    public class MultiCredentialProvider : ICredentialProvider
    {
        private readonly IConfiguration _configuration;
        private readonly YourDbContext  _db;
        private readonly BotIdResolver _resolver;
    
        public MultiCredentialProvider(IConfiguration configuration, YourDbContext db,IBotIdResolver botIdResolver = null)
        {
            _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
            _db = db;
            _resolver = botIdResolver;
        }
    
        // optional replace with botIdResolver
        public int BotId => _configuration.GetBotId();
    
        public async Task<bool> IsValidAppIdAsync(string appId)
        {
            // optional use botIdResolver 
            //var id = _resolver.GetId();
            // work with  dbcontext
            //_db.
        }
    
    }