When to delete generated file using asp.net - c#

I have a template excel file to generate excel files from it.
My code is as follows (This part is to create a new excel file from the template):
string currentFN = PropertyFinalResult[0].Fecha;
string fixCurrentFN = currentFN.Replace('/', '_');
string currentTime = DateTime.Now.ToLongTimeString();
string fixCurrentTime = currentTime.Replace(':', '_');
string addToFileName = fixCurrentTime.Replace(' ', '_');
string newFN = fixCurrentFN + "-" + addToFileName;
string SourceFile = Request.PhysicalApplicationPath + "Template\\ExcelTemplate.xlsx";
string DestFile = Request.PhysicalApplicationPath + "Template\\" + newFN + ".xlsx";
//To keep FileName for posterior deletion
Session["sDestFile"] = DestFile;
try
{
File.Copy(SourceFile, DestFile);
}
catch (Exception ex)
{
lblErrorSavingToDB.Text = "Error: " + ex.Message;
lblErrorSavingToDB.Visible = true;
}
after that I open the new excel file, insert the records in it and then, stream the file to the user by doing this:
//Streaming file to client
string fileName = newFN + ".xlsx";
Response.Redirect("../Template/" + fileName);
Now, my question is, whether the user save or not the file, when should I delete the generated file? I would prefer once the user closes the popup window regarding Open or Save the file. But how to know when the user closes that window?

You can use TransmitFile and then close once the transmission is over. Example:
try
{
Response.ContentType = "application/octet-stream";
Response.AddHeader("content-disposition", "attachment;filename=\"" + Path.GetFileName(path.FullName) + "\"");
Response.AddHeader("content-length", path.Length.ToString());
Response.TransmitFile(path.FullName);
Response.Flush();
}
finally
{
File.Delete(Server.MapPath("~/"+tpacode+".zip"));
}

When to delete the files (or maybe it's better to say "how long to keep the files") is a question that is best answered by your application's business rules.
In the past, in low-traffic applications, I've used a "clean-up" routine to delete files older than a certain threshold. That clean-up gets performed when a new file is created, and at that time any file in the designated folder that was older than the threshold would be deleted.

Related

Trying to dynamically create a zip file causes the zip file to be corrupted

So i wrote this program for my company that dynamically makes a zip folder in their downloads. This code worked perfectly, however, when my server was updated to windows 10, when i attempt to unzip the file, I get this error.
"Cannot complete the compressed folder"
string[] ProductNumberAmount = prodNumber.ToString().Split(' ');
int amountOf = ProductNumberAmount.Count();
Response.ClearHeaders();
Response.ClearContent();
using (ZipFile zip = new ZipFile())
{
Response.ClearHeaders();
Response.ClearContent();
Response.Clear();
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "attachment; filename=" + ProductNumberAmount[0] + "_" + DateTime.Now.ToString("yyyyMMdd") + ".zip");
for (int i = 0; i < amountOf;)
{
string productNumberList = ProductNumberAmount[i];
productNumberList = productNumberList.Replace("\r\n", string.Empty);
string s = "example text";
File.WriteAllText(#"product_detail_" + productNumberList + ".inc", s);
zip.AddFile(#"product_detail_" + productNumberList + ".inc");
i++;
}
zip.Save(Response.OutputStream);
}
Response.Flush();
HttpContext.Current.Response.End();
}
When viewing the zipped folder that was created in notepad, instead of the normal hex text that you would see, there is html text
Again, this exact code worked perfectly before the update so does this have something to do with the IIS server properties being changed. I have been working on this for a couple days and still have not had any luck with anything
Thank you all for your answers! It was an easier fix then anticipated. I set a breakpoint at
"Response.AddHeader("content-disposition", "attachment; filename=" + ProductNumberAmount[0] + "_" + DateTime.Now.ToString("yyyyMMdd") + ".zip");"
and it threw an exception showing that there was folder that needed permission set. Once i have the user "IIS_IUSRS" full permissions in the named folder, the program worked as it originally was intended.
The reason that it probably needed full permissions was because the zipped folder would go directly into the users downloaded folder

Where should I close the File Stream?

I am trying to get the text of a file in C# (config) and to put it into fields. The code itself works, but I need to close the file stream to open a new one futher in the code, but don't know where to put the Close() tag. Can someone help me?
string documentspath = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string rpath = documentspath + #"\Luminous\remember.ini";
if (File.Exists(rpath))
{
try
{
string text = File.ReadAllText(rpath);
string path = text.Split('|')[0];
string process = text.Split('|')[1];
string loadLib = text.Split('|')[2];
pathBox.Text = path;
processBox.Text = process;
if (loadLib == "True")
{
loadLibrary.Checked = true;
}
else
{
manualMap.Checked = true;
}
} catch
{
MessageBox.Show("Config file corrupted. Remembered data has been lost and deleted.");
File.Delete(rpath);
}
} else
{
MessageBox.Show("No config file loaded. Welcome, " + Environment.UserName + ".");
}
EDIT: Here's the code from where I'm opening another file stream.
string documentspath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
if (!Directory.Exists(documentspath + #"\Luminous")) {
Directory.CreateDirectory(documentspath + #"\Luminous");
} else {
string rpath = documentspath + #"\Luminous\remember.ini";
if (!File.Exists(rpath)) {
File.Create(rpath);
File.WriteAllText(rpath, pathBox.Text + "|" + processBox.Text + "|" + loadlibcheck + "|" + manualmapcheck);
} else {
File.WriteAllText(rpath, string.Empty);
File.WriteAllText(rpath, pathBox.Text + "|" + processBox.Text + "|" + loadlibcheck + "|" + manualmapcheck);
}
}
You don't need to close File when using File.ReadAllText().
From MSDN:
File.ReadAllText Method Opens a text file, reads all lines of the file, and then closes the file.
Error appears because of this line:
File.Create(rpath);
Try:
using(File.Create(rpath)) {}
File.Create method actually return FileStream, which have to be disposed. Some info about it can be found on the documentation.
In section "Return Value":
Type: System.IO.FileStream A FileStream that provides read/write
access to the file specified in path.
In section "Remarks":
The FileStream object created by this method has a default FileShare value of None; no other process or code can access the created file until the original file handle is closed.
However, as Chris Dunaway mentioned, there is no need to use File.Create at all, as according to documentation WriteAllText :
Creates a new file, writes the specified string to the file, and then closes the file. If the target file already exists, it is overwritten.
You have two good options:
On the finally clause of your try/catch block.
Change your code to use using statement for your file stream.
You don't have to close anything. File.ReadAllText reads and closes a stream internally. So you can safely invoke another File.ReadAllText if you need to.

Using TextWriter with StreamWriter and Reading/Writing Simultaneously

As the title suggests, I'm attempting to read and write to a file at the same time. I have researched this topic but the answers I have found don't seem to work for me because of the circumstances in my program. I am using multiple FileSystemWatchers to track a large amount of files that are constantly passing through a flow in my network. As the files pass through each part of my flow, a text file is updated(one text file per spot in the flow) that marks the name of the file and the time it was created within the folder. It is unpredictable when files might be passing through, and when they might be writing to the tracker text files. My goal is to be able to read and write to the file simultaneously, in case a user attempts to read to from a text file that is being written to at the exact same time. How would I accomplish this?
//Write to File
private void WriteToFile(string info,string path,string tr)
{
if (!File.Exists(path+#"\"+#tr))
{
var myFile =
File.Create(path + #"\" + #tr);
myFile.Close();
TextWriter tw = new StreamWriter(path + #"\" + #tr, true);
tw.WriteLine(info,true);
tw.Close();
}
else if (File.Exists(path + #"\" + #tr))
{
TextWriter tw = new StreamWriter(path + #"\" + #tr, true);
tw.WriteLine(info);
tw.Close();
}
}
The circumstances you are alluding to seem to say that while multiple attempts can be made to read/write the file at a given time, you still want to ensure that the operations are performed one after another in the correct order that the read or writes got called.
One simple method of ensuring that the read and write operations are synchronized would be to just put a lock or Monitor around the methods. Try the following code for your write method:
private readonly object _locker = new object();
// write the file
private void WriteToFile(string info, string path, string tr)
{
Monitor.Enter(this._locker);
try
{
if (!File.Exists(path + #"\" + #tr))
{
var myFile =
File.Create(path + #"\" + #tr);
myFile.Close();
TextWriter tw = new StreamWriter(path + #"\" + #tr, true);
tw.WriteLine(info, true);
tw.Close();
}
else if (File.Exists(path + #"\" + #tr))
{
TextWriter tw = new StreamWriter(path + #"\" + #tr, true);
tw.WriteLine(info);
tw.Close();
}
}
finally
{
Monitor.Exit(this._locker);
}
}
Then, I would use a very similar construct for reading the file.
// read the file
private string ReadFile(string path)
{
Monitor.Enter(this._locker);
try
{
// read the file here...
}
finally
{
Monitor.Exit(this._locker);
}
}
What the Monitor will do is ensure that the file will not be read until an on-going write operation is complete (and vice-versa). This will ensure that you will not get the old data when you read it, and you will also not over-write the new data (which has not yet been read). This method verifies the integrity of your files at all times.

File.Create is creating a folder instand of file

I'm writing a function which is going to serialize class and save it to file, some classes must be saved in a different folder. I'm using Unity and C#. Here's my code:
public void save<T>(T data, string fileName) where T : class{
if (fileName == "")
Debug.Log ("Empty file path");
FileStream file = null;
try{
if(fileName.IndexOf("/") > 0){
string[] strDirName = fileName.Split(new char[] {'/'});
string dirName = strDirName[0];
if(!Directory.Exists(Application.persistentDataPath + dirName)){
Directory.CreateDirectory(Application.persistentDataPath + "/" + dirName);
}
}
file = File.Create(constructFilePath(fileName));
string a = constructFilePath(fileName);
binFormatter.Serialize(file, data);
Debug.Log ("File saved succesfully" + fileName);
}catch(IOException e){
Debug.Log(e.ToString());
}finally{
if(file != null)
file.Close();
}
}
string constructFilePath(string fileName){
return Path.Combine(Application.persistentDataPath, fileName);
}
I have no idea why it's saving files as folder, this happens since I added this line to construct constructFilePath
if(fileName[0] != "/")
fileName = "/" + fileName;
But without this file it's creating different folder. It's concatenating the Application.persistentDataPath with the folder name and creates the file there
so if my persistentDataPath = C:/Users/User/AppData/LocalLow/DefaultCompany/TestGame and I want to store the file inside this folder in folder a and store file b in it
C:/Users/User/AppData/LocalLow/DefaultCompany/TestGame/a/b
it creates folder with name TestGamea and stores b inside it
C:/Users/User/AppData/LocalLow/DefaultCompany/TestGamea/b
You are evaluating one thing and performing something different here:
if(!Directory.Exists(Application.persistentDataPath + dirName)){
Directory.CreateDirectory(Application.persistentDataPath + "/" + dirName);
}
Change this to:
if(!Directory.Exists(Path.Combine(Application.persistentDataPath, dirName))){
Directory.CreateDirectory(Path.Combine(Application.persistentDataPath, dirName));
}
Like Eric said, use Path.Combine. it will reliably combine path parts and ensure you get the same result every time so you don't have to worry about string manipulation.

Exporting to Outlook (.ics file) from a .NET web application

Basically I'm trying to create and export a .ics file from a C# web application so the user can save it, and open it in Outlook to add something to their calendar.
Here's the code I have at the moment...
string icsFile = createICSFile(description, startDate, endDate, summary);
//Get the paths required for writing the file to a temp destination on
//the server. In the directory where the application runs from.
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
string assPath = Path.GetDirectoryName(path).ToString();
string fileName = emplNo + "App.ics";
string fullPath = assPath.Substring(0, assPath.Length-4);
fullPath = fullPath + #"\VTData\Calendar_Event\UserICSFiles";
string writePath = fullPath + #"\" + fileName; //writepath is the path to the file itself.
//If the file already exists, delete it so a new one can be written.
if (File.Exists(writePath))
{
File.Delete(writePath);
}
//Write the file.
using (System.IO.StreamWriter file = new System.IO.StreamWriter( writePath, true))
{
file.WriteLine(icsFile);
}
The above works perfectly. It writes the file and deletes any old ones first.
My main issue is how to get it to the user?
I tried redirecting the page straight to the path of the file:
Response.Redirect(writePath);
It does not work, and throws the following error:
htmlfile: Access is denied.
NOTE: If I copy and paste the contents of writePath, and paste it into Internet Explorer, a save file dialog box opens and allows me to download the .ics file.
I also tried to prompt a save dialog box to download the file,
System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
response.ClearContent();
response.Clear();
response.ContentType = "text/plain";
response.AddHeader("Content-Disposition", "inline; filename=" + fileName + ";");
response.TransmitFile(fullPath);
response.Flush(); // Error happens here
response.End();
It does not work either.
Access to the path 'C:\VT\VT-WEB MCSC\*some of path omitted *\VTData\Calendar_Event\UserICSFiles' is denied.
Access denied error again.
What may be the problem?
It sounds like you are trying to give the user the physical path to the file instead of the virtual path. Try changing the path so it ends up in the www.yoursite.com/date.ics format instead. This will allow your users to download it. The issue is that they don't have access to the C drive on your server.
Here is a link to how to do this:
http://www.west-wind.com/weblog/posts/2007/May/21/Downloading-a-File-with-a-Save-As-Dialog-in-ASPNET
Basically, you need the following line in your code:
Response.TransmitFile( Server.MapPath("~/VTData/Calendar_Event/UserICSFiles/App.ics") );
Use this instead of the Response.Redirect(writePath); and you should be good to go.

Categories

Resources