首页 > 解决方案 > C# 在构造函数中获取连接详细信息

问题描述

我的数据库类定义如下:

public class DbAdapterService : DbAdapterService
{
      private readonly AppSettings _settings;
      public DbAdapterService(IOptions<AppSettings> settings)
      {
           _settings = settings?.Value;
           DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
           builder.ConnectionString = _settings.ConnectionString;           
      }
}

在上面的类中,我从我的 appsettings.json 中获取我的连接字符串,它工作正常。

现在我们需要从我们类中定义的另一个方法中获取连接字符串用户名和密码。此方法从我们存储的保险库中获取这些详细信息。示例如下:

public class CredentialsService : ICredentialsService 
       {   
         public Credentials GetDetails()
         {
            //return credentials
         }
       }

我的问题是我可以在上面的 DbAdapterService 构造函数中调用这个方法,或者是否有更好的方法来处理这个问题。

谢谢

- 更新 -

public class DbAdapterService : DbAdapterService
{
      private readonly AppSettings _settings;
       public ICredentialsService  _credentialsService;
       private bool isInitialized = false;
      
      public DbAdapterService(IOptions<AppSettings> settings, ICredentialsService  credentialsService)
      {
           _settings = settings?.Value;
           
           _credentialsService = credentialsService;
            if (!isInitialized)
            {
                Initialize(_credentialsService);
            }
           
           DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
           builder.ConnectionString = _settings.ConnectionString;           
      }
      
       public void Initialize(ICredentialsService  credentialsService)
        {
            if (isInitialized)
                return;
            else
            {
               //credentialsService.GetDetails();
                isInitialized = true;
            }          
            
        }
}

标签: c#asp.net.netasp.net-core.net-core

解决方案


您似乎想在构造函数中初始化连接字符串。如果您要使用某些外部组件(例如文件系统、数据库或 API)来检索值,则可能是异步操作。在构造函数中调用异步方法没有可靠的方法。

所以,我们能做些什么?好吧,没有规则说我们必须在构造函数中这样做。构造函数是一个方便的地方,因为它确保在您调用任何其他方法时,初始化已经发生。但是还有其他模式可以实现这一点。这是一个:

public class DbAdapterService : IDbAdapterService
{
    string _connectionString;

    readonly AppSettings _settings;
    readonly ICredentialsService _credentialsService;
    
   public DbAdapterService(IOptions<AppSettings> settings,
                           ICredentialsService  credentialsService)
   {
       _settings = settings.Value;         
       _credentialsService = credentialsService;         
   }

   async Task EnsureInitializedAsync()
   {
       if (!string.IsNullOrEmpty(_connectionString))
       {
           //no need to reinitialize
           //unless the credentials might change during the lifecycle of this object
           return; 
       }

       var credentials = await _credentialsService.GetDetailsAsync();
       var builder = new DbConnectionStringBuilder(_settings.ConnectionString);
       builder.Username = credentials.Username;
       builder.Password = credentials.Password;
       _connectionString = builder.ConnectionString;         
   }

   public async Task DoSomethingAsync()
   {
       await EnsureInitializedAsync();

       //now you can use _connectionString here
   }
}

关键部分是记住在需要使用连接字符串的任何方法中调用 EnsureInitializedAsync()。但至少使用 DbAdapterService 的代码不必知道是否初始化连接字符串。

虽然这种模式对于非异步代码来说不是必需的,但它对于将来可能变得异步的操作非常有用,如果连接的细节可能在运行时实际发生变化,那么这种模式更有意义,但是你的对象是在什么时候构建的你配置 IoC 容器。


推荐阅读