Is having a global Config class a bad thing? - c#

Currently in my personal website I'm building I'm using a global static Config class to hold everything configurable I might need to change that is semi-global. So right now it looks about like this:
public static class Config
{
public static string ConnectionString = "mongodb://localhost";
//more configuration options..
public static MongoDB.Driver.MongoDatabase GetDB(){
MongoServer server = MongoServer.Create(Config.ConnectionString);
MongoDatabase db = server.GetDatabase(Config.Database);
return db;
}
public static Markdown GetMarkdown(){
var options=new MarkdownOptions(){
AutoHyperlink=true,
AutoNewlines=false,
EmptyElementSuffix=" />",
LinkEmails=false,
StrictBoldItalic=true
};
var m=new Markdown(options);
return m;
}
}
Is using a global config class like this an anti-pattern of some sort? Also, I prefer for my connection strings to be outside of web.config. I like my web.config to be as minimal as possible.

Well of the 3 members only 1 is really config, the other two are utility really.
Having configuration in compiled code is really a pain to maintain if those configs need to be changed, since it requires a rebuild, that is really the reason for configuration files.

I do things similar to this but not for settings like connection strings. If the connection string needs to change, you need to update and rebuild your project. If you stored the connection string in your web.config, a simple update allow your app to immediately use the new setting (no recompile).

Earlz ,
Regarding your second question you can do something like this, there is no need to have all the connections or configs in web.config. You can have a separate config file and point that in the web.config file as below
<connectionStrings configSource="config\yourpath\connectionStrings.config"/>
Regarding the first question , write a common method which get the values. Load all the values to a constants file and write a helper class to get those values

The anti-pattern is that you have GetMarkdown and ConnectionString together in the same class because they are both static, yet they really have no functional relationship. GetMarkdown and GetDB both look like factory methods and they should probably be in their own classes.
The Single Responsibility Principle says you should group things together that are likely change for the same reason. It's unlikely that your database connection and markdown config will change at the same time or for the same reason.

We moved our config settings to the database. Makes it easier when moving from Dev to QA to Prod. The blog entry is here.
Related to this, we put the connection string off to the side in a WebEnvironment.config. So now we can promote our code with web.config changes and not worry about the connection string. That blog post is here.

Related

Override dll config

i have a class library, with domain objects (linq based objects, in .net
4.0).
i want to have this library use connection strings for its own app.config.
there are some problems:
following the model used by Settings : ApplicationSettingsBase, i created a
wrapper that should read the settings from app.config.
however, unlike the model, i provide default values.
the problem is that the properties which should load the data from app.config
internal sealed class ApplicationSettings : ApplicationSettingsBase
{
// other properties
[SpecialSetting( SpecialSetting.ConnectionString )]
[global::System.Configuration.DefaultSettingValueAttribute("Server=.;Database=RFPLUSSTD;User Id=SYSADM;Password=SYSADM;")]
public string MainConnectionString
{
get { return (string)this["MainConnectionString"]; }
}
// other properties
}
in app.config:
<connectionStrings>
<add name="MainConnectionString"
connectionString="..."
providerName="System.Data.SqlClient" />
</connectionStrings>
now, this doesn't work...
i tried to set the name of the conn string to the fully qualified name like
namespace.class.property, but to avail.
i don't want to use the default Settings class, used by the dbml because
it compiles the settings :D and i can't change them without recompiling...
i'm already using a different model of app settings class in a project in
1.1, but i thought 3.5 has grown enough and have its own objects, that
work..
So, why is not working and how can i make it work?
Thank you
You need to make sure that you have permissions in the file system to make the change. I hope you have considered that. If you are sure that you changed the config file and if it only brings the default settings, it might be loading the config file from output bin folder not in the project root. If you are sure that the modification fails, please post the error message.
Updated:
Hi Jack, I think the main issue with your code is that it is creating new instance of the ApplicationSettings class every time and if the setting is in user scope, you will be having null value and then it results to default value every time.
You could easily do it with the built in Settings class. By default the Settings can only be accessed within the Assembly, internal sealed partial class Settings (in Settings.Designer.cs). If you change this to public sealed you will be able to access the Settings from any assembly and the next thing is you have to keep the setting to Application Scope not User scope. Once you have done these two, you can retrieve and save without any problem.

App.config multi-project access strategies

My current solution has 3 project with 2 app.config (one for common settings and another for service settings). As of now I'm simply creating static classes to act as a mediator to access values. I do this so I don't have to write ConfigurationManager.AppSettings["SomeKey"] everywhere. This works fine until you want to access an app.config file from a different project.
Here is what I'm currently doing (all properties omitted for brevity).
public class ServiceConfiguration
{
public static readonly string SyncEvery = ConfigurationManager.AppSettings["SyncEveryMinutes"];
}
How can I access an app.config file located in another project? I thought perhaps setting VS to copy the file to the output directory would do the trick however my configuration object is still null.
I can't imaging many good reasons to read another app's configuration in the first place, it just opens a can of worms that isn't worth dealing with.
Expose a class that exposes the project's configured values as properties, and access them from a consuming class.
public class FirstProjectClass
{
public static int SyncEveryMinutes
{
get { return (int)ConfigurationManager.AppSetting["SyncEveryMinutes"] };
}
}
public class SecondProjectClass
{
public void ShowConfigedValue()
{
Console.Writeline("Syncing every {0} minutes", FirstProjectClass.SyncEveryMinutes);
}
}
if you've got complex configuration requirements you can also look into custom configuration sections
ConfigurationManager.OpenExeConfiguration can be helpfull:
http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.openexeconfiguration.aspx
Also: what Jason said - it is usually a bad idea.

Enable "Debug mode" in ASP.NET MVC app through the use of C# directives

My actions in ASP.NET MVC controller are decorated with numerous properties like this
[OutputCache(Duration = 86400, Location = OutputCacheLocation.Client,
VaryByParam = "jsPath;ServerHost")]
[CompressFilter]
public JavaScriptResult GetPendingJavaScript(string jsPath, string serverHost)
What I would like to do is to wrap this in something like #if and #endif, and have DebugMode setting in my web.config file. When this setting would be set to true, the decorating properties should be disregarded - I want to enable debug mode and in debug mode no compression and caching should occur.
So essentially it would be like commenting out those decorating properties (what I'm actually doing now and got fed up with it):
//[OutputCache(Duration = 86400, Location = OutputCacheLocation.Client,
// VaryByParam = "jsPath;ServerHost")]
//[CompressFilter]
Obviously #if and #endif work with defined (#define) C# symbols, I couldn't find any example where this would work with other types of condition (like web.config values, etc.).
Help appreciated
Instead of this, I would make use of Web Deployment Projects, and the configSource attribute in the web.config.
I would split the web.config into two files for each component. For example, for your output cache would be split into outputcache.dev.config and outputcache.live.config. You should enter the config source as the dev config file.
Your dev.config would basically tell your app that you don't want to cache running (enableOutputCache="false").
Then, when you run your deployment project, you can have settings to replace the dev.config strings with live.config instead.
More discussion on configSource and Web Deployment Projects.
As for your CompressFilter problem... Well, I would simply have an app setting value in your config files. Following on from splitting the config files, you would have appsettings.dev.config, and appsettings.live.config. In your dev, you would have something like:
<add key="InLiveMode" value="false" />
And in your live.config, yep, you've guessed it:
<add key="InLiveMode" value="true" />
Then when you use the attribute, you can simply against the InLiveMode app setting.
FYI: I much prefer having some sort of facade class so I'm not dealing with magic strings in the code, but for the sake of simplicity, you'd have something like:
//CompressFilter class
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
bool inLiveMode = bool.Parse(ConfigurationManager.AppSettings["InLiveMode"]);
if(inLiveMode)
{
//Do the compression shiznit
}
}
Sorry, there's nothing in .NET that will cause different parts of your code to compile based on what's in a config file at runtime.
This article demonstrates how to modify or extend your MVC filters (AOP) to cater for the situations you have described. Whereas the config files can be modified for deployment, when running in debug mode the problem still arises.
http://www.avantprime.com/blog/21/how-to-handle-output-caching-in-the-development-environment-for-asp-net-mvc-applications

Class design/best approach for initializing a user configuration file

I want to initialize a user configuration through a user configuration file. The path for the file can be read from the registry.
The file is located in a folder with the user's name.
So I need the following functionality:
Reading a string from registry
building the path to the configuration file
Reading the file into a configuration object
Now there are several approaches to handle this:
First, I need
one "helper"-class for getting the file path (let's call it Shared)
one "container"-class for the configuration information (let's call it Configuration)
So, Shared has a function/property like UserConfigurationFile which returns the path to the configuration file.
To get the path to the file I have a function InitializeUserConfigurationFile() which is called in the constructor of Shared:
class Shared {
public Shared()
{
InitializeUserConfigurationFile();
}
void InitializeUserConfigurationFile()
{
//
// Reads username
//
//
// Reads path from Registry
//
//
// etc.
//
}
//
// etc.
//
}
Any better suggestions?
When I want to Initialize my Container I have different options:
Is it best to initialize the user configuration within the constructor?
Sth. like:
class Container
{
Shared shared = new Shared();
public Container()
{
InitializeUserConfiguration();
}
void InitializeUserConfiguration()
{
LoadConfiguration(shared.UserConfigurationFile);
}
void LoadConfiguration(string filename)
{
//
// Initializes all parameters frome filename
//
}
}
Or through two steps (through an own method LoadConfiguration())?
Sth. like:
Shared shared = new Shared();
Container container = new Container();
container.LoadConfiguration(shared.UserConfigurationFile);
Or inside the constructor of Container by delivering a filename?
Sth. like:
Shared shared = new Shared();
Container container = new Container(shared.UserConfigurationFile);
or everything in Container..?
There are so many ways...
I hope somebody knows a best-approch...
Regards,
Inno
It is better to use standard configuration classes exist in .net. Such as ApplicationSettingsBase and Configuration.
Here you can find good article series:
Unraveling the Mysteries of .NET 2.0 Configuration
Unraveling the Mysteries of .NET 2.0 Configuration
Cracking the Mysteries of .NET 2.0 Configuration
For best practices, don't use the registry, and don't reinvent the wheel.
Since you didn't mention it, have you looked at the System.Configuration namespace?
The .NET Framework constains a perfectly good configuration system that is well tested. It is also the domain of Sys Admins, who also know about config files and the accompanying tools.
So it is unclear why you are reinventing the wheel, possibly making it a little less round.
There are practical reasons to shun the Registry (distribution, backup) but also, as arbiter points out, it is not going to move to other (future) platforms. Did you notice that those namespaces are not starting with System ?

Access User context from a class library

Background:
I have a win app and a web app and a
shared class library.
In my class lib I have some static
methods for SQL queries which pick up
my SQL connection string
I store my SQL connection string in a
Session variable since it is set at
log in time where it is determined
which database to use.
My class lib cannot access my session
variables (yes, of course I can use
HttpContext.Current..., but that wont
work in my winapp)
Solution?
I envision a sort of solution where I have a class for my current user/context and when creating it I inject the preferred behaviour, something like this:
UserContex current = new UserContext();
current.SessionHandler = new AspNetSessionHandler();
However, I would like a static class which I could user without having to pass it along all the time and then it would get it's variables either from the session if used in a web app or from somewhere else (I'm not a winapp developer) if used in a winform.
I will try to conjure up this kind of thing, but it would be great if I found an already working solution and that's why I call on the shared collective madness of you guys
Csla contains a similar setup using a static ApplicationContext class which is discussed in Rockford Lhotka's book Expert C# Business Objects...To deal with the connection string issue I would suggest creating a DataConnection class that returns a static connection string from the config file that way it doesn't matter if the connection string is coming from the Web.config or the App.config
public class DataConnection
{
public static string NameOfConnection
{
get
{
return ConfigurationManager.ConnectionStrings["NameOfConnection"].ConnectionString;
}
}
}

Categories

Resources