Get Value from appsettings.json file in common class - c#

I want to get value using Appsettings from appsettings.json file
My code is in appsettings.json file:
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AppSettings": {
"APIURL": "https://localhost:44303/api"
},
"AllowedHosts": "*"
}
But I don't know how to get that value in common class file.

In general, you want to use strongly-typed configuration. Essentially, you just create a class like:
public class AppSettings
{
public Uri ApiUrl { get; set; }
}
And then, in ConfigureServices:
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
Then, where you need to use this, you'd inject IOptions<AppSettings>:
public class Foo
{
private readonly IOptions<AppSetings> _settings;
public Foo(IOptions<AppSettings> settings)
{
_settings = settings;
}
public void Bar()
{
var apiUrl = _settings.Value.ApiUrl;
// do something;
}
}

Create a class matching the structure of your JSON, and put it in a "common" place:
public class AppSettings
{
public Uri APIURL { get; set; }
}
Create an instance of AppSettings somewhere (what I like to do is create it in ConfigureServices and then register it with the container). For example
// create a new instance
var appsettings = new AppSettings();
// get section from the config served up by the various .NET Core configuration providers (including file JSON provider)
var section = Configuration.GetSection("AppSettings");
// bind (i.e. hydrate) the config to this instance
section.Bind(appsettings);
// make this object available to other services
services.AddSingleton(appsettings);
Then, when you need to use appsettings you can do so by simply injecting it into any services that need it. For example
public class SomeService
{
private readonly AppSettings _settings;
public SomeService(AppSettings settings) => _settings = settings;
...
}

Related

In .net 6, how do I pass the parameter to the constructor when the service initialization comes before the configuration binding of values?

I can't seem to find the solution to my exact problem, because I need to call the dependency injection before calling the builder, but this results in a new object instantiation in the controller class and the values are lost.
If I put this line right after binding, I can get an error saying cannot modify the service after it has been built.
In the older version of .net, since Startup.cs is existing, this doesn't seem to be a problem due to the separation of methods ConfigureService and Configure.
AuthenticationBind.cs
public class AuthenticationBind
{
public int AuthenticationId { get; set; }
public string AuthenticationName { get; set; }
}
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"TestAuthenticationBind": {
"AuthenticationId": "1324556666",
"AuthenticationName": "Test Authentication Name"
},
"AllowedHosts": "*"
}
Program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
builder.Services.AddSingleton<AuthenticationBind>();
var app = builder.Build();
AuthenticationBind tb = new AuthenticationBind();
IConfiguration configuration = app.Configuration;
configuration.Bind("TestAuthenticationBind", tb);
AuthenticationController.cs
private readonly AuthenticationBind authenticationBind;
public AuthenticationController(AuthenticationBind authenticationBind)
{
this.authenticationBind = authenticationBind;
}
Also, can I use the object instance to pass to services.AddSingleton method, instead of the class itself, like below?
builder.Services.AddSingleton<tb>();
It appears you're trying to bind configuration values into models. You can do this by calling IServiceCollection.Configure<T>() - for your code, it would look like this:
builder.Services.Configure<AuthenticationBind>(builder.Configuration.GetSection("TestAuthenticationBind"));
Afterwards, you can use the IOptions<T> interface in your controller to access the (bound) object:
public AuthenticationController(
IOptions<AuthenticationBind> authOptions
)
{
// You can access authOptions.Value here
}
Same goes in the startup class, you can request the IOptions interface like so:
var authOptions = app.Services.GetRequiredService<IOptions<AuthenticationBind>>();

ASP.NET Core receive custom config via HTTP to configure Kestrel

This feels like a simple problem to solve, but in all my searching I'm still yet to find a solution that works for me. Could be another case of not finding what I'm after as I'm not searching the right 'thing', but here we are..
I have a C# Web API program where I want to configure the kestrel server from a config object.
I receive this config into my service via rest call, into a CustomConfig object. I can get this config object either in Program.cs or in Startup.cs, but since I don't want to repeat myself and make additional calls, I don't want to do this in both places.
My preference is to get the config in Startup.cs since that's where the rest of my configuration code sits, and is where I'm already using my CustomConfig object. However, I can't find a way to configure the kestrel server to use the certificate I'm giving it (in Startup.cs), nor can I see a way to inject this config into Startup.cs from Program.cs.
In other projects I have passed the location of the PFX file as an environment variable: ASPNETCORE_Kestrel__Certificates__Default__Path (in which case everything works without additional code config), but in this project all config must be retrieved via rest call, so this is not an option here.
I currently have everything running, but only by making the rest call to get config twice. The current implementation to configure kestrel is storing the PFX in CustomConfig as a base64 string, and configuring in Program.cs:
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
CustomConfig config = CustomConfig() // <- I receive config here
webBuilder.UseStartup<Startup>();
webBuilder.UseKestrel(options =>
{
options.ConfigureHttpsDefaults(d =>
{
byte[] pfxBytes = Convert.FromBase64String(config.Base64PFXBytes);
d.ServerCertificate = new X509Certificate2(pfxBytes, "sslKey");
});
});
});
}
To summarise..
I have a CustomConfig object which is used to configure services in Startup.cs
I want to configure my Kestrel server from my CustomConfig
So I'm looking for help to either:
Get Kestrel to use my PFX within Startup.cs
Pass the CustomConfig object from Program.cs into Startup.cs
Hopefully that makes sense.. Welcome any & all solutions / additional questions for clarity!
Thanks in advance!
ASP.NET Core abstracts configuration using IConfiguration interface. Without going into details, it collects
configurations from various IConfigurationSource and layers them on top of each other, which lets us override a
setting that's defined in one source in another source by defining it with the same key.
1. Implementing an IConfigurationSource
Let's implement an IConfigurationSource. We can use ConfigurationSource abstract class as our starting point. We'll
use an in-memory implementation, then switch to a remote source.
class RemoteConfigurationSource : IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new RemoteConfigurationProvider(_options);
}
private class RemoteConfigurationProvider : ConfigurationProvider
{
public override void Load()
{
// TODO: fetch data from the API
var remoteConfig = new Dictionary<string, string>
{
{ "CertificateOptions:PfxBase64", "MIIKkQIBAz....gfQ" },
{ "CertificateOptions:Password", "secret" },
};
Data = remoteConfig;
}
}
}
Then add this to the configuration builder in the ConfigureHostConfiguration callback:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureHostConfiguration(builder =>
{
// add new source
builder.AddRemoteConfiguration();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>().UseKestrel((context, options) =>
{
var certificateOptions = context.Configuration
.GetSection(KestrelCertificateOptions.ConfigurationKey)
.Get<KestrelCertificateOptions>();
options.ConfigureHttpsDefaults(adapterOptions =>
adapterOptions.ServerCertificate = certificateOptions.Certificate);
});
});
}
public static class ConfigurationBuilderExtensions
{
public static IConfigurationBuilder AddRemoteConfiguration(this IConfigurationBuilder builder) =>
builder.Add(new RemoteConfigurationSource());
}
class KestrelCertificateOptions
{
public const string ConfigurationKey = "CertificateOptions";
public string PfxBase64 { get; set; }
public string Password { get; set; }
public X509Certificate2 Certificate => new X509Certificate2(Convert.FromBase64String(PfxBase64), Password);
}
When we run the app, ASP.NET Core will load and use our in-memory configuration.
2. Fetching configuration data from an API
Now let's fetch the config from a remote API. It needs to return configuration values with sections names delimited with
with a colon :. Here's the same config as JSON, filed under CertificateOptions section:
{
"CertificateOptions:PfxBase64": "MII....oCAgfQ",
"CertificateOptions:Password": "secret"
}
Assume the API wraps returns this data wrapped as:
{
"Application": "MyApp",
"LastChanged": "2021-08-09 14:38:00",
"Data": {
"CertificateOptions:PfxBase64": "MIIK...oCAgfQ",
"CertificateOptions:Password": "secret"
}
}
so we need to take only Data key into account when fetching the data.
class RemoteConfigurationSource : IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new RemoteConfigurationProvider();
}
private class RemoteConfigurationProvider : ConfigurationProvider
{
public override void Load()
{
// We cannot await this method, so have to do sync-over-async.
// Not an issue, because it's a one-time thing.
var result = LoadRemoteConfig().GetAwaiter().GetResult();
Data = result.Data;
}
private async Task<RemoteConfigResult> LoadRemoteConfig()
{
// We cannot use IHttpClientFactory here, since ServiceProvider isn't even built yet.
using var httpClient = new HttpClient();
// ... add headers, token to request
return await httpClient.GetFromJsonAsync<RemoteConfigResult>("https://example.com/path/to/json");
}
}
private class RemoteConfigResult
{
public Dictionary<string, string> Data { get; set; }
}
}
To clean things up a bit, we can move the URL and other credentials to appsettings.json:
{
"Logging": {
/*...*/
},
"RemoteConfiguration": {
"Url": "https://jsonkeeper.com/b/B78I",
"ApplicationId": "myconfigappid",
"Secret": "myconfigapisecret"
}
}
Then build a temporary IConfiguration add as many sources as necessary, then fetch these values:
// Read credentials from appsettings.json
var remoteConfigurationOptions = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false)
.Build()
.GetSection(RemoteConfigurationOptions.ConfigurationKey)
.Get<RemoteConfigurationOptions>();
public class RemoteConfigurationOptions
{
public const string ConfigurationKey = "RemoteConfiguration";
public string Url { get; set; }
public string ApplicationId { get; set; }
public string Secret { get; set; }
}
Then pass this object to our configuration source, which in turns passes it down to the configuration provider

what is diffrence between Configuration binding and IOption Pattern in dotnet core?

I know there are two ways to inject configuration into my other layers class:
first one Configuration binding:
services.AddConfiguration() // enable Configuration Services
var config = new WeblogConfiguration();
Configuration.Bind("Weblog", config); // <--- This
services.AddSingleton(config);
usage:
public class PostsController : Controller
{
PostRepository PostRepo { get; }
WeblogConfiguration Config { get; }
public PostsController(PostRepository postRepo,
WeblogConfiguration config)
{
PostRepo = postRepo;
Config = config;
}
...
}
and IOption Pattern:
services.Configure<WeblogConfiguration>(option => Configuration.GetSection("WeblogConfiguration").Bind(option));
services.AddOptions();
usage:
public class PostsController : Controller
{
PostRepository PostRepo { get; }
WeblogConfiguration Config { get; }
public PostsController(PostRepository postRepo,
IOptions<WeblogConfiguration> config)
{
PostRepo = postRepo;
Config = config.Value;
}
...
}
I want to know the difference between these methods and the cons and pros for each of them.
So far only one difference come into my mind:
The possibility to reload the configuration.
When you bind your WeblogConfiguration and add it as singleton it will be loaded once and never changes.
Once you use the IOptions pattern you could use the reloadOnChange argument when adding the json file and will get updated values via the IOptions.Value method.

How to set default value from AppSettings on a view model in C#?

I am exposing a view on a new API, and want to know how I can set a default value to a property, reading it from my appsettings.json file. How can I do it?
I've tried using dependency injection on the view, but it seems impossible since it's the framework that instantiate the class.
public class FilteringRequest
{
private readonly IAppContext appContext;
public FilteringRequest(IAppContext appContext)
{
this.appContext = appContext;
}
// TODO: appsettings?
// Perhaps something like appContext.DefaultType
public string Type { get; set; } = "top_rated";
// ...
}
This approach doesn't work since I believe the framework is expecting a parameterless default constructor.
An unhandled exception occurred while processing the request.
InvalidOperationException: Could not create an instance of type 'Wanderlust.API.Models.Requests.FilteringRequest'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Alternatively, give the 'request' parameter a non-null default value.
Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.CreateModel(ModelBindingContext bindingContext)
Bear in mind that IAppContext already has all the properties defined in appsettings.json file.
Dependency injection should work. In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// ...
services.Configure<MyAppContext>(Configuration.GetSection(nameof(MyAppContext)));
// ...
}
Define your class MyAppContext:
public class MyAppContext
{
public MyAppContext()
{
}
public string DefaultType { get; set; }
// other public properties here...
}
In your FilteringRequest class:
public class FilteringRequest
{
private readonly MyAppContext _appContext;
public FilteringRequest(Microsoft.Extensions.Options.IOptions<MyAppContext> appContext)
{
_appContext = appContext.Value;
}
string _type;
public string Type
{
get => _type ?? (_type = _appContext.DefaultType);
set => _type = value;
}
// ...
}
To read data from appsettings.json in any class, you just need to pass Configuration with dependency injection by creating IConfiguration field:
public class FilteringRequest
{
private readonly IConfiguration _configuration;
public FilteringRequest(IConfiguration configuration)
{
_configuration = configuration;
Type = _configuration["Model:FilteringRequest:Type"];//set value from appsettings.json file
}
public string Type { get; set; }
// ...
}
appsettings.json:
{
"Model": {
"FilteringRequest": {
"Type": "testdata"
}
}
}
Controller:
public class HomeController : Controller
{
private readonly IConfiguration _configuration;
public HomeController (IConfiguration configuration)
{
_configuration = configuration;
}
public IActionResult Index
{
var modelinstance = new FilteringRequest(_configuration);//create the viewmodel with default 'Type"
return View();
}
}
Refer to :
Getting value from appsettings.json in .net core
Read appsettings.json from a class in .NET Core 2

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