Is it possible to use a lock on one xml file that can potentially be written to from multiple aspx pages at the same time?
I'm asking because MSDN suggest that the lock statement should be used with a private static object instance as the expression, and since there are multiple pages involved i guess i can't use the same object on all the pages?
You can use the File.Open overload that takes a FileShare enum that is set to None. No other thread will be able to open the file until closed.
FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None);
This piece of code will open the (existing) file specified in the path argument, for reading and without any sharing.
Related
I've written a .Net Web API which takes it's inputs, parses them and then stores an XML file on a network share linked to our server. I have also built a Windows service which scans the network share for new files to process our business logic.
This works nearly 100% of the time, but very occasionally (1 in 20,000 times) IIS6 holds a lock on the file it creates and won't clear until IIS is restarted. The locked files are always 0 bytes.
Currently I have a file which has been locked for nearly 20 hours! Here is the code that creates the file:
Try
'-- Make sure the file doesn't already exist
TempFileName = strFullFileName
i = 1
While IO.File.Exists(TempFileName)
TempFileName = strFullFileName.Replace(".xml", "_" & i & ".xml")
i += 1
End While
strFullFileName = TempFileName
'-- Deserialise the message into a file
drSerializer = New XmlSerializer(DetailsOfMsg.GetType)
FS = New FileStream(strFullFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None)
XW = XmlWriter.Create(FS)
drSerializer.Serialize(XW, DetailsOfMsg)
Finally
Try : XW.Flush() : Catch : End Try
Try : FS.Close() : Catch : End Try
Try : XW.Close() : Catch : End Try
FS = Nothing
XW = Nothing
End Try
Why is IIS still holding a lock?
Did you try to wrap the code within "Using" blocks? This ensures that types of FileStream and XmlWriter get disposed once the block's scope ends.
I think you need to separate this process. First create file on say folder X. Once created then move this file from folder X to shared location as there is watcher associated with this network share. Also, once file found then pick it and move to working folder and then start your business process on that file. 0 byte may be indicator of write and watch deadlock.
I can see that, you have created FileStream instance with FileShare = none, whereas your requirement says that, you need simultaneously read and write on shared location.
Correct code would be
FS = New FileStream(strFullFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)
FileShare - A constant that determines how the file will be shared by processes.
For more info - refer this - https://msdn.microsoft.com/en-us/library/5h0z48dh(v=vs.110).aspx
EDIT
From comment, I found that you need lock to be applied for Read operation, and the error you are getting ( not so frequently) might be because of write lock. To avoid this, you can use following.
FS = New FileStream(strFullFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Write)
FileShare.Write - Allows subsequent opening of the file for writing.
If this flag is not specified, any request to open the file for
writing (by this process or another process) will fail until the file
is closed. However, even if this flag is specified, additional
permissions might still be needed to access the file.
I needed a audio conversion library. After already pulling my hair..I have given up on the fact that there is no such audio library out there..every library out there has some or the other problem.
The only option left is ffmpeg which is the best but unfortunately you cannot use it in asp.net (not directly I mean). Every user on the website that will convert a file; will launch an exe?; I think I will hit the server memory max soon.
Bottom Line: I will try using ffmpeg.exe and see how many users it can support simultaneously.
I went to the ffmpeg website and in the windows download section I found 3 different version; static, shared and dev.
Does any one know which would be the best? All packed in one exe (static) or dll's separely and exe small, wrt using it in asp.net?
PS: any one has a good library out there..would be great if you can share.
Static builds provide one self-contained .exe file for each program (ffmpeg, ffprobe, ffplay).
Shared builds provide each library as a separate .dll file (avcodec, avdevice, avfilter, etc.), and .exe files that depend on those libraries for each program
Dev packages provide the headers and .lib/.dll.a files required to use the .dll files in other programs.
ffMpeg is the best library out there from what I have used but I wouldn't recommend trying to call it directly from asp.net.
What I have done, is accepted the upload, stored it on the server, or S3 in my case, then have a worker role (if using something like Azure) and a process that continuously looks and monitors for new files to convert.
If you needed a realtime like solution, you could update flags in your database and have an AJAX solution to poll the database to keep providing progress updates, then a link to download once the conversion is complete.
Personally my approach would be
Azure Web Roles
Azure Worker Role
ServiceBus
The WorkerRole starts up and is monitoring the ServiceBus Queue for messages.
The ASP.NET site uploads and stores the file in S3 or Azure
The ASP.NET site then records information in your DB if needed and sends a message to the ServiceBus queue.
The WorkerRole picks this up and converts.
AJAX will be needed on the ASP.NET site if you want a realtime monitoring solution. Otherwise you could send an email when complete if needed.
Using a queuing process also helps you with load as when you are under heavy load people just wait a little longer and it doesn't grind everything to a halt. Also you can scale out your worker roles as needed to balance loads, should it ever become too much for one server.
Here is how I run ffMpeg from C# (you will need to change the parameters for your requirements)
String params = string.Format("-i {0} -s 640x360 {1}", input.Path, "C:\\FilePath\\file.mp4");
RunProcess(params);
private string RunProcess(string Parameters)
{
//create a process info
ProcessStartInfo oInfo = new ProcessStartInfo(this._ffExe, Parameters);
oInfo.UseShellExecute = false;
oInfo.CreateNoWindow = true;
oInfo.RedirectStandardOutput = true;
oInfo.RedirectStandardError = true;
//Create the output and streamreader to get the output
string output = null; StreamReader srOutput = null;
//try the process
try
{
//run the process
Process proc = System.Diagnostics.Process.Start(oInfo);
proc.ErrorDataReceived += new DataReceivedEventHandler(proc_ErrorDataReceived);
proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
proc.WaitForExit();
proc.Close();
proc.Dispose();
}
catch (Exception)
{
// Capture Error
}
finally
{
//now, if we succeeded, close out the streamreader
if (srOutput != null)
{
srOutput.Close();
srOutput.Dispose();
}
}
return output;
}
I have an ASP.NET running in IIS 7.5 that creates files on the local file system and then attempts to delete after performing some logic in between creation and deletion. I'm running into a situation though where deletion is failing with a response such as "The process cannot access the file 'C:...\Uploads\c1fe593f-85de-4de1-b5d1-7239e1fc0648_Tulips.jpg' because it is being used by another process.'" The file appears to be locked by IIS and I can't delete it. Here's an example of the code for creating and deleteing:
// File.WriteAllBytes(path, rawData); // this seems to leave the file open!
using (var file = File.Create(path))
{
file.Write(rawData, 0, rawData.Length);
file.Close(); // should close when it goes out of scope, but just to be safe
}
Is there some special option I need to pass into File.Create? How do I get around this?
File.WriteAllBytes(path, rawData); should work fine assuming the path parameter you are passing is unique and that you don't have concurrent requests one writing and other trying to read at the same time. To ensure this you could use a ReaderWriterLockSlim to synchronize the access if this situation could potentially occur. Also make sure that there are no other parts of the code that might leak the file handle.
Take a look at SysInternals Process Explorer which could allow you to know exactly where this file handle is leaked.
I have an asp.net mvc application that take a while to load on my production server. I would like to write a script to call my pages every 10 minutes to avoid the pages from being scrapped on the server, which would then cause the server to reload them.
I was thinking of using a SQL Server stored procedure to call my pages every 10 minutes to keep the pages alive.
I've read that I can do this using CLR, but I am not sure how. Does anyone have an example of how to call webpages in a SQL Stored Procedure using CLR?
I have no idea why you would want to use a stored procedure for this.
Just write a simple console application to "call" the page. Then use a scheduled task to run the console application.
Code untested but something like this should work.
You'll probably also need TRUSTWORTHY SET.
ALTER DATABASE Foo SET TRUSTWORTHY ON;
Code:
public partial class WebProc
{
[SqlFunction()]
public static string WebQuery()
{
WebRequest request = HttpWebRequest.Create("http://www.google.com");
WebResponse response = request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader (dataStream);
string responseFromServer = reader.ReadToEnd();
return responseFromServer;
}
}
I have no idea why you would want to use a stored procedure for this.
Just write a simple console application to "call" the page. Then use a scheduled task to run the console application.
You could do that (of course) but that's not what the question was asking ;)
Jafin's answer is correct for the question.
The best answer (IMHO) would be to fix your production server (i.e. reconfigure the settings) so that it doesn't "scrap" your pages every 10 minutes.
Why use a jackhammer (console app or .net inside the database or whatever) when a regular one will do?
I am developing an application to read an excel spreadsheet, validate the data and then map it to a sql table. The process is to read the file via a streamreader, validate the data, manually make corrections to the excel spreadsheet, validate again -- repeat this process until all data validates.
If the excel spreadsheet is open, then when I attempt to read the data via a streamreader I get an error, "The process cannot access the file ... because it is being used by another process." Is there a way to remove the lock or otherwise read the data into a streamreader without having to open and close excel each time?
When you call File.Open to get the stream are you using the overload that allows you to specify FileAccess?
http://msdn.microsoft.com/en-us/library/y973b725.aspx
Note the parameters:
public static FileStream Open(
string path,
FileMode mode,
FileAccess access,
FileShare share
)
You can pass FileAccess.Read to the third param to indicate you only need read-only access. You should also set FileShare.Read to allow others to open the file read-only instead of locking it yourself. Note that if MS Excel opens the file with FileShare.None, you probably wont be able to access it.