iTextSharp - Gửi pdf trong bộ nhớ trong tệp đính kèm email


100

Tôi đã hỏi một số câu hỏi ở đây nhưng vẫn gặp sự cố. Tôi đánh giá cao nếu bạn có thể cho tôi biết tôi đang làm gì sai trong mã của mình. Tôi chạy mã trên từ trang ASP.Net và nhận được "Không thể truy cập luồng đã đóng".

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

Cảm ơn!!!

BIÊN TẬP:

Chỉ để giúp ai đó đang tìm kiếm câu trả lời cho câu hỏi này, mã để gửi tệp pdf được đính kèm vào email mà không cần phải tạo tệp thực tế ở bên dưới (cảm ơn Ichiban và Brianng):

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
Cảm ơn bạn đã đặt câu hỏi này, đó chính xác là những gì tôi đang tìm kiếm.
Phần cứng mua

1
cảm ơn cho dòng của position=0. cứu tôi!
Yisroel M. Olewski

2
Chính xác những gì tôi cần hoạt động hoàn hảo, cảm ơn bạn rất nhiều! Tôi gặp khó khăn khi đóng tài liệu nhưng không đóng được luồng: writer.CloseStream = false; xóa nó cho tôi.
Baxter

2
@Semil khi đặt tiền thưởng cho một câu hỏi cũ với câu trả lời được chấp nhận, bạn thực sự nên chỉ ra bằng cách nào đó những gì bạn bỏ lỡ trong câu trả lời.
mkl

nhà văn.CloseStream = false; cũng đã cứu tôi, thiếu điều đó trong một phương pháp sử dụng iTextSharp để chuyển HTML sang PDF. Trước đây, việc chuyển luồng bộ nhớ đến chức năng thư của tôi không thành công do luồng bị đóng. Cảm ơn.
Alec Menconi

Câu trả lời:


81

Bạn đã thử chưa:

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"));

Nếu bộ nhớ của tôi phục vụ tôi một cách chính xác, điều này đã giải quyết một vấn đề tương tự trong một dự án trước đó.

Xem http://forums.asp.net/t/1093198.aspx


1
Phương thức set_CloseStream chỉ có sẵn trong phiên bản Java. Đây là iTextSharp (.NET)
ichiban

Xin lỗi, một lần nữa, tôi đã không sử dụng iTextSharp (.NET) trong một thời gian, mặc dù phiên bản tôi sử dụng chắc chắn có set_CloseStream.
brianng 28-07-09

1
Đã thay đổi thành nhà văn.CloseStream và bao gồm liên kết liên quan.
brianng 28-07-09

1
Brianng, tôi thực sự đánh giá cao sự giúp đỡ của bạn. Tôi nhận ra bạn và Ichiban đã nắm tay tôi qua nó. Cảm ơn!
Gus Cavalcanti

Nếu chúng ta giữ cho nhà văn sống sót, chúng ta giả sử đến writer.Flush()lúc đó?
Blaise

18

Tôi đã thử mã được đăng bởi brianng và nó hoạt động. Chỉ cần thay đổi đầu mã thành sau:

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
Cảm ơn vì đã dành thời gian để xác minh!
brianng 28-07-09

1
Xin chào Ichiban, Nó biên dịch và nó thực sự gửi email cùng với tệp đính kèm, nhưng tài liệu pdf đính kèm lại có 0kb. Bạn có thực sự mở bản pdf mà một email đã được gửi không?
Gus Cavalcanti

2
@Gustavo, tệp mở chính xác trong trình xem Acrobat. Nó là khoảng 900 Byte. Đảm bảo rằng bạn giữ dòng: memoryStream.Position = 0; ngay sau doc.Close (). Tôi quên đề cập đến. (xem bản cập nhật ở trên)
ichiban

1
ĐÚNG! Cảm ơn bạn rất nhiều chàng trai. Cuối cùng nó đã hoạt động. Vì câu trả lời của Ichiban dựa trên câu trả lời của brianng, tôi nghĩ rằng thật công bằng khi đánh dấu câu trả lời của brianng là đúng.
Gus Cavalcanti

3

Bạn có thể xả tài liệu hoặc luồng bộ nhớ rồi đóng sau khi đính kèm không?


Chào James. Tôi đã làm điều này và kết quả không thay đổi - tôi vẫn gặp lỗi "Không thể truy cập luồng đã đóng". :( ý tưởng khác?
Gus Cavalcanti

3

Có thể đang gọi doc.Close () Xử lý luồng bên dưới. Hãy thử loại bỏ doc.Close () và thay vào đó là dòng đó, đặt memoryStream.Position = 0;

Ngoài ra, bạn có thể sử dụng tệp tạm thời:

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, tôi đã làm theo những gì bạn đề xuất và tệp pdf được gửi đi, nhưng nó chỉ dài 15 byte. Khi tôi thử mở nó, nó bị hỏng. Tôi cảm thấy tôi gần như ở đó với đề nghị của bạn. Bất kỳ ý tưởng khác? Cảm ơn!
Gus Cavalcanti

Sau đó, hãy thử memoryStream.Flush (); trước khi thiết lập Chức vụ
huseyint

Điều tương tự. Tệp được gửi gần như trống rỗng và bị hỏng. :(
Gus Cavalcanti

Bạn đã thử "Tạo tệp tạm thời" chưa?
huseyint 28-07-09

Tôi đang làm việc với nó ngay bây giờ và cho bạn biết trong thời gian ngắn. Cảm ơn!
Gus Cavalcanti

1

Tôi đã gặp vấn đề tương tự và tôi đã sử dụng bài đăng này để giải quyết nó. Trong đoạn mã được viết bởi 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"));

Tôi nghĩ thay vì viết

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

Chỉ cần tạo một Luồng mới

MemoryStream m = new MemoryStream(memoryStream);

và sau đó gọi

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

Cả hai đều hoạt động nhưng tôi nghĩ tốt hơn nên tạo luồng mới


Tại sao tạo luồng mới tốt hơn?
Andy

Nó không thể. Thật lãng phí bộ nhớ và thời gian của CPU vì các byte phải được sao chép từ cái này sang cái kia.
Serguei Fedorov

Không nhớ tại sao tôi nói nó là tốt hơn. Tôi nghĩ tôi có thể có nghĩa là nó rõ ràng hơn. Xin lỗi chỉ nhìn thấy điều này. Đã lâu không gặp :)
Zein Sleiman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.