File used by another process asp.net - c#

I have developed a website in asp.net mvc that reads from a xml-file to display some data. This file is regularly updated by my backend process that builds this xml-file and finally uploads it to my webhost via ftp.
This have been working fine, but in the last week or so I have gotten into a problem. I get the asp.net exception "file is being used by another process". I have no clue what this can be, and I find it very odd. I haven't even changed anything in my code for some months now.
Below you will find a typical method that I use for serializing my xml-file:
public static IEnumerable<FStreamObject> GetStreams()
{
using (FileStream fs = new FileStream(HttpRuntime.AppDomainAppPath+"/ff.xml", FileMode.Open))
{
XmlReader ffXML = XmlReader.Create(fs);
XmlSerializer ser = new XmlSerializer(typeof(FXmlModel));
var sList = (FXmlModel)ser.Deserialize(ffXML);
fs.Close();
return sList.FSObjectList.OrderByDescending(x => x.Cash);
}
}

I guess the other process which updates the content of your file still has a lock on this file. So you may need to fix the code of that to make sure you are releasing any locks /connection to this file once you are done with the file operations.

The problem could be that an Exception is being thrown before the fs.Close() invocation.
Try using a try-catch-fianlly and put the fs.Close() in the finally block.
Also have in mind the Close() method is not destroying the object immediately, you could also try using Dispose() to be sure the reference is being cleaned from memory.
Hope it helps!

Related

Reading file after writing it

I have a strange problem. So my code follows as following.
The exe takes some data from the user
Call a web service to write(and create CSV for the data) the file at perticular network location(say \some-server\some-directory).
Although this web service is hosted at the same location where this
folder is (i.e i can also change it to be c:\some-directory). It then
returns after writing the file
the exe checks for the file to exists, if the file exists then further processing else quite with error.
The problem I am having is at step 3. When I try to read the file immediately after it has been written, I always get file not found exception(but the file there is present). I do not get this exception when I am debugging (because then I am putting a delay by debugging the code) or when Thread.Sleep(3000) before reading the file.
This is really strange because I close the StreamWriter before I return the call to exe. Now according to the documention, close should force the flush of the stream. This is also not related to the size of the file. Also I am not doing Async thread calls for writing and reading the file. They are running in same thread serially one after another(only writing is done by a web service and reading is done by exe. Still the call is serial)
I do not know, but it feels like there is some time difference between the file actually gets written on the disk and when you do Close(). However this baffling because this is not at all related to size. This happens for all file size. I have tried this with file with 10, 50, 100,200 lines of data.
Another thing which I suspected was since I was writing this file to a network location, it could be windows is optimizing the call by writing first to cache and then to network location. So I went ahead and changed the code to write it on drive(i.e use c:\some-directory), rather than network location. But it also resulted in same error.
There is no error in code(for reading and writing). As explained earlier, by putting a delay, it starts working fine. Some other useful information
The exe is .Net Framework 3.5
Windows Server 2008(64 bit, 4 GB Ram)
Edit 1
File.AppendAllText() is not correct solution, as it creates a new file, if it does not exits
Edit 2
code for writing
using (FileStream fs = new FileStream(outFileName, FileMode.Create))
{
using (StreamWriter writer = new StreamWriter(fs, Encoding.Unicode))
{
writer.WriteLine(someString)
}
}
code for reading
StreamReader rdr = new StreamReader(File.OpenRead(CsvFilePath));
string header = rdr.ReadLine();
rdr.Close();
Edit 3
used textwriter, same error
using (TextWriter writer = File.CreateText(outFileName))
{
}
Edit 3
Finally as suggested by some users, I am doing a check for the file in while loop for certain number of times before I throw the exception of file not found.
int i = 1;
while (i++ < 10)
{
bool fileExists = File.Exists(CsvFilePath);
if (!fileExists)
System.Threading.Thread.Sleep(500);
else
break;
}
So you are writing a stream to a file, then reading the file back to a stream? Do you need to write the file then post process it, or can you not just use the source stream directly?
If you need the file, I would use a loop that keeps checking if the file exists every second until it appears (or a silly amount of time has passed) - the writer would give you an error if you couldn't write the file, so you know it will turn up eventually.
Since you're writing over a network, most optimal solution would be to save your file in the local system first, then copy it to network location. This way you can avoid network connection problems. And as well have a backup in case of network failure.
Based on your update, Try this instead:
File.WriteAllText(outFileName, someString);
header = null;
using(StreamReader reader = new StreamReader(CsvFilePath)) {
header = reader.ReadLine();
}
Have you tried to read after disposing the writer FileStream?
Like this:
using (FileStream fs = new FileStream(outFileName, FileMode.Create))
{
using (StreamWriter writer = new StreamWriter(fs, Encoding.Unicode))
{
writer.WriteLine(someString)
}
}
using (StreamReader rdr = new StreamReader(File.OpenRead(CsvFilePath)))
{
string header = rdr.ReadLine();
}

Why isn't this working?

I am trying to just write an array of strings to a file, which SHOULD normally be an easy thing to do. However the following trivial code is throwing an IOException saying that the file is in use by another process. The problem is, the file doesn't even exist until this code is run. And I can guarantee you that there is no other process using the file. So how do I convince the stupid .NET framework that the file is not in use by another process and that it is okay to continue? Because this really shouldn't be that hard.
StreamWriter writer = new StreamWriter(ListFileName);
foreach (string s in InfoLineList)
{
writer.WriteLine(s);
}
This might be because you're not closing the stream when you're done with it, so some handle is getting stuck open somewhere. Perhaps the code is part of a web app, and the web server process keeps that lock around, or the code is being run multiple times. I'd recommend using the stream in a using block:
using(StreamWriter writer = new StreamWriter(ListFileName))
{
foreach (string s in InfoLineList)
{
writer.WriteLine(s);
}
}
This will make sure the StreamWriter is disposed of properly.
If you really want to know what has the file open, use SysInternal's Handle tool to check. I'd be willing to bet it's your own program.
Finally, as I said in my comments, the File.WriteAllLines() method can write an enumerable list of strings to a file all at once:
File.WriteAllLines(ListFileName, InfoListList);

process cannot access the file because it is being used by another process

I am using ASP.NET Webforms with C#. On one page I click submit to create a file on the server.
File.Create(Server.MapPath(ConfigurationManager.AppSettings["LandingPages"])
+ landingPage.FriendlyName);
This works fine and creates the file as expected. However, after it does this it redirects to another page, which reads the file that was just created.
var landingPageContent
= File.ReadAllText(Server.MapPath(ConfigurationManager.AppSettings["LandingPages"])
+ landingPage.FriendlyName);
That's when I get this error.
The process cannot access the file 'c:\code\Content\CMS\LandingPages\Test2' because it is being used by another process.
If I restart IIS then the process releases the file and I can load that page and read the file just fine. Is there something I need to do after File.Create in order to close the file before the redirect?
Did you close the stream returned by File.Create? The name is a bit confusing (it comes all the way from the bowels of WinAPI), but it creates a file and opens it for writing for you.
File.Create returns Filstream, try this:
using (FileStream fs = System.IO.File.Create(...)){}
or shorter:
File.Create(...).Dispose();
try replacing:
File.Create(Server.MapPath(ConfigurationManager.AppSettings["LandingPages"]) + landingPage.FriendlyName);
with:
using(File.Create(Server.MapPath(ConfigurationManager.AppSettings["LandingPages"]) + landingPage.FriendlyName))
{}
so the file handle is immedately disposed/released
Just close it:
var fileStream = File.Create(...);
fileStream.Close();
If you are doing something with created file it would be better wrapping this logic by using block which finally would close a handle:
using (var stream = File.Create(...))
{
// logic
}

XmlSerializer.Serialize doesn't save a file and doesn't throw an exception

I am having problem with saving of my object. Take a look at this code:
public void SerializeToXML(String FileName)
{
XmlSerializer fSerializer = new XmlSerializer(typeof(Configuration));
using (Stream fStream = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
fSerializer.Serialize(fStream, this);
}
}
The problem is that when the user does not have rights to the location on hard disk, this function will not throw me any exception and do not save my file. For example saving to "C:\test.xml" act like nothing happened. And I would like to know if the file has not been saved and it would be good to know the reason why.
I know that I could check if the file on given location exists and throw an exception manualy but shouldn't this be done by the XmlSerializer or FileStream itself?
Thanks for your time
Edit:
As I was suspecting I had to turn on some additional debugging. Since I am using the using clause, the "Enable unmanaged code debugging option" must be check in project properties under the Debug section. After this, the exception is shown in the debugging process.
Edit2
Replacing the above using clause with this code triggers the exception:
public void SerializeToXML(String FileName)
{
XmlSerializer fSerializer = new XmlSerializer(typeof(Configuration));
Stream fStream = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.None);
try
{
fSerializer.Serialize(fStream, this);
}
finally
{
fStream.Close();
}
}
That sounds very strange to me - and it doesn't sound like it has anything to do with the serializer. If you don't have access rights to a particular location, then creating the FileStream should throw an exception; it shouldn't wait until the Serialize line.
Are you absolutely sure that you don't have some catch block higher up which is hiding the problem from you?
I suspect that it has to do with your using statement, because it uses a hidden try-finally construction (where the Dispose() method is called in the finally clause). Information about exceptions which are not visible outside the using block can be found here.
Try replacing the using statement by an instantiation and a call to it's Dispose() method, and I think your problem is solved. Of course, you should afterwards enclose your code in an explicit try-finally structure as part of good programming practice.
Vista file redirection can explain this. It is a feature to allow legacy programs that don't handle UAC properly to still operate. The file gets redirected to the virtual store.
This will happen when you use Visual Studio 2005 or earlier or did something to prevent the manifest from getting embedded in the exe. Fix it by including a manifest.

how to check if a file is being accessed by any other processs and release it?

I am trying to delete/open/edit some files in my C# .Net application.Sometimes i get exception stating the file/directory is being accessed by another process.Is there a way to check if a file/directory is being accessed by process and try to release the file from that process?
No. The only way to do this is to try to access the file, and handle the IOException.
Realistically this is the only safe way anyway. Suppose there was a IsFileInUse() method, and you called it, and it returned "nope, nobody's using that file," and you went ahead and accessed the file. The problem is that in the meantime some other process might have locked or deleted the file. So you'd need to put exception handling around your attempt to access the file anyway. The "test by acquiring" model is the only one that is 100% reliable.
If a file is in use by another process, .NET doesn't provide a way of determining which other process that might be. I believe this would require some pretty low-level unmanaged code though I could be wrong. It is a very low-level operation, if it is possible at all, to "release the file from that process" because that would violate the other process' expectations -- e.g. it thinks it is allowed to write to the file but you have deleted the file and garbaged the handle. I believe you would need to terminate the other process if it's not willing to give up its lock voluntarily.
First, I suppose there are 2 things that may help you:
consider using FileAccess and FileShare flags when opening files
if data from the file is needed only withing the scope of the function use the construction
using(FileStream stream = File.Open(...)) { <file operations> }
this will ensure that file is closed immediately after exiting 'using' block, and not when FileStream object is collected by GC.
Second, there is an unsafe way to get processes that use the file. It is based on debugging features provided by windows. The main idea is to get all system handles and iterate through them to find which are the files handle and additional information. This is done using functions that I'm not sure are documented. If you are interested use google to find more information, but I do not think it is not a good way.
public bool IsInUse(string path)
{
bool IsFree = true;
try
{
//Just opening the file as open/create
using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
{
//we can check by using
fs.CanRead // or
fs.CanWrite
}
}
catch (IOException ex)
{
IsFree = false;
}
return IsFree;
}
string path = "D:\\test.doc";
bool IsFileFree = IsInUse(path);

Categories