3

I am trying to send an email with an attachment by accessing it directly after saving it in the database. To do so I am following this tutorial.

What works?

Storing the attachments in the database is correct as when I go to the details page I can see the image associated with the profile.

What doesn't?

Unfortunately there seems to be a problem with how retrieving files from database works as the attachments are damaged, e.g. image stored in database shows 153328 B, but when sent turns into 117B).

The solution that actually succeeds and sends an email (damaged email) is taken from this link, but when I try to send it using the commented out stream code, the code crashes on the indicated line:

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing); //this line
    }

this is the controller code i use to save and retrieve the attachments:

 public async Task<ActionResult> Create([Bind(Include = "ID,LastName,FirstMidName")] Person person, HttpPostedFileBase upload)
    {
        if (ModelState.IsValid)
        {
            if (upload != null && upload.ContentLength > 0)
            {
                var avatar = new File
                {
                    FileName = System.IO.Path.GetFileName(upload.FileName),
                    FileType = FileType.Avatar,
                    ContentType = upload.ContentType
                };
                using (var reader = new System.IO.BinaryReader(upload.InputStream))
                {
                    avatar.Content = reader.ReadBytes(upload.ContentLength);
                }
                person.Files = new List<File> { avatar };
            }
            db.People.Add(person);
            db.SaveChanges();
            //await SendEmail(person.ID);
            var message = new MailMessage();
            var file = db.Files.Find(person.ID);
            Attachment attachment;
            var stream = new MemoryStream();
            try
            {
                stream.Write(file.Content, 0, file.Content.Length - 1);
                attachment = new Attachment(stream, file.FileName);
            }
            catch
            {
                stream.Dispose();
                throw;
            }
            //When i use this bit of code, I receive an error "Cannot access a closed stream
            //using (var stream = new MemoryStream())
            //{
            //    stream.Write(file.Content, 0, file.Content.Length - 1);
            //    attachment = new Attachment(stream, file.FileName);

            //}
            var fileSize = file.Content.Length;
            message.Attachments.Add(attachment);
            message.To.Add(new MailAddress("recipient@gmail.com"));  // replace with valid value
            message.From = new MailAddress("sender@outlook.com");  // replace with valid value
            message.Subject = "Your email subject";
            message.BodyEncoding =  System.Text.Encoding.UTF8;
            message.Body = "<p>file size: </p>" + "<p>" + fileSize + "</p>";
            message.IsBodyHtml = true;
            message.BodyEncoding = System.Text.Encoding.UTF8;

            using (var smtp = new SmtpClient())
            {
                //when i try to send the mail asynchronously the view with the form just keeps showing "waiting for localhost"
                //await smtp.SendMailAsync(message);
                smtp.Send(message);
                return RedirectToAction("Index");
            }

        }

        return View(person);
    }

Additional Question Would it be a good idea to send the attachment inside of the save to database part?

EDIT I have just tried sending the attachment with the below line of code:

 message.Attachments.Add(new Attachment(upload.InputStream, Path.GetFileName(upload.FileName)));

added after:

 person.Files = new List<File> { avatar }; 

But still receive damaged attachment..

EDIT 2:
enter image description here
enter image description here
filesize

Community
  • 1
  • 1
f78xd23
  • 117
  • 2
  • 15

2 Answers2

3

I think this line

var file = db.Files.Find(person.ID)

should actually be (you were trying to get a file using a person id):

var file = db.Files.Find(avatar.ID)

but, in your case you don't need to retrieve it from the database. You already have the bytes there, so just wrap them in a MemoryStream, as you can't directly send the upload.InputStream without storing it in memory:

attachment = new Attachment(new MemoryStream(avatar.Content), file.FileName);
Cristi Pufu
  • 9,002
  • 3
  • 37
  • 43
  • Thanks alot! I have actually tried something similar in my original project few days ago, but I definetly wasn't using MemoryStream. I tried with Stream instead of MemoryStream i.e. new Stream(avatar.Content)... but it kept going underlined so I dismissed this idea. Additionally I thought to myself that adding the file to database then retrieving is a bit redundant. So I guess i was circling around the solution for ages. This way or another, thanks! – f78xd23 May 27 '16 at 23:31
0

Looking at this quickly, I'd look at the obvious.

var file = db.Files.Find(person.ID);

Look at what this is returning. It may well be that after this object is being used, depending on what object it is, may have been disposed of already.

The reason being is you're attempting to read from the file.Content.Length which may be the very cause to the problem because it doesn't have a value or whatever.

Step through the logic, line by line. Break it down from the most simple, and build it up slowly until you get to the cause. Also, think about abstracting the logic from the controller and implementing a service that deals with this action. Check out repository pattern, unit of work and dependency injection as a side note.

Ultimately, your issue, I think it's just the fact that you're not checking all the "what if it wasn't the way you expected" type errors, which in all is why you should most probably also have some tests in place. :P

Deconstruct, start from basics and build your way up. Doing this, I'm sure you will find the problem. :)

David Tansey
  • 5,813
  • 4
  • 35
  • 51
Heracles
  • 91
  • 2
  • I am debugging the application on every time I try to get it to work, each time correct file is shown that's why I am confused. This way or another thanks for mentioning repository pattern and the other two. I will look into them. – f78xd23 May 27 '16 at 22:24