ASP.NET Core MVC App Settings - asp.net-core

I'm trying to use configuration variables on my ASP.NET Core MVC project.
This is where I've got so far:
Created an appsettings.json
Created an AppSettings class
Now I'm trying to inject it on the ConfigureServices, but my Configuration class is either not recognized or when using the full reference: "Microsoft.Extensions.Configuration" the GetSection Method is not recognized, i.e.
Configuration class not being recognized
GetSection method not being recognized
Any ideas on how to use this?

The whole configuration approach in .NET Core is really flexible, but not at all obvious at the beginning. It's probably easiest to explain with an example:
Assuming an appsettings.json file that looks like this:
{
"option1": "value1_from_json",
"ConnectionStrings": {
"DefaultConnection": "Server=,\\SQL2016DEV;Database=DBName;Trusted_Connection=True"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
To get the data from appsettings.json file you first need to set up a ConfigurationBuilder in Startup.cs as follows:
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);
if (env.IsDevelopment())
{
// For more details on using the user secret store see https://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets<Startup>();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
You can then access the configuration directly, but it's neater to create Options classes to hold that data, which you can then have injected into your controller or other classes. Each of those options classes represent a different section of the appsettings.json file.
In this code the connections strings are loaded into a ConnectionStringSettings class and the other option is loaded into a MyOptions class. The .GetSection method gets a particular part of the appsettings.json file. Again, this is in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
... other code
// Register the IConfiguration instance which MyOptions binds against.
services.AddOptions();
// Load the data from the 'root' of the json file
services.Configure<MyOptions>(Configuration);
// load the data from the 'ConnectionStrings' section of the json file
var connStringSettings = Configuration.GetSection("ConnectionStrings");
services.Configure<ConnectionStringSettings>(connStringSettings);
These are the classes that the settings data are loaded into. Note how the property names pair up with the settings in the json file:
public class MyOptions
{
public string Option1 { get; set; }
}
public class ConnectionStringSettings
{
public string DefaultConnection { get; set; }
}
Finally, you can then access those settings by injecting an OptionsAccessor into the controller as follows:
private readonly MyOptions _myOptions;
public HomeController(IOptions<MyOptions > optionsAccessor)
{
_myOptions = optionsAccessor.Value;
var valueOfOpt1 = _myOptions.Option1;
}
Generally, the whole configurations settings process is pretty different in Core. Thomas Ardal has a good explanation of it on his site here: http://thomasardal.com/appsettings-in-asp-net-core/
There's also a more detailed explanation of Configuration in ASP.NET Core in the Microsoft documentation.
NB: This has all evolved a bit in Core 2, I need to revisit some of the answer above, but in the meantime this Coding Blast entry by Ibrahim Ĺ uta is an excellent introduction with plenty of examples.
NB No. 2: There are a number of configuration mistakes that are easy to make with the above, have a look at this answer if it doesn't behave for you.

tomRedox 's answer was highly helpful - Thanks.
Also, I've changed the following references to the following versions, to get it working.
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.2",
"Microsoft.Extensions.Configuration.Json": "1.1.1"

Related

Configure JwtBearerOptions from a configuration file

I am trying to find a documentation how to configure a jwt bearer and its JwtBearerOptions in asp.net core from a configuration file using a microsoft predefined confuration section/keys. There is no explanation in Mucrosoft docs about this is possible or not. I feel that it should be possible because everything in the .net core generation is using the options pattern.
Here is an example how the same technique is used to configure a Kestrel host.
This is not a real answer to the initial question. However I am very happy with this solution.
After several hours of digging into the AspNetCore source code I found that the JwtBearerOptions are added to the DI as a named options. This means that you cannot provide the configuration from a config file without writing code. However I found an acceptable solution which will work for the majority of cases.
I do not have a list of all available keys and the sample here is showing only two of them. You can inspect the public properties of the JwtBearerOptions and add them in the appsettings.json. They will be picked and used by the framework.
See the code bellow and the comments there for details how this works:
appsettings.json
{
"Cronus": {
"Api": {
"JwtAuthentication": {
"Authority": "https://example.com",
"Audience": "https://example.com/resources"
}
}
}
}
Startup.cs
public class Startup
{
const string JwtSectionName = "Cronus:Api:JwtAuthentication";
private readonly IConfiguration configuration;
public Startup(IConfiguration configuration)
{
this.configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
// Gets the settings from a configuration section. Notice how we specify the name for the JwtBearerOptions to be JwtBearerDefaults.AuthenticationScheme.
services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, configuration.GetSection(JwtSectionName));
// OR
// Gets the settings from a configuration. Notice how we specify the name for the JwtBearerOptions to be JwtBearerDefaults.AuthenticationScheme.
services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, configuration);
services.AddAuthentication(o =>
{
// AspNetCore uses the DefaultAuthenticateScheme as a name for the JwtBearerOptions. You can skip these settings because .AddJwtBearer() is doing exactly this.
o.DefaultAuthenticateScheme = Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer();
}
}
services.AddAuthentication(defaultScheme: JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(o => Configuration.Bind("JwtBearerOptions", o));
where
application settings.json
{
"JwtBearerOptions": {
"Audience": "Your aud"
}
}

ASP.NET Core 2.x OnConfiguring get connectionstring string from appsettings.json

Just started messing with ASP.NET Core, pretty impressive so far. In the code generated,(see below). I want to change the hardcoded connection string to get it from the appsettings.json file.
This is apparently impossible. I haven't found a single example that works (or even builds).
What's going on??
Please help
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseSqlServer("Server=xxxxxxx;Database=xxxxx;Trusted_Connection=True;");
}
}
The link provided solves the problem in one area but doesn't work here in OnConfiguring. What am I doing wrong ?
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_1);
var connection = Configuration.GetConnectionString("ConnectionName");
services.AddDbContext<SurveyContext>(options => options.UseSqlServer(connection));
}
// 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.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
In the startup class of a .NET Core project you usually register this in the ConfigureServices function.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<YourContext>(options => options.UseSqlServer(connection));
}
When you are in the startup class of a .NET Core it is no problem to read the values from appsettings.json.
You could read more at Microsoft, i.e. here: https://learn.microsoft.com/en-us/ef/core/get-started/aspnetcore/existing-db
In the place where you want to access the appsettings.json,
JToken jAppSettings = JToken.Parse(
File.ReadAllText(Path.Combine(Environment.CurrentDirectory,
"appsettings.json")));
Now since you have the object, you can access its contents.
Let me know if it works.
When you use the Scaffold-DbContext, by default it hard codes your string into the DbContext class (so it works out of the box). You will need to register your DbContext in your startup class to proceed. To set this up, you can check the instructions in this answer.
Note that the Configuration property directly connects to your appsettings.json and several other locations. You can read more about it in this documentation. While you can always use the appsettings.json file, it is generally recommended to have your secure secrets in an external json file outside your source code. The best solution for this during development is using the secret manager. The easiest way to use this is right click on your project on visual studio and select "manage user secrets". This will open a json file that is already connected to your Configuration object.
Once this is set up, you need to use dependency injection to access your db context.
public class HomeController : Controller
{
public HomeController(SurveyContext context)
{
// you can set the context you get here as a property or field
// you can use visual studio's shortcut ctrl + . when the cursor is on "context"
// you can then use the context variable inside your actions
}
}
When you use using, it creates a new connection each time. Using injection makes sure only one connection is created per request no matter how many times it is used.

.NET Core 2, DI, configuration file

I am studying .NET Core 2 and I don't like how DI is managed... on the web I read something like the following steps:
creating an interface like IService
creating an implementation for IService
adding it on the scope of .NET Core container into Startup.Configuration method resolving the dependency.
finally I can use it into the constructor of my custom controller.
In .NET classic I used a dedicated XML configuration file to manage dependencies: can I use a configuration file (JSON or XML are the same) to do the same I would have to do into Startup.Configuration method?
...otherwise someone can explain me the reason why configure the services into Startup.Configuration is the better way?
Thanks so much...
First, to answer your question "can I use a configuration file", the answer is emphatically "yes". Why shouldn't you is answered later, but for now, here's a poor man's version of how you might do this by adding to your appsettings.json file. Note that this code is not optimal, but is designed to show you how you could implement this solution.
Let's start with some classes to hold the data:
public class ServicesConfiguration
{
public IEnumerable<ServiceItem> Singleton { get; set; }
public IEnumerable<ServiceItem> Transient { get; set; }
}
public class ServiceItem
{
public string Service { get; set; }
public string Implementation { get; set; }
}
Now add a section to your JSON file, you may even want to keep this file external to the main config, but that's an implementation detail I will leave up to you:
{
//snip main config....
"Services" : {
"Singleton": [
{
"Service": "YourNamespace.IFoo1, YourNamespace",
"Implementation": "YourNamespace.Foo1, YourNamespace"
},
{
"Service": "YourNamespace.IFoo2, YourNamespace",
"Implementation": "YourNamespace.Foo2, YourNamespace"
}
],
"Transient": [
{
"Service": "YourNamespace.IBar1, YourNamespace",
"Implementation": "YourNamespace.Bar1, YourNamespace"
}
]
}
}
And now an extension method to configure it all:
public static IServiceCollection AddFromConfigurationFile(this IServiceCollection services,
IConfigurationSection configuration)
{
var servicesConfiguration = configuration.Get<ServicesConfiguration>();
foreach(var service in servicesConfiguration.Singleton)
{
services.AddSingleton(Type.GetType(service.Service), Type.GetType(service.Implementation));
}
foreach(var service in servicesConfiguration.Transient)
{
services.AddTransient(Type.GetType(service.Service), Type.GetType(service.Implementation));
}
//Other scopes here...
return services;
}
And call it in ConifigureServices like this:
services.AddFromConfigurationFile(Configuration.GetSection("Services"));
So, nice and simple right? Why shouldn't you do this? A few ideas off the top of my head:
Why change how almost all DI implementations work? If it ain't broke, why fix it? Just because you are used to a particular method, doesn't mean it's a good idea.
Type safety: You lose compile time checking of the types you specify in the configuration file.
Security: Having this in a config file would let someone change the implementation to a class of their own choice.
I'm sure there are more, but... it's your app!

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

How can we store configuration data in new asp.net vnext?

How can we store configuration data in new asp.net vnext? web.config still there(system.web removed, so no any web.config,but I like it) or using new json file for configuration data.
Configuration used best is a starting point to strongly typed options. So what you want to do in startup is register an Options object, set it up with data you read from configuration, and get it from the DI system in the rest of your code.
Example:
Create an Options object
public class ApplicationOptions
{
public bool MyOption { get; set; }
}
Read the configuration and setup the options object then register it in DI
public void Configure(IApplicationBuilder app)
{
// rest of setup
var applicationOptions = new ApplicationOptions();
string myOption;
if (configuration.TryGet("MyOption", out myOption) &&
myOption.Equals("True", StringComparison.OrdinalIgnoreCase))
{
applicationOptions.MyOption = true;
}
// For the scenario above also the code below will work.
// It is currently limited to desktop (ASPNET50, NET45) only.
// services.Configure<ApplicationOptions>(configuration);
services.AddInstance<ApplicationOptions>(applicationOptions);
// more setup
}
And resolve it in your code
public class MyController : Controller
{
public IActionResult Index(ApplicationOptions options)
{
// do something with the options
}
}
Edit: with any practical reusable options object, the code setting it up will probably happen outside the startup class.
In the breaking changes (beta 6), Microsoft.Framework.ConfigurationModel assembly name changed to Microsoft.Framework.Configuration
This is the modified startup class
public IConfiguration Configuration { get; set; }
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
var configurationBuilder = new ConfigurationBuilder(appEnv.ApplicationBasePath).
.AddJsonFile("config.json")
.AddEnvironmentVariables();
Configuration = configurationBuilder.Build();
}
Not sure exactly what kind of data you are trying to store but this work for me. I created this file myconfig.json and store that data that I need in a JSON format.
This will register your configuration file, I added this code in the startup.cs page.
Configuration = new Configuration()
.AddJsonFile("config.json")
.AddJsonFile("myconfig.json")
.AddEnvironmentVariables();
To get the data that you need from the your JSON file you need to this at any point on your code.
IConfiguration Configuration = new Configuration().AddJsonFile("myconfig.json");
var jsonNodes = Configuration.Get("SomeJsonNode");
string someJsonString = Configuration.Get("someJsonString");
FYI: At the moment that I tested that code json array were not supported. Not sure if they fixed that now.