如何在 ASP.NET Core 中从 .NET Standard 类库项目中读取连接字符串

6
在我的解决方案中,我有一个ASP.NET Core Web项目和一个.NET Standard类库项目。类库项目是数据访问层,我想从我的appsettings.json(ASP.NET Core项目)中读取连接字符串到我的数据访问层。
我找到了一些答案,比如Andrii Litvinov的回答,看起来非常容易实现,但他还提到了通过依赖注入实现的方法。我不想选择简单捷径的方法,而是寻找依赖注入的实现方式?
我不确定在我的类库中拥有appsettings.json并通过IConfigurationRoot进行注册是否是更好的选择(如JRB在这里所解释的那样),但在我的情况下,连接字符串在Web项目的appsettings.json文件中,我希望在我的类库项目中使用构造函数依赖注入实现来使用连接字符串。

1
有人介意告诉我这个投票反对的理由吗? - Learning Curve
可能是如何在.NET Core中读取连接字符串?的重复问题。 - Christian Gollhardt
1
@Christian,我可以看到那个问题中提到了在类库项目中读取它的内容? - Learning Curve
1
据我理解,这指的是在类库项目中创建appsettings.json文件并将其注册到IConfigurationRoot的情况。在我的情况下,我的类库项目中没有任何appsettings文件,我也不需要注册那个已经可以在我的Web项目中访问的IConfiguration。如果我理解有误,请纠正我。 - Learning Curve
1
@Nkosi 关于耦合问题的看法:我不知道哪种方法更真实,是在类库中拥有一个appsetting并将其注册到IConfigurationRoot中,还是通过IConfiguration构造函数依赖注入从Web项目中读取它,就像Alex所回答的那样。XY问题的问题:是的,我可以说它已经进入了XY问题的一面,而Christian的答案则表明了我的问题已经足够清楚,我问如何在我的类库项目中读取asp.net Core appsettings文件以获取连接字符串。 - Learning Curve
显示剩余2条评论
4个回答

9
您可以注入实现了 IConfiguration 接口的类的实例。 请参见此处
假设在您的 .net core 应用程序中,有一个配置文件看起来像这样:
{
  "App": {
    "Connection": {
      "Value": "connectionstring"
    }
  }
}

在您的数据访问层(类库)中,可以依赖于 IConfiguration


(意思是,在数据访问层中,可以使用 IConfiguration 接口作为依赖项)
public class DataAccess : IDataAccess
{
    private IConfiguration _config;

    public DataAccess(IConfiguration config)
    {
        _config = config;
    }

    public void Method()
    {
        var connectionString = _config.GetValue<string>("App:Connection:Value"); //notice the structure of this string
        //do whatever with connection string
    }
}

现在,在您的 ASP.net Core 网站项目中,您需要“连接”(wire up)依赖关系。 在 Startup.cs 中,我正在使用默认模板中的以下内容:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddSingleton<IConfiguration>(Configuration); //add Configuration to our services collection
        services.AddTransient<IDataAccess, DataAccess>(); // register our IDataAccess class (from class library)
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseMvc();
    }
}

现在,当你的类库中的代码被执行时,构造函数将获得你在Web应用程序中设置的 IConfiguration 实例。
注意: 如果您愿意,可以创建强类型的设置类,有关更多信息,请参见此处

为了使用IConfiguration,我需要在我的数据访问层项目中安装Microsoft.Extensions.Configuration包吗? - Learning Curve
@LearningCurve 是的,你会的。 - Alex
3
如果有人在寻找同样的解决方案,这里有一个更新。_config.GetValue不再可用,而是改为使用_config.GetSection。 - Learning Curve
@Alex,我觉得我可能没有正确使用你的建议。在Startup.cs中进行了连接后,我期望构造函数会“传递IConfiguration实例”,但似乎并没有发生这种情况。当构造函数认为它没有得到所需的内容时,我会收到以下错误:“没有提供与'ConnectionManager.ConnectionManager(IConfiguration)'的必需形式参数'config'对应的参数”我需要手动传递“config”吗? - David Mays

4
我建议使用选项模式(Options pattern)。您可以创建包含配置数据的类,例如:
public class ConnectionStringConfig
{
    public string ConnectionString { get; set; }
}

在启动时将其注册:

public void ConfigureServices(IServiceCollection services)
{
   ...    
   services.Configure<ConnectionStringConfig>(Configuration);
}

并将其注入到您的数据访问层中

private readonly ConnectionStringConfig config;

public Repository(IOptions<ConnectionStringConfig> config) 
{
    this.config = config.Value;
}

我在我的问题中已经提到了这种方法(指Andrii Litvinov),出于好奇,您为什么认为这种方法更好,而Andrii本人建议使用依赖注入? - Learning Curve
@LearningCurve 这是一种依赖注入的方法,而Andrii的解决方案则是通过静态类共享值。在应用程序的可测试性方面,DI方法更好。 - Alex Riabov
我想表达的是通过构造函数进行依赖注入。 - Learning Curve
1
我建议除了应用程序的组合根之外,不要在任何地方使用 IOptions<T>,而是让 Repository 类直接依赖于 ConnectionStringConfig,如此处所述:https://simpleinjector.org/aspnetcore#working-with-ioptions-t。 - Steven
@Steven 是正确的。在组合根之外的任何地方使用 IOptions 都是不好的编程实践。 - user10728126
1
@AlexRiabov,我正在查看您的示例,它似乎是一个好的路线,但如何定义要使用哪个连接字符串名称并不清楚。 - c-sharp-and-swiftui-devni

0

我在我的program.cs文件中解决了这个问题,只需添加以下内容:

    builder.Services.AddDbContext<YourContextClassHere>(options =>
    {
        options.UseSqlServer(builder.Configuration.GetConnectionString("Web_Project_app_settings_connection_string_here"));
    });

请注意,在我的项目中,我的上下文类位于类库中,我从 Web 项目引用了该类库。这是针对 .Net Core 6 的。没有任何现有的答案如此明确地提供了解决方案,这就是为什么我觉得值得在这里添加的原因。 - jason

0

这很简单...在启动文件startup.cs或一个独立的类库项目中,像以下代码一样在组合根处使用IOptions:

  services.AddScoped<IDbConnection, OracleConnection>();
        services.AddScoped<IDbConnection, SqlConnection>();
        services.Configure<DatabaseConnections>(configuration.GetSection("DatabaseConnections"));
        services.AddScoped(resolver =>
        {
            var databaseConnections = resolver.GetService<IOptions<DatabaseConnections>>().Value;
            var iDbConnections = resolver.GetServices<IDbConnection>();
            databaseConnections.OracleConnections.ToList().ForEach(ora =>
            {
                ora.dbConnection = iDbConnections.Where(w => w.GetType() == typeof(OracleConnection)).FirstOrDefault();
                ora.dbConnection.ConnectionString = ora.ConnectionString;
                //ora.Guid = Guid.NewGuid();
            });
            databaseConnections.MSSqlConnections.ToList().ForEach(sql =>
            {
                sql.dbConnection = iDbConnections.Where(w => w.GetType() == typeof(SqlConnection)).FirstOrDefault();
                sql.dbConnection.ConnectionString = sql.ConnectionString;
                //sql.Guid = Guid.NewGuid();
            });
            return databaseConnections;
        });

上面使用了 Configuration 类来映射 appsettings.json 部分,其中包含您的连接字符串。以下是 appsettings.json 文件的示例:

      "DatabaseConnections": {
"OracleConnections": [
  {
    "Alias": "TestConnection1",        
    "ConnectionString": "Data Source=(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) (HOST = ) (PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = ) ) );User Id=;Password=;"
  },
  {
    "Alias": "TestConnection2",        
    "ConnectionString": "Data Source=(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) (HOST = ) (PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = ) ) );User Id=;Password=;"
  }
],
"MSSqlConnections": [
  {
    "Alias": "Music",
    "ConnectionString": "Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=C:\\Users\\MusicLibrary.mdf;Integrated Security=True;Connect Timeout=30"
  }
]
}

IOptions 现在让我能够在 startup.cs 中靠近组合根设置我的连接字符串。

这是我用来映射连接字符串的类:

        public class DatabaseConnections : IDatabaseConnections
        {
            public IEnumerable<Connection> OracleConnections { get; set; }
            public IEnumerable<Connection> MSSqlConnections { get; set; }
        }

现在任何服务层都可以访问多个数据库连接和每个请求提供程序!
Github项目:https://github.com/B-Richie/Dapper_DAL

这个解决方案需要使用Dapper DAL吗? - David Mays

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接