在ASP.NET 5中,使用IConfigurationRoot将应用程序的连接字符串传递到存储库类库

28

我有一个ASP.NET 5 MVC Web应用程序,在Startup.cs中,我看到了公共属性

IConfigurationRoot Configuration 

目前设置为 builder.Build();

在整个MVC Web应用程序中,我可以简单地这样做

Startup.Configuration["Data:DefaultConnection:ConnectionString"]

appsettings.json文件中获取连接字符串。

如何使用构造函数注入将在ASP.NET 5 MVC appsettings.json中指定的连接字符串传递给我的Repository类库?

更新:
以下是所有其他存储库都继承的基本存储库(如您所见,我现在在此处添加了硬编码连接字符串):

public class BaseRepo
{
    public static string ConnectionString = "Server=MYSERVER;Database=MYDATABASE;Trusted_Connection=True;";

    public static SqlConnection GetOpenConnection()
    {
        var cs = ConnectionString;
        var connection = new SqlConnection(cs);
        connection.Open();
        return connection;
    }
}
在我的asp.net 5 web应用程序中,我在appsettings.json文件中拥有以下内容,它相当于在.net 4.5 web应用程序中添加连接字符串:

在我的asp.net 5 web应用程序中,在appsettings.json文件中我有以下内容,这相当于在.net 4.5 web应用程序中添加连接字符串:

  "Data": {
    "DefaultConnection": {
      "ConnectionString": "Server=MYSERVER;Database=MYDATABASE;Trusted_Connection=True;"
    }
  }

此外,在我的 asp.net 5 网站应用程序中,我在 Startup.cs 中有以下默认代码,它将站点配置加载到类型为 IConfigurationRoot 的公共属性中:

 public IConfigurationRoot Configuration { get; set; }
// Class Constructor
        public Startup(IHostingEnvironment env)
        {
            // Set up configuration sources.
            var builder = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json")
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

            if (env.IsDevelopment())
            {
                // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
                builder.AddUserSecrets();
            }

            builder.AddEnvironmentVariables();
            Configuration = builder.Build();
        }

现在在我的asp.net web应用程序中,如果我想要访问任何appsettings,我只需要执行以下操作:Startup.Configuration["Data:DefaultConnection:ConnectionString"]

但不幸的是,我无法从我的类库中执行此操作。

如果有人想要尝试并找出解决方法,请按照以下步骤进行:

  1. 创建一个新的ASP.NET 5 MVC Web应用程序。
  2. 将另一个类型为Class Library(Package)的项目添加到该项目中。
  3. 找出一种方法将appsettings从ASP.NET 5 MVC应用程序传递到Class Library。

更新后,我仍然不能完全理解。这是我的代码:

public class BaseRepo
{
    private readonly IConfigurationRoot config;

    public BaseRepo(IConfigurationRoot config)
    {
        this.config = config;
    }
}

由于BaseRepo现在需要构造函数参数,因此此类声明无法工作。

public class CustomerRepo : BaseRepository, ICustomerRepo
{
    public Customer Find(int id)
    {
        using (var connection = GetOpenConnection())
        {
            ...
        }
    }
}

1
你不应该在各处传递连接字符串,而是应该在 web.config 文件中指定它,并在应用程序代码的一个位置检索它。无论哪个单一点是,它都应该作为依赖项放置在需要它的类中。 - Luke
1
在ASP.NET 5中,没有Web.Config文件,而且有些事情处理方式略有不同。我知道如何在我的Web应用程序中设置连接字符串,但我相信在ASP.NET 5中,我可以使用构造函数注入将其传递给我的数据仓库类库。 - Blake Rivell
1
这篇文章更深入地探讨了问题,我正在尝试使用它来找出解决方案。看起来解决方案是创建一个自定义的AppSettings类。https://weblog.west-wind.com/posts/2015/Jun/03/Strongly-typed-AppSettings-Configuration-in-ASPNET-5 - Blake Rivell
4
我希望了解如何从我的appsettings.json文件获取任何值并将其传递到我的存储库类库中。我知道使用EntityFramework时,DbContext已被注入到存储库类库中。但我不使用Entity Framework,只是用基于字符串的SQL存储库来使用Dapper。因此,我使用连接字符串(我没有)创建SQL连接,然后查询我的数据库。我只需要一种方法来将任何应用程序级别的设置传递到我的存储库类库或业务类库中,使用的是ASP.NET 5. - Blake Rivell
2
你能用你的工作版本更新一下吗? - ganders
显示剩余8条评论
7个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
32

在你的Startup.cs文件中添加以下方法

public void ConfigureServices(IServiceCollection services) {
    services.AddSingleton(_ => Configuration);
}

然后像这样更新您的BaseRepo类:

public class BaseRepo {
    private readonly IConfiguration config;

    public BaseRepo(IConfiguration config) {
        this.config = config;
    }

    public SqlConnection GetOpenConnection() {
        string cs = config["Data:DefaultConnection:ConnectionString"];
        SqlConnection connection = new SqlConnection(cs);
        connection.Open();
        return connection;
    }
}

1
这正是我一直在寻找的!非常感谢。 - Blake Rivell
1
这里有一个问题。当我的子仓库继承自BaseRepo时,我会收到一个错误,说:BaseRepo没有不带参数的构造函数。我正在尝试做类似于public class CustomerRepo: BaseRepo, ICustomerRepo这样的事情。 - Blake Rivell
1
我搞定了!关键是找到了如何将参数传递给基类的方法,就像这样:public CustomerRepo(IConfigurationRoot config) : base(config) { } - Blake Rivell
我认为你在代码中犯了一个错误。你不能将 GetOpenConnection() 设为静态,并且访问实例 config 字段成员。 - James Wilkins
1
使用以下代码替换原有代码: string cs = config.GetConnectionString("DefaultConnection"); - Nick G.
显示剩余11条评论

15

ASP.NET提供了自己的方法来传递配置设置。

假设你在你的appSettings.json文件中有以下代码:

{
  "Config": {
    "Setting1": 1,
    "Setting2": "SO"
  }
}

那么您需要这样的一个类:

public class MyConfiguration
{
    public int Setting1 { get; set; }

    public string Setting2 { get; set; }
}

通过添加以下行,您可以使用此配置来配置您的服务

services.Configure<MyConfigurationDto>(Configuration.GetSection("Config"));

配置 ConfigureServices

然后,您可以通过以下方式在构造函数中注入配置:

public class SomeController : Controller
{
    private readonly IOptions<MyConfiguration> config;

    public ServiceLocatorController(IOptions<MyConfiguration> config)
    {
        this.config = config;
    }

    [HttpGet]
    public IActionResult Get()
    {
        return new HttpOkObjectResult(config.Value);
    }
}

这个例子是针对控制器的。但是你可以在应用程序的其他层中做同样的事情。


在这行代码 services.Configure<MyConfigurationDto>(Configuration.GetSection("Config")); 中,是 MyConfiguration 还是 MyConfigurationDto? - Juan
可能是MyConfiguration。 - Raj K

3

另一种稍微不同的方法是在您的类库中创建一个静态类,在其中从Startup.csConfigure(..)方法中调用一个方法:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ...
    ConnectionManager.SetConfig(Configuration);
}
在这种情况下,我已经在ConfigureServices中将配置添加为单例:
services.AddSingleton(_ => Configuration);

我的ConnectionManager看起来像这样:

public class ConnectionManager
{
    private static IConfiguration currentConfig;

    public static void SetConfig(IConfiguration configuration)
    {
        currentConfig = configuration;
    }

    /// <summary>
    /// Get a connection to the database.
    /// </summary>
    public static SqlConnection GetConnection
    {
        get
        {
            string connectionString = currentConfig.GetConnectionString("MyConnection");
            // Create a new connection for each query.
            SqlConnection connection = new SqlConnection(connectionString);
            return connection;
        }
    }
}

这种方法可能存在关于对象生命周期之类的问题,我并不喜欢 static 类,但据我所知它是可行的。您甚至可以从配置文件中提取 ConnectionString 并仅发送该信息,而不是传递整个 Configuration


喜欢这种方法。因为我需要在我的第四层中使用连接字符串,而且我不想在各个层之间传递配置信息,这让我感到不满意。 - Muzafar Khan

3

我在我的仓库类中有一个构造函数,它接受数据库连接字符串作为参数。当我将我的仓库添加到注入中时,这对我很有效。在startup.cs文件的ConfigureServies()方法中添加以下内容:

services.AddScoped<IRepos>(c => new Repos(Configuration["DbConnections:ConnStr1"]));

IRepos.cs是接口,Repos.cs是实现它的类。当然,Configuration只是对已构建的IConfigurationRoot对象的引用。


2

已经有一个扩展方法可以从aspsettings.json中获取连接字符串。

  1. Define your connection strings in appsettings.json like this:

     {
         "ConnectionStrings": {
             "Local": "Data source=.\\SQLExpress;Initial Catalog=.......",
             "Test:": "Data source=your-server;......"
         },
         "Logging": {
             "IncludeScopes": false,
             "LogLevel": {
                 "Default": "Debug",
                 "System": "Information",
                 "Microsoft": "Information"
             }
         }
    }
    
  2. In your public void ConfigureServices(IServiceCollection services) method inside your Startup.cs, you can get the connection string like this:

    var connectionString = this.Configuration.GetConnectionString("Local");
    
  3. The GetConnectionString extension is from Microsoft.Extensions.Configuration.
  4. Enjoy :)

更新

一开始我不想详细解释,因为这个问题已经被标记为已回答。但是我想在这里加上我的两分钱。

如果你确实需要将整个IConfigurationRoot对象注入控制器中,@Chrono展示了正确的方法。

如果你不需要整个对象,只需获取连接字符串,在ConfigureServices()调用内部将其传递给DbContext,然后将DbContext注入控制器即可。@Prashant Lakhlani 表示了正确的方法。

我只是说,在 @Prashant Lakhlani 的帖子中,你可以使用GetConnectionString扩展来稍微简化代码。


这种方法的限制是你需要在类中引用 Configuration 对象。虽然它存在于 Startup.cs 中,但你需要将其注入到类中。 - ChrisP

1
如果您的项目中的 startUp.cs 文件中包含 ConfigureServices 方法。
services.AddEntityFramework()
             .AddSqlServer()
             .AddDbContext<YourDbContext>(options =>
                 options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

而你的存储库 cs 文件具有以下构造函数注入

public class MyRepo : IRepo
{
    private readonly YourDbContext dbContext;
    public MyRepo(YourDbContext ctx)
    {
        dbContext = ctx;
    }
}
"

YourDbContext将被自动解析。

"

2
很遗憾,我没有使用Entity Framework,因此我没有设置DbContext。我在我的DAL中使用Dapper,因此我只需要应用程序的连接字符串来创建SQL连接。是否仍然有一种方法可以将其从应用程序的设置传递到存储库? - Blake Rivell
从代码上看,你的做法是正确的,能否提供一下你的存储库的通用代码是什么样的? - Prashant Lakhlani

0
你需要做的是在类库项目中创建一个类,以访问网站项目中的appsettings.json并返回连接字符串。
{
    private static string _connectionString;

    public static string GetConnectionString()
    {
        if (string.IsNullOrEmpty(_connectionString))
        {
            var builder = new ConfigurationBuilder()
           .AddJsonFile("appsettings.json");
            Configuration = builder.Build();
            _connectionString = Configuration.Get<string>("Data:MyDb:ConnectionString");
        }
        return _connectionString;
    }
    public static IConfigurationRoot Configuration { get; set; }

}

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