Add custom section to .NET Core local.settings.json - configuration

I'm writing my first Azure function (based on .NET Core 2.x), and I'm struggling to extend the app settings with my custom mapping table.
I have a file local.settings.json, and I have tried to extend it with a "custom" config section that contains a few "key/value" pairs - something like this:
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
... (standard config settings) ...
},
... (more default sections, like "Host" and "ConnectionStrings")
"MappingTable" : {
"01" : "Value1",
"02" : "Value2",
"03" : "Value3",
"else" : "Value4"
}
}
I get the IConfiguration injected into my worker class via constructor injection, and it works just fine for the "basic" default values stored in the "Values" section:
public MyWorker(IConfiguration config)
{
_config = config;
string runtime = _config["FUNCTIONS_WORKER_RUNTIME"]; // works just fine
// this also works fine - the "customSection" object is filled
var customSection = _config.GetSection("MappingTable");
// but now this doesn't return any values
var children = customSection.GetChildren();
// and trying to access like this also only returns "null"
var mapping = customSection["01"];
}
I'm stuck here - all the blog post and articles I find seem to indicate to do just this - but in my case, this just doesn't seem to work. What am I missing here? I'm quite familiar with the full .NET framework config system - but this here is new to me and doesn't really make a whole lot of sense just yet......
I have also tried to move the entire MappingTable section to appSettings.json - but that didn't change anything, I'm still getting back only null when trying to access my custom config section's values....
Thanks!
Update: all the suggested ways of doing this work just fine with a standard ASP.NET Core 2.1 web app - but in the Azure function, it's not working. Seems like code in an Azure Function is treating configuration differently than a regular .NET Core code base ...

I did something similar using .net core 3.0
local.settings.json
{
"AppSettings":{
"MappingTable" : {
"01" : "Value1"
}
}
}
Reading appsettings:
private void AppSettings()
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
var 01 = config["AppSettings:MappingTable:01"];
}
In the Azure portal, you need to add this as an application setting.
In your Function App -> Configuration -Application Settings -> New Application setting
Name:AppSettings:MappingTable:01
Value:Value1

A R G H ! ! !
I knew it - such a stupid little mistake - but with rather massive consequences.....
In my startup class, I had this code (plus some more):
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient();
var config = new ConfigurationBuilder()
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
.....
}
}
but what was missing is this one line of code after the call to .Build() above:
builder.Services.AddSingleton<IConfiguration>(config);
Somehow, the settings in the Values section of local.settings.json were present and accessible, but any custom config sections weren't.
Adding this one line has solved my problem - now I can easily read the MappingTable from my local.settings.json (or appsettings.json) file and use it in my code.

Related

Retrieve a connection string from appsetting.json in a simple console app (Core 3.1)

I'm writing a very simple console app that needs to dig into a database and read values. I'm having issues getting the connection string from the appsettings.json. After a whole load of googling I've found a bunch of solutions, each of which with their own issues such as being out of date or just returning null values with no obvious reason why. The main (and most common) method i've found to do it is as below:
static void Main()
{
var configuration = GetConfiguration();
var connectionString = configuration.GetSection("ConnectionsStrings").GetSection("DbName");
}
public static IConfigurationRoot GetConfiguration()
{
var builder = new ConfigurationBuilder().AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
return builder.Build();
}
This somewhat works but just returns a null value where I'd expect the connection string.
The appsettings.json is as below:
{
"ConnectionStrings": {
"DbName": "Connection string"
}
}
If anyone can spot anything obvious and help me along, it'd be much appreciated.
Warning to everyone out there. Don't be like me. Don't add your appsettings.json then for 17 hours completely forget to check the properties and make it an embedded resource while getting annoyed that your returned value is just null all the time. You would think after years of coding I'd learn my lesson....

EmbedIO with a list of unknown web APIs

I want to have a modular EmbedIO setup with a dynamic list of unknown web API controller types. I thought it'd be easy :( But at the moment I'm stuck at registering the web APIs:
// Some APIs to setup at the EmbedIO webserver in "Server"
Dictionary<string, WebApiController> apis = ...;
// Register the APIs at the webserver
foreach(KeyValuePair<string, WebApiController> kvp in apis)
{
// Exception: "Controller type must be a subclass of WebApiController."
Server.WithWebApi(kvp.Key, m => m.WithController(() => kvp.Value));
}
The problem is: The factory method needs to return the final type of the controller object. Everything else seems to fail.
I tried with dynamic instead of WebApiController or returning object and giving the type as first parameter for WithController - whatever I tried, it resulted in an exception; Or when I use a class WebApiControllerWrapper : WebApiController and a Dictionary<string, WebApiControllerWrapper>, the exported controller methods of the final type are missing, because they're not defined in WebApiControllerWrapper.
It seems the only way is to use reflection for the generic call of WithController - or does anyone know another working solution (I'm in .NET Standard 2.1)?
I was able to solve it with an expression tree that calls a generic method to create the factory function:
public class ModularWebApiController : WebApiController
{
public Func<T> CreateFactoryMethod<T>() where T : WebApiController => () => (T)this;
}
public static class Extensions
{
public static WebApiModule WithController(this WebApiModule webApiModule, ModularWebApiController api)
{
Delegate factoryFunc = Expression
.Lambda(Expression.Call(
Expression.Constant(api),
typeof(ModularWebApiController).GetMethod("CreateFactoryMethod").MakeGenericMethod(api.GetType())
))
.Compile();
return (WebApiModule)typeof(WebApiModuleExtensions)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Single(mi => mi.IsGenericMethod & mi.Name == "WithController" && mi.GetParameters().Length == 2)
.MakeGenericMethod(api.GetType())
.Invoke(null, new object[] { webApiModule, factoryFunc.DynamicInvoke(Array.Empty<object>()) });
}
}
I only had to ensure that all web API controller types extend the ModularWebApiController type, and I had to change the modular web API setup for EmbedIO:
Dictionary<string, ModularWebApiController> apis = ...;
foreach(KeyValuePair<string, ModularWebApiController> kvp in apis)
{
Server.WithWebApi(kvp.Key, m => m.WithController(kvp.Value));
}
After browsing the EmbedIO source I think this seems to be the only way to have a modular web API setup, where the code doesn't know which web API controller types are going to be used.
Now I'm able to load and instance any web API controller type configured in a JSON configuration file like this:
[
{
"Type": "name.space.WebApiControllerTypeName",
"Path": "/webapipath/"
},
{
"Type": "name.space.AnotherWebApiControllerTypeName",
"Path": "/anotherwebapipath/"
}
]
Just for example. I wonder why it seems that nobody else want to do this ;)

Azure Durable Function AppSettings

I'm trying to create an azure durable function but it's very difficult to find some normal guides on this subject. I've setup the DI and I try to read the settings of the function but it crashes
I have setup an Azure Function project in VS 2019 and added a Durable Orchestrator Function Template. I removed all the "static" references from the class and all seem to work fine until I add the configurationbuilder in the startup file
Can anyone explain to me how this should work or give some guidance, where to find some explanation of the configuration of a durable functions ? What should I have in the host.json , local.settings.json and how this changes be when I publish it on the portal ?
My case is this. The startup file looks like this
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
[assembly: FunctionsStartup(typeof(DurableFunctions.Startup))]
namespace DurableFunctions
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var settings = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
}
}
}
The host.json is like this
{
"version": "2.0"
}
The local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
}
And the error I get when I start the debugger is this
This is output:
[11/8/2019 10:29:04 AM] A host error has occurred during startup operation '8b80bc94-2b98-408b-895f-c5697430acfd'.
[11/8/2019 10:29:04 AM] Microsoft.Azure.WebJobs.Extensions.DurableTask: Value cannot be null.
[11/8/2019 10:29:04 AM] Parameter name: hostConfiguration.
Value cannot be null.
Parameter name: provider
You want to instead override the ConfigureAppConfiguration method in your FunctionStartup class (https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#customizing-configuration-sources).
The following example takes the one provided in the documentation a step further by adding user secrets.
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
FunctionsHostBuilderContext context = builder.GetContext();
builder.ConfigurationBuilder
.SetBasePath(context.ApplicationRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
.AddJsonFile($"appsettings.{context.EnvironmentName}.json", optional: true, reloadOnChange: false)
.AddUserSecrets(Assembly.GetExecutingAssembly(), true, true)
.AddEnvironmentVariables();
}
By default, configuration files such as appsettings.json are not automatically copied to the Azure Function output folder. Be sure to review the documentation (https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#customizing-configuration-sources) for modifications to your .csproj file. Also note that due to the way the method appends the existing providers it is necessary to always end with .AddEnvironmentVariables().
A deeper discussion on configuration in an Azure Function can be found at Using ConfigurationBuilder in FunctionsStartup
Did you get a response to this?
Did you try adding the local settings from the json, before the Environment Variables?
var config = new ConfigurationBuilder()
.SetBasePath(context.FunctionAppDirectory)
// This gives you access to your application settings in your local development environment
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: false)
.AddJsonFile("secret.settings.json", optional: true, reloadOnChange: false)
// This is what actually gets you the application settings in Azure
.AddEnvironmentVariables()
.Build();
I am having trouble when I deploy, I have set up a variable group yet they are not being picked up.

Value cannot be null. Parameter name: connectionString appsettings.json in starter

I am trying to write my connection string in my appsettings.json file and bring it into my startup file but I keep getting a Value cannot be null.
Parameter name: connectionString. I have been using various examples but can't seem to see this new setup with ASP.NET 1.0 Core startup class.
Appsetting.json file:
{
"Data": {
"DefaultConnection": {
"ConnectionString": "Data Source=server;Initial Catalog=dbase;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
}
Method attempting
Startup.cs
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();
}
public void ConfigureServices(IServiceCollection services)
{
var connStr = Configuration.GetConnectionString("DefaultConnection");
System.Console.WriteLine(connStr);
services.AddDbContext<DbContext>(options => options.UseSqlServer(connStr)); //error right here -- Null value
}
First of all, the
"Data": {
"ConnectionStrings": {
"DefaultConnection": "Data Source=server;Initial Catalog=dbase;Trusted_Connection=True;MultipleActiveResultSets=true"},
}
Is slightly different from the structure you get when you add a "Asp.NET Configuration File" in Visual Studio. When you do that you get
"ConnectionStrings": {
"DefaultConnection": "Data Source=server;Initial Catalog=dbase;Trusted_Connection=True;MultipleActiveResultSets=true"},
without the "Data" JavaScript Object. So that's why the extension method isn't working. It expects this structure. You can use this structure (the one with "Data") anyway and get your connection string like so:
var connectionString = Configuration["Data:ConnectionStrings:DefaultConnection"];
Notice that you are navigating through the JavaScript object tree using : instead of .. That's due to some cross-platform issues with using the ..
If you edit out the "Data":{} you can do this :
var connectionString = Configuration["ConnectionStrings:DefaultConnection"];
Now the extension method will work. Underneath the Microsoft extensions it is the same thing as the code above.
var config2 = Configuration.GetConnectionString("DefaultConnection");
I was missing the letter 's' after the ConnectionString property name in the appsettings.json when using Configuration.GetConnectionString("name")
If you want to copy
"ConnectionStrings ": {
"SpyStore": "Server=(localdb)\\mssqllocaldb;Database=SpyStore;Trusted_Connection=True;MultipleActiveResultSets=true;"
}
The method wording GetConnectionString confused me, I hovered over it and oh be hold it was looking for ConnectionStrings property name instead of ConnectionString
DefaultConnection is the inner object in the json structure and it is the child of Data object.
So if you want to be exact with your config file you can use
var connStr = Configuration.GetSection("Data")
.GetSection("DefaultConnection")["ConnectionString"];
I got this because I had a connection string with a \ in it, which needed escaping to be a \\. So my localdb connection string was causing a load error like this:
"DefaultConnection": "Server=(localdb)\myinstance;Integrated Security=true;Initial Catlog=my-localdb;"
and was fixed by making it:
"DefaultConnection": "Server=(localdb)\\myinstance;Integrated Security=true;Initial Catlog=my-localdb;"
this is was the message that appeared me
Value cannot be null.
Parameter name: connectionString
I fix it changed in the startup these lines
services.AddDbContext<AppIdentityDbContext>(options =>
options.UseSqlServer(
Configuration["Data:BookStoreContext:ConnectionString"]));
To
services.AddDbContext<AppIdentityDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("BookStoreContext")));
I had got similar error.My "appsettings.json" file was not loading because the properties of the file was Copy to Output Directory -> Do not Copy. I set that to Copy always save and rebuild.It worked.
in asp.net core you must add IConfiguration to startUp contractor method and assignee this Parameter to a property inherited from IConfiguration inside class
public class Startup
{
public Startup(IConfiguration configuration)
{
this.Configuration = configuration;
}
public IConfiguration Configuration { get; }
my issue is fixed by fixing a typo
I experienced this problem using asp.net core 3.0.
The workaround fix for me is:
Instead of:
var connectionString =
Configuration["ConnectionStrings:DefaultConnection"];
Use this:
var connectionString =
Configuration["ConnectionStrings::DefaultConnection"];
The emphasis here is the double colon in the connection configuration.
Another mistake in my case was that I was using ConnectionString, instead ConnectionStrings (Note last 's')
Maybe you can try this:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer("DefaultConnection")
);
Then set your appsettings.json do something like this:
"ConnectionStrings:": {
"DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=HOME1_DATABASE;Trusted_Connection=True;MultipleActiveResultSets=true"
},
After that, when a I add migration via the console, it succeeds.
While using Postgres SQL the appsettings.Development.json must contain
"ConnectionStrings": {
"DefaultConnection": "User ID=user;Password=xxxx;Host=127.0.0.1;Port=5432;Database=abc;Pooling=true"
}
Content in the Startup.cs file would be like
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>
(p => p.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));
}
The correct way to add connection strings into your appsetting.json file is the following:
"ConnectionStrings":{
"DefaultConnection":"Server=localdb)\\MSSQLLocalDB;Datbase=MyShop;Trusted_Connection=true"
}
I get it,it was because the name of connection string that in app settings was difference from that in the configuration that in Startup !!!
The right code of connection String Configuration in startup
// replace NAMEHERE with the name of the class that inherits from DbContext
services.AddDbContextPool <NAMEHERE> (opts => opts.UseSqlServer(Configuration.GetConnectionString("here put the same Connection string name that in appsettings")));
I fought with the null connection string issue far too long, only to find I was doing this:
builder.Services.AddDbContext<MlDataContext>(provider => new MlDataContext(config.GetConnectionString("ConnectionStrings:SqlConnectionString")));
I was using both the ConnectionStrings: prefix AND GetConnectionString. When I removed the prefix it worked:
builder.Services.AddDbContext<MlDataContext>(options => options.UseSqlServer(config.GetConnectionString("SqlConnectionString")));
For Postgre Db, Below worked for me
private readonly IConfiguration _config;
string connectionString;
public DataBaseContext(IConfiguration config)
{
_config = config;
connectionString= _config.GetValue<string>("ConnectionStrings:sampleConnection");
}
Config file:
"ConnectionStrings": {
"sampleConnection":".."
}
Start up file:
services.AddScoped();
In my case I had two IConfiguration definitions in my Startup class. Not helpful :)
I had this error on the day when usin Asp.Net Core 5. I tried all above solutions with no satisfaction. Then I deleted the "ConnectionStrings" section the appsettings.json file and launched a migration. After the error, I rewrote the section and launched again the migration. All worked fine.
Please make sure you have all you connection strings defined in the app.json.
My problem was I had two different projects that added a dbContext in their services config
The identity project which made a reference to the identityDb
The persistence project that all my data access logic
I solved the issue by having both connection strings defined in the app.json
try it, it will work for you on version 3.0.0.
public class Startup
{
private readonly IConfiguration configuration;
public Startup(IConfiguration configuration)
{
this.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.AddControllersWithViews();
services.AddDbContext<DataContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("MyPortfolio"));
});
}
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"MyPortfolio": "Data Source=(localdbd)\MSSQLLocalDB; initail catalog=MyPortfolioDB; Integrated Security=true"
}
}
I had the same problem and this fixed it for me:
connStr = Configuration.GetConnectionString("DefaultConnection");
change to:
connStr = Configuration["DefaultConnection:ConnectionString"]
I am having the same error but realize to be an typo.
"ConnectionStringd": {
"DefaultConnection": "Server=localhost;Database=BookListRazor;Trusted_Connection=True;MutipleActiveResultSets=True"
},
the correct typing should be
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=BookListRazor;Trusted_Connection=True;MutipleActiveResultSets=True"
},
Remove this line from YourProjectName.csproj file:
<Nullable>enable</Nullable>
In my case this is a new deployment to a new server. It turns out the environment variable ASPNETCORE_ENVIRONMENT was not set, so .NET Core couldn't get the connection string from appsettings.PROD file, and thus passed null to options.UseSqlServer(connection).
Once I created a new environment variable ASPNETCORE_ENVIRONMENT and set its value to PROD, problem is solved.
instead of using the method given below
builder.Services.AddDbContext<FullstackAPIcontext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("FullStackConnectionString")));
You can directly add the connection string after Usesqlserver .The code snippet is given below
builder.Services.AddDbContext<FullstackAPIcontext>(options =>
{
options.UseSqlServer("Server=myserver;Database=FullstackDb;Trusted_Connection=SSPI;Encrypt=false;TrustServerCertificate=true");
});
You need to change your appsetting.jsonto:
{
"Data": {
"ConnectionStrings": {
"DefaultConnection": "Data Source=server;Initial Catalog=dbase;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
}
And now will be working:
var connStr = Configuration.GetConnectionString("DefaultConnection");

Startup.cs error (ASP.Net Core configuration)

I am trying to set up an ASP.Net Core application to read in configuration settings from a json file. I am using VS2015 and .NetCore 1.0 (with .Net Core Tools preview 2). I am having problems getting a simple piece of boiler plate code to compile.
I am using the following code, which was published at
http://asp.net-hacker.rocks/2016/03/21/configure-aspnetcore.html
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
if (env.IsDevelopment())
{
// This will push telemetry data through Application Insights
// pipeline faster, allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}
Configuration = builder.Build();
}
However, the IDE/compiler complains that 'the name "Configuration" does not exist in the current context' (last line of code). The only suggestion from the IDE is to include Microsoft.Extensions.Configuration. However this is a namespace which does not contain an object or property named "Configuration".
In addition 'AddApplicationInsightsSettings' fails with does IConfigurationBuilder not contain a definition for AddApplicationInsightsSettings and no extension method AddApplicationInsightsSettings accepting a first argument of type IConfigurationBuilder could be found
Any suggestions please ?
Thanks
Simply add Configuration property to your Startup class, tutorial has missed this 'step':
public IConfigurationRoot Configuration { get; set; }
ConfigurationBuilder.Build() method just returns instance of IConfigurationRoot, that you should save, if need to get settings further in Startup class (in ConfigureServices method for example).
Regarding second error, looks like you didn't add the Application Insights dependency:
{
"dependencies": {
"Microsoft.ApplicationInsights.AspNetCore": "1.0.0"
}
}