I've noticed that when using the Settings object that's created by a Windows Forms application, any spaces in the "Company Name" field of the assembly info are replaced by underscores in the path of the user.config file. For example, in XP the path to the user.config file will be something like:
\Documents and Settings\user\Local Settings\Application Data\Company_Name_Here\App\Version\user.config
But this only seems to be happening to my own applications. I've got lots of .NET applications installed on my machine, but none of the other directory names under Application Data contain underscores (the spaces are preserved).
What gives? It's not a big deal, but I'm just wondering why this only seems to be happening to my applications, and if there's a way to change this behavior that I'm not aware of.
Quoting someone who worked at Microsoft
<Company Name> - is typically the string specified by the AssemblyCompanyAttribute (with the caveat that the string is escaped and truncated as necessary, and if not specified on the assembly, we have a fallback procedure).
and
Q: Why is the path so obscure? Is there any way to change/customize it?
A: The path construction algorithm has to meet certain rigorous requirements in terms of security, isolation and robustness. While we tried to make the path as easily discoverable as possible by making use of friendly, application supplied strings, it is not possible to keep the path totally simple without running into issues like collisions with other apps, spoofing etc.
The LocalFileSettingsProvider does not provide a way to change the files in which settings are stored. Note that the provider itself doesn't determine the config file locations in the first place - it is the configuration system. If you need to store the settings in a different location for some reason, the recommended way is to write your own SettingsProvider. This is fairly simple to implement and you can find samples in the .NET 2.0 SDK that show how to do this. Keep in mind however that you may run into the same isolation issues mentioned above .
might give some hint of explanation.
So other applications might have used an individual settings provider that supports whitespaces.
The restrictions of the default .NET settings provider are also mentioned here:
Each application setting must have a unique name; the name can be any combination of letters, numbers, or an underscore that does not start with a number, and cannot contain spaces. The name can be changed through the Name property.
Related
I have a C# app that needs to be localized. I can use the RESX .NET MUI strategy to do that. Now, I have a separate team that is providing additional localized resources (XML files) post build/compile time. I'd like to take advantage of .NETs MUI strategy which provides a nice fallback mechanism, but I can't seem to find a way to make that happen.
Note, I have thought about adding the localized file names (which I know) in my App's string resources file. However, if at runtime the file doesn't exist, then I'll have problems (and no way to automatically fallback).
So, is there a way to utilize the .NET MUI strategy in this scenario?
Option 1:
You can store the XML files in a resource, and then get a stream object to read it, which uses the same approach as is done with strings, etc. See http://msdn.microsoft.com/en-us/library/zxee5096.aspx for that.
Option 2:
You can also apply the same basic approach as that used by resources yourself. I've found it convenient with web applications which are often based on a lot of files (.aspx, .html, .css, .js, .png, etc) anyway. Say you've got a bunch of directories like:
localised/en/SomeFile1.xml (and etc....)
localised/en-US/SomeFile1.xml (and etc....)
localised/en-GB/SomeFile.xml
localised/fr/SomeFile.xml
I come along with my en-IE prefernces, and you don't match that, but you do match en and that's good enough (okay ideally you should pick up that en-IE is closer to en-GB than en-US, but that's totally into the bonus-credit territory and much better than .NET will do with resources).
Your matching algorithm should be:
Try to find a match for the locale sought, return if found.
Drop off the end of the locale, so en-GB-OED becomes en-GB, en-GB becomes en- and so on. If that doesn't remove the whole thing, go back to step 1 with this new locale.
Try zxx (zxx isn't used by .NET afaik, but it is used with BCP 47/RFC 4647 and ISO 639 for items with no lingual content - e.g. a passport photo of you is locale zxx because it's just as appropriate to go with a French document as a Yoruba or Welsh one).
Try a "default" locale as defined by you (or error if your application promises to make a good match).
At that point, you'll be doing slightly better than what resource files do. Still, mostly option 1 is a lot simpler and is far more self-contained.
We have quite some room for improvement in our application lifecycle management. We don't use TFS or any other suite (shame on us, I know).
Anyway, one of the aspects we currently ponder about is code identity.
In other words: Auditors ask us how we ensure that the software tested and accepted by the departments is exactly and with no alternations the assembly we deploy for productive use and not some tinkered-with version. "That's easy", we say, "it isn't!". Because some configuration variables are set between approval and release, the ClickOnce hashes differ and thus does the whole thing.
That's the story so far, but we want (and have) to get better at what we do, so there's no way around creating our assemblies stateless and oblivious to their environment. But then we will have to set the environment at runtime, our options here are:
Using Application settings and excluding the application configuration from the ClickOnce hash. This sucks because we can't sign the ClickOnce Manifest that way, so users will always be prompted a "watch out, you don't know this guy" kind of message.
Passing Query-String parameters to the application file and using those to distinguish between test and productive environment. I don't like this because it's too open and enables any user to control the important bits (like dbhost or whatever).
Passing in something like "is_test=1" means there's a lot of inline-switching going on, and that on the other hand could mean that the assembly behaves different in production than in test, which brings us back to the start, although we've ensured Assembly-Identity on the way.
I think all that is rather unsatisfying and there must be a better way to do it. How can this be done by little means (meaning without TFS or similar monstrosities)?
I just messed around with the ApplicationDeployment class a little. I think what I have now is pretty close to what I was looking for.
private static void GetDeploymentEnvironment()
{
if (ApplicationDeployment.IsNetworkDeployed)
{
ApplicationDeployment dep = ApplicationDeployment.CurrentDeployment;
FileInfo f = new FileInfo(dep.UpdateLocation.AbsolutePath + ".env");
if (f.Exists)
{
/// read file content and apply settings
}
}
}
This enables me to put a file in the deployment folder (where the .application-file resides) that I can use to override settings. If there is no such file, well...nothing gets overridden. Whatever I do with the content of this file, the Assembly Identity is preserved.
EDIT : Just a hint, as you see this is useful only for applications deployed as Online Only. You cannot start the same ClickOnce .application file from different locations in the Available Offline scenario.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
What is the best way to store user settings for a .NET application?
I have found alot of VERY different examples as to how one would save application settings (per user) from a Winforms application.
I imagine that the correct way to do this is very simple in c# and am hoping someone can enlighten me?
At some point, the answer boils down to a matter of taste. I'd say you'll end up with at least these options:
store it in the registry, where you have the HKEY_CURRENT_USER key. Everything under it is user-specific. This is usually preferred when you want to store a bunch of small key-value pairs. The main advantage of this system is that your settings are easy to find and share throughout several different applications. To follow this path, you can start from here.
using .NET Application settings, provides the easiest way to access your settings at runtime. Again, it's better for using with key-value pairs of small-sized data. IMO, the main advantages of this method is its simplicity and the fact that it empowers you to use some .NET classes as values (not forcing you to convert everything into more basic types). To follow this path, you can start from here.
store it in User Data folders, which are usually hidden under the user's profile directory. This is preferred when you want to store a large amount of data or any number of files. The main advantage of this method is that you can manipulate your data as you would with any files (that may also be a disadvantage). To follow this path, you can start from here.
You can use the settings infrastructure provided by .NET. In your project's property pages, go to the Settings page, and define your settings. You can define the scope of each setting as "Application" or "User". A class will be automatically generated to access these settings from code.
To access settings Foo and Bar, use :
// Read settings
textBoxFoo.Text = Properties.Settings.Default.Foo;
// Write settings
Properties.Settings.Default.Bar = checkBoxBar.IsChecked;
// Save settings
Properties.Settings.Default.Save();
I would use Application Settings. It's pretty straightforward and will take care of some issues for you (such as not having write access to the folder where your app may be installed without administrative access, which rules out directly using app.config for your settings).
Given that (at least on NTFS) the filesystem on Windows is case insensitive, I would like to compare String fileA to String fileB as such:
fileA.Equals(fileB, StringComparison.CurrentCultureIgnoreCase)
The question then becomes which culture I should use, does the default current (ui?) culture suffice? I can't seem to find any BCL methods for this purpose.
You should use StringComparison.OrdinalIgnoreCase, according to Best Practices for Using Strings in the .NET Framework.
The string behavior of the file system, registry keys and values, and environment variables is best represented by StringComparison.OrdinalIgnoreCase.
If you use a culture for matching the strings, you may get in a sitation where for example the names "häl.gif" and "hal.gif" would be considered a match.
This is not possible to do reliably.
Yes, the case conversion for the file system is case-insensitive.
But the case conversion table is stored on the file system itself (for NTFS), and it does change between versions (for instance the Vista case conversion table was brought to the Unicode 5 level, so Vista NTFS and XP NTFS have different case conversion rules).
And the thing that matters is the OS that formatted the file system, not the current OS.
Then you can run into all kind of problems with other file systems (Mac OS does some kind of Unicode normalization (not the standard one)), Linux does not do anything, but Samba (implementing the Windows file sharing protocol) does. And has other tables than Windows.
So what happens if I map a letter to a network disk shared by Linux or Mac OS?
In general you should never try to compare file names. If you want to know if it is there, try to access it.
Marcus,
You might want to at look at the answer for another StackOverflow question, which is very similar: Win32 File Name Comparison , which in turn mentions http://www.siao2.com/2005/10/17/481600.aspx .
Following a link in another answer to the same question and digging further, I came across the following MSDN article http://msdn.microsoft.com/en-us/library/ms973919.aspx . It is worth a read in general, but when it comes to file name comparison it recommends using StringComparison.OrdinalIgnoreCase. See Table 1 in the article, which contains file paths as one of the data types handled or the following the quote:
So, when interpreting file names, cookies, or anything else where something like the å combination can appear, ordinal comparisons still offer the most transparent and fitting behavior.
Hopes this helps,
Boaz
Maybe you could try this:
http://msdn.microsoft.com/en-us/library/zkcaxw5y.aspx
You could use InvariantCulture (look at http://msdn.microsoft.com/en-us/library/4c5zdc6a.aspx).
In your example:
FileA.Equals(FileB,StringComparison.InvariantCultureIgnoreCase )
I tried this.
Path.GetFullPath(path1).Equals(Path.GetFullPath(path2))
I'm really confused by the various configuration options for .Net configuration of dll's, ASP.net websites etc in .Net v2 - especially when considering the impact of a config file at the UI / end-user end of the chain.
So, for example, some of the applications I work with use settings which we access with:
string blah = AppLib.Properties.Settings.Default.TemplatePath;
Now, this option seems cool because the members are stongly typed, and I won't be able to type in a property name that doesn't exist in the Visual Studio 2005 IDE. We end up with lines like this in the App.Config of a command-line executable project:
<connectionStrings>
<add name="AppConnectionString" connectionString="XXXX" />
<add name="AppLib.Properties.Settings.AppConnectionString" connectionString="XXXX" />
</connectionStrings>
(If we don't have the second setting, someone releasing a debug dll to the live box could have built with the debug connection string embedded in it - eek)
We also have settings accessed like this:
string blah = System.Configuration.ConfigurationManager.AppSettings["TemplatePath_PDF"];
Now, these seem cool because we can access the setting from the dll code, or the exe / aspx code, and all we need in the Web or App.config is:
<appSettings>
<add key="TemplatePath_PDF" value="xxx"/>
</appSettings>
However, the value of course may not be set in the config files, or the string name may be mistyped, and so we have a different set of problems.
So... if my understanding is correct, the former methods give strong typing but bad sharing of values between the dll and other projects. The latter provides better sharing, but weaker typing.
I feel like I must be missing something. For the moment, I'm not even concerned with the application being able to write-back values to the configuration files, encryption or anything like that. Also, I had decided that the best way to store any non-connection strings was in the DB... and then the very next thing that I have to do is store phone numbers to text people in case of DB connection issues, so they must be stored outside the DB!
If you use the settings tab in VS 2005+, you can add strongly typed settings and get intellisense, such as in your first example.
string phoneNum = Properties.Settings.Default.EmergencyPhoneNumber;
This is physically stored in App.Config.
You could still use the config file's appSettings element, or even roll your own ConfigurationElementCollection, ConfigurationElement, and ConfigurationSection subclasses.
As to where to store your settings, database or config file, in the case of non-connection strings: It depends on your application architecture. If you've got an application server that is shared by all the clients, use the aforementioned method, in App.Config on the app server. Otherwise, you may have to use a database. Placing it in the App.Config on each client will cause versioning/deployment headaches.
Nij, our difference in thinking comes from our different perspectives. I'm thinking about developing enterprise apps that predominantly use WinForms clients. In this instance the business logic is contained on an application server. Each client would need to know the phone number to dial, but placing it in the App.config of each client poses a problem if that phone number changes. In that case it seems obvious to store application configuration information (or application wide settings) in a database and have each client read the settings from there.
The other, .NET way, (I make the distinction because we have, in the pre .NET days, stored application settings in DB tables) is to store application settings in the app.config file and access via way of the generated Settings class.
I digress. Your situation sounds different. If all different apps are on the same server, you could place the settings in a web.config at a higher level. However if they are not, you could also have a seperate "configuration service" that all three applications talk to get their shared settings. At least in this solution you're not replicating the code in three places, raising the potential of maintenance problems when adding settings. Sounds a bit over engineered though.
My personal preference is to use strong typed settings. I actually generate my own strongly typed settings class based on what it's my settings table in the database. That way I can have the best of both worlds. Intellisense to my settings and settings stored in the db (note: that's in the case where there's no app server).
I'm interested in learning other peoples strategies for this too :)
I think your confusion comes from the fact that it looks like your first example is a home-brewed library, not part of .NET.
The configurationmanager example is an example of built-in functionality.
I support Rob Grays answer, but wanted to add to it slightly. This may be overly obvious, but if you are using multiple clients, the app.config should store all settings that are installation specific and the database should store pretty much everything else.
Single client (or server) apps are somewhat different. Here it is more personal choice really. A noticable exception would be if the setting is the ID of a record in the database, in which case I would always store the setting in the database with a foreign key to ensure the reference doesn't get deleted.
Yes - I think I / we are in the headache situation Rob descibes - we have something like 5 or 6 different web-sites and applications across three independent servers that need to access the same DB. As things stand, each one has its own Web or App.config with the settings described setting and / or overriding settings in our main DB-access dll library.
Rob - when you say application server, I'm not sure what you mean? The nearest thing I can think is that we could at least share some settings between sites on the same machine by putting them in a web.config higher in the directory hierarchy... but this too is not something I've been able to investigate... having thought it more important to understand which of the strong or weak-typed routes is 'better'.