iTextSharp - Invio di PDF in memoria in un allegato e-mail


100

Ho posto un paio di domande qui, ma continuo ad avere problemi. Apprezzerei se tu potessi dirmi cosa sto sbagliando nel mio codice. Eseguo il codice sopra da una pagina ASP.Net e ottengo "Impossibile accedere a un flusso chiuso".

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

Grazie!!!

MODIFICARE:

Giusto per aiutare chi cerca la risposta a questa domanda, il codice per inviare un file pdf allegato ad una mail senza dover creare fisicamente il file è di seguito (grazie a Ichiban e 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
Grazie per aver posto questa domanda, è esattamente quello che stavo cercando.
Hardwareguy

1
grazie per la linea del position=0. mi ha salvato!
Yisroel M. Olewski

2
Esattamente quello che mi serve funziona perfettamente, grazie mille! Ero bloccato sulla chiusura del documento ma non dello stream: writer.CloseStream = false; chiarito tutto per me.
Baxter

2
@Semil quando metti una taglia su una vecchia domanda con una risposta accettata, dovresti davvero indicare in qualche modo cosa ti manca nella risposta.
mkl

writer.CloseStream = false; salvato anche me, mancava questo in un metodo che utilizza iTextSharp per trasformare HTML in PDF. Prima, il passaggio del flusso di memoria alla funzione di posta non era riuscito a causa della chiusura del flusso. Grazie.
Alec Menconi

Risposte:


81

Hai provato:

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

Se la mia memoria mi serve correttamente, questo ha risolto un problema simile in un progetto precedente.

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


1
Il metodo set_CloseStream è disponibile solo nella versione Java. Questo è iTextSharp (.NET)
ichiban

Mi dispiace, ancora una volta non uso iTextSharp (.NET) da un po ', anche se la versione che ho usato aveva sicuramente set_CloseStream.
brianng

1
Modificato in writer.CloseStream e incluso collegamento correlato.
brianng

1
Brianng, apprezzo davvero il tuo aiuto. Mi rendo conto che tu e Ichiban avete tenuto la mia mano attraverso di essa. Grazie!
Gus Cavalcanti

Se manteniamo in vita lo scrittore, quando dovremmo farlo writer.Flush()allora?
Blaise

18

Ho provato il codice pubblicato da brianng e ha funzionato. Basta cambiare la parte superiore del codice in questo:

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
Grazie per aver dedicato del tempo alla verifica!
brianng

1
Ciao Ichiban, compila e invia effettivamente l'e-mail con l'allegato, ma il documento pdf allegato presenta 0kb. Hai effettivamente aperto il pdf inviato da un'email?
Gus Cavalcanti

2
@Gustavo, il file si apre correttamente nel visualizzatore di Acrobat. Si tratta di circa 900 byte. Assicurati di mantenere la riga: memoryStream.Position = 0; subito dopo doc.Close (). Ho dimenticato di dirlo. (vedi aggiornamento sopra)
ichiban

1
SÌ! Grazie mille ragazzi. Finalmente ha funzionato. Poiché la risposta di Ichiban era basata su quella di brianng, penso sia giusto contrassegnare la risposta di brianng come corretta.
Gus Cavalcanti

3

Puoi scaricare il documento o il flusso di memoria e poi chiuderlo dopo averlo allegato?


Ciao James. L'ho fatto e il risultato non è cambiato: ricevo ancora l'errore "Impossibile accedere a un flusso chiuso". :( Altre idee?
Gus Cavalcanti

3

Probabilmente la chiamata a doc.Close () Elimina il flusso sottostante. Prova a rimuovere doc.Close () e invece di quella riga imposta memoryStream.Position = 0;

In alternativa puoi usare un file temporaneo:

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, ho fatto quello che mi hai suggerito e il file pdf viene inviato, ma è lungo solo 15 byte. Quando provo ad aprirlo, è danneggiato. Sento di essere quasi arrivato con il tuo suggerimento. Altre idee? Grazie!
Gus Cavalcanti

Quindi prova memoryStream.Flush (); prima di impostare la posizione
huseyint

Stessa cosa. Il file viene inviato quasi vuoto e danneggiato. :(
Gus Cavalcanti

Hai provato "Creazione di un file temporaneo"?
huseyint

Ci sto lavorando proprio ora e ti faccio sapere a breve. Grazie!
Gus Cavalcanti

1

Ho avuto lo stesso problema e ho usato questo post per risolverlo, nel codice scritto da 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"));

Penso invece di scrivere

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

Basta creare un nuovo flusso

MemoryStream m = new MemoryStream(memoryStream);

e poi chiama

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

Entrambi funzionano ma penso che sia meglio creare il nuovo flusso


Perché è meglio creare un nuovo flusso?
Andy

Non è. È uno spreco di memoria e tempo di CPU perché i byte devono essere copiati dall'uno all'altro.
Serguei Fedorov

Non ricordo perché ho detto che è meglio. Penso che potrei voler dire che è più chiaro. Scusa, ho visto questo. È passato molto tempo :)
Zein Sleiman
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.