How to execute a method one time in ASP.net - c#

I have web form which has a button.When you click that button,it will create a text file and write something to it.Just imagine like i am writing large things of 1G content ,which will change once in a day.And this is an asp.net application and many users will use.So suppose first user clicks at morning 6.o clock it will generate .Now i want to resuse it for others rather creating a new one till next morning 6 o clock.How to do it.I am posting a small prototype code
try
{
File.WriteAllText("E:\\test.txt", "welcome");
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
NB:This is an asp.net application so cant think of thread.So i am not thinking
While(true)
{
Thread.Sleep() etc
}

Use File.GetLastWriteTime Method to check last modification in file
try
{
if(!File.Exists("E:\\test.txt") )
{
File.WriteAllText("E:\\test.txt", "welcome");
}
else
{
if(File.GetLastWriteTime(path).Day != DateTime.Now.Day)
{
//code for next day
}
}
}
catch (Exception ex)
{
Response.Write(ex.Message);
}

Assuming you are making a new file every day, and already have delete logic in place at the end of the day.
Check and see if the file exists before you create it.
try
{
if (//file does not exist)
File.WriteAllText("E:\\test.txt", "welcome");
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
You could also check on the date of the file and if outside of your parameters then delete and create a new one (in the same if condition as the 'exists' logic).

Perhaps you should try using an Application variable to store the last time the file has been written ( a date value ) and just be sure that the file is only ever written once per day. For example:
Dim dt as DateTime
If TryCast(Application("LastFileWrite"), dt) Then
If String.Compare(dt.Date.ToString(), Now.Date.ToString()) <> 0 Then
' we're a different day today, go ahead and write file here
End If
Else
' we've never writting this application variable, this is
' the first run, go ahead and write file here as well
End If
For more information about the Application state, take a look at the following documentation:
https://msdn.microsoft.com/en-us/library/bf9xhdz4(v=vs.71).aspx

This should prevent two or more threads from writing the same file twice.
The first thread to grab the lock will create the file, then the other threads will skip creating the file with the second check of the file inside the lock.
public static object fileLock = new object();
public void createFile()
{
if (File.Exists("filepath") == false) {
lock (fileLock) {
if (File.Exists("filepath") == false) {
File.WriteAllText("E:\\test.txt", "welcome");
}
}
}
}

Related

Execute code after return

On my web API, I want to delete a folder after my return statement.
public string Post(HttpRequestMessage request)
{
//Do cool stuff with request
try
{
return "10.0.2.2:8080/myFolder/index.html";
}
finally
{
Thread.Sleep(60000);
Directory.Delete(myFolder, true);
}
}
What I expected is that the device making the POST could get the return statement and load the html file. After a minute, we delete this file to free space on the server.
What happens is that the return statement is actually sent after the finally statement.
How can I run code after a return statement with delay, without delaying the return?
There is no way to do that and it would be bad anyway, since you would keep resources (webserver threads for example) busy waiting.
Write another process (preferably a Windows service if you are on Windows) that checks the directory periodically and deletes all files of a certain age.
you can't execute code after return
in my opinion you can check files if the file created before 1m delete it
DirectoryInfo objDirectoryInfo = new
DirectoryInfo(Server.MapPath("~/files"));
foreach (FileInfo File in objDirectoryInfo.GetFiles) {
if ((File.LastAccessTime < DateTime.Now.AddMinutes(-1))) {
File.Delete();
}
}

C# SQLite insert and select at the same time [duplicate]

This question already has answers here:
SQLite Concurrent Access
(8 answers)
Closed 8 years ago.
I'm developing an app with C# and SQLite. My problem is, I need to execute INSERT query and SELECT query at the same time. If I explain with more detail my problem is;
Let's say my database name is myDB,
I'm importing a 1 MB text file to myDB. While this import is processing, is another window (in the same app and using same connection and same database file) can execute a SELECT query?
Thank you for helping!
Ok, why you need select? you will get something of the insert and put in another table? Or the program need keep run like nothing are running?
if you need select to put in another table, you can use it:
select * from table order by cod desc limit 1;
or, if you need keep running, you will need a thread, its a example:
onLoad()
{
Thread t = new Thread(new ThreadStart(t_trigger));
t.Start();
}
private void t_trigger()
{
table_insert(string d)
}
private delegate void delegate_table_insert(string d);
private void table_insert(string d)
{
if (InvokeRequired)
{
try
{
Invoke(new delegate_table_insert(table_insert), d);
}
catch (Exception ex)
{
//MessageBox.Show(ex.Message);
}
}
else
{
try
{
// here run the code
}
catch (Exception ex)
{
//MessageBox.Show(ex.Message);
}
}

FileSystemWatcher - is File ready to use

When a file is being copied to the file watcher folder, how can I identify whether the file is completely copied and ready to use? Because I am getting multiple events during file copy. (The file is copied via another program using File.Copy.)
When I ran into this problem, the best solution I came up with was to continually try to get an exclusive lock on the file; while the file is being written, the locking attempt will fail, essentially the method in this answer. Once the file isn't being written to any more, the lock will succeed.
Unfortunately, the only way to do that is to wrap a try/catch around opening the file, which makes me cringe - having to use try/catch is always painful. There just doesn't seem to be any way around that, though, so it's what I ended up using.
Modifying the code in that answer does the trick, so I ended up using something like this:
private void WaitForFile(FileInfo file)
{
FileStream stream = null;
bool FileReady = false;
while(!FileReady)
{
try
{
using(stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
FileReady = true;
}
}
catch (IOException)
{
//File isn't ready yet, so we need to keep on waiting until it is.
}
//We'll want to wait a bit between polls, if the file isn't ready.
if(!FileReady) Thread.Sleep(1000);
}
}
Here is a method that will retry file access up to X number of times, with a Sleep between tries. If it never gets access, the application moves on:
private static bool GetIdleFile(string path)
{
var fileIdle = false;
const int MaximumAttemptsAllowed = 30;
var attemptsMade = 0;
while (!fileIdle && attemptsMade <= MaximumAttemptsAllowed)
{
try
{
using (File.Open(path, FileMode.Open, FileAccess.ReadWrite))
{
fileIdle = true;
}
}
catch
{
attemptsMade++;
Thread.Sleep(100);
}
}
return fileIdle;
}
It can be used like this:
private void WatcherOnCreated(object sender, FileSystemEventArgs e)
{
if (GetIdleFile(e.FullPath))
{
// Do something like...
foreach (var line in File.ReadAllLines(e.FullPath))
{
// Do more...
}
}
}
I had this problem when writing a file. I got events before the file was fully written and closed.
The solution is to use a temporary filename and rename the file once finished. Then watch for the file rename event instead of file creation or change event.
Note: this problem is not solvable in generic case. Without prior knowledge about file usage you can't know if other program(s) finished operation with the file.
In your particular case you should be able to figure out what operations File.Copy consist of.
Most likely destination file is locked during whole operation. In this case you should be able to simply try to open file and handle "sharing mode violation" exception.
You can also wait for some time... - very unreliable option, but if you know size range of files you may be able to have reasonable delay to let Copy to finish.
You can also "invent" some sort of transaction system - i.e. create another file like "destination_file_name.COPYLOCK" which program that copies file would create before copying "destination_file_name" and delete afterward.
private Stream ReadWhenAvailable(FileInfo finfo, TimeSpan? ts = null) => Task.Run(() =>
{
ts = ts == null ? new TimeSpan(long.MaxValue) : ts;
var start = DateTime.Now;
while (DateTime.Now - start < ts)
{
Thread.Sleep(200);
try
{
return new FileStream(finfo.FullName, FileMode.Open);
}
catch { }
}
return null;
})
.Result;
...of course, you can modify aspects of this to suit your needs.
One possible solution (It worked in my case) is to use the Change event. You can log in the create event the name of the file just created and then catch the change event and verify if the file was just created. When I manipulated the file in the change event it didn't throw me the error "File is in use"
If you are doing some sort of inter-process communication, as I do, you may want to consider this solution:
App A writes the file you are interested in, eg "Data.csv"
When done, app A writes a 2nd file, eg. "Data.confirmed"
In your C# app B make the FileWatcher listen to "*.confirmed" files. When you get this event you can safely read "Data.csv", as it is already completed by app A.
(Edit: inspired by commets) Delete the *.confirmed filed with app B when done processing the "Data.csv" file.
I have solved this issue with two features:
Implement the MemoryCache pattern seen in this question: A robust solution for FileSystemWatcher firing events multiple times
Implement a try\catch loop with a timeout for access
You need to collect average copy times in your environment and set the memory cache timeout to be at least as long as the shortest lock time on a new file. This eliminates duplicates in your processing directive and allows some time for the copy to finish. You will have much better success on first try, which means less time spent in the try\catch loop.
Here is an example of the try\catch loop:
public static IEnumerable<string> GetFileLines(string theFile)
{
DateTime startTime = DateTime.Now;
TimeSpan timeOut = TimeSpan.FromSeconds(TimeoutSeconds);
TimeSpan timePassed;
do
{
try
{
return File.ReadLines(theFile);
}
catch (FileNotFoundException ex)
{
EventLog.WriteEntry(ProgramName, "File not found: " + theFile, EventLogEntryType.Warning, ex.HResult);
return null;
}
catch (PathTooLongException ex)
{
EventLog.WriteEntry(ProgramName, "Path too long: " + theFile, EventLogEntryType.Warning, ex.HResult);
return null;
}
catch (DirectoryNotFoundException ex)
{
EventLog.WriteEntry(ProgramName, "Directory not found: " + theFile, EventLogEntryType.Warning, ex.HResult);
return null;
}
catch (Exception ex)
{
// We swallow all other exceptions here so we can try again
EventLog.WriteEntry(ProgramName, ex.Message, EventLogEntryType.Warning, ex.HResult);
}
Task.Delay(777).Wait();
timePassed = DateTime.Now.Subtract(startTime);
}
while (timePassed < timeOut);
EventLog.WriteEntry(ProgramName, "Timeout after waiting " + timePassed.ToString() + " seconds to read " + theFile, EventLogEntryType.Warning, 258);
return null;
}
Where TimeoutSeconds is a setting that you can put wherever you hold your settings. This can be tuned for your environment.

How to wait for an Autoreset event to occur before taking any other action?

This is about the AutoResetEvent in C#. I tried to read other answers but I could not make sense and apply to my scenario. I am not writing any threading application. Just a small application to read/validate a file and update.
So I have this requirement to write some code for reading a fixed length file, validating it and then if it is valid upload it to Database.
I got everything working until I got stuck with the AutoResetEvent. So here is what is happening. Once the data is parsed/read I validate it using Flat File Checker utility in C#. So I called the functions into my application. Here is the snippet.
private AutoResetEvent do_checks = new AutoResetEvent(false);
public bool ValidationComplete = false;
This part goes in initialization code:
this._files.Validated += new EventHandler<SchemaValidatedEventArgs>(FileSetValidated);
public bool ValidateFile()
{
try
{
RunValidation();
return true;
}
catch (Exception e)
{
log.Error("Data Validation failed because :" + e.Message);
return false;
}
}
private void RunValidation()
{
// Use Flat File Checker user interface to create Schema file.
do_checks = _files.RunChecks();
log.Debug("Validation Started");
}
This is the method that is getting called asnchronusly during the validation process:
public void FileSetValidated(Object sender, SchemaValidatedEventArgs e)
{
try
{
ValidationComplete = e.Result;
if (IsDataValid)
{
log.Debug("Data is validated and found to be valid.");
}
else
{
log.Debug("Data is validated and found to be Invalid");
}
}
finally
{
do_checks.Set();
}
}
What is happening is that even before I get any value set into ValidationComplete the code is checked for Validation complete and because it is set by default to false, it returns false. The code in the FileSetValidated gets executed after that so the database update never happens.
The reason is that I cannot change the code because the Flat File Checker only accepts an AutoResetEvent as a return variable in RunChecks method.
******Here is what I did now*******
private AutoResetEvent do_checks;
public bool ValidateFile()
{
try
{
string extFilePath = surveyFile.ExtFilePath;
File.Copy(extFilePath, localTempFolder + "ExtractFile.Dat");
RunValidation();
if (!do_checks.WaitOne(TimeSpan.FromSeconds(30))) {
// throw new ApplicationException("Validation took more than expected!");
}
return true;
}
catch (Exception e)
{
log.Error("Data Validation failed because :" + e.Message);
return false;
}
}
private void RunValidation()
{
// Use Flat File Checker user interface to create Schema file.
do_checks = _files.RunChecks();
do_checks.WaitOne();
log.Debug("Validation Started");
}
Also I moved the part where data about validation gets passed on towards the beginning of the event handler so atleast that part gets executed. This helped but I am not sure if it is correct.
I have never worked with that lib, so I just downloaded it and looked into the code.
First of all, as "500 - Internal Server Error" already mentioned, it seems that part of the code is missing, at least "try" in the FileSetValidated method. I don't see any place where you are waiting for the event via WaitOne.
You don't need to create do_checks by yourself, because _files.RunChecks() creates AutoResetEven for this particular file's processing. So if you are using the same field for that event - you will get issue if you will need to process few files at the same time. So keep separate event for each file, in any case I don't see reason to keep that references as members if you don't want to stop processing in the middle (if you will call do_checks.Set() during processing, it will cancel processing without finishing it).
As I see in the lib code, you should not call do_checks.Set() in the FileSetValidated method, because it will be set, once processing will be done, so you can just write:
var do_checks = _files.RunChecks();
do_checks.WaitOne();
Feel free to share if that helped.
UPDATE:
I am not able to check that lib now to undestand why do_checks is set after starting processing, but I can suggest you to use your initial code with next RunValidation method:
private void RunValidation()
{
do_checks.Reset(); //reset state
_files.RunChecks(); //don't store event from the lib
log.Debug("Validation Started");
do_checks.WaitOne(); //Wait for FileSetValidated to set this event
}
Before exiting the ValidateFile function you need to wait for the validation to complete (wait on the AutoResetEvent) and return the validation result.
Try something like this:
public bool ValidateFile()
{
//try
{
RunValidation();
//Allocate enough time for the validation to occur but make sure
// the application doesn't block if the _files.Validated event doesn't get fired
if(!do_checks.WaitOne(TimeSpan.FromSeconds(10)))
{
throw ApplicationException("Validation took more than expected!");
}
return ValidationComplete;
}
//I would not catch the exception since having an error doesn't mean that the file
//is invalid. Catch it upper in the call stack and inform the user that the validation
//could not be performed because of the error
//catch (Exception e)
//{
// log.Error("Data Validation failed because :" + e.Message);
// return false;
//}
}

Change file address

suppose we have c:\\d1\\d2\\d3\\... where there are many files and directories in d3.
we want to move all items in d3 to c:\\d1\\new\\.
how to do it clean and safe?
c:\\d1\\new exists!
If c:\d1\new does not exist yet, and you don't want to keep an empty c:\d1\d2\d3 folder afterward, you can use the Directory.Move() method:
using System.IO;
try {
Directory.Move(#"c:\d1\d2\d3", #"c:\d1\new");
} catch (UnauthorizedAccessException) {
// Permission denied, recover...
} catch (IOException) {
// Other I/O error, recover...
}
If c:\d1\new does exist, you'll have to iterate over the contents of c:\d1\d2\d3 and move its files and folders one by one:
foreach (string item in Directory.GetFileSystemEntries(#"c:\d1\d2\d3")) {
string absoluteSource = Path.Combine(#"c:\d1\d2\d3", item);
string absoluteTarget = Path.Combine(#"c:\d1\new", item);
if (File.GetAttributes(absoluteSource) & FileAttributes.Directory != 0) {
Directory.Move(absoluteSource, absoluteTarget);
} else {
File.Move(absoluteSource, absoluteTarget);
}
}
Use Directory.Move
Also, MSDN has a handy table of what functions to use for Common I/O Tasks which is a good reference for questions like this.
try
{
System.IO.Directory.Move(#"c:\d1\d2\d3\", #"c:\d1\new\");
}
catch(...)
{
}
The Move method can throw any of the following exceptions that depending on your usage may or may not be thrown. So you need to code the exception handler in a manner that suits your application.
System.IO.IOExeption
System.UnauthorizedAccessException
System.ArgumentException
System.ArgumentNullException
System.IO.PathToLongException
System.IO.DirectoryNotFoundException
As an general example (you probably don't want/need to display message boxes on errors):
try
{
System.IO.Directory.Move(#"c:\d1\d2\d3\", #"c:\d1\new\");
}
catch (System.UnauthorizedAccessException)
{
MessageBox.Show("You do not have access to move this files/directories");
}
catch(System.IO.DirectoryNotFoundException)
{
MessageBox.Show("The directory to move files/directories from was not found")
}
catch
{
MessageBox.Show("Something blew up!");
}
Finally, it is worth mentioning that the call to Move will block the current thread until the move is complete. So if you are doing this from a UI it will block the UI until the copy is complete. This might take some time depending on how many files/directories are being move. Therefore it might be prudent to run this in a seperate thread and/or display a cycling progress bar.
Use Directory.Move.
Moves a file or a directory and its contents to a new location.

Categories

Resources