Store / Retrieve ConnectionString from appSettings.json in ASP.net Core 2 MVC app - asp.net-core

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");
}
}

Related

ASP.NET Core how to init connection string in first run-time?

I am building an enterprise application and i want for the first time the use run the website to be able to choose the SQL server to connect to, and the Database in that server. after that the application always run on that configurations like normal asp.net core app do.
I know that connection string is stored in appsettings.json so i was thinking about changing it's value at run-time after choosing this configuration, but after searching a lot i think this is not possible.
What do suggest is there a way to do this ?
Set reloadOnChange to true when you are adding appsettings.json to ConfigurationBuilder:
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
then create a class for connection string
public class ConnectionString
{
public string Default {get; set;}
}
And in ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.Configure<ConnectionString>(Configuration.GetSection("ConnectionStrings"));
}
Now this configuration is available through dependency injection.
public class HomeController : Controller
{
private readonly ConnectionString _connectionString;
public HomeController(IOptionsSnapshot<ConnectionString> connectionString)
{
_connectionString = connectionString.Value;
}
}
IOptionsSnapshot can reload configuration data when it changes.
More info about Configuration.
You must to load the appsettings.json file in Program.cs
public static void Main(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false)
.Build();
string conStr = configuration.GetConnectionString("DefaultConnection");
// your code
var host = WebHost.CreateDefaultBuilder();
host.Run();
}
Make sure that you have installed following NuGet Packages before connect to the SQL Server Db.
First you have to create connection strings in appsettings.json like below
"ConnectionStrings": {
"DefaultConnection": "Server=DESKTOP-O57GSNN\\MSSQLSERVERNEW,Database=BookListRazor;Trusted_Connection=True;MultipleActiveResultSets=True"},
Here, DefaultConnection is connection Name you are going to use.Please provide any meaningful name you want and it will be use when configuring.Also provide Server Name from SQL Server Management Studio(see the picture below) and Provide a name for your database (Will be created).
Then create ApplicationDbContext.cs file and type below code
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Book> Book { get; set; }
}
Book is the Model in my App.
Finally configure it with SQL Server configuration inside ConfigureServices method in Startup.cs file.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(option => option.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddRazorPages().AddRazorRuntimeCompilation();
}
DefaultConnection is connection Name which was already mentioned in appsettings.json

How to pass IOptions through Dependency injection to another Project

I have a WebApplication targetting .net core.
I have also created a Class Library targetting .net core as well.
I am creating a Users Repository following this Dapper tutorial Here
It would be nice to be able to provide the option that was injected in start up of the WebApplication into the project that will be the data access layer.
Here is the code for the Users Repository in a separate project.
class UsersRepository
{
private readonly MyOptions _options;
private string connectionString;
public UsersRepository(IOptions iopt/// insert Option here )
{
_options = iopt.Value;
connectionString = _options.connString;
}
public IDbConnection Connection
{
get
{
return new SqlConnection(connectionString);
}
}
The WebApplication Project Startup looks as follows.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<MyOptions>(Configuration);
services.AddMvc();
}
and of course MyOptions is a class in the web application that has only one property connString
One possible design is to make a new interface for your repository configuration inside your class library, and have your MyOptions type implement that interface.
For example, in your class library you can do the following:
public interface IRepositoryConfig
{
string ConnectionString { get; }
}
public class UserRepository
{
public UserRepository(IRepositoryConfig config)
{
// setup
}
}
And in your WebAPI Startup class you can wire this up as follows:
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<MyOptions>(Configuration);
services.AddMvc();
services.AddScoped<IRepositoryConfig>(s =>
s.GetService<IOptions<MyOptions>>().Value
);
services.AddScoped<UserRepository>();
}
Doing this will allow you to use the Asp.Net Core configuration/options framework without having to reference any Asp.Net DLLs in your class library directly.

Best practices for config file in netcoreapp1.1

I have added the access to the appsettings.json file as a framework service in my Startup.cs:
public IConfigurationRoot Configuration { get; }
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.Configure<AppConfig>(Configuration);
services.AddMvc();
}
So now I have access to the configuration file from my controllers:
public class HomeController : Controller
{
private readonly AppConfig _appConfig;
public HomeController(IOptions<AppConfig> appConfig, ConfigContext configContext)
{
_appConfig = appConfig.Value;
}
}
That's working but what's currently a good practice in netcoreapps for accessing the config file from classes outsite my controller scope?
I mean that I would not like to pass always the required config variables to other methods, example:
public IActionResult AnyAction() {
SomeStaticClass.SomeMethod(_appConfig.var1, _appConfig.var2, _appConfig.var3...)
//or always have to pass the _appConfig reference
SomeStaticClass.SomeMethod(_appConfig)
}
In previous versions of .NET Framework if I required access to the config file from "SomeStaticClass" I used to use ConfigurationManager in any class that I need access to the web.config.
What's the correct way to do it in a netcoreapp1.1 ? either ConfigurationManager like or dependency injection approach works for me.
I think this question is more about how you can get a contextual variable from a static class. I think this will accomplish what you want but I'm not sure why you want a static class or what you are trying to do with it (see XY Problem).
public class HomeController : Controller
{
private readonly AppConfig _appConfig;
public HomeController(IOptions<AppConfig> appConfig, ConfigContext configContext)
{
_appConfig = appConfig.Value;
SomeStaticClass.SomeStaticMember = appConfig.Value
}
public IActionResult AnyAction() {
SomeStaticClass.SomeMethod(); //The get the value you want from within
}
}
EDIT:
You can use Newtonsoft.Json, it's a dependency of Microsoft.AspNet.Mvc.ModelBinding which is a dependency of Microsoft.AspNet.Mvc
string fileContents = string.Empty;
using (StreamReader file = File.OpenText(#".\appsettings.json"))
{
fileContents = file.ReadAllLines();
}
configs= JsonConvert.DeserializeObject(fileContents );
What I did is to create the following class:
public static class Configuration
{
private static IConfiguration _configuration;
static Configuration()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
_configuration = builder.Build();
}
public static string GetValue(string key)
{
return _configuration.GetValue<string>(key, null);
}
public static string GetValue(string section, string key)
{
return _configuration.GetSection(section).GetValue<string>(key);
}
}
However it doesn't use the environment logic that is used in Startup.cs using the IHostingEnvironment parameter.

How to change App.config to json config file in .Net Core

my project uses App.config to read config property. Example:
ConfigurationManager.AppSettings["MaxThreads"]
Do you know of a library which I can use to read config from json. Thanks.
The ConfigurationManager static class is not generally available in ASP.NET Core. Instead you should use the new ConfigurationBuilder system and strongly typed configuration.
For example, by default, a configuration is built up in your Startup class using something similar to the following:
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)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
This will load configuration from the appsettings.json file and append the keys the configuration root. If you have an appsettings file like the following:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"ThreadSettings" : {
"MaxThreads" : 4
}
}
Then you can then create a strongly typed ThreadSettings class similar to the following:
public class ThreadSettings
{
public int MaxThreads {get; set;}
}
Finally, you can bind this strongly typed settings class to your configuration by adding a Configure method to your ConfigureServices method.
using Microsoft.Extensions.Configuration;
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ThreadSettings>(Configuration.GetSection("ThreadSettings"));
}
You can then inject and access your settings class from anyother place by injecting it into the constructor. For example:
public class MyFatController
{
private readonly int _maxThreads;
public MyFatController(ThreadSettings settings)
{
maxThreads = settings.MaxThreads;
}
}
Finally, if you really need access to the underlying configuration you can also inject that in ConfigureServices to make it available in your classes.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(Configuration);
}
You can read more about configuration on the docs or on various blogs

Setting Up ASP.NET Identity Core in an empty ASP.NET Core Web Application

I am trying to start a new web application project and I wanted to use the asp.net identity database (the one with all the AspNet tables (AspNetUsers, AspNetRoles etc)).
I have tried to follow numerous guides, these among other:
bitoftech.net/2015/01/21/asp-net-identity-2-with-asp-net-web-api-2-accounts-management/
johnatten.com/2014/04/20/asp-net-mvc-and-identity-2-0-understanding-the-basics/
tektutorialshub.com/asp-net-identity-tutorial-basics/%20%22ASP.Net%20Identity%20Tutoria
benfoster.io/blog/aspnet-identity-stripped-bare-mvc-part-1
However when I tried to create the database I get this error.
I have also tried to do it by mimicking the template project (ASP.NET Core Web Application(.Net Core)) in Visual Studio with the same result or this one
This is how my project looks like, its basically the template minus the Controllers, Views and Models.
Startup.cs
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath);
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
//var connectionString = #"Data Source=(localdb)\mssqllocaldb;Initial Catalog=Northwind;Integrated Security=True;Pooling=False";
//services.AddEntityFramework()
// .AddSqlServer()
// .AddDbContext<NorthwindContext>(o =>
// o.UseSqlServer(connString));
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
app.UseDeveloperExceptionPage();
app.UseStaticFiles();
app.UseIdentity();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
ApplicationUser.cs
public class ApplicationUser : IdentityUser
{
}
ApplicationDbContext.cs
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
I just want to have an empty project with asp.net identity, preferably in SQL server instead of in localdb. Does anyone have a easy guide or know why it does not work for me?
EDIT1
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : this("Data Source=ACLAP;Initial Catalog=tmpCore;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False") { }
}
EDIT2
I have put up the project on github.
github.com/KiBlob/test
Just an idea, do you have defined the DefaultConnection in your appsettings.json file?
Mine looks like this:
{
"ConnectionStrings": {
"DefaultConnection": "Server=[SERVER];Database=[DB];Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
Try setting the connection there and then run Update-Database again.
Note: If you have multiple projects in your solution, make sure that the Default project in the package manager console is pointing to the project where the connection is set before running Update-Database.