Thoughts on how to refer to web.config key names in code - asp.net

When your web.config or app.config file has an appsettings entry, what is the best way to refer to its key in your code file?
Developers I have worked with have differing opinions on this. Some say to hard code the string and others suggest that there should be a file containing string constants and in your code, you use the constant as the appsettings key.
I would be interested in hearing other opinions on this. What do you do? Why is it the best?

String constants are better than nothing, but I'd initially vote for using a configuration class to provide strongly typed, intellisense friendly access to the config values. If I were stuck with using AppSettings for some reason.
In a more perfect world, I would vote for avoiding appSettings altogether and using custom configuration classes as they are much, much cleaner in the long run.

Skip the string constants, and create a configuration wrapper class instead.
class MyConfiguration
{
public static string SomeConfigValue
{
get
{
return WebConfigurationManager.AppSettings["SomeConfigValue"];
}
}
public static int SomeOtherConfigValue
{
get
{
return int.Parse(WebConfigurationManager.AppSettings["SomeOtherConfigValue"];
}
}
//..and so on
}
Then you could get it like this:
string s = MyConfiguration.SomeConfigValue;
int i = MyConfiguration.SomeOtherConfigValue;
(You might consider not going the static route if you want to remove dependencies on the configuration system while unittesting)

String Constants for the win.
Keeping common strings in string constants makes things easier to maintain. If a key in your config file changes names, you only have to change it in one spot rather than worrying about finding every instance of the hard-coded string throughout your application.

I've always been a fan of Rick Strahl's method.
As for static strings being unwieldy, break your class down into subclasses and properties if you need to. For example in an application I'm currently working on, I have App.Settings for general settings, App.EmailSettings for email settings, and App.EventSettings for event logging settings.

Related

C#/ASP.NET MVC 4 Instantiate Object Derived From Interface In Factory Method

Currently have a Factory class that features a GetSelector function, which returns a concrete implementation of ISelector. I have several different classes that implement ISelector and based on a setting I would like to receive the appropriate ISelector back.
public interface ISelector
{
string GetValue(string Params);
}
public class XmlSelector : ISelector
{
public string GetValue(string Params)
{
// open XML file and get value
}
}
public static class SelectorFactory
{
public static ISelector GetSelector()
{
return new XmlSelector(); // Needs changing to look at settings
}
}
My question is what is the best way to store the setting? I am aware of using AppSettings etc. but I'm not sure whether I want to have to store strings in the web.config and perform a switch on it - just seems to be really tightly coupled in that if a new implementation of ISelector is made, then the Factory would need to be changed. Is there any way of perhaps storing an assembly name and instantiating based on that?
Thanks,
Chris
It is hard to say, because I don't know the architecture of your particular project, but at a first glance what I would do is if the objects associated with ISelector can be decoupled from your web application, I would put these objects in a class library along with the factory. Your factory will need to be changed if you implement a new ISelector, but if you can decouple the whole ISelector family from your actual web application the depth of the refactoring you will have to do will be minimal compared to a monolithic architecture.
Personally, I tend to avoid AppSettings, web.config settings and the like for mission-critical design questions. Using the web.config as an example, I have seen applications where architectural data is stored for ease of configurability. The problem is that after compilation your web.config can be changed (that is the purpose of it after all) and if the implementation of your classes depends on very specific values being chosen, you are running a risk of a crash when someone inadvertently modifies the wrong value.
Like I said all this depends entirely on your application architecture, but my reflex would be to split out the components that could be subject to future modification into a class library. Loose coupling is your friend ;).
Instead of doing it in AppSettings, I think a better approach will be to create a separate XML file, which will only hold the mappings and from that file you can iterate through the mappings and return correct instance in GetSelector().

Managing Urls in WebForms

I have a large Webforms application. In many places throughout the application we set the navigation urls of hyperlinks in code behind. Hard coding string literals seems like a bad idea.
hlVideos.NavigateUrl = "/path/to/some/page.aspx";
This doesn't seem like a good idea either, since it could require me to have a constant string on every page that needs it:
private const string PathToSomePage = "/path/to/some/page.aspx";
hlVideos.NavigateUrl = PathToSomePage;
I've thought about a single class with a bunch of const strings in it that can be accessed. This seems like it would be an open/closed principle violation, requiring me to add another constant every time that I add a new page.
public class UrlManager
{
public const string PathToSomePage = "/path/to/some/page.aspx";
public const string PathToSomeOtherPage = "/path/to/some/other/page.aspx";
public const string PathToYetAnotherPage = "/path/to/yet/another/page.aspx";
}
How is everyone else handling this? Maybe I'm over complicating this, although I am dealing with a hundred urls or so with many pages referencing each url.
Consider using a resource file. That way you can maintain a consistent reference to pages, but it is easily maintainable in code and easily hot-fixed post-deployment if the situation requires.
You can try to write some T4 template to generate your UrlManager file class. Something like T4MVC. Look here for WebForms example T4Mvc web forms

How can I improve our CM.AppSettings references

ASP.NET 3.5
Classes throughout our solution referenced ConfigurationManater.AppSettings[""] to get appSettings (from web.config).
We decided we weren't happy with that. Folks were mistyping appSetting key names in code (which compiled fine), and it was cumbersome to track usages. And then there's the duplicated strings throughout the codebase as you reference the same appSettings all over the place.
So, we decided that only one class would be allowed to reference the ConfigurationManager, and the rest of the solution would reference that class when it needed the value of a certain appSetting. ConfigurationManater.AppSettings[""] was static, so we exposed a bunch of static read-only properties off of our single Settings class.
public class Settings {
public static string Foo {
get {
return ConfigurationManager.AppSettings["Foo"];
}
}
}
That worked pretty well, until we needed to mock the settings in our tests. We created an interface to enable our mocking (was this a mistake of any kind?).
public interface ISettings {
string Foo {
get;
set;
}
}
public class Settings : ISettings {
public string Foo {
get {
return ConfigurationManager.AppSettings["Foo"];
}
}
}
And now we're injecting the ISettings instance as a dependency of the objects which use settings values (the class/interface are in a project that everyone can reference without problems).
In places where we can't inject an existing instance (e.g. Global.asax), we construct a new instance into a static field.
Given all of that, what would you recommend we change, and why?
Using an interface to represent configuration is a good idea. But your implementation looks a little off.
Joshua Flanagan wrote about writing application configuration code in a way that specific configuration sections can be injected into your code. This is a good idea, as it really decouples your code from worrying about details behind configuration. Have a read.
I think this will address the issue you are having re. testability.

Reading Application Configuration during Application_Start

Consider a web application that resizes large tiff files on the fly. Each large tiff file is resized into a jpg thumbnail and larger jpg when the user invokes the operation. The dimensions of these converted files is always the same.
During a code review yesterday, one of the other developers asked me why I set those dimensions in my global.asax like so:
Application["resizedImageWidth"] = int.Parse(ConfigurationManager.AppSettings["ResizedImageWidth"]);
, instead of just looking up the value via a Configuration file during the actual method invocation. I store the widths in the configuration file in the event the end user's after testing the application would like to alter dimensions so I would not have to change code inline.
The reasoning I gave was to prevent the read from the configuration file each time an image was generated, but could not answer if there was similar overhead during a lookup to application level variables. This optimization probably doesn't affect performance to a large scale, but I wanted to know what the community thought the more efficient solution was, i.e. set them during Application start up, or read them on the fly during method invocation.
Generally you should read from the configuration on the fly as you need it. The framework will cache the configuration file, so it is fairly performant. And I believe (Don't quote me) that ASP.Net can monitor and bring in the changes to a configuration file without restarting the application.
I typically like to create a Configuration class which will hide the details of where the value is stored:
public static class Config
{
public static int GetXDimension()
{
...
}
}
This keeps your calling code clean from the configuration code, and if you find I'm wrong, you won't have to change your code everywhere.
You are correct to store this value in an Application object. Indeed, that is the express purpose behind the provision of Application: to hold values that are to be available across all pages and users of the application.
It will indeed be more performant as the application settings are held in memory. It should be pretty obvious that reading from memory is significantly faster than reading from your configuration file (not to mention the lookup via the ConfigurationManager.AppSettings class method and the integer parse).
Any changes to the web.config file will indeed result in a restart of the application. Indeed, this is how I restart my application (when needed) during testing. If you need to change this value "on the fly" you may even want to store this value in a "Configuration" table in your database rather than keeping it in the Web.config file so that changing it doesn't reboot the App.
One trick that I have used is similar to Josh's Config class: I have a "BusinessLogic" class and I place a small handful of settings in static variables of this class so that I can access them in a type-safe manner. It isn't hard and the payoff is pretty obvious in terms of readability.
I would recommend expanding Josh's answer and call it on demand, but then cache it into a private variable:
public static class Config
{
private static int? xDimension;
public static int GetXDimension()
{
if(xDimension == null)
xDimension = int.Parse(ConfigurationManager.AppSettings["ResizedImageWidth"]);
return xDimension.Value;
}
}
or into the Application:
public static class Config
{
public static int GetXDimension()
{
if(Application["xDimension"] == null)
Application["xDimension"] = int.Parse(ConfigurationManager.AppSettings["ResizedImageWidth"]);
return (int)Application["xDimension"];
}
}

ASP.NET Localized web site -- updating on the fly

I think I have a solution to this, but is there a better way, or is this going to break on me?
I am constructing a localized web site using global/local resx files. It is a requirement that non-technical users can edit the strings and add new languages through the web app.
This seems easy enough -- I have a form to display strings and the changes are saved with code like this snippet:
string filename = MapPath("App_GlobalResources/strings.hu.resx");
XmlDocument xDoc = new XmlDocument();
XmlNode xNode;
xDoc.Load(filename);
xNode = xDoc.SelectSingleNode("//root/data[#name='PageTitle']/value");
xNode.InnerText = txtNewTitle.Text;
xDoc.Save(filename);
Is this going to cause problems on a busy site? If it causes a momentary delay for recompilation, that's no big deal. And realistically, this form won't see constant, heavy use. What does the community think?
I've used a similar method before for a very basic "CMS". The site wasn't massively used but it didn't cause me any problems.
I don't think changing a resx will cause a recycle.
We did something similar, but used a database to store the user modified values. We then provided a fallback mechanism to serve the overridden value of a localized key.
That said, I think your method should work fine.
Have you considered creating a Resource object? You would need to wrap your settings into a single object that all the client code would use. Something like:
public class GuiResources
{
public string PageTitle
{
get return _pageTitle;
}
// Fired once when the class is first created.
void LoadConfiguration()
{
// Load settings from config section
_pageTitle = // Value from config
}
}
You could make it a singleton or a provider, that way the object is loaded only one time. Also you could make it smart to look at the current thread to get the culture info so you know what language to return.
Then in your web.config file you can create a custom section and set restartOnExternalChanges="true". That way, your app will get the changed when they are made.

Resources