Distribuição de saída RDLC como um anexo de email
Pergunta
Nosso aplicativo WinForms há muito tempo permitiu uma opção "impressão" que basicamente usa o RDLC.
O cliente solicitou que adicionamos um recurso que permita que os usuários enviem a saída "impressa" por e -mail.
Agora, sabemos que um arquivo EMF é criado (na pasta Temp) como uma espécie de subproduto oculto do nosso processo de impressão atual.
Parece -nos que podemos simplesmente pegar esse arquivo EMF e anexá -lo a um novo email e o trabalho é feito.
- Esta é a melhor opção?
- Podemos confiar em um arquivo EMF ser aberto por qualquer máquina Windows?
- Como identificamos o arquivo EMF? ... apenas parece ser nomeado
%TEMP%\DiaryGrid_1.emf
atualmente. Ok, então o diarygrid é o nome do nosso arquivo RDLC, mas o _1 é adicionado em algum lugar ao longo do caminho.
Solução
Eu fiz isso antes. Fiz isso exportando programaticamente o relatório para um PDF para um local específico, e enviamos por e -mail o arquivo PDF e o excluímos. Vou tentar encontrar o código para você (não em casa agora)
EDITADO:
Desculpe pelo mais tarde. Agora estou em casa e darei a você alguns blocos de código que acho que lhe darão ajuda para reclamar sua tarefa. Incluirei alguns comentários para o código para que você possa entender algumas coisas específicas no meu projeto. Esse código é testado e está funcionando bem em meus clientes, mas tenho certeza de que pode ser melhorado. Por favor, deixe -me saber se você pode melhorar este código;)
Primeiro de tudo, exportaremos o relatório para o 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;
}
Agora, precisamos de uma classe que controla o sistema de correio. Todo sistema de email tem suas próprias características, então talvez você precise modificar esta classe. O comportamento da classe é simples. Você só precisa preencher as propriedades e ligar para o método de envio. No meu caso, o Windows não me permita excluir o arquivo PDF depois de enviar (o Windows diz que o arquivo está em uso), então eu programo o arquivo a ser excluído na próxima reinicialização. Dê uma olhada no método de exclusão. Observe que o método de envio use uma classe Cutom chamada MailConfig. Esta é uma classe pequena que possui algumas seqüências de configuração, como host, nome de usuário e senha. O correio será enviado usando esses parâmetros.
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);
}
}
Agora, você pode criar um formulário para solicitar os destinatários, adicionar alguma validação, etc., retornar a você uma instância da classe de email ... ou você pode simplesmente "codificar" os valores e preencher a classe.
Aqui está o código que eu uso em um botão para chamar este formulário, no meu exemplo, ele se chama 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();
}
Neste exemplo, SenmailView.CurrentItem é a instância da classe de email. Simplesmente precisamos ligar para o envio de Methis e o trabalho está realizado.
Esta é a maior resposta que eu já escrevi, então ... Espero que ajude: D Se você tiver algum problema em usá -la, me ligue. A propósito, não tenho muito orgulho do meu inglês, então me perdoe se o texto tiver algum erro.