I'm using WinForms. I made a simple Image Viewer application using a picturebox to display my images. I made a way to create temporary files. These files are always picture files. When my application is done using the image i want to be able to delete these temporary on FormClosing files located at: C:\Users\taji01\AppData\Local\Temp\8bd93a0dec76473bb82a12488fd350af To do that i cannot simply call File.Delete(C://picture.jpg) because my application is still using them even though there is another picture displaying in my application. So i tried to dispose it but i couldn't figure how how to do that. Should i be using a using statement? Is there a better way to dispose and delete the file or is there a way to make this work?
_fileName = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
File.Copy(imagePath, _fileName);
_stream = new FileStream(_fileName, FileMode.Open, FileAccess.Read, FileOptions.DeleteOnClose);
this._Source = Image.FromStream(_stream);
Error: "The process cannot access the file C:\picture.jpg because it is being used by another process" Exeption thrown: 'System.IO.IO.Exception' in msconrlib.dll (The process cannot access the file 'C:\picture.jpg' because it is being used by another procesas")
You need to Close() your FileStream.
I think a Transaction manager will do what you want. Check out .NET Transactional File Manager. When you rollback your Transaction, it should delete your temp files automatically, as long as they were created within the Transaction scope.
Here you need to dispose the object of MailMessage.
For Ex.
// Sends email using SMTP with default network credentials
public static void SendEmailToCustomer(string To, string From, string BCC, string Subject, string Body, bool IsBodyHtml, string attachedPath = "") {
//create mail message
MailMessage message = !string.IsNullOrEmpty(From) ? new MailMessage(From, To) : new MailMessage(From, To);
//create mail client and send email
SmtpClient emailClient = new SmtpClient();
//here write your smtp details below before sending the mail.
emailClient.Send(message);
//Here you can dispose it after sending the mail
message.Dispose();
//Delete specific file after sending mail to customer
if (!string.IsNullOrEmpty(attachedPath))
DeleteAttachedFile(attachedPath);
}
//Method to delete attached file from specific path.
private static void DeleteAttachedFile(string attachedPath) {
File.SetAttributes(attachedPath, FileAttributes.Normal);
File.Delete(attachedPath);
}
Related
I'm working with C# on Windows servers for a web application stored on the IIS Server.
I would like to create an eml file from :
an html content (string)
some attachments that are loaded in memory
a string subject
string recipients
string sender
The main problem is that I am not allowed to store files on the host server (not even in a temporary directory or if I delete them after).
I saw many threads explaining how to create an eml file with the help of SmtpClient. But we always need to use a directory to save the file.
Do someone knows a way to do that ? Or to create a directory in memory (which seems undoable) ?
Thanks for everyone who will read me
[EDIT]
Using jstedfast's answer below and the Mime documentation, I could figure a way. Here is a POC in case someone needs it later.
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Joey", "joey#friends.com"));
message.To.Add(new MailboxAddress("Alice", "alice#wonderland.com"));
message.Subject = "How you doin?";
var builder = new BodyBuilder();
// Set the plain-text version of the message text
builder.TextBody = #"Hey Alice,
What are you up to this weekend? Monica is throwing one of her parties on
Saturday and I was hoping you could make it.
Will you be my +1?
-- Joey
";
// We may also want to attach a calendar event for Monica's party...
builder.Attachments.Add("test.pdf", attachmentByteArray);
// Now we just need to set the message body and we're done
message.Body = builder.ToMessageBody();
using (var memory = new MemoryStream())
{
message.WriteTo(memory);
}
Look into using MimeKit.
You can write the MimeMessage objects to any type of stream that you want, including a MemoryStream.
This question already has answers here:
SMTP Send is locking up my files - c#
(5 answers)
Closed 4 years ago.
Why, after this code executes, can I not manually delete the generated file? I get this error message:
The action can't be completed because the file is open in IIS Express Workers Process.
The code:
System.IO.File.AppendAllText("Filename.txt", "Some Text");
The application is a web application and running in IIS. My understanding was AppendAllText automatically closes the file handle.
I am not using this code to log. The purpose of the code is to create a CSV file that is then attached to an email. If I execute the code and email the file, the file is never sent. If I then restart IIS (to release the lock) and execute only the code to mail the file (no generation), it works.
The code to attach the file...
SmtpClient mailClient = new SmtpClient();
MailMessage msg = new MailMessage();
... Add From, Subject, Body, etc... here
msg.Attachments.Add(new Attachment(filename));
mailClient.Send(msg);
No exceptions are thrown, nothing is written to the log file indicating problems. The email is simply not sent and if I go to the generated file and attempt to delete it, I cannot as IIS has it locked. I believe the lock is why the email is never sent.
File.AppendAllText close the file itself after writing it. But you are facing the issue probably because the file is shared across multiple session in your web application. Use lock to prevent concurrent access.
You should handle the code you provided in a different way for web application.
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
System.IO.StreamWriter writer = new System.IO.StreamWriter(ms);
writer.Write("Some Text");
writer.Flush();
writer.Dispose();
ms.Position = 0;
System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Text.Plain);
System.Net.Mail.Attachment attach = new System.Net.Mail.Attachment(ms, ct);
attach.ContentDisposition.FileName = "Filename.txt";
SmtpClient mailClient = new SmtpClient();
MailMessage msg = new MailMessage();
msg.Attachments.Add(attach);
mailClient.Send(msg);
}
In the above example attachment is created in-memory insteed of storing in file-system.
I have a stream of byte[] which I write to a temporary file and then I send it to another method which attaches it to an email. I then want to delete the temporary folder. The code snippet I am using is as follows.
byte[] blackboxBytes = Convert.FromBase64String(backBoxBase64);
uniqueTempFolder = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));
zipFilePath = Path.Combine(uniqueTempFolder.FullName, "BlackBox.zip");
File.WriteAllBytes(zipFilePath, blackboxBytes);
sendEmail (deviceFQN, message, ZipFilePath);
s_Log.Warn("Email sent");
//recursive delete of the whole folder
uniqueTempFolder.Delete(true);
s_Log.Warn("In BB zipFilePath after delete");
When I run, the email is getting sent and I get the log "Email sent". but after that I get an error message and the temporary directory is not deleted.
IOError: [Errno 32] The process cannot access the file 'BlackBox.zip' because it is being used by another process.
I am deleting the directory only after the email method finishes processing. So I don't know why the folder is still being processed. Any pointers will be greatly appreciated.
Also I have no access to the sendEmail method, so how can I solve this....can I probably put my code in a synchronous block or something
The retun type of sendEmail is void...I cannot modify sendEmail , but I see it has a lock when it sends the email(dispatchEmailTask).......
lock (m_QueueLock) { m_DispatchEmailTasks.Enqueue (dispatchEmailTask);}
so in my code, how can I wait for it to complete before I delete the file?
There was no way to do this because the sendEmail sent the emails to a queue and there was no handler returned to let me know the action was competed. So in the end I created a cleanup job that ran daily to clean up the files.
This is because you are working with Streams which are normally In-Memory and normally employ locks for purposes of single calls. This means you can only use a stream once and have to re-create it again in case you want to perform additional operations on the file or directory.
The problem in your code is when you are writing the zip file to the directory, the stream does not get release. A Using statement coupled up together with a StreamWriter all under System.IO will help you in this as shown in the code below.
byte[] blackboxBytes = Convert.FromBase64String(backBoxBase64);
var uniqueTempFolder =
Directory.CreateDirectory(Path.Combine(Path.GetTempPath(),
Path.GetRandomFileName()));
var zipFilePath = Path.Combine(uniqueTempFolder.FullName,
"BlackBox.zip");
using (StreamWriter writer = new StreamWriter(zipFilePath))
{
writer.Write(blackboxBytes);
}
sendEmail(deviceFQN, message, ZipFilePath);
s_Log.Warn("Email sent");
//recursive delete of the whole folder
uniqueTempFolder.Delete(true);
s_Log.Warn("In BB zipFilePath after delete");
Currently I just created a program which can send the .xls file, I used google smtp server so I can already sent email with that server in my program. And inside my program, based on my date, I can create .xls file with today date and time. What I want to know is this file will be used to be attachment for the email. How I can do it?
Currently my file name is DateTime.Now.ToString("yyyyMMdd_hhss") + ".xls" so I can create based on today date and time. How I can retrieve the file name to be used as email attachment?
I am assuming you are using the .NET's default Emal api found in the System.Net.Mail namespace.
You can add the file as an attachment to the System.Net.Mail.MailMessage object.
The System.Net.Mail.Attachment class accepts a constructor that can take the stream which you could have used to create the xls file. So, if you create the excel file on the fly, you'll probably already have a reference to the stream where it is written. Then you need to use the code below:
using (Stream myXlsFileStream = new MemoryStream())
{
// assumig you populate the stream like this...
WriteXlsToStream(myXlsFileStream);
myXlsFileStream.Flush();
MailMessage message = new MailMessage();
// configure mail message contents ...
using (Attachment xlsAttachment = new Attachment(
myXlsFileStream,
"FileNameToAppearInEmail.xls",
"application/xls"))
{
message.Attachments.Add(xlsAttachment);
// send the message
}
}
Please, note that the stream must not be closed, and all data should have been written to it. You may need to call myXlsFileStream.Flush() (as in above code) before adding the attachment, in order to ensure that the file is entirely written.
I am having issue with deleting file created just to send an email with attachment and then view it in browser. now i need to delete this file as this is created to just send email. how can i do this.
here is what i have got so far.
public void SendEmail()
{
EmailClient.Send(mailMessage);
//View PDF Certificate in Browser
ViewPDFinBrowser((string)fileObject);
DeleteGeneratedTempCertificateFile((string)fileObject));
}
public void ViewPDFinBrowser(string filePath)
{
PdfReader reader = new PdfReader(filePath);
MemoryStream ms = new MemoryStream();
PdfStamper stamper = new PdfStamper(reader, ms);
stamper.ViewerPreferences = PdfWriter.PageLayoutSinglePage | PdfWriter.PageModeUseThumbs;
stamper.Close();
Response.Clear();
Response.ContentType = "application/pdf";
Response.OutputStream.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
Response.OutputStream.Close();
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
public static void DeleteGeneratedTempCertificateFile(Object fileObject)
{
string filePath = (string)fileObject;
if (File.Exists(filePath))
{
File.Delete(filePath);
}
}
So here are the steps i need when i call SendEmail()
1) Sends an email with the attachment --> Temp file created
2) view the temp file in the browser
3) delete the temp file
I can understand that as long as file is in response object, i can not do anything with it because i get the error message ("File used by another process). If i close the response stream then file will be deleted but then i cant view it in browser.
i was thinking if i can manage to somehow open the file to view in browser in new window on button click, i will be able to delete the file.
OR
i am thinking i can delete the file after 10 min. as user wont be on site viewing the PDF for more then 1-2 mins.
please advice me one of the solution with example code.
appreciate your time and help.
As others have said, it's better to use the MemoryStream as-is without writing temporary files to the disk. Sometimes implementations of 3rd party components just won't allow this and in such cases after writing the binary contents of the PDF file, be sure to call close (and/or possibly dispose, always check MSDN or 3rd party API docs what the .Close() actually does) to all streams that are no longer needed. In your case close ms and reader after completing the http request.
In most cases, consider implementing the using pattern. See http://msdn.microsoft.com/en-us/library/aa664736.aspx for more details. However remember that there are caveats to this approach too, for example in WCF clients which can cause exceptions within (and thus not actually disposing all contents inside the using clause).
Also, keep in mind any concurrency issues. Keep the temporary file name random enough and consider situations where the file already exists on the local disk (i.e. fail the operation and do not send out binary to the request which the requester is not supposed to see etc).