iTextSharp - отправка PDF в памяти во вложении электронной почты

100

Я задал здесь пару вопросов, но проблемы все еще возникают. Буду признателен, если вы скажете мне, что я делаю неправильно в своем коде. Я запускаю приведенный выше код со страницы ASP.Net и получаю «Невозможно получить доступ к закрытому потоку».

var doc = new Document();

MemoryStream memoryStream = new MemoryStream();

PdfWriter.GetInstance(doc, memoryStream);
doc.Open();
doc.Add(new Paragraph("First Paragraph"));
doc.Add(new Paragraph("Second Paragraph"));

doc.Close(); //if I remove this line the email attachment is sent but with 0 bytes 

MailMessage mm = new MailMessage("username@gmail.com", "username@gmail.com")
{
    Subject = "subject",
    IsBodyHtml = true,
    Body = "body"
};

mm.Attachments.Add(new Attachment(memoryStream, "test.pdf"));
SmtpClient smtp = new SmtpClient
{
    Host = "smtp.gmail.com",
    Port = 587,
    EnableSsl = true,
    Credentials = new NetworkCredential("username@gmail.com", "my_password")
};

smtp.Send(mm); //the "Cannot Access a Closed Stream" error is thrown here

Спасибо!!!

РЕДАКТИРОВАТЬ:

Чтобы помочь кому-то, кто ищет ответ на этот вопрос, ниже приведен код для отправки файла в формате pdf, прикрепленного к электронному письму, без необходимости его физического создания (спасибо Ичибану и Бриангу):

var doc = new Document();
MemoryStream memoryStream = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream);

doc.Open();
doc.Add(new Paragraph("First Paragraph"));
doc.Add(new Paragraph("Second Paragraph"));

writer.CloseStream = false;
doc.Close();
memoryStream.Position = 0;

MailMessage mm = new MailMessage("username@gmail.com", "username@gmail.com")
{
    Subject = "subject",
    IsBodyHtml = true,
    Body = "body"
};

mm.Attachments.Add(new Attachment(memoryStream, "filename.pdf"));
SmtpClient smtp = new SmtpClient
{
    Host = "smtp.gmail.com",
    Port = 587,
    EnableSsl = true,
    Credentials = new NetworkCredential("username@gmail.com", "password")

};

smtp.Send(mm);
Гас Кавальканти
источник
3
Спасибо, что задали этот вопрос, это именно то, что я искал.
Hardwareguy,
1
спасибо за строку position=0. спас меня!
Исроэль М. Олевски
2
Именно то, что мне нужно, отлично работает, большое спасибо! Я застрял при закрытии документа, но не потока: writer.CloseStream = false; прояснил это для меня.
Baxter
2
@Semil, когда назначает награду за старый вопрос с принятым ответом, вы действительно должны каким-то образом указать, что вы упускаете в ответе.
mkl
писатель.CloseStream = false; спас меня, не хватало этого в методе, который использует iTextSharp для преобразования HTML в PDF. Раньше передача потока памяти моей почтовой функции не удалась из-за закрытия потока. Спасибо.
Алек Менкони, 02

Ответы:

81

Ты пробовала:

PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream);

// Build pdf code...

writer.CloseStream = false;
doc.Close();

// Build email

memoryStream.Position = 0;
mm.Attachments.Add(new Attachment(memoryStream, "test.pdf"));

Если мне не изменяет память, это решило аналогичную проблему в предыдущем проекте.

См. Http://forums.asp.net/t/1093198.aspx

Brianng
источник
1
Метод set_CloseStream доступен только в версии Java. Это iTextSharp (.NET)
ichiban
Извините, я снова давно не использовал iTextSharp (.NET), хотя в используемой мной версии определенно был set_CloseStream.
brianng
1
Изменен на writer.CloseStream и включает связанную ссылку.
brianng
1
Брианнг, я очень ценю вашу помощь. Я понимаю, что вы и Ичибан как бы держали меня за руку. Спасибо!
Gus Cavalcanti
Если мы сохраним писателя в живых, когда же writer.Flush()тогда?
Blaise
18

Я попробовал код, опубликованный brianng, и он сработал. Просто измените верхнюю часть кода на это:

var doc = new Document();
MemoryStream memoryStream = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream); //capture the object
doc.Open();
doc.Add(new Paragraph("First Paragraph"));
doc.Add(new Paragraph("Second Paragraph"));
writer.CloseStream = false; //set the closestream property
doc.close(); //close the document without closing the underlying stream
memoryStream.Position = 0;

/* remainder of your code stays the same*/
ичибан
источник
3
Спасибо, что нашли время проверить!
brianng
1
Привет, Ичибан, он компилируется и фактически отправляет электронное письмо с вложением, но в прикрепленном PDF-документе встречается 0 КБ. Вы действительно открыли PDF-файл, отправленный по электронной почте?
Gus Cavalcanti
2
@Gustavo, файл правильно открывается в программе просмотра Acrobat. Это около 900 байт. Убедитесь, что вы сохранили строку: memoryStream.Position = 0; сразу после doc.Close (). Я забыл об этом упомянуть. (см. обновление выше)
ichiban
1
ДА! Большое вам спасибо, ребята. Наконец-то это сработало. Поскольку ответ Ичибана был основан на ответе Брианнга, я думаю, что будет справедливо отметить ответ Брианга как правильный.
Gus Cavalcanti
3

Можете ли вы очистить документ или поток памяти, а затем закрыть его после прикрепления?

Джеймс Конильяро
источник
Привет, Джеймс. Я сделал это, и результат не изменился - я все еще получаю ошибку «Невозможно получить доступ к закрытому потоку». :( Другие идеи?
Гас Кавальканти
3

Вероятно, вызов doc.Close () удаляет базовый поток. Попробуйте удалить doc.Close () и вместо этой строки установите memoryStream.Position = 0;

В качестве альтернативы вы можете использовать временный файл:

var tempFilePath = Path.GetTempFileName();

try 
{           
    var doc = new Document();

    PdfWriter.GetInstance(doc, File.OpenWrite(tempFilePath));
    doc.Open();
    doc.Add(new Paragraph("First Paragraph"));
    doc.Add(new Paragraph("Second Paragraph"));

    doc.Close();

    MailMessage mm = new MailMessage("username@gmail.com", "username@gmail.com")
    {
        Subject = "subject",
        IsBodyHtml = true,
        Body = "body"
    };

    mm.Attachments.Add(new Attachment(tempFilePath, "test.pdf"));
    SmtpClient smtp = new SmtpClient
    {
        Host = "smtp.gmail.com",
        Port = 587,
        EnableSsl = true,
        Credentials = new NetworkCredential("username@gmail.com", "my_password")
    };

    smtp.Send(mm);
}
finally
{
    File.Delete(tempFilePath);
}
Huseyint
источник
huseyint, я сделал то, что вы предложили, и файл pdf отправлен, но его длина всего 15 байт. Когда я пытаюсь открыть его, он поврежден. Я чувствую, что почти согласился с вашим предложением. Есть другие идеи? Спасибо!
Gus Cavalcanti
Затем попробуйте memoryStream.Flush (); перед установкой Позиции
huseyint
То же самое. Файл отправляется почти пустым и поврежденным. :(
Gus Cavalcanti
Вы попробовали "Создание временного файла"?
huseyint
Я работаю над этим прямо сейчас и вскоре дам вам знать. Спасибо!
Gus Cavalcanti
1

У меня была такая же проблема, и я использовал этот пост, чтобы решить ее. В коде, написанном brianng

PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream);

// Build pdf code...

writer.CloseStream = false;
doc.Close();

// Build email

memoryStream.Position = 0;
mm.Attachments.Add(new Attachment(memoryStream, "test.pdf"));

Я думаю вместо того, чтобы писать

writer.CloseStream = false and memoryStream.Position = 0;

Просто создайте новый поток

MemoryStream m = new MemoryStream(memoryStream);

а потом позвони

mm.Attachments.Add(new Attachment(memoryStream, "test.pdf"));

Оба работают, но я думаю, что лучше создать новый поток

Зейн Слейман
источник
Почему лучше создать новый поток?
Энди
Это не. Это пустая трата памяти и процессорного времени, потому что байты нужно копировать из одного в другой.
Сергей Федоров
Не помню, почему я сказал, что лучше. Думаю, я имел в виду, что так яснее. Извините только что увидел это. Давно :)
Зейн Слейман