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("[email protected]", "[email protected]")
{
    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("[email protected]", "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("[email protected]", "[email protected]")
{
    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("[email protected]", "password")

};

smtp.Send(mm);
Gus Cavalcanti
quelle
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

brianng
quelle
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*/
Ichiban
quelle
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?

James Conigliaro
quelle
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("[email protected]", "[email protected]")
    {
        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("[email protected]", "my_password")
    };

    smtp.Send(mm);
}
finally
{
    File.Delete(tempFilePath);
}
huseyint
quelle
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

Zein Sleiman
quelle
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