iTextSharp - In-Memory-PDF in einem E-Mail-Anhang senden


100

Ich habe hier ein paar Fragen gestellt, habe aber immer noch Probleme. Ich würde mich freuen, wenn Sie mir sagen könnten, was ich in meinem Code falsch mache. Ich führe den obigen Code von einer ASP.Net-Seite aus und erhalte die Meldung "Kann nicht auf einen geschlossenen Stream zugreifen".

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

Vielen Dank!!!

BEARBEITEN:

Um jemandem bei der Suche nach der Antwort auf diese Frage zu helfen, finden Sie unten den Code zum Senden einer an eine E-Mail angehängten PDF-Datei, ohne die Datei physisch erstellen zu müssen (danke an Ichiban und 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
Vielen Dank, dass Sie diese Frage gestellt haben. Es ist genau das, wonach ich gesucht habe.
Hardwareguy

1
danke für die linie der position=0. rettete mich!
Yisroel M. Olewski

2
Genau das, was ich brauche, funktioniert perfekt. Vielen Dank! Ich war beim Schließen des Dokuments festgefahren, aber nicht des Streams: writer.CloseStream = false; hat es für mich geklärt.
Baxter

2
@Semil Wenn Sie eine alte Frage mit einer akzeptierten Antwort belohnen, sollten Sie wirklich irgendwie angeben, was Sie in der Antwort vermissen.
mkl

writer.CloseStream = false; rettete mich auch, fehlte das in einer Methode, die iTextSharp verwendet, um HTML in PDF umzuwandeln. Zuvor war das Übergeben des Memorystreams an meine E-Mail-Funktion fehlgeschlagen, da der Stream geschlossen wurde. Vielen Dank.
Alec Menconi

Antworten:


81

Hast du es versucht:

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

Wenn mein Gedächtnis mir richtig dient, hat dies ein ähnliches Problem in einem früheren Projekt gelöst.

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


1
Die Methode set_CloseStream ist nur in der Java-Version verfügbar. Dies ist iTextSharp (.NET)
ichiban

Entschuldigung, ich habe iTextSharp (.NET) schon eine Weile nicht mehr verwendet, obwohl die Version, die ich verwendet habe, definitiv set_CloseStream hatte.
Brianng

1
Geändert zu writer.CloseStream und zugehöriger Link.
Brianng

1
Brianng, ich schätze deine Hilfe sehr. Mir ist klar, dass du und Ichiban meine Hand irgendwie durchgehalten haben. Vielen Dank!
Gus Cavalcanti

Wenn wir den Schriftsteller am Leben erhalten, wann sollen wir es writer.Flush()dann tun ?
Blaise

18

Ich habe den Code von brianng ausprobiert und es hat funktioniert. Ändern Sie einfach den oberen Rand des Codes wie folgt:

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
Vielen Dank, dass Sie sich die Zeit genommen haben, dies zu überprüfen!
Brianng

1
Hallo Ichiban, es wird kompiliert und es sendet tatsächlich die E-Mail mit dem Anhang, aber das angehängte PDF-Dokument enthält 0 KB. Haben Sie das PDF tatsächlich geöffnet und eine E-Mail gesendet?
Gus Cavalcanti

2
@Gustavo, die Datei wird im Acrobat Viewer korrekt geöffnet. Es sind ungefähr 900 Bytes. Stellen Sie sicher, dass Sie die Zeile beibehalten: memoryStream.Position = 0; direkt nach doc.Close (). Das habe ich vergessen zu erwähnen. (siehe Update oben)
Ichiban

1
JA! Vielen Dank Jungs. Es hat endlich funktioniert. Da Ichibans Antwort auf Brianngs basiert, halte ich es für fair, Brianngs Antwort als richtig zu markieren.
Gus Cavalcanti

3

Können Sie spülen Sie das Dokument oder Speicherstrom und schließen Sie es dann , nachdem Sie es anhängen?


Hallo James. Ich habe dies getan und das Ergebnis hat sich nicht geändert. Ich erhalte immer noch den Fehler "Auf einen geschlossenen Stream kann nicht zugegriffen werden". :( Andere Ideen?
Gus Cavalcanti

3

Wahrscheinlich wird doc.Close () aufgerufen. Entspricht dem zugrunde liegenden Stream. Versuchen Sie, doc.Close () zu entfernen, und setzen Sie anstelle dieser Zeile memoryStream.Position = 0;

Alternativ können Sie eine temporäre Datei verwenden:

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, ich habe getan, was Sie vorgeschlagen haben, und die PDF-Datei wird gesendet, aber sie ist nur 15 Byte lang. Wenn ich versuche, es zu öffnen, ist es beschädigt. Ich fühle mich mit Ihrem Vorschlag fast da. Irgendwelche anderen Ideen? Vielen Dank!
Gus Cavalcanti

Versuchen Sie dann memoryStream.Flush (); vor dem Einstellen der Position
huseyint

Gleiche Sache. Die Datei wird fast leer und beschädigt gesendet. :(
Gus Cavalcanti

Haben Sie "Erstellen einer temporären Datei" ausprobiert?
Huseyint

Ich arbeite gerade daran und lasse es Sie in Kürze wissen. Vielen Dank!
Gus Cavalcanti

1

Ich hatte das gleiche Problem und habe diesen Beitrag verwendet, um es zu lösen. In dem von brianng geschriebenen Code

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

Ich denke anstatt zu schreiben

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

Erstellen Sie einfach einen neuen Stream

MemoryStream m = new MemoryStream(memoryStream);

und dann anrufen

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

Beide funktionieren, aber ich denke, es ist besser, den neuen Stream zu erstellen


Warum ist es besser, einen neuen Stream zu erstellen?
Andy

Es ist nicht. Es ist eine Verschwendung von Speicher und CPU-Zeit, da die Bytes von einem zum anderen kopiert werden müssen.
Serguei Fedorov

Ich erinnere mich nicht, warum ich gesagt habe, dass es besser ist. Ich denke, ich könnte gemeint haben, dass es klarer ist. Entschuldigung, habe das gerade gesehen. Schon lange :)
Zein Sleiman
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.