Попытка использовать PdfStamper и MemoryStream для добавления данных в существующий PDF-файл, а затем по электронной почте

Вот мой кусок кода. Он компилируется нормально, и когда я запускаю событие, я получаю электронное письмо, но затем я получаю эту ошибку. ОШИБКА вложения электронной почты в Adobe при открытии (Acrobat не может открыть «Att00002.pdf», потому что это либо не поддерживаемый тип файла, либо потому что файл был поврежден (например, он был отправлен как вложение электронной почты и не был правильно декодирован).

string agentName = "My Name";            
MemoryStream _output = new MemoryStream();
            PdfReader reader = new PdfReader("/pdf/Agent/Specialist_Certificate.pdf");
            using (PdfStamper stamper = new PdfStamper(reader, _output))
            {
                AcroFields fields = stamper.AcroFields;
            // set form fields
            fields.SetField("FIELD_AGENT_NAME", agentName);
            fields.SetField("FIELD_DATE", AvalonDate);

            // flatten form fields and close document
            stamper.FormFlattening = true;
            SendEmail(_output);
            DownloadAsPDF(_output);
            stamper.Close();
        }

private void SendEmail(MemoryStream ms)
{
    Attachment attach = new Attachment(ms, new System.Net.Mime.ContentType("application/pdf"));
    EmailHelper.SendEMail("[email protected]", "[email protected]", null, "", "Avalon Cert", "Hope this works", EmailHelper.EmailFormat.Html,attach);
}

ОТРЕДАКТИРОВАНО ****************************************

        using (MemoryStream _output = new MemoryStream())
        {
            using (PdfStamper stamper = new PdfStamper(reader, _output))
            {
                AcroFields fields = stamper.AcroFields;
                // set form fields
                fields.SetField("FIELD_AGENT_NAME", agentName);
                fields.SetField("FIELD_DATE", AvalonDate);

                // flatten form fields and close document
                stamper.FormFlattening = true;
            }
            SendEmail(_output);
        }

person user1566783    schedule 13.10.2015    source источник
comment
Попробуйте закрыть PdfStamper перед вызовом SendEmail. Вы, вероятно, присоединяете только часть байтового потока PDF, потому что еще не все сброшено для вывода.   -  person rhens    schedule 13.10.2015
comment
Когда я меняю его на Stamper.Close(); ОтправитьЭлектронную почту (_output); Я получаю эту ошибку при отправке электронной почты System.ObjectDisposedException: невозможно получить доступ к закрытому потоку   -  person user1566783    schedule 13.10.2015


Ответы (1)


Вы звоните stamper.close() внутри using (PdfStamper stamper = new PdfStamper(reader, _output)). using автоматически закроет штамп при выходе из него в дополнение к вашему ручному закрытию (), поэтому технически штамп пытается закрыться дважды. Из-за этого он также пытается закрыть MemoryStream более одного раза. Вот откуда исходит исключение.

Я бы использовал метод, описанный в ответе здесь, для ваших MemoryStream и PdfStamper (измененный и взятый из: c-itextsharp">Настройка PdfStamper для работы с MemoryStreams (c#, itextsharp)):

using (MemoryStream _output = new MemoryStream()) {
  using (PdfStamper stamper = new PdfStamper(reader, _output)) {
// do stuff      
  }    
}
person Rick Burns    schedule 13.10.2015
comment
Я согласен с этим, но я бы пошел еще дальше и выступил за полный шаблон kuujinbo, который я также всегда использую, и он должен возвращать массив байтов вместо потока. Если вам понадобится поток позже, просто оберните массив байтов новым. Да, там есть пара дополнительных циклов ЦП, но на самом деле не так много. Проблема с передачей потоков — это именно то, на что указывает UncleRico, и это то, что другие люди могут возиться с ними, закрывая их, устанавливая позиции или что-то еще. - person Chris Haas; 13.10.2015
comment
Итак, куда бы я поместил свой SendEmail(_output); тогда кусок? Если я поставлю его за пределы использования PdfStamper, я получу сообщение об ошибке, говорящее, что поток уже закрыт. - person user1566783; 14.10.2015
comment
@user1566783 user1566783 Я бы посоветовал сначала создать ваш штампованный PDF-файл и закрыть его, используя приведенный выше код в качестве шаблона. Затем в качестве вторичного процесса прикрепите его к своему электронному письму, используя метод SendEmail(). Помните, что в одном случае ваш MemoryStream используется для записи информации, ваш процесс прикрепления использует тот же самый MemoryStream для чтения из него (не очень хорошая вещь). - person Rick Burns; 14.10.2015
comment
Так ты говоришь что-то вроде этого? Поскольку использование закрывает штамп, я отправляю электронное письмо, а затем использование потока памяти также закрывается. Или, как Крис сказал выше, я должен попытаться поместить его в массив байтов, а затем отправить его во вложении таким образом? - person user1566783; 14.10.2015
comment
@user1566783. Мне нравится подход Криса, однако я успешно использовал потоки памяти, как указано в моем ответе. Так что любой будет работать. Я бы предпочел использовать два потока памяти: один для записи нового PDF-файла, а затем другой для чтения результирующего объединенного PDF-файла для использования в вашей электронной почте. - person Rick Burns; 14.10.2015
comment
Хорошо, я смог поднять его и работать. Спасибо ребята за помощь! - person user1566783; 14.10.2015