I have a long-running REST API method which compiles an XML file. The user makes a request to initiate this compilation, the basic file is created, and the user is then given a unique ID with which to query for progress.
When called, the progress-reading method opens the file with read-only access, instantiates an XDocument
object and counts the number of elements therein.
The code which populates the XML file is accessed with
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
{
var xmlDoc = XDocument.Load(fs);
foreach (...)
{
// add the element to xmlDoc
xmlDoc.Save(filePath);
}
}
And the code which reads the file in order to count the number of elements
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
var xmlDoc = XDocument.Load(fs);
// count elements
}
However, in the populating method an exception is thrown on xmlDoc.Save(filePath);
The process cannot access the file '...' because it is being used by another process.
As I understood it, opening the FileStream with FileShare.Read
allows another process to open the file with read-only access (and I believe this is happening) and likewise using FileShare.ReadWrite
in the reading/counting method would permit the populating process to open the file with write-access.
Why doesn't the above code allow both processes to do what I expect?
When you call
xmlDoc.Save(filePath)
you pass filename, so XmlDocument
does not use your fs
stream you opened for writing. Instead it opens yet another stream internally, which of course fails because you already have one stream opened for writing.
Instead, seek to the beginning of the stream and then call
xmlDoc.Save(fs);
You may also set stream length to zero before saving (to truncate old contents), though not completely sure irs necessary.