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

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.

Related

URLRewrite middleware that depends on Config dependency injection/scoped service. .Net Core

Struggling a little with Dependency Injection/Scoped Services with a rewrite rule class.
I have a redirects class which implements IRule
class ActivateRedirects : IRule
{
public void ApplyRule(RewriteContext context)
{
// Do stuff here which relies on CoreSettings (info below)
}
}
I also have a CoreSettings class which contains various settings, some of which are required for ApplyRule to work, it is initialised in startup.cs as follows.
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "site.json"), optional: false, reloadOnChange: true);
IConfigurationRoot root = configurationBuilder.Build();
CoreSettings s = new CoreSettings();
services.Configure<CoreSettings>(root.GetSection("Website"));
So you can see above, CoreSettings is created as a Service, which in most cases I can consume with DI:
public class SomeOtherClass{
private CoreSettings Settings;
public SomeOtherClass(Microsoft.Extensions.Options.IOptionsSnapshot<CoreSettings> S)
{
Settings = S.Value;
}
// Do stuff with Settings ....
}
I have read up on several pages on why I can't simply add DI to the ActivateRedirects Class, or explicitly pass the value in using app.ApplicationServices.GetRequiredService but everything I have read is telling what I can't do, I can't find anything to tell me what I can!!
Before I am told to rewrite the code to not require CoreSettings for Rewriting, I can't do that because one of the rewrite rules depends on a condition which is set by a remote server via a REST API and what is needed in the CoreSettings class is the API credentials used to create the REST Client.
It is possible to do what you want. I'll assume your class is defined as follows:
public class ActivateRedirects : IRule
{
private readonly CoreSettings _coreSettings;
public ActivateRedirects(CoreSettings coreSettings)
{
_coreSettings = coreSettings;
}
public void ApplyRule(RewriteContext context)
{
}
}
Read the configuration file, as before:
services.Configure<CoreSettings>(root.GetSection("Website"));
Next, setup your RewriteOptions:
var coreSettings = app.ApplicationServices.GetRequiredService<IOptions<CoreSettings>>();
var activateRedirects = new ActivateRedirects(coreSettings.Value);
var rewriteOptions = new RewriteOptions();
rewriteOptions.Rules.Add(activateRedirects);
app.UseRewriter(rewriteOptions);
If you put a breakpoint inside ActivateRedirects, and send a request, you'll see the CoreSettings field has been populated.
Update
I think this scenario is what IOptionsMonitor<T> might be designed for. It's registered as a singleton, but is notified of options changes. Change ActivateRedirects to:
public class ActivateRedirects : IRule
{
private readonly IOptionsMonitor<CoreSettings> _coreSettings;
public ActivateRedirects(IOptionsMonitor<CoreSettings> coreSettings)
{
_coreSettings = coreSettings;
}
public void ApplyRule(RewriteContext context)
{
}
}
and change how the instance is constructed to:
var coreSettings = app.ApplicationServices.GetRequiredService<IOptionsMonitor<CoreSettings>>();
var activateRedirects = new ActivateRedirects(coreSettings);
For me, editing the configuration does now show updated values in CoreSettings. One caveat is I don't know how that notification process works. If this ends up reading the configuration directly on each request, then it will scale really poorly, so I'd advise giving it a good test first.

Vuejs access / expose object from within ASP.NET Core app

Working on a project in ASP.NET Core MVC with VueJS as my frontend. I am looking for a solution to expose server objects to my Vuejs frontend to store it in my Vuex store so I can access them anywhere in my app.
For example, the build version / app version, appname, company name, ...
Some of these are located in the appsettings.json, others are in the .csproj file which I can read using a service.
I want to expose a json object during startup which contains these properties.
What do I have so far:
I have a root AppConfig class which contains all the properties.
AppConfig.cs
public class AppConfig : IValidatableConfig
{
public string AppName { get; set; }
public string ShortName { get; set; }
public int CurrentYear => DateTime.Now.Year;
/// Company Section
public CompanySettings CompanySettings { get; set; }
/// <summary>
/// Validate AppConfig
/// </summary>
/// <returns></returns>
public bool IsValid() => !string.IsNullOrEmpty(AppName) &&
!string.IsNullOrEmpty(ShortName) && CompanySettings != null &&
!string.IsNullOrEmpty(CompanySettings.Name) && !string.IsNullOrEmpty(CompanySettings.Url);
}
Startup.cs
// Bind IConfiguration AppConfig section to strongly typed object
services.Configure<AppConfig>(Configuration.GetSection("AppConfig"));
// Explicitly register the AppConfig object by delegating to the IOptions object
services.AddSingleton(resolver => {
var config = resolver.GetRequiredService<IOptions<AppConfig>>().Value;
if (config.IsValid()) return config;
// We have found issues with the appsettings config, throw exception to notify!
throw new InvalidConfigurationException(typeof(AppConfig));
});
Possible solution but don't like it this way:
Add props to my view root container to expose every property and then store them in my vuex store.
Don't like this because when a new property gets added I need to change a lot of files to make it work.
So I would like to have a solution which parse the AppConfig during startup to a json object and then get it into my Vuejs container.
Other solution
I could use a .env file in my vuejs to store these variables like this:
VUE_APP_ROOT_API = https://localhost:44320/api
VUE_APP_NAME_FOOTER = My Custom APP
VUE_APP_NAME_SHORT = My App
VUE_APP_COMPANY_NAME = Company
VUE_APP_COMPANY_URL = https://test.be
VUE_APP_YEAR = 2019
VUE_APP_VERSION = 0.0.1-local
But how can I dynamically update my version coming from my .csproj file?
Solved it by writing an extension on the HtmlHelper which renders a script tag holding server variables:
public static IHtmlContent RenderServerVariablesScript(this IHtmlHelper html)
{
var str = #"<script type=""text/javascript"">
var base = {};
base.sys = {};
base.sys.serverVariables = {""version"": ""0.0.1-local""};
window.base = base;</script>";
return html.Raw(str);
}
Then in my _layout I use:
#Html.RenderServerVariablesScript()
For this to work I needed to import my namespace in the _ViewImports file.

Options Configuration with dynamic (runtime) values

I have a MySettings class which I want to configure as Options to make it available via the dependency injection.
Currently I do (in an service builder extension method):
services.Configure<MySettings>(configuration.GetSection(MySettings.CustomSectionName));
My problem is that one part of the settings comes from the appsettings and other values are only known at runtime (startup).
So I try to find out how to configure the settings with adding the runtime provided values. I tried to add the values to the configuration
configuration["SectionName:ValueX"] = "my runtime value";
That did not work and ValueX is always null (when the options are injected in the controller).
Any suggestions for me?
You could try register MySettings instead of IOptions<MySettings> like
public void ConfigureServices(IServiceCollection services)
{
var mySettings = new MySettings();
Configuration.Bind("MySettings", mySettings);
mySettings.Title = "Hello";
services.AddSingleton(mySettings);
}
And use MySettings like
public class HomeController : Controller
{
private readonly MySettings _settings;
public HomeController(MySettings settings)
{
_settings = settings;
}
public IActionResult Index()
{
return Ok(_settings);
}
You can use IPostConfigureOptions< TOptions > interface to achieve what you want
services.PostConfigure<CustomOptions>(customOptions =>
{
customOptions.Option1 = "post_configured_option1_value";
});
Reference: https://learn.microsoft.com/en-us/dotnet/core/extensions/options#options-post-configuration

ASP.NET Core MVC App Settings

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"

how to access endpoint configuration in a custom NServiceBus profile handler

I'm migrating code from NSBv4 to NSBv5 (5.2.12 to be exact) and I have a custom profile implementation:
public class MyProfileHandler : IHandleProfile<PerformanceCounters>
{
public MyProfileHandler()
{
}
public void ProfileActivated(BusConfiguration config)
{
// I need to do something based on endpoint configuration, e.g. endpoint name
// this used to work in NSBv4:
// var endpointName = Configure.EndpointName;
}
}
How can I access endpoint configuration here?
I'm hosting this app using NServiceBus.Host (v6.0.0 if it matters) and this is where the IHandleProfile<T> interface comes from.
BusConfiguration is a configuration builder and it seems it's not possible to read anything useful from it. I tried to inject an instance of Configure to the constructor of my profile handler, but then it crashes - NSB needs the handler to have a parameterless constructor.
Implementing IWantTheEndpointConfig is not an option as well, as it is deprecated in v5 and it causes a compilation error. Its obsolete error message states:
IHandleProfile is now passed an instance of Configure
(which would be perfect for my case), but this is not true as far as I can tell (there is no Configure passed to ProfileActivated() and I can't see how I can inject it).
Is my only option to reimplement the profile handler using a completely different approach, or am I missing something?
NServiceBus.Core has an issue how it sets the endpoint name (and unfortunately also the endpoint version) on the BusConfiguration. The set endpoint name is added to the settings dictionary too late. You can work around that issue by doing the following:
public class EndpointConfig : IConfigureThisEndpoint
{
public void Customize(BusConfiguration configuration)
{
var customConfig = new EndpointConfiguration
{
EndpointName = "YourEndpointName",
};
configuration.EndpointName(customConfig.EndpointName);
configuration.GetSettings().Set<EndpointConfiguration>(customConfig);
}
}
public class EndpointConfiguration
{
public string EndpointName { get; set; }
}
BusConfiguration is essentially a dictionary on steroids. If you want to get access to what has been set in the BusConfiguration in the profile handler you can do the following (i.ex. get the endpoint name):
public class MyProfileHandler : IHandleProfile<PerformanceCounters>
{
public void ProfileActivated(BusConfiguration config)
{
var customConfig = config.GetSettings().Get<EndpointConfiguration>();
var endpointName = customConfig.EndpointName;
}
}
In the normal NServiceBus Host the interface offers only the one parameter, BusConfiguration. On Azure the interface offers two methods, where one actually has the Configure object.