[英].Net Core Cant read connection string from appsettings.json
[英]How to read connection string from appsettings.json in DotNetCore 2.2?
這里有很多關於如何做到這一點的帖子,但無論我嘗試什么配置,我似乎都無法獲得我的數據庫連接字符串。 startup.cs 是從 Microsoft 項目模板為 Core 2.2 自動配置的,據我所知,它沒有任何問題。 我沒有使用 EF,也不想加載一些第 3 方黑匣子來讓它工作。
這是 Startup.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace TestWebApplication1
{
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.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// 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();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
這是 appsettings.json 文件:
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Data Source=mydbserver;Initial Catalog=mydatabase;Integrated Security=True;Persist Security Info=False;"
}
}
在另一篇文章中,以下應該可以工作,但不能:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace TestAppWithService
{
public class TestDB
{
string conString = Microsoft.Extensions.Configuration.ConfigurationExtensions.GetConnectionString(this.Configuration, "DefaultConnection");
}
}
名為 TestDB.cs 的文件被設置為編譯,為了踢球,我把它放在根文件夾中(不管我把 class 放在哪里:model,Z594C103F2C6E04C3D18AB059F031 等關鍵字不可用)在當前情況下。 (下面有一條波浪線)。 我不知道如何繼續或尋找什么,這里的答案很多,有各種各樣的調整,但根據 MS,這應該可以正常工作。 我是 dotnetcore 的新手,並認為我已經弄清楚了這種依賴注入的東西,但我仍然卡住了。
這不會編譯
public class TestDB
{
string conString = Microsoft.Extensions.Configuration.ConfigurationExtensions.GetConnectionString(this.Configuration, "DefaultConnection");
}
考慮到它試圖被使用的上下文。
對IConfiguration
的訪問應僅限於組合根,在本例中為Startup
必須在組合根之外注入IConfiguration
可以被視為代碼異味,並且當前的自我回答存在一些應該重構的設計問題。
首先,解決連接字符串問題,應該引入以下支持抽象和實現。
public class ConnectionStrings {
public string DefaultConnection { get; set; }
}
public interface IDbConnectionFactory {
IDbConnection Create(string connectionString);
}
public class SqlConnectionFactory : IDbConnectionFactory {
public IDbConnection Create(string connectionString) {
return new SqlConnection(connectionString);
}
}
public interface IDataProvider {
List<DropDownOption> CalcSelectDDSizeAndTilesPerBoxAll();
}
和數據 class 重構遵循更可靠的設計方法
public class MyDataProvider : IDataProvider {
static string LastErrorMsg = string.Empty;
private readonly string connectionString;
private readonly IDbConnectionFactory connectionFactory;
public MyDataProvider(ConnectionStrings connections, IDbConnectionFactory connectionFactory) {
this.connectionString = connections.DefaultConnection;
this.connectionFactory = connectionFactory;
}
public List<DropDownOption> CalcSelectDDSizeAndTilesPerBoxAll() {
var options = new List<DropDownOption>();
try {
using (IDbConnection connection = connectionFactory.Create(connectionString)) {
using (IDbCommand command = connection.CreateCommand()) {
command.CommandText = "CalcSelectDDSizeAndTilesPerBoxAll";
command.CommandType = CommandType.StoredProcedure;
command.CommandTimeout = 30;
connection.Open();
using (IDataReader r = command.ExecuteReader(CommandBehavior.CloseConnection)) {
while (r.Read()) {
DropDownOption option = new DropDownOption {
value = r["SizeAndNumInBox"].ToString(),
text = r["Descr"].ToString()
};
options.Add(option);
}
}
LastErrorMsg = string.Empty;
}
}
} catch (Exception ex) {
LastErrorMsg = ex.Message;
//consider logging error
options = new List<DropDownOption>();
}
return options;
}
}
注意支持的ConnectionStrings
和IDbConnectionFactory
的顯式注入以及它們如何影響目標CalcSelectDDSizeAndTilesPerBoxAll
function 的實現。
這樣,所有支持的抽象和實現都應該在啟動時注冊
public void ConfigureServices(IServiceCollection services) {
services.Configure<CookiePolicyOptions>(options => {
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
//bind object model
ConnectionStrings connections = Configuration.Get<ConnectionStrings>();
//add it to the service collection so that is accessible for injection
services.AddSingleton(connections);
//register connection factory
services.AddSingleton<IDbConnectionFactory, SqlConnectionFactory>();
//register data provider
services.AddSingleton<IDataProvider, MyDataProvider>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
最后,controller 可以只依賴於它實際需要什么來執行它的 function 而不必充當信使並傳遞注入的成員
public class ServicesController : Controller {
private readonly IDataProvider myData;
public ServicesController(IDataProvider myData) {
this.myData = myData;
}
public IActionResult Index() {
return View();
}
// service returning json for dropdown options fill for tile calculator
public IActionResult GetCalcDDOptions() {
var calcOptions = myData.CalcSelectDDSizeAndTilesPerBoxAll();
return Ok(calcOptions);
}
}
來自 VS2019 (dotnetcore 2.2) 的默認模板,Startup.cs 不需要任何更改。 在 controller 我添加了一些東西:
using Microsoft.Extensions.Configuration;
在我的 controller class 中,我添加了:
private readonly IConfiguration configuration;
public ServicesController(IConfiguration config)
{
this.configuration = config;
}
我更改了 model class 中的方法以接受配置作為參數。 這是從 controller 調用的樣子:
var calcOptions = MyData.CalcSelectDDSizeAndTilesPerBoxAll(this.configuration);
完整的 controller 代碼(供參考):
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using TestAppWithService.Models;
namespace TestAppWithService.Controllers
{
public class ServicesController : Controller
{
private readonly IConfiguration configuration;
public ServicesController(IConfiguration config)
{
this.configuration = config;
}
public IActionResult Index()
{
return View();
}
// service returning json for dropdown options fill for tile calculator
public IActionResult GetCalcDDOptions()
{
var calcOptions = MyData.CalcSelectDDSizeAndTilesPerBoxAll(this.configuration); //note: pass the config to the model
return new ObjectResult(calcOptions);
}
}
}
在 model 中,我添加了:
using Microsoft.Extensions.Configuration;
然后在方法中添加了連接信息參數:
public static List<DropDownOption> CalcSelectDDSizeAndTilesPerBoxAll(IConfiguration config)
在方法內部,獲取數據庫連接字符串很簡單:
string dbconn = config.GetConnectionString("DefaultConnection");
model 的完整代碼:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Extensions.Configuration;
namespace TestAppWithService.Models
{
// This is for custom database functions for services
public class MyData
{
static string LastErrorMsg = string.Empty;
public static List<DropDownOption> CalcSelectDDSizeAndTilesPerBoxAll(IConfiguration config)
{
Boolean HasErrors = false;
var retval = new List<DropDownOption>();
string dbconn = config.GetConnectionString("DefaultConnection");
using (SqlConnection conn = new SqlConnection(dbconn))
{
using (SqlCommand cmd = new SqlCommand("CalcSelectDDSizeAndTilesPerBoxAll", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 30;
try
{
conn.Open();
using (SqlDataReader r = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
if (r.HasRows)
{
while (r.Read())
{
DropDownOption ddo = new DropDownOption();
ddo.value = r["SizeAndNumInBox"].ToString();
ddo.text = r["Descr"].ToString();
retval.Add(ddo);
}
}
}
LastErrorMsg = string.Empty;
}
catch (Exception ex)
{
LastErrorMsg = ex.Message;
HasErrors = true;
}
}
if (!HasErrors)
{
return retval;
}
else
{
return new List<DropDownOption>(); //just an empty list returned
}
}
}
}
}
順便說一句,這里是使用該服務的帶有 JavaScript 的視圖(測試頁):
@{
ViewData["Title"] = "Test";
}
<script type="text/javascript">
$(function () {
$("#btnFillDD").click(function () {
RetrieveCalcOptionsDD();
});
function RetrieveCalcOptionsDD() {
var ddl = $("#TilesInCartonBySize");
var oldEvent = ddl.attr("onchange");
ddl.attr("onchange", ""); //remove change event
$.ajax({
url: '../Services/GetCalcDDOptions',
dataType: 'json',
method: 'get',
success: function (retdata) {
ddl.empty();
$.each(retdata, function () {
ddl.append($("<option></option>").val(this['value']).html(this['text']));
});
},
error: function (err) {
console.log('Error (RetrieveCalcOptionsDD): ' + JSON.stringify(err, null, 2));
}
});
ddl.attr("onchange", oldEvent); //add change event back
};
});
</script>
<h1>Test</h1>
<p><button id="btnFillDD">Click Me</button></p>
<p>
<select id="TilesInCartonBySize" class="calcText" onchange="calculate(this.form);">
</select>
</p>
請注意,此“服務”只是返回 json 的視圖(因此您可以將其用於任何事情)。
一切都很好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.