What's best way to include configuration settings with assembly?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I was a Java developer so I'm used to using property files as a means to keep
configuration settings for my apps. I'm wondering what options are there with
..NET?

Some settings I want to include are like a root directory for a target
program on the user's machine my app uses, which they would be prompted to
supply at startup. Normally the registry is used for this but I'd rather not
use the registry if possible. Isn't there some kind of way to include or
makeconfiguration files for assemblies?
 
W.G. Ryan eMVP said:
Add a config file to the project - there's a template for them on add new
item.

--
W.G. Ryan MVP (Windows Embedded)

TiBA Solutions
www.tibasolutions.com | www.devbuzz.com | www.knowdotnet.com

I've looked into this before- and the problem I found with these files is
that apparently they are read-only... I need to be able to update this on the
client side based on what the user does, like my example in the original
post- they will have to set a base directory which can be changed.

Unless I'm doing it wrong- how do you programmatically change values in the
config files?
 
The app config file should only be used to store read-only configuration
settings. This makes sense, as the application and the config file are
stored in the "Program Files" directory. Normal users have read-only access
to the "Program Files" directory, so it makes sense to put read-only files
in there.
Of course, some hatefull programmers will try to write in there anyway,
forcing me to run their apps as administrator. Very, Very, Very Bad Thing To
Do!

Well behaved applications store their machine-wide settings and data in
application-specific folders under the CommonApplicationData folder and user
settings and data under the ApplicationData or LocalApplicationData folder.
E.g. Outlook stores you mailbox under the LocalApplicationData folder
(typically C:\Documents and Settings\SomeUser\Local Settings\Application
Data\Microsoft\Outlook).
The difference between AppData and LocalAppData is that anything placed in
AppData is part of the user's roaming profile and follows him to any machine
he logs on.

You can get the actual location of these folders from the System.Environment
class, e.g:
System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData);
System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData);

Once you decide where to store the app's settings, you can store them
manually as an XML file, or you can use Microsoft's Configuration Management
Application Block
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/cmab.asp).
The Application Block provides greater flexibility because it allows you to
store the settings in a file, the registry or a database.

BTW, these restrictions are imposed by Windows themselves, not .NET. In
fact, an application that wants to get the "Designed for Windows" logo must
comply with them.
 
PK, thank you for the information. I have been looking around and I think I
found something called "Isolated Storage" which seems to reduce some of the
overhead in reading/writing files in your own section of the Documents and
Settings folder you just mentioned. But I thinkI'll go with a traditional INI
style file- seems silly to me to use XML and then use a DataSet to access the
data like I'm finding on some online tutorials- doesn't anyone worry about
overhead, performance or memory footprints anymore?

Thanks again for your reply
 
Config files can do so much I couldn't begin to really get into it - in a
much more elegant way than an .ini file ever could. Remoting is probably
the biggest area but if you look at the exception management block - there's
another great example.

Isolated Storage rocks - it's a good alternative.

Not sure what you mean by using a DataSet afterwards - you can use
<appSettings> directly or you can write your own configuration section
handlers - which is a really cool way to handle things.
 
Just use ISO storage and serialize/deserialize your config class with
XmlSerializer. Simple and plenty fast for this usage. If you have to parse
a file anyway, why not let XmlSerializer do it instead of doing it manually?
 
Here is a one class example of the idea. I would add another class just for
the XmlSerializer and serialize/deserialize that class. That way, you can
make the AppConfig ctor() private. That way, only public way to get
instance is with static Load method.

using System;
using System.Xml.Serialization;
using System.IO;
using System.IO.IsolatedStorage;
using System.Reflection;

namespace MyAppConfig
{
/// <summary>
/// AppConfig is loaded and saved to ISO storage as XML. You can
/// use this class to load and save your application settings for
/// your assembly. Just add any fields you need in the class as
/// public fields or public properties with *both get and set accessors
/// as required by XmlSerializer.
///
/// Note: It would be better to create another class just for the
/// serialization such as XmlAppConfig that contains just the
/// public fields you want to save and operate on that. We could
/// then remove the public default constructor below. However this
/// is a simple one class example.
///
/// Code Example:
/// // Load appconfig. Could put in Form Load event.
/// string configFile = "appconfig.xml";
/// AppConfig appConfig = AppConfig.Load(configFile);
///
/// // Update it as your config changes in your app.
/// appConfig.X = 6;
///
/// // Save it to storage. Could put in Form Closing event.
/// appConfig.Save();
/// </summary>
public sealed class AppConfig
{
private string isoFileName;
public int X = 2; // Default.
public int Y = 3; // Default.
// ... Add any others...

public AppConfig() // Default public constructor for XmlSerializer only.
{
}

public string FileName
{
get { return this.isoFileName; }
}

public AppConfig(string isoFileName)
{
this.isoFileName = isoFileName;
}

public void ResetDefaults()
{
AppConfig mac = new AppConfig(this.isoFileName);
mac.Save();
this.X = mac.X;
this.Y = mac.Y;
}

public static AppConfig Load(string file)
{
IsolatedStorageFile isoStore =
IsolatedStorageFile.GetStore(IsolatedStorageScope.Assembly |
IsolatedStorageScope.User, null, null);

if ( ! AppConfig.ISOFileExists(isoStore, file) )
{
AppConfig ac = new AppConfig(file);
ac.Save();
return ac;
}

string xml = AppConfig.ReadFromISOFile(isoStore, file);
Console.WriteLine("Xml:\n"+xml);
try
{
AppConfig mac = AppConfig.FromXmlString(xml);
mac.isoFileName = file;
return mac;
}
catch
{
// Xml not valid - may be corrupted or wrong version, etc.
// Rewrite it with defaults.
AppConfig ac = new AppConfig(file);
ac.Save();
return ac;
}
}

public void Save()
{
string xml = ToXmlString();

IsolatedStorageFile isoStore =
IsolatedStorageFile.GetStore(IsolatedStorageScope.Assembly |
IsolatedStorageScope.User, null, null);
AppConfig.WriteToISOFile(isoStore, isoFileName, xml);
}

public string ToXmlString()
{
string data = null;
XmlSerializer ser = new XmlSerializer(typeof(AppConfig));
using(StringWriter sw = new StringWriter())
{
ser.Serialize(sw, this);
sw.Flush();
data = sw.ToString();
return data;
}
}

public static AppConfig FromXmlString(string xmlString)
{
if ( xmlString == null )
throw new ArgumentNullException("xmlString");

AppConfig mac = null;
XmlSerializer ser = new XmlSerializer(typeof(AppConfig));
using (StringReader sr = new StringReader(xmlString))
{
mac = (AppConfig)ser.Deserialize(sr);
}
return mac;
}

private static bool ISOFileExists(IsolatedStorageFile isoStore, string
fileName)
{
if ( isoStore == null )
throw new ArgumentNullException("isoStore");
if ( fileName == null || fileName.Length == 0 )
return false;

string[] names = isoStore.GetFileNames("*");
foreach(string name in names)
{
if ( string.Compare(name, fileName, true) == 0 )
return true;
}
return false;
}

private static void WriteToISOFile(IsolatedStorageFile isoStore, string
fileName, string data)
{
// Assign the writer to the store and the file TestStore.
using(StreamWriter writer = new StreamWriter(new
IsolatedStorageFileStream(fileName, FileMode.Create, isoStore)))
{
writer.Write(data);
}
}

private static string ReadFromISOFile(IsolatedStorageFile isoStore, string
fileName)
{
string sb = null;
using(StreamReader reader = new StreamReader(new
IsolatedStorageFileStream(fileName, FileMode.Open, isoStore)))
{
sb = reader.ReadToEnd();
}
return sb.ToString();
}
}
}
 
Back
Top