Where does WebConfigurationManager.AppSettings write its data? Not to web.config - c#

I am trying to use WebConfigurationManager.AppSettings[string] to read/write values to be stored in a configuration file on the server. I thought that it read/wrote it to the Web.config file, or maybe app.config. However, I ran the following test code - which the first time through (as desired) it throws an exception and but writes 'NOTSet' to that configuration entry - this allows me go easily go edit the file and change it to the correct value.
After running it a 2nd time, I can see the value returned is "NOTSet" - exactly as I would like. The code is working exactly as planned.
Except - Where is it written? I did a 'baregrep NOTSet .' - which recursively searched the ENTIRE project source directory and ONLY found the line in code that set the var - which means it was not written to anything in the entire project tree - not web.config, app.config or any other file.
I sighed, and said it must be in the registry - I searched the whole registry for anything with that value, then tried the key value - nothing.
Yet, running the program IS pulling the value that was set on the last run! Where did my data go? I want to be able to edit the value- and more importantly, have a FILE that I can copy to the production web server with all the GUIDs set correctly.
public enum Guids
{
IncidentSourceEnumPortal,
WorkItemClass,
WorkItemManagementPack
}
public class GuidConsts
{
static readonly Dictionary<Guids, Guid> GuidList = new Dictionary<Guids, Guid>();
public static Guid Guids(Guids guidId)
{
if (!GuidList.ContainsKey(guidId))
{
string id = WebConfigurationManager.AppSettings[guidId.ToString()];
Guid newGuid;
if ( (id == null) || Guid.TryParse(id, out newGuid))
{
WebConfigurationManager.AppSettings[guidId.ToString()] = "NOTSet";
throw new Exception(String.Format("Invalid guid - not found in Config: {0}", guidId));
}
GuidList.Add(guidId, newGuid);
return newGuid;
}
return GuidList[guidId];
}
}

To save the web.config file you need to call Configuration.Save() to persist changes. They are not automatically saved when you change a value:
https://msdn.microsoft.com/en-us/library/ms134088%28v=vs.110%29.aspx
Writing to web.config on the fly is not really advisable anyway, for one thing it will cause the app pool to be restarted potentially resulting in loss of session state across your application and probably other application-wide things you don't want to happen.

Related

Application changes not taking effect

I have made a change to a method used in a Functiod in a mapping file but it seems the new code is not taking effect, ever.
I have deployed properly, started the application, restarted related host instance (actually all host instances I could find) and still, the old code seems to execute.
Here's the, simple, method:
public string RemoveNonNumericChars(string stIn, int maxLength)
{
string strOut;
try
{
strOut = Regex.Replace(stIn, "[^0-9]", "");
System.Diagnostics.EventLog.WriteEntry("BizTalk Server 2009", strOut);
return strOut.Substring(0, maxLength);
}
catch
{
return string.Empty;
}
}
I added the writing to EventLog line to see that this code is indeed being executed, but I don't get anything in "Application" event logs.
I do NOT get an empty string being returned, so it really does seem like the old code that's being executed prior to me fixing the method.
What am I missing exactly ?
Thank you.
For some reason, the script is not able to correctly retrieve the Build Config selected in Visual Studio, it's taken from Debug when I'm actually trying to build it for a Test environment. I should have known, thanks anyways.

Properties.Settings has no setter

I decided to use Properties.Settings to store some application settings for my ASP.net project. However, when trying to modify the data, I get an error The property 'Properties.Settings.Test' has no setter, since this is generated I have no idea what I should do to change this as all my previous C# Projects have not had this issues.
My guess is that you defined the property with the Application scope, rather than the User scope. Application-level properties are read-only, and can only be edited in the web.config file.
I would not use the Settings class in an ASP.NET project at all. When you write to the web.config file, ASP.NET/IIS recycles the AppDomain. If you write settings regularly, you should use some other settings store (e.g. your own XML file).
As Eli Arbel already said you can’t modify values written in web.config from your application code. You can only do this manually but then the application will restart and this is something you don’t want.
Here is a simple class you can use to store values and make them easy to read and modify. Just update the code to suite your needs if you’re reading from XML or database and depending on whether you want to permanently store modified values.
public class Config
{
public int SomeSetting
{
get
{
if (HttpContext.Current.Application["SomeSetting"] == null)
{
//this is where you set the default value
HttpContext.Current.Application["SomeSetting"] = 4;
}
return Convert.ToInt32(HttpContext.Current.Application["SomeSetting"]);
}
set
{
//If needed add code that stores this value permanently in XML file or database or some other place
HttpContext.Current.Application["SomeSetting"] = value;
}
}
public DateTime SomeOtherSetting
{
get
{
if (HttpContext.Current.Application["SomeOtherSetting"] == null)
{
//this is where you set the default value
HttpContext.Current.Application["SomeOtherSetting"] = DateTime.Now;
}
return Convert.ToDateTime(HttpContext.Current.Application["SomeOtherSetting"]);
}
set
{
//If needed add code that stores this value permanently in XML file or database or some other place
HttpContext.Current.Application["SomeOtherSetting"] = value;
}
}
}
Here:
http://msdn.microsoft.com/en-us/library/bb397755.aspx
is the solution for your problem.

Getting back variables after a program crashes

I am trying to find a way to get back my previous variable's value so that I can resume my application to it's previous running state before it crashed when I MANUALLY relaunch it. I am currently using a 'config' file that is saved in the project folder. Is there a better way to do this?
Some small parts of my code that I want to save.
if (EventID == WIA.EventID.wiaEventItemCreated)
{
if (d != null)
{
foreach (Property p in d.Properties)
{
if (p.Name.Equals("Pictures Taken"))
Console.WriteLine("Taken");
}
wiaImageFile = (WIA.ImageFile)(d.Items[d.Items.Count].Transfer(FormatID.wiaFormatJPEG));
wiaImageFile.SaveFile(Properties.Settings.Default.FolderNameRaw + "\\" + imageCount + ".jpg");
imageCount++;//I want to save this count so that I can continue the sequence even after the application crashes
Pluck.Default.PhotoExistsInDirectory = true;
FacebookControls fbc = new FacebookControls();
if(Properties.Settings.Default.UseFB == true)
fbc.UploadPhotos();
}
}
A config file is a good answer in general. Your other options are usually the registry or the database, but I would argue that a config file is a safer option.
The thing about persisting this information is that it may cause an error again, and if so you'll want to be able to discard it easily. A file (of course stored in user settings space) is perhaps the way to do that. If need be you can instruct the user to delete the file. It's a more complicated fix for a user to access the registry or the database.
Also, you should wrap up your state in an appropriate object, and build initialization logic that initializes the state object and has mechanism for not loading for the config file.
I use config files. I also have a global exception handler that catches any exceptions and offers the chance to save any files (including those that the user is working on) before the app closes.
I would also agree with C Ross that you may persist the data that caused the app to fail. Another option that will not get you right back is to persist the settings at regular intervals using a timer or background process. I use this with several backups a bit like the system restore feature in windows.
You can handle UnhandledException, Application_ThreadException and Application.ApplicationExit Event, and try saving your data there:
http://www.switchonthecode.com/tutorials/csharp-tutorial-dealing-with-unhandled-exceptions
As #C. Ross said, user config file is a good choice.
Of course, first you'll have to preserve your application's state in some object during runtime.

Reset settings to SpecialFolder

I store the directory path of a folder in Properties.Settings.Default.Temporary and I allow the user to change this value and other settings using a PropertyGrid.
When the user decides to reset the Settings, I would like to change Properties.Settings.Default.Temporary to the value of System.IO.Path.GetTempPath() by using Properties.Settings.Default.Reset()
I know about System.Configuration.DefaultSettingValueAttribute. Something like this:
[global::System.Configuration.DefaultSettingValueAttribute(System.IO.Path.GetTempPath())]
does not work.
I also read Storing default value in Application settings (C#), which described a related problem, but I wonder if there is a way to solve my problem in the way described above.
The DefaultSettingValueAttribute.Value property is a string, therefore you cannot pass a function call to be called when the value is used. In fact there is no ability to pass code to an attribute: only literals are possible.
Instead in your applications code where you reset the settings, follow this by setting and settings that you want to have values that are not literals at compile time (eg. dependent on the execution environment).
I just had an idea for a workaround myself:
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute(null)]
public string TemporaryDirectory
{
get
{
if (this["TemporaryDirectory"] == null)
{
return System.IO.Path.GetTempPath();
}
return ((string)this["TemporaryDirectory"]);
}
set
{
if (System.IO.Directory.Exists(value) == false)
{
throw new System.IO.DirectoryNotFoundException("Directory does not exist.");
}
this["TemporaryDirectory"] = value;
}
}
I don't know, if this has any side effects, but so far it seems to work. I am sorry that I had this idea shortly after posting. I should've thought about the problem a bit longer.

File existence check after a folder rename returns an incorrect value on UNC share

On a Windows 7 (or server) box, we have a folder on a UNC share (cross machine UNC, not localhost). We rename that folder, and then check for the existence of a file at the new folder location. Even though it exists, it takes almost 5 seconds for File.Exists to return true on it.
Full repro can be found on https://github.com/davidebbo/NpmFolderRenameIssue. Here is the core code:
// This file doesn't exist yet
// Note that the presence of this existence check is what triggers the bug below!!
Console.WriteLine("Exists (should be false): " + File.Exists("test/test2/myfile"));
// Create a directory, with a file in it
Directory.CreateDirectory("test/subdir/test");
File.WriteAllText("test/subdir/test/myfile", "Hello");
// Rename the directory
Directory.Move("test/subdir/test", "test/test2");
var start = DateTime.UtcNow;
// List the files at the new location. Here, our file shows up fine
foreach (var path in Directory.GetFiles("test/test2"))
{
Console.WriteLine(path);
}
for (; ; )
{
// Now do a simple existence test. It should also be true, but when
// running on a (cross machine) UNC share, it takes almost 5 seconds to become true!
if (File.Exists("test/test2/myfile")) break;
Console.WriteLine("After {0} milliseconds, test/test2/myfile doesn't show as existing",
(DateTime.UtcNow - start).TotalMilliseconds);
Thread.Sleep(100);
}
Console.WriteLine("After {0} milliseconds, test/test2/myfile correctly shows as existing!",
(DateTime.UtcNow - start).TotalMilliseconds);
So it seems like the initial existence check causes the existence value to be cached, causing this bogus behavior.
Questions: what is the explanation for this? What's the best way to avoid it?
NOTE: this issue initially arose when using npm (Node Package Manager) on Windows. The code I have here is a C# port of the repro. See https://github.com/isaacs/npm/issues/2230 for the original Node/npm issue. The goal is to find a way to address it.
David,
The redirector implements a negative "File Not Found" cache which prevents a client from flooding a server with file not found requests. The default cache time is 5 seconds but you can modify the FileNotFoundCacheLifetime registry value to control the cache or disable it by setting this value to 0.
Details: http://technet.microsoft.com/en-us/library/ff686200(v=WS.10).aspx
There are multiple levels of caching in network code. This could slow down the time the file existence finally shows up.
A solution would be not to use file shares but create a simple client/server architecture where the server returns the file existence from the local file system. That should really speed up item detection times.
My guess would be that if you tried to open the file even if File.Exists says it doesn't exist yet it should be opened correctly so you can use the server existence information. If that won't work you can simply add a download option to the server/client architecture.
Once I knew about the "File Not Found" cache, I was able to get around the problem by using a FileInfo object, which implements a Refresh() method. Your code could do this instead:
FileInfo testFile = new FileInfo("test/test2/myfile");
Console.WriteLine("Exists (should be false): " + testFile .Exists);
Directory.Move("test/subdir/test", "test/test2");
testFile.Refresh();
// the FileInfo object should now be refreshed, and a second call to Exists will return a valid value
if (testFile.Exists)
{
...
}

Categories

Resources