C# AutoSave cleanup; best practice? - c#

I've got a class that represents a document (GH_Document). GH_Document has an AutoSave method on it which is called prior to every potentially dangerous operation. This method creates (or overwrites) an AutoSave file next to the original file.
GH_Document also contains a method called DestroyAutoSaveFiles() which removes any and all files from the disk that have been created by the AutoSave function. I call this method on documents when the app closes down, and also when documents get unloaded. However, it appears I missed a few cases since AutoSave files are still present after some successful shutdowns.
So this got me thinking. What's the best way to handle situations like this? Should I track down all possible ways in which documents can disappear and add autosave cleanup logic everywhere? Or should I implement IDisposable and perform cleanup in GH_Document.Dispose()? Or should I do this in GH_Document.Finalize()?
The only time I want an autosave file to remain on disk is if the application crashes. Are Dispose and Finalize guaranteed to not be called in the event of a crash?

Are Dispose and Finalize guaranteed to not be called in the event of a crash?
In general, no, although it depends on how your application crashes. In C# it will usually be the result of an uncaught exception propagating up to the top level. In this case, any finally clauses will be executed on the way up the stack, and that includes Dispose calls from using statements.
If the application is terminated suddenly (for example by killing it in Task Manager) the finally clauses will not be called, but you shouldn't rely on this behaviour.
A simple solution is to put your auto save files in a hidden directory with a special naming convention and delete all autosave files in that directory on successful shutdown.

Related

Settings.Default.Save() and Cursor.LoadFromStream lead to System.IO.IOException

Two strange exceptions happened in .NET built-in components.
It's the same IO exception: "The process cannot access the file '......' because it is being used by another process".
In "cursor" case it's about ".tmp" file and exception happens somewhere at the end of the sequence of calls, when WPF grid is remeasured:
System.Windows.Controls.Grid.MeasureCell
...
System.Windows.Controls.GridViewColumnHeader.GetCursor
...
System.Windows.Input.Cursor.LoadFromStream <-- here
In "settings" case it's about ".newcfg" file and happens exactly on "save" method call.
The question is: how is this possible? And how to handle/prevent it?
I guess default implementations close XMLWriters and do everything correctly.
We had a single user with the same problem as your "settings" case (it's about ".newcfg"). It turns out that when they switched off their Norton Antivirus, the problem went away!
Some research I did prior to that may be of use:
Check if you have more than one thread capable of calling Settings.Default.Save(). If multiple threads are competing, it might produce this error, although I understand .NET is supposed to make this thread-safe.
It might possibly be happening if you have multiple calls to Settings.Default.Save() in quick succession, within the same thread. This can happen if several classes (e.g. user/custom controls) each want to save some settings, but none should have to be aware of the others' need to do this, and closing down the parent form causes each control to call the Save().
Check the user has appropriate write permissions in the target folder AND in the folder where the .exe is located. My colleague has seen a bizarre connection between the two!
Find all instances in your code where you call Settings.Default.Save(), and set a break point on all of them. When you run the program, you might notice some suspicious behaviour or pattern in the way they get called.
Hope this helps!

Can logging to text file in ASP.net WEb server cause locks

Can logging to text file in ASP.net WEb server cause locks
Thi is my code:
var outStream = new FileStream(Server.MapPath("~\\bin\\error.txt"), FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
As you see FileShare is both read and write.
So far I have not seen any issues. Are you aware of possible issues using this method. (I do not want to log error to windows event)
Not 100% sure I understand what you are asking, but any time something writes to a file, the file is locked by that application for the period of time that it takes to complete the write. If there is another application writing to the same file at times, there will be the potential for conflict. If both applications are coded to handle conflicts of this nature, then all will be fine. So if you are coding to handle this situation, you would put the write method in a TRY block within a WHILE block. If an error occurs writing, then it would stay in the while block and pause for a second or something and then try again. Once the write is successful, break out of the while block. You may also want to put in a counter and limit the number of tries.
Just be aware that if you do this that the thread will sit here until the write is successful, so if you don't want this to hold up your application it needs to be done with another thread.
I think you would just want to do a lock on a static object that wraps the File I/O. This static object would ensure the file updates are thread safe.
With respect to Mr. Hinkle, I had always heard one would not want to have multiple try/catch fails inside a while loop as pure design -- unless I'm missing something. I can see where practically this would work, but I always thought exceptions should not become part of the "main flow" in this way.

how to catch program shutdown to release resources?

In my program i'm using
logWriter = File.CreateText(logFileName);
to store logs.
Should I call logWriter.Close() and where? Should it be finalizer or something?
The normal approach is to wrap File.CreateText in a using statement
using (var logWriter = File.CreateText(logFileName))
{
//do stuff with logWriter
}
However, this is inconvenient if you want logWriter to live for the duration of your app since you most likely won't want the using statement wrapping around your app's Main method.
In which case you must make sure that you call Dispose on logWriter before the app terminates which is exactly what using does for you behind the scenes.
Yes you should close your file when you're done with it. You can create a log class ( or use an existing one like log4net ) and implement IDisposable and inside the Dispose-method you release the resources.
You can wrap it with a using-block, but I would rather have it in a seperate class. This way in the future you can handle more advance logging, for instance, what happens when your application runs on multiple threads and you try to write to the file at the same time?
log4net can be configured to use a text-file or a database and it's easy to change if the applications grows.
If you have a log file which you wish to keep open, then the OS will release the file as part of shutting the process down when the application exits. You do not actually have to manage this explicitly.
One issue with letting the OS clean up your file handle, is that your file writer will use buffering and it may need flushing before it will write out the remains of its buffer. If you do not call close\dispose on it you may lose information. One way of forcing a flush is to hook the AppDomain unload event which will get called when your .Net process shuts down, e.g.:
AppDomain.CurrentDomain.DomainUnload += delegate { logWriter.Dispose(); };
There is a time limit on what can occur in a domain unload event handler, but writing the remains of a file writer buffer out is well within this. I am assuming you have a default setup i.e. one default AppDomain, otherwise things get tricky all round including logging.
If you are keeping your file open, consider opening it with access rights that will allow other processes to have read access. This will enable a program such as a file tailer or text editor to be used to read the file whilst your program is running.

Using C# is it possible to test if a lock is held on a file

BACKGROUND:
I use an offset into a file and the Filestream lock/unlock menthods to control read/write access. I am using the following code to test if a lock is currently held on the file
try
{
fs.Lock( RESERVED_BYTE, 1 );
fs.Unlock( RESERVED_BYTE, 1 );
rc = 1;
}
catch
{
rc = 0;
}
QUESTION:
My goal is to eliminate the try/catch block. Is there some better way to see if the lock exists?
EDIT:
Note: This question is not about if the file exists. I already know it does. It is about synchronizing write access.
You can call the LockFile Windows API function through the P/Invoke layer directly. You would use the handle returned by the SafeFileHandle property on the FileStream.
Calling the API directly will allow you to check the return value for an error condition as opposed to resorting to catching an exception.
Noah asks if there is any overhead in making the call to the P/Invoke layer vs a try/catch.
The Lock file makes the same call through the P/Invoke layer and throws the exception if the call to LockFile returns 0. In your case, you aren't throwing an exception. In the event the file is locked, you will take less time because you aren't dealing with a stack unwind.
The actual P/Invoke setup is around seven instructions I believe (for comparison, COM interop is about 40), but that point is moot, since your call to LockFile is doing the same thing that the managed method does (use the P/Invoke layer).
Personally I would just catch a locked file when trying to open it. If it's unlocked now, it may be locked when you try to open it (even if it's just a few ms later).
My goal is to eliminate the try/catch block
Remember, the file system is volatile: just because your file is in one state for one operation doesn't mean it will be in the same state for the next operation. You have to be able to handle exceptions from the file system.
In some circumstances you can also use WCT, it's usually implmented by debugger's or profilers, however it can be used from any code as the usual debugger requirement of being the thread which has the debug port open is not a pre-requisit. As such WCT is a very comprehensive and precise information regarding lock contention.
A managed example (all-be-it somewhat trickey), show's utility for this specific sub-set of the native debug API's on the CLR.
I don't think it's possible without try, catch.

How can I reliably guarantee access to a file/folder?

-What is the most foolproof way of ensuring the folder or file I want to manipulate is accessible (not read-only)?
-I know I can use ACL to add/set entries (make the file/folder non-readonly), but how would I know if I need to use security permissions to ensure file access? Or can I just add this in as an extra measure and handle the exception/negative scenario?
-How do I know when to close or just flush a stream? For example, should I try to use the streams once in a method and then flush/close/dipose at the end? If I use dispose(), do I still need to call flush() and close() explicitly?
I ask this question because constantly ensuring a file is available is a core requirement but it is difficult to guarantee this, so some tips in the design of my code would be good.
Thanks
There is no way to guarantee access to a file. I know this isn't a popular response but it's 100% true. You can never guarantee access to a file even if you have an exclusive non-sharing open on a Win32 machine.
There are too many ways this can fail that you simply cannot control. The classic example is a file opened over the network. Open it any way you'd like with any account, I'll simply walk over and yank the network cable. This will kill your access to the file.
I'm not saying this to be mean or arrogant. I'm saying this to make sure that people understand that operating on the file system is a very dangerous operation. You must accept that the operation can and will fail. It's imperative that you have a fallback scenario for any operation that touches disk.
-What is the most foolproof way of ensuring the folder or file I want to manipulate is accessible (not read-only)?
Opening them in write-mode?
Try and write a new file into the folder and catch any exceptions. Along with that do the normally sanity checks like folder/files exists etc.
You should never change the folder security in code as the environment could drastically change and cause major headaches. Rather ensure that the security is well documented and configured before hand. ALternatively use impersonation in your own code to ensure you are always running the required code as a user with full permissions to the folder/file.
Never call Dispose() unless you have no other choice. You always flush before closing the file or when you want to commit the content of the stream to the file/disk. The choice of when to do it depends on the amount of data that needs to be written and the time involved in writing the data.
100% foolproof way to ensure a folder is writable - create a file, close it, verify it is there, then delete it. A little tedious, but you asked for foolproof =)
Your better bet, which covers your question about ACL, is to handle the various exceptions if you cannot write to a file.
Also, I always call Close explicitly unless I need to read from a file before I'm done writing it (in which case I call flush then close).
Flush() - Synchronizes the in-memory buffer with the disk. Call when you want to write the buffer to the disk but keep the file open for further use.
Dispose(bool) - Releases the unmanaged resource (i.e. the OS file handle) and, if passed true, also releases the managed resources.
Close() - Calls Dispose(true) on the object.
Also, Dispose flushes the data before closing the handle so there is no need to call flush explicitly (although it might be a good idea to be flushing frequently anyway, depending on the amount and type of data you're handling).
If you're doing relatively atomic operations to files and don't need a long-running handle, the "using" paradigm is useful to ensure you are handling files properly, e.g.:
using (StreamReader reader = new StreamReader("filepath"))
{
// Do some stuff
} // CLR automagically handles flushing and releasing resources

Categories