how to make dynamic sql string in asp.net startup.cs? [duplicate] - c#

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

IConfiguration is always NULL .NET CORE in Blazor app / Razor

IConfiguration is always null no matter what i try.. I have also tried to add singleton to the startup class, but always null...
Startup class
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
Here is my Security class
IConfiguration _configuration { get;} **<<always null**
public Security(IConfiguration configuration) **<<always null**
{
_configuration = configuration;
}
public string GetConnectionString()
{
string connectionString = _configuration.GetConnectionString("localDb");
return connectionString;
}
Here is my Index.Razor page
namespace WebbiSkoolsQuizManager.Pages
{
public class IndexBase : ComponentBase
{
public IConfiguration Configuration { get; }
public async Task TryLogin(string user, string pass)
{
}
public async Task AddUserHash(string username, string password)
{
Security secure = new Security(Configuration);
string connectionstring = secure.GetConnectionString();
}
}
}
Appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionKeys": {
"localDb": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=Quiz;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"
},
"AllowedHosts": "*"
}
Thank you in advance, i have searched high and low, regarding a fix for blazor specific but i cant find anything.. (P.S its .Net core 3)
I guess this: public IConfiguration Configuration { get; }
Should be:
[Inject]
public IConfiguration Configuration { get; }
Note: You can't simply define a property of a service, and expect it to be populated... If you're using a Razor component class definition (.cs) as in your case, you can inject the service by using the [Inject] attribute. If you're using a Razor component (.razor), you can either use the #inject directive at the view portion of the component, as for instance:
#page "/"
#inject IConfiguration Configuration
or in the #code section, like this:
#code
{
[Inject]
public IConfiguration Configuration { get; }
}
Note also that if you want to inject a service into a normal C# class, you'll need to use constructor injection
I started a new blazor project (.Net 6) and when I #inject the IConfiguration to my .razor file, the configuration object turns out to be always null.

How to read connection string from appsettings.json in a DBContext file in Asp.Net Core? [duplicate]

This question already has answers here:
Get ConnectionString from appsettings.json instead of being hardcoded in .NET Core 2.0 App
(13 answers)
Closed 3 years ago.
I have defined a connection string in the appsettings.json file. now I want to read it in my TextDBConext file, how can I do it?
public class TestContext: DbContext
{
public DbSet<TestTable> TestTable { get; set; }
public TestContext()
{
}
public IConfiguration Configuration { get; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Connection string"); //I have hardcoded here, but I want from appsettings.json
}
}
Appsettings.json file:
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"connection_string": "Connection String"
}
}
You can setup your db context in the startup file and not override OnConfiguring at all.
Just add a constructor that takes DbContextOptions<TContext> to your DbContext class. This constructor should pass on the parameter to the base class' constructor,
then call AddDbContext<TContext> in your Startup.Configure as follows:
// your TestContext showing constructor
public class TestContext : DbContext
{
public TestContext(DbContextOptions<TestContext> options) : base(options){ }
}
// Then in Startup.cs
public class Startup
{
public IConfiguration Configuration {get;}
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TeamsDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("connection_string")));
}
}
Worth noting is that the AddDbContext<TContext> method has overloads that allow setting the service lifetime for the context to Singleton or Transient if you so wish. The default is Scoped.
You can inject IConfiguration into TestContext constructor and then use GetConnectionString(string name) method to get the connection string.
So..
public class TestContext : DbContext
{
private readonly IConfiguration _configuration;
public TestContext(IConfiguration configuration)
{
_configuration = configuration;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_configuration.GetConnectionString("Your Connection String Name"));
}
}

How to read connection string inside .NET Standard Class library project from ASP.NET Core

In my solution, I have a ASP.NET Core web project and a .NET Standard class library project. Class library project is the data access layer and I want to read the connection string from my appsettings.json (ASP.NET Core project) in my data access layer.
I have found few answers such as by Andrii Litvinov which looks like quite straight forward to implement but he also mentioned about implementing through Dependency Injection. I don't want to choose the easy shortcut way but looking for the dependency injection implementation?
I am not sure if having appsettings.json in my class library and then registering it through IConfigurationRoot is the better option (as explained here by JRB) but in my scenario, the connection string is in the appsettings.json file of the web project and I wan't constructor dependency injection implementation in my class library project to consume the connection string.
You can inject an instance of a class that implements IConfiguration
See Here
Let's assume in your .net core app, you have a configuration file that looks something like this:
{
"App": {
"Connection": {
"Value": "connectionstring"
}
}
}
In your data access layer (class library) you can take a dependency on 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
}
}
Now, in your ASP.net Core web project, you need to 'wire up' your dependency.
In Startup.cs, I'm using this (from the default boilerplate template)
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();
}
}
Now, when your code in your class library gets executed, the ctor gets handed the instance of IConfiguration you have set up in your web app
Note:
You can create strongly typed settings class if you'd prefer, see here for more information
I would suggest Options pattern. You can create the class with configuration data, e.g.:
public class ConnectionStringConfig
{
public string ConnectionString { get; set; }
}
Register it on Startup:
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<ConnectionStringConfig>(Configuration);
}
and inject in your data access layer
private readonly ConnectionStringConfig config;
public Repository(IOptions<ConnectionStringConfig> config)
{
this.config = config.Value;
}
It's pretty simple...use IOptions at the composition root like so in startup.cs or in a separate class library project:
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;
});
Above uses the Configuration class to map the appsettings.json section that houses your connection strings. Here's an example of the appsettings.json file:
"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 now gives me the ability to set my connection string at runtime in startup.cs close to the composition root.
Here's my class I'm using to map my connection strings:
public class DatabaseConnections : IDatabaseConnections
{
public IEnumerable<Connection> OracleConnections { get; set; }
public IEnumerable<Connection> MSSqlConnections { get; set; }
}
Now any service layer has access to multiple db connections and provider per request!
Github project: https://github.com/B-Richie/Dapper_DAL
This was solved for me in my program.cs file just adding this:
builder.Services.AddDbContext<YourContextClassHere>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("Web_Project_app_settings_connection_string_here"));
});

Startup.cs in ASP.NET 5 class library

I created a ASP.NET class library in my ASP.NET5 application. I wanted to add Startup.cs file in order to load some configuration from .json (ConnectionString) file to use it in project and add it to DI. Then I wanted to inject AppSettings into my DbContext which is in the same project. But this is not working, it seems code in Startup class is never executed.
Injecting AppSettings into DbContext throws Exception
InvalidOperationException: Unable to resolve service for type 'Beo.Dal.Properties.AppSettings' while attempting to activate 'Beo.Dal.DataContexts.ApplicationDbContext'.
DbContext
private static bool IsCreated;
private AppSettings AppSettings;
public ApplicationDbContext(AppSettings settings)
{
AppSettings = settings;
if (!IsCreated)
{
Database.AsRelational().ApplyMigrations();
IsCreated = true;
}
}
Did I miss somthing or I got it all wrong? I already got one Startup.cs in MVC project and it works fine. Can I use it in class library at all? If not how should I load this .json?
This is what I was actually doing inside:
public class Startup
{
public AppSettings Settings { get; set; }
public IConfiguration Configuration { get; set; }
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
.AddJsonFile("config.json")
.AddJsonFile($"config.{env.EnvironmentName}.json", optional: true);
builder.AddEnvironmentVariables();
Configuration = builder.Build();
Settings = new AppSettings();
}
public void Configure(IApplicationBuilder app)
{
string connectionString;
if (Configuration.TryGet("Data:DefaultConnection:ConnectionString", out connectionString))
{
Settings.ConnectionString = connectionString;
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddInstance(Settings);
}
}
You can't have a second Startup.cs file because a class library is not a project that can startup. What you should do is take advantage of the dependency injection and add your DbContext to the services. Now when you need the DbContext for your repositories it'll be ready to go.
There is an example in the DI docs for Core http://docs.asp.net/en/latest/fundamentals/dependency-injection.html#using-framework-provided-services

ASP.NET 5 (vNext) - Getting a Configuration Setting

I'm writing a basic app to learn ASP.NET 5. One area I find very confusing is configuration. Prior to ASP.NET 5, I could do the following:
var settingValue = ConfigurationManager.AppSettings["SomeKey"];
I would have lines of code like that sprinkled throughout my code. Now, in the vNext world, I have a config.json file that looks like this:
config.json
{
"AppSettings": {
"SomeKey":"SomeValue"
}
}
Then in Startup.cs, I have the following:
Startup.cs
public IConfiguration Configuration { get; set; }
public Startup(IHostingEnvironment environment)
{
Configuration = new Configuration()
.AddJsonFile("config.json");
}
From there, I'm totally stumped. I have MyClass.cs in /src/Website/Code/Models/MyClass.cs.
MyClass.cs
public class MyClass
{
public string DoSomething()
{
var result = string.Empty;
var keyValue = string.Empty; // TODO: What do I do here? How do I get the value of "AppSettings:SomeKey"?
return result;
}
}
How do I get the value of "AppSettings:SomeKey"?
ASP.NET 5 makes heavy use of Dependency Injection, so if you are also using Dependency Injection then this is very simple. If you examine the sample MVC6 project, you can see how this works:
First, there's a class AppSettings defined in Properties, which is a strongly-typed version of the options your class supports. In the sample project, this just contains SiteTitle.
public class AppSettings
{
public string SiteTitle { get; set; }
}
Then, this class is initialised through dependency injection in ConfigureServices. Configuration here is the one you created in the constructor of the Startup class.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettings>(Configuration.GetSubKey("AppSettings"));
// ...
}
Then, assuming your class is instantiated by the dependency injection container, you can simply ask for an IOptions and you'll get one. For example, in a controller you could have the following:
public class HomeController
{
private string _title;
public HomeController(IOptions<AppSettings> settings)
{
_title = settings.Options.SiteTitle;
}
}
I use ASP.NET 5 dependency injection, like so.
config.json:
{
"random": "Hello World!"
}
startup.cs:
public class Startup
{
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
.AddJsonFile("config.json");
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<IConfiguration>(sp => { return Configuration; });
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc(routes =>
{
routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Controller:
public class HomeController : Controller
{
IConfiguration config;
public HomeController(IConfiguration config)
{
this.config = config;
}
public IActionResult Index()
{
var template = "<marquee>{0}</marquee>";
var content = string.Format(template, config.Get("random"));
return Content(content, "text/html");
}
}
I highly recommend using the OptionsModel instead of reading the configuration directly. It allows strong typed model binding to configuration.
Here is an example: GitHub.com/aspnet/Options/test/Microsoft.Extensions.Options.Test/OptionsTest.cs
For your particular case create a model:
class AppSettings {
public string SomeSetting {get;set;}
}
and then bind it to your configuration:
var config = // The configuration object
var options = ConfigurationBinder.Bind<AppSettings>(config);
Console.WriteLine(options.SomeSetting);
That way you don't have to worry from where the setting comes from, how it is stored or what is the structure. You simply predefine your options model and magic happens.
Use this:
var value = Configuration.Get("AppSettings:SomeKey");
Based on this blog post. The colon is similar to dot notation and is used for navigation down the hierarchy.
If you need the value in other classes, you should inject it in. ASP.NET has built in dependency injection, but if you just need one instance of MyClass you can new it up instead of setting up a DI container.
public IConfiguration Configuration { get; set; }
public Startup(IHostingEnvironment environment)
{
Configuration = new Configuration()
.AddJsonFile("config.json");
//generally here you'd set up your DI container. But for now we'll just new it up
MyClass c = new MyClass(Configuration.Get("AppSettings:SomeKey"));
}
public class MyClass
{
private readonly string Setting; //if you need to pass multiple objects, use a custom POCO (and interface) instead of a string.
public MyClass(string setting) //This is called constructor injection
{
Setting = setting;
}
public string DoSomething()
{
var result = string.Empty;
//Use setting here
return result;
}
}

Categories