This happens with the Emulator as well as with the real device, in Debug-Mode as well as in Release-Mode.
In the app I store several application settings successfully - from simple value types to more complex objects and lists of objects.
With "WP POWER TOOLS" I can track the file "__ApplicationSettings" in the root of the IsolatedStorage. It is "well filled" - in the first lines I find some classes and assemblies, that define the complex type definitions, and below the XML starts with the <ArrayOfKeyValueOfstringanyType...>
So, everything looks normal to me so far.
When I close my app, the last piece of running code is the "Application_Closing"-Handler in App.xaml.cs. In this moment I can check the ApplicationSettings the last time - everything is okay.
For example: I check the count of the entries:
var count = System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.Count;
...and the count is right and the keys/values are right.
Then - I restart the app at once (Visual-Studio-Debugging is not interrupted) and the first piece of running code is the ctor App() in App.xaml.cs.
In the first line I check the count of ApplicationSettings-Entries again, and: it is 0 !!!
But: WP POWER TOOLS still show me, that the "__ApplicationSettings"-File is existing and is still filled like before.
(The consequence of this error is afterwards, that with the first attempt to save any setting again, the whole __ApplicationSettings-File is overwritten and contains just the one new setting.)
So what could be preventing the App from "using" the existing "__ApplicationSettings"-File???
Thanks in advance!
(PS 1: I already experienced, that all ApplicationSettings are destroyed, when there happens an Exception while saving the settings. I investigated all of that already and are 99.9% sure, that there is no Exception anymore.)
(PS 2: Just to make it clear: It is NOT the case, that the complete IsolatedStorage is gone. I have also another file for logging purposes, that I write to the root of the IsolatedStorage. This file is always there. Also the __ApplicationSettings file is not "deleted", it just seems, that the app doesn´t "read" it when launching.)
I tried the repro scenario with an app of mine and confirmed what I expected, that IsolatedStorageSettings.ApplicationSettings.Count was nonzero on entry to the App() ctor upon running the app for a second time in the same emulator process. So there is hope for you to get to this desired state too!
Since you report that the _ApplicationSettings file is not empty, I'll guess 2 possibilities: Maybe an app (or some other process?) keeps the _ApplicationSettings file open when the 2nd run of the app is trying to open the file for reading? MSFT doesn't document how the read is done, so maybe the file is opened with FileShare.None, or with FileShare.Read but some other process still has the file open for writing? I have no idea how to test this on the emulator, but on the real device you might try this scenario:
Run the app for the first time, verify it saves a non-empty _ApplicationSettings.
Restart the phone device (debugger will disconnect)
Run the app for the second time, with a breakpoint in App() ctor.
After 2) I would be confident no other process could have the file open, so the app should be able to read its contents without interference. But if you discover that it still has zero count in 3), then another possibility exists:
Maybe the restarted app encounters an error trying to deserialize the settings from the file into your data structure(s)? The error might not prevent the data from being serialized when the first run of the app is exiting.
To check this possibility, first look for error messages in the Output, Debug window. Do you see any errors when restarting the app the a second time?
If you don't see any helpful error messages, the next thing to try is to simplify the data structures being saved as settings. Try cutting down to just one setting that is a simple type like an int or string. See whether that can be restored correctly, then add more of your settings back into the file until you home in on the one which causes a problem.
Do you call Save on settings? Does it throw any error?
Related
When calling File.WriteAllText to generate files, intermittently the c# windows form program will hit a catch block due to an Exception with the message of "FileStream was asked to open a device that was not a file. For support for devices like 'com1:' or 'lpt1:', call CreateFile, then use the FileStream constructors that take an OS handle as an IntPtr."
The stacktrace shows Microsoft.Win32.Win32Native.SafeCreateFile as being where it got to last.
After days of researching and trying to find out why this was happening, most articles talk about the reserved file names like com and etc. However, this exception is hit in the middle of exporting files after getting through a few files already. These files don't have any reserved names in them. They all have the same path except for at the end of the file name where a hyphen and padded number for which file it is on is added. Since this gets through similar named files, I believed that this wasn't what was actually happening. The other issue is I could do the same export process multiple times and not get it to happen every time. In fact out of 100 or so export processes it would maybe happen only once even though nothing in the name or path had changed.
Today I found a way to actually get it to happen almost every time. If I go to Chrome and open say "a.singlediv.com" to test with, start the export, then as the export is running I repeatedly reload the div site, it will 99% of the time halt the export and hit the exception mentioned above.
Does anyone have any advice that could lead me to why this Exception message is shown for doing this? Task Manager doesn't seem to have any glaring issues with Memory or CPU overload and a log is being posted to our SQL server after hitting the Exception so I also dont believe it is a network issue.
Update
I was able to find out more about when the error happens with testing yesterday. When refreshing the website repeatedly, I tried a couple different ways of exporting to get more information.
A custom configuration file, a text file, and an excel file are used as setup files for our program. I made identical folders on the Desktop and on a mapped drive which points to a folder located on our server for where the setup files are located as well as where the exports will be saved. I tried a couple different ways of loading these files and export locations.
If I load the setup files from the Desktop folder and save to the Desktop, or load from the Desktop folder and save to the mapped drive, or load from the mapped drive and save to the Desktop folder all of these don't seem to hit the Exception. So far the only way I have gotten the Exception to occur is when I load from the mapped drive and save to the mapped drive while doing the constant refreshing of the div website.
Attached below is a screenshot of the Exception.ToString() (Except for our custom methods that called File.WriteAllText() before in the StackTrace). I manually added returns between each method call so that it is easier to read.
Workaround Update
Per Mason's suggestion I wrapped my File.WriteAllText call in a Polly Retry which has seemed to so far allowed the export to finish every file while debugging the code.
I first did a RetryPolicy.Execute that wrapped the File.WriteAllText. Before File.WriteAllText I wrote the Attempt # it was on to the Output window and after it wrote a message about completing. I did get an Attempt #2 but was getting Attempt #1 and completed for every time it was called which was not easy to see since it happens over 2000 times. So I tried to add an if statement to check if this was not the first attempt and if it wasn't it would write the Attempt # and that the retry handled Exception to the Output window. However, after adding these if statements I didn't get any Attempt #s and it didn't break on the Exception but I also saw that the Output window did have a line about hitting the Exception so I assume that means that the Retry handled it? I would of expected to see Attempt #2 and Retry handled Exception around the Exception message in the Output window since it didn't stop and created every file needed. I have added a code snippet of what I added below.
int attempt = 0;
Polly.Retry.RetryPolicy retryIfException = Policy.Handle<System.NotSupportedException>().Retry(3);
retryIfException.Execute(() =>
{
if (attempt>0)
{
Console.WriteLine($"Attempt #{++attempt}");
}
File.WriteAllText(saveLocation, this.currentFileText.ToString());
if (attempt>1)
{
Console.WriteLine("Retry handled Exception");
}
});
I'm trying to figure out how to inform the user that the app crashed because of a missing config file. I could use
if (!File.Exists("application.exe.config"))
{
CreateLaunchErrorLog("Message....");
Environment.Exit(0);
}
but the application crashes before the Main method. Any way around to get this to work?
The config file is intended to be modified by the user.
If the application is crashing prior to main because of the missing config file, you might want to rethink how you are structuring your program.
For example, you may want to write a function that checks for the config and then loads all of its values, as the first function called from main or in a setup routine when the program loads.
This gives you the added benefit that besides displaying a message, you could recreate the file with reasonable defaults and then continue on with the rest of the program.
These answers might help too.
The application should not crash even if the configuration file does not exists unless the file is being used through code. Are you sure the config file or any app setting is not being called before?
I have the following piece of code in my application:
if (!Directory.Exists(myPath))
Directory.CreateDirectory(myPath);
If I run it in a regular unit test sometimes it passes, sometimes not. The directory is always there (I made sure of it, so technically it will never be "created" by code). But every once in a while Directory.Exists(myPath) returned false, which makes the code try to create the folder and then I get an UnauthorizedAccessException!
The funny thing here is if I put a breakpoint on the CreateDirectory, and then move the yellow arrow up back to test, the test returns true!
What's going on?
myPath is \\nameOfLocalMachine\sharedFolder. The share is reliable and constantly used... .NET 4.0
I just made a fiddler simulate 3000 sequentials requests. 175 failed... All with the same message:
Access to the path '\nameOfLocalMachine\sharedFolder\randomFileName.json' is denied
This mishap is pretty normal on Windows. Programs open a handle on a directory like this and specify delete sharing. Which permits anybody to delete the directory, even though the program is using it. The directory won't actually disappear from the file system until that handle is closed. What follows is that trying to recreate that directory cannot work, it still exists. Windows generates an "access denied" error, reported in your C# program with the UnauthorizedAccessException.
While that sounds like an obscure feature, every program in Windows does this. Every process has a default working directory, the value of Environment.CurrentDirectory. Creating a handle on such a directory ensures that it cannot disappear while the program is using it. There are other cases, FileSystemWatcher would be another example. Or a program busy iterating the directory. Anti-malware and search indexers are notorious for hard to diagnose sources of such errors.
Otherwise a standard hazard of a multi-tasking operating system. You are not the only one using the file system. Not repeatedly deleting and creating the same directory ought to be very high on your list. If this is absolutely necessary then rename the directory first before you delete it. You'd still fail to delete the renamed directory but you won't fail recreating it. You can delete it later, next time you need to do this. Much lower odds for trouble then. Because more time passed.
CONCLUSION AT BOTTOM OF POST
I'm a novice with C# and have only just begun using System.IO, but haven't been able to find information on my issue so wanted to ask the guys here:
I have a program that when run, creates a directory, then writes to a .txt file what the most recent value of a certain variable was, so that if the program is interrupted or the computer loses power, restarting the program will retrieve that stored number from the .txt file.
I've simply done this:
string INSTATR = LastValue.ToString();
System.IO.File.WriteAllText(#"C:\\DotTempFiles\\"+Instrument.Name+"ATR.txt", INSTATR);
My first time running this program, the file was created, and I found that on every cycle the number in the file was being overwritten to the last valid number just as I wanted.
However, once I went to the DotTempFiles directory and deleted the .txt file using Shift+Del, the file has never returned upon running the program as I thought it would. If I delete the entire directory and run the program, the directory is recreated but still not the file.
If I run the program using a different Instrument.Name, that new file is created as expected, but the original one that I once manually deleted is still not showing, even after computer restarts.
I can't find any information leads online, so does anyone have an idea? Thank you!
EDIT (more info): People asked a few questions so I'm adding more information (thank you)
There are no errors being reported. It compiles fine, and when running, there is an output window that usually alerts me to errors like if I reference an object that is null, or try to read from an empty file, etc. No errors like this are occurring.
More background on what the program is. There is a stock trading program called NinjaTrader that has their own API based on C#. They wouldn't support the questions I have because it's outside the normal scope of the script development they intended people to use, and that's ok with me. The program itself is a trading strategy that is run within NinjaTrader, and it exposes default programmer access to these two main methods:
Initialize()
protected override void OnBarUpdate() //this is the main part of the program that gets called every time a change has occurred to one of the bars on the stock chart.
In the variable declaration section I have this:
System.IO.DirectoryInfo di = Directory.CreateDirectory(#"C:\\DotTempFiles");
And in OnStartUp() I have this:
//Set up ReadMe file in the temp directory in case people wonder why it keeps appearing
string README = "This DotTempFiles directory is created by the strategy every time it is run, and temporary text files with the name [instrumentsymbol]ATR.txt are written into it containing the last highest ATRStopValue for the strategy, which if it is stopped and restarted with an open position, it will read from that file to get back the best value instead of recalculating it with possibility of a lower unwanted value.";
System.IO.File.WriteAllText(#"C:\\DotTempFiles\\README.txt", README);
Every time OnBarUpdate() is called, which can be up to a few times per second, it first calculates a double called LastValue which is a number related to the stock price, then it converts it to a string INSTATR, then writes it to a .txt file.
string INSTATR = LastValue.ToString();
System.IO.File.WriteAllText(#"C:\\DotTempFiles\\"+Instrument.Name+"ATR.txt", INSTATR);
And this is every single piece of code I have connected to this issue. As I mentioned above, it created the file the first time, but since I've deleted the file in windows explorer, it isn't able to recreate it. However, deleting the directory and restarting the strategy program does recreate that directory.
OnTermination() is not being used to close or delete the file in any way (just in case people wanted to ask) -- I am not using any other code to interact with the file than the ones already shown. Thanks!
EDIT 2 (Update after reading comments): Thank you guys for your comments and help. What I'll do when I get back to my home is try recreating the minimal version of this with an empty program containing just these lines of code and see what the outcome is, and I'll post updates in either way.
EDIT 3: Thank you Steve, that is a very good idea that I should use from now on for these kinds of things.
EDIT 4 (Conclusion): Well, I found out that I overlooked something simple about my own code logic. I was setting the File.WriteAllText to trigger any time the Double variable increased in value, not on every call of the OnBarUpdate method. Because of this, the file would not be written except once every few hours or so and now I see that everything is working properly. I am sorry that I made all these people read this post since it was based on another issue of my own fault. However, I am very thankful to everyone for their comments that helped me get to this point, and to Steve and Mark Lakata for their tips that I learned some new good things from.
I found out there is nothing wrong with the file creation, it was the fact that my coding logic was just calling for it far less frequently than I assumed it was (once every few hours vs several times per second)
When I call FileInfo(path).LastAccessTime or FileInfo(path).LastWriteTime on a file that is in the process of being written it returns the time that the file was created, not the last time it was written to (ie. now).
Is there a way to get this information?
Edit: To all the responses so far. I hadn't tried Refresh() but that does not do it either. I am returned the time that the file was started to be written to. The same goes for the static method, and creating a new instance of FileInfo.
Codymanix might have the answer, but I'm not running Windows Server (using Windows 7), and I don't know where the setting is to test.
Edit 2: Nobody finds it interesting that this function doesn't seem to work?
The FileInfo values are only loaded once and then cached. To get the current value, call Refresh() before getting a property:
f.Refresh();
t = f.LastAccessTime;
Another way to get the current value is by using the static methods on the File class:
t = File.GetLastAccessTime(path);
Starting in Windows Vista, last access time is not updated by default. This is to improve file system performance. You can find details here:
http://blogs.technet.com/b/filecab/archive/2006/11/07/disabling-last-access-time-in-windows-vista-to-improve-ntfs-performance.aspx
To reenable last access time on the computer, you can run the following command:
fsutil behavior set disablelastaccess 0
As James has pointed out LastAccessTime is not updated.
The LastWriteTime has also undergone a twist since Vista. When the process has the file still open and another process checks the LastWriteTime it will not see the new write time for a long time -- until the process has closed the file.
As a workaround you can open and close the file from your external process. After you have done that you can try to read the LastWriteTime again which is then the up to date value.
File System Tunneling:
If an application implements something like a rolling logger which closes the file and then renames it to a different file name you will also run into issues since the creation time and file size of the "old" file is remembered by the OS although you did create a new file. This includes wrong reports of the file size even if you did recreate log.txt from scratch which is still 0 bytes in size. This feature is called OS File System Tunneling which is still present on Windows 8.1 . An example how to work around this issue check out RollingFlatFileTracelistener from Enterprise Library.
You can see the effects of file system tunneling on your own machine from the cmd shell.
echo test > file1.txt
ren file1.txt file2.txt
Wait one minute
echo test > file1.txt
dir /tc file*.txt
...
05.07.2015 19:26 7 file1.txt
05.07.2015 19:26 7 file2.txt
The file system is a state machine. Keeping states correctly synchronized is hard if you care about performance and correctness.
This strange tunneling syndrome is obviously still used by application which do e.g. autosave a file and move it to a save location and then recreate the file again at the same location. For these applications it makes to sense to give the file a new creation date because it was only copied around. Some installers do also such tricks to move files temporarily to a different location and write the contents back later to get past some file exists check for some install hooks.
Have you tried calling Refresh() just before accessing the property (to avoid getting a cached value)? If that doesn't work, have you looked at what Explorer shows at the same time? If Explorer is showing the wrong information, then it's probably something you can't really address - it might be that the information is only updated when the file handle is closed, for example.
There is a setting in windows which is sometimes set especially on server systems so that modified and accessed times for files are not set for better performance.
From MSDN:
When first called, FileSystemInfo
calls Refresh and returns the
cached information on APIs to get
attributes and so on. On subsequent
calls, you must call Refresh to get
the latest copy of the information.
FileSystemInfo.Refresh()
If you're application is the one doing the writing, I think you are going to have to "touch" the file by setting the LastWriteTime property your self between each buffer of data you write. Some psuedocode:
while(bytesWritten < totalBytes)
{
bytesWritten += br.Write(buffer);
myFileInfo.LastWriteTime = DateTime.Now;
}
I'm not sure how severely this will affect write performance.
Tommy Carlier's answer got me thinking....
A good way to visualise the differences is seperately running the two snippets (I just used LinqPAD) simliar to below while also running sysinternals Process Monitor.
while(true)
File.GetLastAccessTime([file path here]);
and
FileInfo bob = new FileInfo(path);
while(true){
string accessed = bob.LastAccessTime.ToString();
}
If you look at Process Monitor while running the first snippet you will see repeated and constant access attempts to the file for the LinqPAD process. The second snippet will do an initial access of the file, for which you will see activity in process monitor, and then very little afterwards.
However if you go and modify the file (I just opened the text file I was monitoring using FileInfo and added a character and saved) you will see a series of access attempts by the LinqPAD process to the file in process monitor.
This illustrates the non-cached and cached behaviour of the two different approachs respectively.
Will the non-cached approach wear a hole in the hard drive?!
EDIT
I went away feeling all clever over my testing and then used the caching behaviour of FileInfo in my windows service (basically to sit in a loop and say 'Has-file-changed-has-file-changed...' before doing processing)
While this approach worked on my dev box, it did not work in the production environment, ie the process just kept running regardless if the file had changed or not. I ended up changing my approach to checking and just used GetLastAccessTime as part of it. Don't know why it would behave differently on production server....but I am not too concerned at this point.