Reputation: 14214
I am building a class library using C# and .NET Core. I am trying to use configuration from a config.json
file. Here are the contents of that file:
config.json
{
"emailAddress":"someone@somewhere.com"
}
In an attempt to use config.json
for my configuration, I'm referencing Microsoft.Framework.ConfigurationModel.Json
in my project.json
file. In my code, I have the following:
MyClass.cs
using Microsoft.Framework.ConfigurationModel;
public class MyClass
{
public string GetEmailAddress()
{
// This is the approach I had been using since .NET 2.0:
// return ConfigurationManager.AppSettings["emailAddress"];
return ?; // What goes here?
}
}
Since .NET 2.0, I had been using ConfigurationManager.AppSettings["emailAddress"]
. However, I'm now trying to learn how to do it the new way via IConfiguration
. My problem is, this is a class library. For that reason, I'm not sure how, or where, or when, the configuration file gets loaded. In traditional .NET, I just needed to name a file web.config
for ASP.NET projects and app.config
for other projects. Now, I'm not sure. I have both an ASP.NET MVC 6 project and an XUnit project. So, I'm trying to figure out how to use config.json
in both of these scenarios.
Thank you!
Upvotes: 76
Views: 155164
Reputation: 2379
Supports both appSettings.json and appSettings.Development.json:
using Microsoft.Extensions.Configuration;
using System.IO;
public static class Config
{
private static IConfiguration configuration;
static Config()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appSettings.json", optional: true, reloadOnChange: true)
.AddJsonFile("appSettings.Development.json", optional: true, reloadOnChange: true);
configuration = builder.Build();
}
public static string Get(string name)
{
string appSettings = configuration[name];
return appSettings;
}
public static IConfigurationSection GetSection(string name)
{
return configuration.GetSection(name);
}
}
Section
var cosmosDb = new CosmosDbProviderConfiguration();
Config.GetSection(CosmosDbProviderConfiguration.CosmosDbProvider).Bind(cosmosDb);
Key
var email = Config.Get("no-reply-email");
Upvotes: 34
Reputation: 6943
In .NET 6.0+ This was the solution I found for getting the connectionString for entity framework. There were some issues finding the correct nuget package (Microsoft.Extensions.Configuration.Json). Hopefully this saves everyone some trouble.
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
//nuget package: Microsoft.Extensions.Configuration.Json
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json");
var builder = new ConfigurationBuilder();
builder.AddJsonFile(path);
var root = builder.Build();
var connectionString = root.GetSection("ConnectionStrings").GetSection("DefaultConnection").Value;
optionsBuilder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
}
}
Upvotes: 3
Reputation: 1133
In case someone want to see it, for Asp.net Core .Net 5.0 example. I have gone through above answers and tweak my code little bit for my application.
If you want to see how to use this into console application visit my answer on this link, I have added example with email address as well.
My AppSettings.Json is:
{
"AppSettings": {
"FTPLocation": "\\\\hostname\\\\c$\\\\FTPMainFolder\\\\ftpFolder\\\\Test\\",
"FTPUri": "ftp://hostname.domainname.com/foldername/",
"CSVFileName": "Test Load Planning.csv"
},
"ConnectionStrings":
{
"AppDbConnString": "Server=sqlserverhostname.domainname.com;Database=DBName;Trusted_Connection=True; MultipleActiveResultSets=true" },
"ADSecurityGroups": { "UserSecurityGroups": "AD-DL-GROUP-NAME;AD-DL-GROUP2-NAME"},
"Logging":
{
"LogLevel": {
"Default": "Warning"
}
}
}
My LoginController.cs is:
using Microsoft.Extensions.Configuration;
public class LoginController : BaseController
{
private readonly ILoginDataServices _loginDataServices;
private readonly IConfiguration _configuration;
public IActionResult Index()
{
return View();
}
public LoginController(ILoginDataServices loginDataServices, IConfiguration configuration)
{
_loginDataServices = loginDataServices;
_configuration = configuration;
}
public bool CheckLogin(string userName, string password)
{
if (CheckIfValidEmployee(userName))
{
//////checking code here....
}
else
{
return false;
}
}
bool CheckIfValidEmployee(string userName)
{
var securityGroups = _configuration.GetSection("ADSecurityGroups:UserSecurityGroups").Value.Split(';');
Console.WriteLine(securityGroups);
////////Code to check user exists into security group or not using variable value
}
Upvotes: -1
Reputation: 11
You can also set properties of the class library with right-click on a .csproject -> properties-> settings-> add a new property in the right window. Make sure to select access modifier as public in Access Modifier dropdown.
Now, add a class library project reference to your .net core project.
Create appSettings.cs class as mentioned below
public class AppSettings
{
public string MyConnectionString { get; set; }
}
Set key-value appSettings.json
"AppSettings": {
"MyConnectionString": "yourconnectionstring",
},
Now, we just need to get connection string from appSettings.json and set properties into class library in Startup.cs as below.
// This method gets called by the runtime. Use this method to add services to the container
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
// inject App setting
var appSettingSection = Configuration.GetSection("AppSettings");
services.Configure<AppSettings>(appSettingSection);
var appsetting = appSettingSection.Get<AppSettings>();
// set connection string in .csproject properties.
classLibraryProject.Properties.Settings.Default.Properties["MyConnectionString"].DefaultValue = appsetting.MyconnectionString;
}
Note:
I hope this may help.
Upvotes: 0
Reputation: 1402
Never used it but a quick search lead me to this...
var configuration = new Configuration();
configuration.AddJsonFile("config.json");
var emailAddress = configuration.Get("emailAddress");
Maybe you could try that.
Upvotes: 22
Reputation: 2397
IMO class libraries should be agnostic to application settings data. Generally, the library consumer is the one concerned with such details. Yes, this isn't always true (e.g. if you have a class that does RSA encryption/decryption, you may want some private configuration to allow for the private key gen/storage), but for the most part, it is true.
So, in general, try to keep application settings out of the class library and have the consumer provide such data. In your comment you mention a connection string to a database. This is a perfect example of data to be kept OUT of a class library. The library shouldn't care what database it's calling to to read, just that it needs to read from one. Example below (I apologize if there's some mistakes as I am writing this on the fly from memory):
Library
Library class that uses a connection string
public class LibraryClassThatNeedsConnectionString
{
private string connectionString;
public LibraryClassThatNeedsConnectionString(string connectionString)
{
this.connectionString = connectionString;
}
public string ReadTheDatabase(int somePrimaryKeyIdToRead)
{
var result = string.Empty;
// Read your database and set result
return result;
}
}
Application
appsettings.json
{
"DatabaseSettings": {
"ConnectionString": "MySuperCoolConnectionStringWouldGoHere"
}
}
DatabaseSettings.cs
public class DatabaseSettings
{
public string ConnectionString { get; set; }
}
Startup.cs
public class Startup
{
public Startup(IHostingEnvironment env)
{
Configuration = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables()
.Build();
}
public IConfigurationRoot Configuration { get; }
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// Setup logging
// Configure app
}
public void ConfigureServices(IServiceCollection services)
{
// Configure services
services.Configure<DatabaseSettings>(Configuration.GetSection("DatabaseSettings"));
services.AddOptions();
// Register our class that reads the DB into the DI framework
services.AddTransient<IInterfaceForClass, ClassThatNeedsToReadDatabaseUsingLibrary>();
}
}
Class that uses the library class to read the database
public interface IInterfaceForClass
{
string ReadDatabaseUsingClassLibrary(int somePrimaryKeyIdToRead);
}
public class ClassThatNeedsToReadDatabaseUsingLibrary : IInterfaceForClass
{
private DatabaseSettings dbSettings;
private LibraryClassThatNeedsConnectionString libraryClassThatNeedsConnectionString;
public ClassThatNeedsToReadDatabaseUsingLibrary(IOptions<DatabaseSettings> dbOptions)
{
this.dbSettings = dbOptions.Value;
this.libraryClassThatNeedsConnectionString = new LibraryClassThatNeedsConnectionString(this.dbSettings.ConnectionString);
}
public string ReadDatabaseUsingClassLibrary(int somePrimaryKeyIdToRead)
{
return this.libraryClassThatNeedsConnectionString.ReadTheDatabase(somePrimaryKeyIdToRead);
}
}
Some controller class that handles UI stuff to read from the DB
public class SomeController : Controller
{
private readonly classThatReadsFromDb;
public SomeController(IInterfaceForClass classThatReadsFromDb)
{
this.classThatReadsFromDb = classThatReadsFromDb;
}
// Controller methods
}
TL;DR
Try to avoid using application settings in a class library. Instead, have your class library be agnostic to such settings and let the consumer pass those settings in.
Edit:
I added in dependency injection into a controller class to demonstrate using dependency injection to build the class that reads from the DB. This lets the DI system resolve the necessary dependences (e.g. the DB options).
This is one way of doing it (and the best way). Another way is to inject the IOptions into the controller and manually newing up the class that reads from the DB and passing the options in (not best practice, DI is a better way to go)
Upvotes: 118
Reputation: 1049
First in your .csproj
file add a target that hocks in the build process, see the link for more options if the following doesn't fit your needs, like publication
<Target Name="AddConfig" AfterTargets="AfterBuild">
<Copy SourceFiles="config.json" DestinationFolder="$(OutDir)" />
</Target>
you can use it like follows
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Extensions.Configuration;
using System;
public class MyClass {
public string GetEmailAddress() {
//For example purpose only, try to move this to a right place like configuration manager class
string basePath= System.AppContext.BaseDirectory;
IConfigurationRoot configuration= new ConfigurationBuilder()
.SetBasePath(basePath)
.AddJsonFile("config.json")
.Build();
return configuration.Get("emailAddress");
}
}
Upvotes: 4