I have a Winform app that has 16 SQL Connections currently stored in the DAL Projects Settings.settings.
I am trying to write a "Manager" class to simplify this(like here). However, most of the examples I find on the web seem to use ConfigurationSettings.AppSettings["something"]. While, I WAS using Properties.Settings.Default.something.
Can someone, please, explain which is considered CORRECT and why for a Desktop applications?
I think the correct way is to use the app.config file and store them in the connectionStrings section?
Then you can access them like:
ConfigurationManager.ConnectionStrings["something"].ConnectionString
You could write a wrapper around that easily if that is too "ugly".
public class ConnectionManager
{
public string Something
{
get
{
// TODO: check to make sure the configuration exists and throw an exception perhaps
return ConfigurationManager.ConnectionStrings["something"].ConnectionString;
}
}
}
Oops...as pointed out I meant to do ConfigurationManager and not ConfigurationSettings.
I've never been a big fan of putting sql connection strings into configuration files for software. Users have a habit of goofing them up out of curiosity or stupidity (or some combination of the two). I like to put all of my connection strings (development, model, production, whatever) into the Properties of my data access library, and include within it a ConfigurationSettings class that I use to access them based on some property that is set by the consuming application:
public class ConfigurationSettings
{
public static string MyConnectionString
{
get
if(ConfigurationSettings.TestMode)
return Properties.Settings.Default.MyConnectionStringTest;
else
return Properties.Settings.Default.MyConnectionStringProd;
}
}
// I typically only have test and not-test. This could
// easily be some other combination of values to satisfy
// multiple environments.
public static bool TestMode { get; private set;}
}
This allows me to call the static properties of this class through a common name and have all connection strings available depending on some criteria. This gets your specific datasets, entities, whatever data model you're using from being in the business of worrying about connection strings and the settings can be compiled into the .dll (and no longer need to worry about them). This method can also be modified to pull settings from an app.config (which I do for ASP.Net sites) in a similar method.
UPDATE: There really is no "correct" way as you imply. The app.config was designed to hold configuration settings that are modifiable without rebuilding the application. Property Settings were designed to hold settings that are not modifiable. So both are perfectly valid. Probably the most "correct" way is a way that makes sense both for your application and for your development team.
We prefer to use Properties.Settings (aka. settings.settings) because it's strongly typed. Don't try to do fancy tricks that have different environments (dev/prod) in the same config file. It is much easier to have a separate config file per environment, and to rename the configs when you deploy them. i.e.
app.config
app.stage.config
app.test.config
app.prod.config
We use PowerShell scripts (batch files on steroids) to do our deployments. I'll simplify what we do as a traditional batch file - (pseudo code/untested sample):
#echo off
:: %1 is the environment name (first parameter)
setlocal
set source=c:\tfs\project\bin\release\
set target=\\server\share\path\
xcopy /s/e %source% %target%
:: Using a copy command to rename/overwrite the env specific version
if exists %target%\app.%1.config copy /y %target%\app.%1.config %target%\app.config
Properties.Settings.Default are generally used to save application internal state like the color of the background, to remember user settings.
ConfigurationSettings is actually the "Manager" class you were talking about and can access other custom sets of settings from the app.config file, including connection strings.
Related
I have a C# project that outputs a dll: foo.dll. This foo.dll internally uses a legacy library legacy.dll. Here is how my library foo.dll will be used: first I upload these files: foo.dll, legacy.dll, and legacy.dll.config to a third party; then the third party starts up a process which loads my main library foo.dll and executes some functions. When foo.dll is being run, I see exception thrown in legacy.dll saying some configuration "baz" cannot be found. However, I can verify that the configuration "baz" is defined in the legacy.dll.config file. So I think the file legacy.dll.config is not loaded by the process.
So I wonder how config.dll files are used. In my case, considering foo.dll is the only thing within my control, is there a way to load the legacy.dll.config file?
One solution is to place the configuration section that your legacy.dll requires in the configuration (app.config or web.config) for the application that references it.
Do you have control over your legacy application - in other words, are you able to modify it? One occasional challenge is that when all of these extra values are dumped into the configuration it can be more difficult to tell where they are used. They can even get left in the configuration long after you stop using legacy.dll because no one knows what they are and they're afraid to remove them.
Going the other way, if the values are missing from the configuration, it's best not to throw a confusing NullReferenceException or configuration exception that requires someone to dig into the legacy code and figure out why it doesn't work.
There are a few things you can do to make this easier:
One is that your legacy.dll can look for configuration values that are distinct and separate from the rest of your configuration.
That could mean a separate configuration section like
<section name="stuffTheLegacyDllNeeds" type="Legacy.LegacySettingsConfiguration, Legacy" />
<stuffTheLegacyDllNeeds>
....
</stuffTheLegacyDllNeeds>
Or you can disambiguate the appSettings keys with some convention like
<add key="myLegacyLibrary:someSetting" value="true" />
You can also make it easier for other developers by throwing useful exception messages if a required key is missing, like "Legacy requires appSettings key 'xyz' which was not found." They still have to figure out where to find the values but at least they have a clear understanding of the problem.
Also, if you find that Legacy.dll doesn't change settings often or ever, you can code it to replace missing values with default values. That way they can override the defaults if they need to by adding configuration values. But if they don't need the defaults they can just not supply configuration values.
One more approach - this is the one I personally prefer:
Make your legacy class depend on an interface for settings like
public interface ISettings
{
bool SomeSetting { get; }
int SomeOtherSetting { get; }
}
and make your legacy class require an instance of ISettings in its constructor. Now the app that references it "knows" about the settings because it can't use the class without providing it. Your legacy library can provide an implementation like
public class ConfigurationSettings : ISettings
that reads from configuration, and the referencing app could choose to use it. Or it could supply another class that implements the interface. It could also provide a class that contains default values which the referencing app could change. It could also have a set of defaults that it uses internally if the referencing app doesn't provide any values.
Now,
The referencing application knows that your class needs these settings.
The referencing application can choose how to provide them.
Your legacy library no longer depends on the configuration. It depends on an abstraction - ISettings - which can be implemented using configuration or some other way. That means your legacy library will be easier to unit test. Code that explicitly depends on configuration values is much harder to test, or likely never even gets tested.
We are a group of C#/.NET 4.5 developers working on the same application.
The application has a set of configurations related to each developer machine, like the connection string to the DB, network related settings (proxies, IPs, credentials) and a LOT MORE.
Because the application has grown we are incurring in a lot of environment related configurations like for example:
If this is MyPC then load the connection string for my PC.
If this is the XDeveloperPC then specify proxy’s settings.
Also if new developers leaves or join the group, then the process to update the file becomes a total head ache. Maintaining the file has become very hard and is a possible source of bug and errors.
I was thinking in having specific app.config files related to each developer environment like:
app_MyPC.config
app_XDeveloperPC.config
And when the application builds or executes then specify which one to load as if it where the default app.config of the application. Then, when the application or any class or method refers to a given configuration (like the connection string) is access to this configuration file as if it where accessing to the app.config default file.
I would not want to create a Configuration class that builds immediately when the application starts because then I should have references from every place to this class and the application is quite large, with a bunch of projects and dlls.
I rather prefer to hear some opinions and what do you think should be the best way to achieve this.
Is it possible to achieve this?
How?
Do you know a better approach?
FYI, please note that .NET only loads one config file for the whole application. You could try multiple config files something as like specified here,
Multiple App.Config Files in .NET Class library project
Hope this helps...
You can specify sections of app.config to be loaded from another file. See this answer
However, you might have to customize the above solution, the app.config files and the way configs are organized.
Another approach is to use a custom settings file instead of app.config. This will need some code change to use the config file. This config can either be an XML or a JSON file (JSON is easy to deal with). You can use an inheritance model wherein generic settings come from one file, specific settings come from another file and so on. Also, you can load settings from such file at runtime and change application behavior on the fly.
If you decide to use custom config file, and if you already have lot of code written considering App.config file, you can abstract the app.config calls to a method and let that method deal with where to pull the settings value from. That way you can minimize the code change and keep everything tidy.
Maybe you can use the machine.config file (C:\Windows\Microsoft.NET\Framework\your Framework version\Config\machine.config)
If I go to Project -> Myproject Properties -> Settings I can create a settings file for the entire project. However supposed each class requires its own configuration file. Is there a similar way to do this at the class level?
By way of example suppose I have a parent class Car with subclasses Ford and Honda. I want to have a single property YEAR and a single piece of code for reading the YEAR property. I could do this by having two configuration files with the same YEAR property. If I used Ford.YEAR and Honda.YEAR than I would need two separate pieces of code for parsing the data which could get messy for a large number of classes.
It's not really designed for that.
You can use the System.Configuration.ConfigurationSettings classes to open a file explicitly in code to read your settings from. THis will work however the designer will give you no assistance creating your settings files.
Do you have an issue with class wide settings?
Another way that might help you is to create a custom configuration section which you can put in the file. Then you can split each of your classes settings into it's own configuration section. That might suit your purposes?
Configuration data is stored for an executable in its config file (which is a single file, regardless of the number of "settings" files in your project) and is not class-specific. You can set naming conventions for your setting keys configuration options related to a class like ClassName.ConfigName.
You could to create specific sections for your subclasses: How to: Create Custom Configuration Sections Using ConfigurationSection
When you start a .net application, it takes your entry point assembly configuration file and load it up into memory. But just one.
So, if you have a MyApplication.exe which uses a MyLibrary.dll and both have configuration files, just MyApplication.exe.config will be loaded.
You'd have to do it manually, as the others have suggested. However, I'd strongly recommend against this, as I would think you'd have a configuration nightmare to deal with in the end.
As per the other answers, no configuration files are not class specific, you'd be best off creating a class which handles retrieving and setting configuration (a ConfigManager-style interface).
I'd have to ask you though, do you really want configuration per class?
That sounds like a configuration management nightmare scenario. You'd have to entertain scenarios where configuration is either missing or invalid on a per-class basis - and take appropriate steps accordingly.
If your design calls for per-class configuration, perhaps you would be better served storing it in a database or using another medium?
Many of the current IoC containers would allow you to do such a thing through its dependency injection (DI) possibilities. In fact, when XML configuration was all the rage in DI land, you would pretty much get all this out of the box. Today many IoC containers support a programmatic way of setting up dependencies, which you can quite easily hook to whatever XML file you want to provide. Check out this example with the IoC container StructureMap:
IContainer c = new Container();
c.Configure(ce=>
ce.For(typeof(A)).Use(typeof(A)).WithProperty("Test").EqualTo("Hello"));
var a = c.GetInstance<A>();
Debug.Assert(a.Test == "Hello");
By parsing an XML file containing information like targeted type, name of the property, its value, and then calling the above API, you can get what you want.
What's the difference between the WebConfigurationManager and the ConfigurationManager?
When should I use one over the other?
UPDATED
I just looked at the WebConfigurationManager, and for some reason, you can't access the connection strings as you do in the ConfigurationManager (like an array). Can anyone tell me why MS made it like this? It seems to be a pain to get the connection string you need using the WebConfigurationManager.
UPDATED AGAIN with CAVEAT!
If you don't have a reference to the System.Configuration namespace added to your project, then Visual Studio will show an error when you try and access the WebConfigurationManager.ConnectionStrings like an array!
WebConfigurationManger knows how to deal with configuration inheritance within a web application. As you know, there could be several web.config files in one applicaion - one in the root of the site and any number in subdirectories. You can pass path to the GetSection() method to get possible overridden config.
If we'd looke at WebConfigurationManager with Reflector then things are clear:
public static object GetSection(string sectionName)
{
...
return ConfigurationManager.GetSection(sectionName);
}
public static object GetSection(string sectionName, string path)
{
...
return HttpConfigurationSystem.GetSection(sectionName, path);
}
WebConfigurationManager is made specifically for ASP.NET applications.
WebConfigurationManager provides additional methods to load configuration files applicable to Web applications.
ConfigurationManager provides also methods to load configuration files applicable to ".exe" applications.
I’d suggest taking a look at WebConfigurationManager and see if it provides you with anything you simply cannot do with ConfigurationManager and use it instead, otherwise using ConfigurationManager will make it far easier to have your code be used seamlessly between web and desktop aps.
Not sure what you mean about the connection strings.
Calling WebConfigurationManager.ConnectionStrings returns a System.Configuration.ConnectionStringSettingsCollection, which is the same as you would get if you called ConfigurationManager.ConnectionStrings.
Otherwise, as XOR says, it's designed to handle multiple hierarchical web.configs, combining them as required as you move around the folders in an application.
Although WebConfigurationManager is located in the System.Web assembly the ConnectionStringSettingsCollection that it returns is located in System.Configuration.
If you are getting the error
Cannot apply indexing with [] to an expression of type
'System.Configuration.ConnectionStringSettingsCollection'
while trying to access the array index...
WebConfigurationManager.ConnectionStrings["Name"].ConnectionString
make sure you have a reference to assembly System.Configuration
I have an asp.net mvc project that uses some search methods in a seperate library.
This library needs to know the location of my lucene index files.
private static string lucenePath = ConfigurationManager.AppSettings["lucenePath"];
public static ColorList SearchColors(Query query) {
return new ColorList(
new IndexSearcher(Path.GetFullPath(lucenePath)),
query);
}
This correctly reads my configured lucenePath from the web.config's application key node.
But how can I get the correct full path from this relative path? Path.GetFullPath gives me a completely incorrect path.
--Conclusion--
If you want to go full-out, tvanfosson's answer is probably for you.
I, however, kept it a little more brain dead by using the following:
Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
ConfigurationManager.AppSettings["luceneIndex"].TrimStart('\\'));
This will look in the caller's app.config for an appkey called "path" and combine its value to the caller's path. The TrimStart() makes sure that the config file can both contain a leading \ or not.
Server.MapPath(string);
Since you are referencing this from a separate library, you might have to jump through a bunch of hoops to get access to the HttpServerUtitity or introduce some coupling to classes that are difficult to mock. You might want to consider having a single configuration class that loads properties from the web configuration that gets injected into your library via constructor/setter. To make it easier to test against, you could define an interface that could be mocked in your unit tests and have it implement that. The configuration class could use the HttpServerUtility to obtain the absolute path and store it internally to be reused.