In my docker-compose.yaml, I'm setting environment variables to an api service with
env_file:
- db.env
db.env
MYSQL_DATABASE=db_name
MYSQL_ROOT_PASSWORD=root
MYSQL_USER=user
MYSQL_PASSWORD=pass
How to access them to connect to the database with a string like this?
string _connectionString = $"server={Env["MYSQL_SERVER_NAME"]}; database={Env["MYSQL_DATABASE"]}; user={Env["MYSQL_USER"]}; password={Env["MYSQL_PASSWORD"]}";
This is an invaluable reference: Configuration in .Net - essentially, a lot of the plumbing is already done for you.
So, if for example you wanted to set that in your startup Program.cs:
var builder = WebApplication.CreateBuilder(args);
....
string _connectionString = $"server={builder.Configuration["MYSQL_SERVER_NAME"]}...
With DI, in a MVC controller for example:
public class SomeController: Controller
{
public SomeController(ILogger<HomeController> logger, IConfiguration configuration)
{
string _connectionString = $"server={configuration["MYSQL_SERVER_NAME"]}....
In a Razor Page:
public class HelloModel: PageModel
{
public HelloModel(ILogger<HomeController> logger, IConfiguration configuration)
{
string _connectionString = $"server={configuration["MYSQL_SERVER_NAME"]}....
Hth..
Related
I'm new to Net Core WebAPI, I'm developing Core Web API without EF. I got stuck were i'm not able to get Connection String from appsetting.json into my Repository
I have created Constructor of CommonRepository and used IConfiguration to get connection string value
public CommonRepository(IConfiguration configuration)
{
_configuration = configuration;
}
private readonly IConfiguration _configuration;
but while creating object of common repository it is giving an error
CommonRepository commonRepository =new CommonRepository();
There is no argument given that corresponds to the required formal parameter 'configuration' of 'CommonRepository.CommonRepository(IConfiguration)'
You could refer the following code to create and use the CommonRepository, then, get the connection string.
CommonRepository:
public interface ICommonRepository
{
string GetConnectionstring();
}
public class CommonRepository : ICommonRepository
{
private readonly IConfiguration _configuration;
public CommonRepository(IConfiguration configuration)
{
_configuration = configuration;
}
public string GetConnectionstring()
{
return _configuration.GetConnectionString("DefaultConnection");
}
}
Register the above repository in the Startup.ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<ICommonRepository, CommonRepository>();
}
Controller:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly ICommonRepository _commonRepositoty;
public HomeController(ILogger<HomeController> logger, ICommonRepository commonRepository)
{
_logger = logger;
_commonRepositoty = commonRepository;
}
public IActionResult Index()
{
var str = _commonRepositoty.GetConnectionstring();
return View();
}
The result like this:
More detail information, see Dependency injection in ASP.NET Core.
This is normally done using dependency injection which should be setup in the startup.cs file. As such:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfiguration>(Configuration);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
}
}
ASP.Net will automatically pass in the config to this class from the host. We use this to create a singleton which will inject the config into all constructors that use IConfiguration as a parameter. Explained Here
I am migrating a web app from asp.net mvc to .net core (.net 5), and this has got me stuck.
The site is configured in IIS to accept request from multiple URLs like site1.example.com and site2.example.com. Each site has its own database, accessed through entity framework core.
In the old .net framework, I was able to use one of the events in the global.asax.cs to parse the incoming request URL and lookup the correct tenant database from a configuration file. I'm trying to set up something similar in asp.net core mvc.
Here's the relevant part of my ConfigureServices method in the startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddSingleton<ITenantIdentifier, UrlTenantIdentifier>();
services.AddDbContext<myDbContext>((serviceProvider, dbContextBuilder) =>
{
var tenantIdentifier = serviceProvider.GetRequiredService<ITenantIdentifier>();
var connectionString = Configuration.GetConnectionString(tenantIdentifier.GetCurrentTenantId() + "myDataModel");
dbContextBuilder.UseSqlServer(connectionString);
}, ServiceLifetime.Scoped);
//other services configured below...
}
Then the tenant identifier looks like this:
public interface ITenantIdentifier
{
string GetCurrentTenantId();
}
public class UrlTenantIdentifier : ITenantIdentifier
{
readonly IHttpContextAccessor _httpContextAccessor;
readonly ILogger<UrlTenantIdentifier> _logger;
public UrlTenantIdentifier(IHttpContextAccessor httpContextAccessor, ILogger<UrlTenantIdentifier> logger)
{
_httpContextAccessor = httpContextAccessor;
_logger = logger;
}
public string GetCurrentTenantId()
{
//_httpContextAccessor is null here
//logic below for parsing URL and finding if we're site1 or site2
}
}
Is there a correct way of doing this now that I'm not aware of? How can I set up the entity framework database context for dependency injection when I don't know the connection string key until runtime? Am I going to be stuck configuring separate sites and virtual directories in IIS?
Refactor the DbContext to override the OnConfiguring member. Inject configuration and context accessor and perform configuration there.
public class myDbContext : DbContext {
private readonly ITenantIdentifier tenantIdentifier;
private readonly IConfiguration configuration;
public myDbContext(IConfiguration configuration, ITenantIdentifier tenantIdentifier) {
this.configuration = configuration;
this.tenantIdentifier = tenantIdentifier;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
var connectionString = configuration
.GetConnectionString(tenantIdentifier.GetCurrentTenantId() + "myDataModel");
optionsBuilder.UseSqlServer(connectionString);
}
}
Trying to access the request context at the time the DbContext is being created/initialized is too early in the request flow to get access to the desired information. It needs to happen after the context has already been initialized and injected.
public void ConfigureServices(IServiceCollection services)
services.AddHttpContextAccessor();
services.AddSingleton<ITenantIdentifier, UrlTenantIdentifier>();
services.AddDbContext<myDbContext>(); //Simplified since configuration is internal
//other services configured below...
}
Reference DbContext Lifetime, Configuration, and Initialization
I'm looking for the best practice way to store a connection string in appsettings.json in a .net Core 2 MVC app (like you do in web.config in MVC 5).
I want to use Dapper not EF (I found many EF examples).
Something like this:
{
"ConnectionStrings": {
"myDatabase": "Server=.;Database=myDatabase;Trusted_Connection=true;"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
Surely there are many examples online? Nothing I can find that is for .net core 2.0.
Several things have changed between 1 and 2 and I want to ensure I'm using version 2 best practices.
I've found this - but it seems to be .net core 1:
Visual Studio 2017 - MVC Core - Part 05 - Connection String from appsettings.json
This uses key value pair appsettings - not the connectionstrings:
Read AppSettings in ASP.NET Core 2.0
Again it's unclear if this is .net Core 1 or 2: Net Core Connection String Dapper visual studio 2017
Define your connection string(s) in appsettings.json
{
"connectionStrings": {
"appDbConnection": "..."
}
}
Read its value on Startup
If you follow the convention and define your connection string(s) under connectionStrings, you can use the extension method GetConnectionString() to read its value.
public class Startup
{
public IConfiguration Configuration { get; private set; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
// Since you said you're using Dapper, I guess you might want to
// inject IDbConnection?
services.AddTransient<IDbConnection>((sp) =>
new SqlConnection(this.Configuration.GetConnectionString("appDbConnection"))
);
// ...
}
}
Use IDbConnection within the repository?
public interface ISpecificationRepository
{
Specification GetById(int specificationId);
}
public SpecificationRepository : ISpecificationRepository
{
private readonly IDbConnection _dbConnection;
public SpecificationRepository(IDbConnection dbConnection)
{
_dbConnection = dbConnection;
}
public Specification GetById(int specificationId)
{
const string sql = #"SELECT * FROM [YOUR_TABLE]
WHERE Id = #specId;";
return _dbConnection
.QuerySingleOrDefault<Specification>(sql,
new { specId = specificationId });
}
}
Just need the connection string in a POCO?
You might use the Options Pattern.
Define a class that exactly matches the JSON object structure in appsettings.json
public class ConnectionStringConfig
{
public string AppDbConnection { get; set; }
}
Register that configuration on Startup
public void ConfigureServices(IServiceCollection services)
{
// ...
services.Configure<ConnectionStringConfig>(
this.Configuration.GetSection("connectionStrings")
);
// ...
}
Receive the accessor in your POCO
public class YourPoco
{
private readonly ConnectionStringConfig _connectionStringConfig;
public YourPoco(IOptions<ConnectionStringConfig> configAccessor)
{
_connectionStringConfig = configAccessor.Value;
// Your connection string value is here:
// _connectionStringConfig.AppDbConnection;
}
}
Notes:
See my sample codes on how to read values from appsettings.json both on Core 1.x and 2.0.
See how I setup if you have more than 1 connection string.
Just put like shown below in appsettings.json.
"ConnectionStrings": {
"DefaultConnection": "Data Source=;Initial Catalog=;Persist Security Info=True;User ID=; Password=;"
}
In Startup.cs fetch it as mentioned below:
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
}
Use dependency injection to inject configuration in controller like mentioned below:
public class MyController : Controller
{
private readonly IConfiguration _configuration;
private string connectionString;
public MyController(IConfiguration configuration)
{
_configuration = configuration;
connectionString = _configuration.GetConnectionString("DefaultConnection");
}
}
Check my controller code bellow. The thing is i am using first AccountController to access my database context and second one want to access of my appsettings.json file with IConfiguration. But C# not giving to to name same named controller. So how can i access IConfiguration and database context at a time on same Controller file? Please note: I am using .net core mvc 2.1 Picture attached with error. Thanks in advance
Controller code:
public class AccountController : Controller
{
public AppDataCtx DataCtx { get; }
public AccountController(AppDataCtx DataCtx)
{
this.DataCtx = DataCtx;
}
private IConfiguration _configuration;
public IConfiguration AccountController(IConfiguration Configuration)
{
_configuration = Configuration;
}
}
I'm trying to get connection string dynamically from appsettings.json file. I see that I can do that via Configuration property of startup class. I've marked Configuration field as static field and access it across the app.
I'm wondering if there is a better way to get connection string value from .NET Core app.
You can check my blog article on ASP.NET Core Configuration here.
In it I also go through Dependency Injection of configuration options.
Quote:
There are a couple ways to get settings. One way would be to use the
Configuration object in Startup.cs.
You can make the configuration available in your app globally through
Dependency Injection by doing this in ConfigureServices in Startup.cs:
services.AddSingleton(Configuration);
You can do a thread-safe Singleton of your IConfiguration variable declared in the Startup.cs file.
private static object syncRoot = new object();
private static IConfiguration configuration;
public static IConfiguration Configuration
{
get
{
lock (syncRoot)
return configuration;
}
}
public Startup()
{
configuration = new ConfigurationBuilder().Build(); // add more fields
}
private readonly IHostingEnvironment _hostEnvironment;
public IConfiguration Configuration;
public IActionResult Index()
{
return View();
}
public ViewerController(IHostingEnvironment hostEnvironment, IConfiguration config)
{
_hostEnvironment = hostEnvironment;
Configuration = config;
}
and in class that you want connection string
var connectionString = Configuration.GetConnectionString("SQLCashConnection");