I have an application which i have some configuration files for cache, queue, and database.
public class ServerConfiguration: ConfigurationSection
{
[ ConfigurationProperty( FOO, DefaultValue = "", IsRequired = false ) ]
public string FOO
{
get { return (string)this[FOO]; }
set { this[FOO] = value; }
}
}
this is what i do for config files and I also have some inheritance hierarchy.
What do you use to handle configurations and what are some best practices for this purpose?
I love and use the Microsoft configuration library extensively but I try to make sure that my applications are not dependent on it. This usually involves having my configuration section implement an interface, so your example would look like:
public class ServerConfiguration : ConfigurationSection, IServerConfiguration
{
[ ConfigurationProperty( FOO, DefaultValue = "", IsRequired = false ) ]
public string FOO
{
get { return (string)this[FOO]; }
set { this[FOO] = value; }
}
}
public interface IServerConfiguration
{
public string FOO { get; } //Unless I am updating the config in code I don't use set on the interface
}
Now where ever you use your configuration in your code you only need to worry about IServerConfiguration and you can change your implementation without having to change the usages. Sometimes I just start of with a hard coded class during development and only change it to a configuration section when I actually need to have different values in different environments.
If you are using a configuration section you are also dependent on the ConfigurationManager. I have hidden this from my code by using an IConfigurationProvider[T] where T would be IServerConfiguration, you can see an example of this on my blog under configuration ignorance.
http://bronumski.blogspot.com/search/label/Configuration
Related
I have a few similar classes with similar configurations in it.
So, I want to create a base Class with common configuration, after that inherit it in child config class and in the end initialize it in logic class:
public class OptionsBase
{
public string ConnectionKey { get; set; }
}
public class OptionsChild: OptionsBase
{
public string ChildName{ get; set; }
}
My json file:
"OptionsBase": {
"ConnectionKey": "basekey"
},
"OptionsChild": {
"ChildName" "child1"
}
Expecting to use it like this:
public class Child1
{
private readonly OptionsChild _options;
public Child1(IOptions<OptionsChild> options)
{
_options = options.Value;
}
public void Example()
{
var valueFromParent = _options.ConnectionKey;
}
}
How can I do it without duplication in json file and without using additional common class with common options?
It is web app, config initialization executed like this:
service.Configure<OptionsChild>(config.GetSection("OptionsChild"));
Thank you!
EDIT: I found the solution and added an answer. Please, let me know if the solution is OK.
I have found an answer, here it is described, exactly what I wanted to receive.
It is a bit workaround, need to configure each configuration class twice, but this way I can use base options without duplicating options in child options class and also I don't need to duplicate configuration in JSON file
Please, let me know if the solution is OK.
i need a config file for my applications and i've looked through internet without really finding what I want, I want to set my config to a var and use it like config.somethingInTheConfig.
I tried some things but it didn't work,
the config file :
{
"id": 00,
"somethings": true,
"yes": "idkjustsomething"
}
the Config class :
class Config
{
public static int id { get; set; }
public static bool somethings { get; set; }
public static string yes { get; set; }
}
Code to read it
using (StreamReader streamReader = new StreamReader("config.json"))
{
string json = streamReader.ReadToEnd();
Config config = JsonConvert.DeserializeObject<Config>(json);
Console.WriteLine(config.id);
}
I want it to show the id in the config in the console but it doesn't work nd gives me an error, anyone could help ?
The properties are marked static.
JsonConvert will not be able to read values into the static properties.
And since you are not defining values for them at design time, the properties will be set to their default values unless you manually change them.
This really amazes me. I am reading values from appsettings.json using Configuration.GetSection method and in nutshell my appsettings.json looks like below:
"AppSettings":
{
"PathPrefix": "",
"Something": "Something else",
"Clients":{"foo": "bar"}
}
Now I surprises me is that if I do something like below:
var foo = Configuration.GetSection("AppSettings:Clients:foo").Value;
Then it gets the value correctly. It gets the value bar
However, when I do
var clients = Configuration.GetSection("AppSettings:Clients").Value;
it returns null. It's not only this field, whenever I call getSection method to get any complex object then it returns null but when I call it to get a basic string value then it gets the value correctly even though seeminglyi, it had problems in getting its parent element. This baffles me and raises three questions:
Why would it have issues getting complex values but not getting basic string values?
Is it by design? If so , why?
If I want to load entire object, how do I do that?
You can load an entire object using a strongly typed object.
First, create a class (or classes) to hold you settings. Based on your example this would look like:
public class AppSettings
{
public string PathPrefix { get; set; }
public string Something { get; set; }
public Clients Clients { get; set; }
}
public class Clients
{
public string foo { get; set; }
}
Now, you need to add the Options service to your service collection and load your settings from the configuration:
public void ConfigureServices(IServiceCollection services)
{
// This is only required for .NET Core 2.0
services.AddOptions();
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
services.AddMvc();
}
You now access the properties by injecting them into your class, for example:
public class HomeController : Controller
{
private readonly AppSettings _settings;
public HomeController(IOptions<AppSettings> settings)
{
_settings = settings.Value;
}
}
You can also load suboptions in the ConfigureService method by specifying the configuration section to load e.g.
services.Configure<Clients>(Configuration.GetSection("AppSettings:Clients");
Now you can inject IOptions<Clients> to access those settings
The official documentation can be found here
What would you expect it to return? You can get complex objects using the Get<T> extension method. Try this:
var clients = Configuration.GetSection("AppSettings:Clients").Get<YourClientsType>();
Recently we learned about AppDomain Recycling of IIS and how it affects static variables setting them to their primary values (nulls, 0s, etc).
We use some static variables that are initialized in a static constructor (for first time initialization, configuration values like "number of decimal places", "administrator email", etc... that are retrieved from DB) and then only read their value along the website execution.
Whats the best way of solving this problem? Some possible ideas:
Checking if variable is null/0 at each retrieval (don't like it because of a possible performance impact + time spent to add this check to each variable + code overload added to the project)
Somehow preventing AppDomain Recycling (this reset logic doesn't happen in Windows forms with static variables, shouldn't it work similarly as being the same language in both environments? At least in terms of standards as static variables management)
Using some other way of holding these variables (but we think that for being some values used for info as global reference for all users, static variables were the best option performance/coding wise)
Subscribing to an event that is triggered in those AppDomain Recycling so we can reinitialize all those variables (maybe best option if recycling can't be prevented...)
Ideas?
I would go with the approach that you don't like.
Checking if variable is null/0 at each retrieval (don't like it because of a possible performance impact + time spent to add this check to each variable + code overload added to the project)
I think it's faster than retireving from web.config.
You get a typed object
Its not a performance impact as you are not going to database on every retrieval request. You'll go to database (or any source) only when you find that current value set to its default value.
Checking the null wrapped into code:
public interface IMyConfig {
string Var1 { get; }
string Var2 { get; }
}
public class MyConfig : IMyConfig {
private string _Var1;
private string _Var2;
public string Var1 { get { return _Var1; } }
public string Var2 { get { return _Var2; } }
private static object s_SyncRoot = new object();
private static IMyConfig s_Instance;
private MyConfig() {
// load _Var1, _Var2 variables from db here
}
public static IMyConfig Instance {
get {
if (s_Instance != null) {
return s_Instance;
}
lock (s_SyncRoot) {
s_Instance = new MyConfig();
}
return s_Instance;
}
}
}
Is there any reason why you can't store these values in your web.config file and use ConfiguationManager.AppSettings to retrieve them?
ConfigurationManager.AppSettings["MySetting"] ?? "defaultvalue";
In view of your edit, why not cache the required values when they're first retrieved?
var val = HttpContext.Cache["MySetting"];
if (val == null)
{
val = // Database retrieval logic
HttpContext.Cache["MySetting"] = val;
}
It sounds like you need a write-through (or write-behind) cache, which can be done with static variables.
Whenever a user changes the value, write it back to the database. Then, whenever the AppPool is recycled (which is a normal occurrence and shouldn't be avoided), the static constructors can read the current values from the database.
One thing you'll have to consider: If you ever scale out to a web farm, you'll need to have some sort of "trigger" when a shared variable changes so the other servers on the farm can know to retrieve the new values from the server.
Comments on other parts of your question:
(don't like [Checking if variable is null/0 at each retrieval] because of a possible performance impact + time spent to add this check to each variable + code overload added to the project
If you use a write-through cache you won't need this, but in either case The time spent to check a static variable for 0 or null should be negligible.
[AppDomain recycling] doesn't happen in Windows forms with static variables, shouldn't it work similarly as being the same language in both environments?
No, WebForms and WinForms are completely different platforms with different operating models. Web sites should be able to respond to many (up to millions) of concurrent users. WinForms are built for single-user access.
've resolved this kind of issue, following a pattern similar to this. This enabled me to cater for handling circumstances where the data could change. I set up my ISiteSettingRepository in the bootstrapper. In 1 application I get the configuration from an XML file but in others I get it from the database, as and when I need it.
public class ApplicationSettings
{
public ApplicationSettings()
{
}
public ApplicationSettings(ApplicationSettings settings)
{
ApplicationName = settings.ApplicationName;
EncryptionAlgorithm = settings.EncryptionAlgorithm;
EncryptionKey = settings.EncryptionKey;
HashAlgorithm = settings.HashAlgorithm;
HashKey = settings.HashKey;
Duration = settings.Duration;
BaseUrl = settings.BaseUrl;
Id = settings.Id;
}
public string ApplicationName { get; set; }
public string EncryptionAlgorithm { get; set; }
public string EncryptionKey { get; set; }
public string HashAlgorithm { get; set; }
public string HashKey { get; set; }
public int Duration { get; set; }
public string BaseUrl { get; set; }
public Guid Id { get; set; }
}
Then a "Service" Interface to
public interface IApplicaitonSettingsService
{
ApplicationSettings Get();
}
public class ApplicationSettingsService : IApplicaitonSettingsService
{
private readonly ISiteSettingRepository _repository;
public ApplicationSettingsService(ISiteSettingRepository repository)
{
_repository = repository;
}
public ApplicationSettings Get()
{
SiteSetting setting = _repository.GetAll();
return setting;
}
}
I would take a totally different approach, one that doesn't involve anything static.
First create a class to strongly-type the configuration settings you're after:
public class MyConfig
{
int DecimalPlaces { get; set; }
string AdministratorEmail { get; set; }
//...
}
Then abstract away the persistence layer by creating some repository:
public interface IMyConfigRepository
{
MyConfig Load();
void Save(MyConfig settings);
}
The classes that can read and write these settings can then statically declare that they depend on an implementation of this repository:
public class SomeClass
{
private readonly IMyConfigRepository _repo;
public MyClass(IMyConfigRepository repo)
{
_repo = repo;
}
public void DoSomethingThatNeedsTheConfigSettings()
{
var settings = _repo.Load();
//...
}
}
Now implement the repository interface the way you want (today you want the settings in a database, tomorrow might be serializing to a .xml file, and next year using a cloud service) and the config interface as you need it.
And you're set: all you need now is a way to bind the interface to its implementation. Here's a Ninject example (written in a NinjectModule-derived class' Load method override):
Bind<IMyConfigRepository>().To<MyConfigSqlRepository>();
Then, you can just swap the implementation for a MyConfigCloudRepository or a MyConfigXmlRepository implementation when/if you ever need one.
Being an asp.net application, just make sure you wire up those dependencies in your Global.asax file (at app start-up), and then any class that has a IMyConfigRepository constructor parameter will be injected with a MyConfigSqlRepository which will give you MyConfigImplementation objects that you can load and save as you please.
If you're not using an IoC container, then you would just new up the MyConfigSqlRepository at app start-up, and manually inject the instance into the constructors of the types that need it.
The only thing with this approach, is that if you don't already have a DependencyInjection-friendly app structure, it might mean extensive refactoring - to decouple objects and eliminate the newing up of dependencies, making unit tests much easier to get focused on a single aspect, and much easier to mock-up the dependencies... among other advantages.
I have a Config class like this:
public class MyConfig : ConfigurationSection
{
[ConfigurationProperty("MyProperty", IsRequired = true)]
public string MyProperty
{
get { return (string)this["MyProperty"]; }
set { this["MyProperty"] = value; }
}
}
And it is being instantiated by another class like this
(MyConfig)ConfigurationManager.GetSection("myConfig")
We are making some changes and are now storing the configuration file in the DB as an xml, exactly like it is currently in the config file.
I would like to maintain the MyConfig as a ConfigurationSection for backwards compatibility but still be able to instantiate it by using the XML string retrieved from the DB.
Is it possible? If so, how? (Keep in mind it should still work as instantiated above)
Here is how I usually do it: just add these members to the MyConfig class:
public class MyConfig : ConfigurationSection
{
private static MyConfig _current;
public static MyConfig Current
{
get
{
if (_current == null)
{
switch(ConfigurationStorageType) // where do you want read config from?
{
case ConfigFile: // from .config file
_current = ConfigurationManager.GetSection("MySectionName") as MyConfig;
break;
case ConfigDb: // from database
default:
using (Stream stream = GetMyStreamFromDb())
{
using (XmlTextReader reader = new XmlTextReader(stream))
{
_current = Get(reader);
}
}
break;
}
}
return _current;
}
}
public static MyConfig Get(XmlReader reader)
{
if (reader == null)
throw new ArgumentNullException("reader");
MyConfig section = new MyConfig();
section.DeserializeSection(reader);
return section;
}
}
This way, you have nothing to change in the MyConfig class, but you still need to change the way your customers access it with this kind of code:
string myProp = MyConfig.Current.MyProperty;
If you need to get any System.Configuration.ConfigurationSection stored in database, you may consider writing generic section reader like this:
public class ConfigurationSectionReader where T : ConfigurationSection, new()
{
public T GetSection( string sectionXml )
{
T section = new T();
using ( StringReader stringReader = new StringReader( sectionXml ) )
using ( XmlReader reader = XmlReader.Create( stringReader, new XmlReaderSettings() { CloseInput = true } ) )
{
reader.Read();
section.GetType().GetMethod( "DeserializeElement", BindingFlags.NonPublic | BindingFlags.Instance ).Invoke( section, new object[] { reader, true } );
}
return section;
}
}
This will work for all classes that override DeserializeElement method. e.g.
protected override void DeserializeElement( XmlReader reader, bool serializeCollectionKey )
{
XmlDocument document = new XmlDocument();
document.LoadXml( reader.ReadOuterXml() );
MyProperty = document.DocumentElement.HasAttribute( "MyProperty" )
? document.DocumentElement.Attributes[ "MyProperty" ].Value
: string.Empty;
}
Than you could get a section like this:
var reader = new ConfigurationSectionReader();
var section = reader.GetSection( sectionXml ); // where sectionXml is the XML string retrieved from the DB
My suggestion would be to keep your current MyConfig class but load your XML from your database in the constructor, then in each property of your MyConfig, you can put in logic to determine where you get the value from (either database or .config file) if you need to pull config from either location, or have it fall back if the value is empty.
public class MyConfig : ConfigurationSection
{
public MyConfig()
{
// throw some code in here to retrieve your XML from your database
// deserialize your XML and store it
_myProperty = "<deserialized value from db>";
}
private string _myProperty = string.Empty;
[ConfigurationProperty("MyProperty", IsRequired = true)]
public string MyProperty
{
get
{
if (_myProperty != null && _myProperty.Length > 0)
return _myProperty;
else
return (string)this["MyProperty"];
}
set { this["MyProperty"] = value; }
}
}
This is a hard problem. You could have a config file with some deliberately incorrect XML, override OnDeserializeUnrecognizedElement in your ConfigurationSection and then effectively bypass the file to ConfigurationSection mapping (essentially set your properties manually) - some refactoring would be needed, but you can still expose the same properties etc. It is a bit WTF, but possibly workable.
I essentially describe how to do this with LINQ to XML in this blog post. In all of my code now I don't have classes that rely on ConfigurationSection, I use the technique described in my blog post to bypass that and return POCOs through an interface. This has made my code more unit testable, as I can easily use a stub for the interface.
I can also easily move my configuration into a DB should I wish to do so- I just create a new class that implements my configuration interface and switch it in my IoC configuration. Microsoft didn't design the configuration system to be flexible, so you have to take that into consideration when using it in your own code.
The only other way I can think of is to write the DB config out to a file and then read it in, but that is also weird!
Rather old question, but just playing around with a solution to this. It's similar to Simon Mourier's approach (which I like a better in some ways - less hacky) but does mean any code that calls System.Configuration.ConfigurationManager.GetSection() will continue to work without having to change them to use the static method, so might result in less code change overall.
The first basic caveat is that I have no idea if this works with nested sections, but I'm almost certain it won't. The nearly-main caveat is that it requires changes to the config section class, so you can only use it with custom sections that you have the source to (and are allowed to change!)
The second and MAIN CAVEAT is that I'm just playing around with this, I'm not using it in either development and definitely not production, and simply smearing my own code over the base functionality like this may well have knock-on effects that do not show up in my example. Use at your own risk.
(Having said that, I'm testing it in an Umbraco site so with loads of other config sections going on, and they still all work, so I think it has no immediately awful effects)
EDIT: This is .NET 4, not 3.5 as per the original question. No idea if that wil make a difference.
So, here's the code, pretty simple, just override DeserializeSection to use an XML reader that loads from a database.
public class TestSettings : ConfigurationSection
{
protected override void DeserializeSection(System.Xml.XmlReader reader)
{
using (DbConnection conn = /* Get an open database connection from whatever provider you are using */)
{
DbCommand cmd = conn.CreateCommand();
cmd.CommandText = "select ConfigFileContent from Configuration where ConfigFileName = #ConfigFileName";
DbParameter p = cmd.CreateParameter();
p.ParameterName = "#ConfigFileName";
p.Value = "TestSettings.config";
cmd.Parameters.Add(p);
String xml = (String)cmd.ExecuteScalar();
using(System.IO.StringReader sr = new System.IO.StringReader(xml))
using (System.Xml.XmlReader xr = System.Xml.XmlReader.Create(sr))
{
base.DeserializeSection(xr);
}
}
}
// Below is all your normal existing section code
[ConfigurationProperty("General")]
public GeneralElement General { get { return (GeneralElement)base["General"]; } }
[ConfigurationProperty("UI")]
public UIElement UI { get { return (UIElement)base["UI"]; } }
...
...
}
I'm using ASP.Net, so to make it work, you do need a web.config, but then hey, I need somewhere for connection strings anyway or I'm not going to connect to a database at all.
Your custom section should be defined as normal in <configSections/>; the key to making this work is to then put an empty element in place of your normal settings; i.e. in place of <TestSettings configSource="..."/> or you inline settings, simply put <TestSettings/>
The configuration manager will then load all sections, see the existing <TestSettings/> element, and deserialize it, at which point it hits your override and loads the XML from the database instead.
NOTE: The deserialize expects a document fragment (it expects to be called when the reader is already located at a node), not a whole document, so if your sections are stored in separate files, you must remove the <?xml ?> declaration first, or you get Expected to find an element.