Распространение выходных данных RDLC в виде вложения электронной почты

StackOverflow https://stackoverflow.com/questions/3849276

  •  27-09-2019
  •  | 
  •  

Вопрос

Наше приложение winforms уже давно допускает опцию "печать", которая в основном использует RDLC.

Клиент попросил нас добавить функцию, позволяющую пользователям отправлять "распечатанные" выходные данные по электронной почте.

Теперь мы знаем, что файл EMF создается (в папке TEMP) как своего рода скрытый побочный продукт нашего текущего процесса печати.

Нам кажется, что мы можем просто взять этот EMF-файл и прикрепить его к новому электронному письму, и работа будет выполнена.

  1. Это лучший вариант?
  2. Можем ли мы полагаться на то, что файл EMF будет открыт на любом компьютере с Windows?
  3. Как мы идентифицируем файл EMF?...просто кажется, что его назвали %TEMP%\DiaryGrid_1.emf в настоящее время.Итак, DiaryGrid - это имя нашего файла RDLC, но _1 добавляется где-то по пути.
Это было полезно?

Решение

Я делал это раньше.Я сделал это, экспортировав программный отчет в формате PDF в определенное место, затем мы отправили PDF-файл по электронной почте и удалили его.Я постараюсь найти код для вас (сейчас его нет дома).

ОТРЕДАКТИРОВАННЫЙ:

Извини за позднее.Теперь я дома и дам вам несколько блоков кода, которые, я думаю, помогут вам выполнить вашу задачу.Я включу некоторые комментарии к коду, чтобы вы могли понять некоторые особенности моего проекта.Этот код протестирован и хорошо работает в моих клиентах, но я уверен, что его можно улучшить.Пожалуйста, дайте мне знать, если вы можете улучшить этот код ;)

Прежде всего, мы экспортируем отчет в формат pdf.

private string ExportReportToPDF(string reportName)
{
   Warning[] warnings;
   string[] streamids;
   string mimeType;
   string encoding;
   string filenameExtension;
   byte[] bytes = ReportViewer1.LocalReport.Render(
      "PDF", null, out mimeType, out encoding, out filenameExtension,
       out streamids, out warnings);

   string filename = Path.Combine(Path.GetTempPath(), reportName);
   using (var fs = new FileStream(filename, FileMode.Create))
   {
      fs.Write(bytes, 0, bytes.Length);
      fs.Close();
   }

   return filename;
}

Теперь нам нужен класс, который управляет почтовой системой.Каждая почтовая система имеет свои собственные характеристики, поэтому, возможно, вам потребуется изменить этот класс.Поведение класса простое.Вам нужно только заполнить свойства и вызвать метод Send.В моем случае Windows не позволяет мне удалять PDF-файл после его отправки (Windows сообщает, что файл используется), поэтому я программирую удаление файла при следующей перезагрузке.Взгляните на метод удаления.Пожалуйста, обратите внимание, что в методе send используется класс cutom с именем MailConfig.Это небольшой класс, который содержит несколько конфигурационных строк, таких как Host, Имя пользователя и пароль.Письмо будет отправлено с использованием этих параметров.

public class Mail
{
   public string Title { get; set; }
   public string Text { get; set; }
   public string From { get; set; }
   public bool RequireAutentication { get; set; }
   public bool DeleteFilesAfterSend { get; set; }

   public List<string> To { get; set; }
   public List<string> Cc { get; set; }
   public List<string> Bcc { get; set; }
   public List<string> AttachmentFiles { get; set; }

   #region appi declarations

   internal enum MoveFileFlags
   {
      MOVEFILE_REPLACE_EXISTING = 1,
      MOVEFILE_COPY_ALLOWED = 2,
      MOVEFILE_DELAY_UNTIL_REBOOT = 4,
      MOVEFILE_WRITE_THROUGH = 8
   }

   [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
   static extern bool MoveFileEx(string lpExistingFileName,
                                 string lpNewFileName,
                                 MoveFileFlags dwFlags);

   #endregion

   public Mail()
   {
      To = new List<string>();
      Cc = new List<string>();
      Bcc = new List<string>();
      AttachmentFiles = new List<string>();
      From = MailConfig.Username;
   }

   public void Send()
   {
      var client = new SmtpClient
      {
         Host = MailConfig.Host,
         EnableSsl = false,
      };

      if (RequireAutentication)
      {
         var credentials = new NetworkCredential(MailConfig.Username, 
                                                 MailConfig.Password);
         client.Credentials = credentials;
      }

      var message = new MailMessage
      {
         Sender = new MailAddress(From, From),
         From = new MailAddress(From, From)
      };

      AddDestinataryToList(To, message.To);
      AddDestinataryToList(Cc, message.CC);
      AddDestinataryToList(Bcc, message.Bcc);

      message.Subject = Title;
      message.Body = Text;
      message.IsBodyHtml = false;
      message.Priority = MailPriority.High;

      var attachments = AttachmentFiles.Select(file => new Attachment(file));
      foreach (var attachment in attachments)
         message.Attachments.Add(attachment);

      client.Send(message);

      if (DeleteFilesAfterSend)
         AttachmentFiles.ForEach(DeleteFile);
   }

   private void AddDestinataryToList(IEnumerable<string> from,
      ICollection<MailAddress> mailAddressCollection)
   {
      foreach (var destinatary in from)
         mailAddressCollection.Add(new MailAddress(destinatary, destinatary));
   }

   private void DeleteFile(string filepath)
   {
      // this should delete the file in the next reboot, not now.
      MoveFileEx(filepath, null, MoveFileFlags.MOVEFILE_DELAY_UNTIL_REBOOT);
   }
}

Теперь вы можете создать форму для запроса адресатов, добавить некоторую проверку и т.д., которая вернет вам экземпляр класса Mail...или вы можете просто "жестко закодировать" значения и заполнить класс.

Вот код, который я использую в кнопке для вызова этой формы, в моем примере она называется SendMailView.

private void BtnSendByMail_Click(object sender, EventArgs e)
{
   SendMailView sendMailView = new SendMailView();

   if (sendMailView.ShowDialog()== DialogResult.OK)
   {
      Mail mail = sendMailView.CurrentItem;
      mail.AttachmentFiles.Add(ExportReportToPDF("Invoice.pdf"));
      mail.DeleteFilesAfterSend = true;
      mail.RequireAutentication = true;
      mail.Send();
   }
   sendMailView.Dispose();
}

В этом примере senMailView.CurrentItem является экземпляром класса mail.Нам просто нужно позвонить в службу отправки сообщений, и работа будет выполнена.

Это самый большой ответ, который я когда-либо писал в SO...Я надеюсь, это поможет вам: D Если у вас возникнут какие-либо проблемы с его использованием, позвоните мне.Кстати, я не очень горжусь своим английским, так что простите меня, если в тексте есть какие-то ошибки.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top