5 04 2017
Trabalhando com o Report Viewer no MVC
O Report Viewer só tem suporte nativo ao Windows Forms e Web Forms, ou seja, quem trabalha com outras plataformas (como WPF ou MVC) precisa fazer alguns ajustes para poder utilizá-lo nos seus projetos. No caso do WPF, é só adicionar um WindowsFormsHost com o controle do Report Viewer dentro, como eu mostrei neste artigo. Já no ASP.NET MVC, ou adicionamos um WebForm (não recomendado) ou utilizamos uma biblioteca que possibilita a criação dos relatórios no “estilo MVC” de desenvolver.
Eu já escrevi um artigo mostrando como utilizar o Report Viewer no ASP.NET MVC, onde eu mostro as duas modalidades mencionadas acima. Devido à popularidade desse artigo, eu resolvi fazer uma versão em vídeo explorando um pouco mais a ideia da utilização da biblioteca “ReportViewerForMVC“. No vídeo eu mostro também um problema que temos ao utilizá-la com sub-relatórios. Confere aí:
Biblioteca ReportViewerForMVC
A biblioteca que podemos utilizar para trabalharmos com o Report Viewer no MVC (sem termos que adicionar um WebForm manualmente) é a “ReportViewerForMVC“. Como você pode reparar no site da biblioteca no CodePlex, ela não tem sido atualizada há um bom tempo. Porém, ela funciona bem com a versão 11 do Report Viewer, então ela acaba dando conta do recado.
Para adicionarmos uma referência a essa biblioteca no nosso projeto, nós utilizamos o NuGet. Basta procurarmos por “ReportViewerForMVC” na janela de gerenciamento de pacotes do NuGet ou digitarmos “Install-Package ReportViewerForMVC” no Package Manager Console:
Essa biblioteca adicionará a referência às dlls “Microsoft.ReportViewer.WebForms” e “ReportViewerForMvc“.
Outras referências necessárias
Em computadores que tenham a runtime do Report Viewer instalada, somente a referência à biblioteca já é o suficiente para que o nosso projeto funcione. Porém, para o caso em que a versão correta da runtime do Report Viewer não estiver instalada, algumas outras referências serão necessárias.
Por segurança, eu recomendo que você adicione pelo NuGet as referências às bibliotecas “MicrosoftReportViewerWebForms” e “Microsoft.SqlServer.Types” (versão 11.0.0):
O código do Controller
Uma vez adicionadas todas as referências necessárias, vamos partir para a criação do código do nosso Controller. Adicione um novo Controller vazio do MVC na pasta “Controllers” para que possamos fazer essa implementação.
A ideia é muito simples. Primeiramente nós temos que carregar os dados da nossa fonte de dados e armazená-los em um DataSet ou coleção. Em seguida, nós criamos uma instância da classe “Microsoft.Reporting.WebForms.ReportViewer” e configuramos algumas propriedades (como caminho do relatório e sua fonte de dados). Por fim, nós retornamos essa instância de “ReportViewer” através da ViewBag.
Veja só este exemplo:
// C# public ActionResult Index() { var ds = ObterDados(); var viewer = new Microsoft.Reporting.WebForms.ReportViewer(); viewer.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Local; viewer.LocalReport.ReportPath = Request.MapPath(Request.ApplicationPath) + @"CaminhoDoSeuRelatorio.rdlc"; viewer.LocalReport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource("NomeDoDataSetNoRelatorio", (System.Data.DataTable)ds.NomeDaDataTable)); ViewBag.ReportViewer = viewer; return View(); }
' VB.NET Dim Ds = ObterDados() Dim Viewer = New Microsoft.Reporting.WebForms.ReportViewer() Viewer.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Local Viewer.LocalReport.ReportPath = Request.MapPath(Request.ApplicationPath) + "CaminhoDoSeuRelatorio.rdlc" Viewer.LocalReport.DataSources.Add(New Microsoft.Reporting.WebForms.ReportDataSource("NomeDoDataSetNoRelatorio", DirectCast(Ds.NomeDaDataTable, System.Data.DataTable))) ViewBag.ReportViewer = Viewer Return View()
E como fica a View?
Com o Controller em mãos, podemos partir para a criação da nossa View. O código dela é muito simples. Primeiramente nós temos que adicionar uma referência à biblioteca “ReportViewerForMvc” (com uma cláusula “using” no início da View). Adicionada essa referência, nós teremos alguns métodos extras à nossa disposição, como o “Html.ReportViewer“. Ao chamarmos esse método passando a instância do ReportViewer da ViewBag, o relatório será renderizado naquele local:
<!-- C# --> @using ReportViewerForMvc; @{ ViewBag.Title = "Index"; } <h2>Relatório</h2> @Html.ReportViewer(ViewBag.ReportViewer as Microsoft.Reporting.WebForms.ReportViewer)
<!-- VB.NET --> @Imports ReportViewerForMvc @Code ViewData("Title") = "Index" End Code <h2>Index</h2> @Html.ReportViewer(DirectCast(ViewBag.ReportViewer, Microsoft.Reporting.WebForms.ReportViewer))
Execute o projeto e veja o resultado:
Ajuste automático do tamanho do controle
Se observarmos o resultado apresentado na imagem acima, veremos que o controle está com um tamanho fixo (o tamanho padrão). No controle do Report Viewer web, temos a possibilidade de configurarmos um tamanho dinâmico, ou seja, o controle será automaticamente redimensionado dependendo do tamanho do relatório.
Para atingirmos esse resultado, temos que alterar a propriedade “SizeToReportContent” para verdadeiro, além de configurarmos o Width e Height de forma que eles ocupem 100% da área disponível na View. Coloque este código antes de retornar o controle para a ViewBag e veja a diferença:
// C# viewer.SizeToReportContent = true; viewer.Width = System.Web.UI.WebControls.Unit.Percentage(100); viewer.Height = System.Web.UI.WebControls.Unit.Percentage(100);
' VB.NET Viewer.SizeToReportContent = True Viewer.Width = System.Web.UI.WebControls.Unit.Percentage(100) Viewer.Height = System.Web.UI.WebControls.Unit.Percentage(100)
Problemas com sub-relatórios
A biblioteca Report Viewer for MVC funciona muito bem até o momento em que tivermos que trabalhar com sub-relatórios. Para exibirmos um relatório que tenha sub-relatório, o código do Controller ficaria assim:
// C# DataSet ds; public ActionResult Index() { ds = ObterDados(); var viewer = new Microsoft.Reporting.WebForms.ReportViewer(); viewer.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Local; viewer.LocalReport.ReportPath = Request.MapPath(Request.ApplicationPath) + @"CaminhoDoSeuRelatorio.rdlc"; viewer.LocalReport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource("NomeDoDataSetNoRelatorio", (System.Data.DataTable)ds.NomeDaDataTable)); viewer.LocalReport.SubreportProcessing += LocalReport_SubreportProcessing; ViewBag.ReportViewer = viewer; return View(); } private void LocalReport_SubreportProcessing(object sender, Microsoft.Reporting.WebForms.SubreportProcessingEventArgs e) { e.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource("NomeDoDataSetNoSubRelatorio", (System.Data.DataTable)ds.NomeDaDataTableDetalhe)); }
' VB.NET Private Ds As DataSet Public Function Index() As ActionResult Ds = ObterDados() Dim Viewer = New Microsoft.Reporting.WebForms.ReportViewer() Viewer.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Local Viewer.LocalReport.ReportPath = Request.MapPath(Request.ApplicationPath) + "CaminhoDoSeuRelatorio.rdlc" Viewer.LocalReport.DataSources.Add(New Microsoft.Reporting.WebForms.ReportDataSource("NomeDoDataSetNoRelatorio", DirectCast(Ds.NomeDaDataTable, System.Data.DataTable))) AddHandler Viewer.LocalReport.SubreportProcessing, AddressOf LocalReport_SubreportProcessing Viewer.SizeToReportContent = True Viewer.Width = System.Web.UI.WebControls.Unit.Percentage(100) Viewer.Height = System.Web.UI.WebControls.Unit.Percentage(100) ViewBag.ReportViewer = Viewer Return View() End Function Private Sub LocalReport_SubreportProcessing(sender As Object, e As Microsoft.Reporting.WebForms.SubreportProcessingEventArgs) e.DataSources.Add(New Microsoft.Reporting.WebForms.ReportDataSource("NomeDoDataSetNoSubRelatorio", DirectCast(Ds.NomeDaDataTableDetalhe, System.Data.DataTable))) End Sub
Porém, se testarmos esse cenário com um breakpoint no evento “SubReportProcessing“, veremos que ele não será disparado. Isso acontece porque a biblioteca tem um bug que evita o disparo desse evento. Existe até uma “issue” criada no site da biblioteca falando sobre esse problema.
No link acima você pode notar que eu respondi aquela “issue” com a correção necessária para que os sub-relatórios funcionem. Eu fiz essa correção, recompilei a biblioteca e você pode baixar a versão corrigida aqui. Substitua essa dll na pasta “packages” e na pasta “Bin” do seu projeto para que os sub-relatórios funcionem corretamente. E acompanhe este repositório no meu GitHub, onde eu pretendo dar manutenção nessa biblioteca e disponibilizar atualizações.
Baixe o projeto de exemplo
Para baixar o projeto de exemplo desse artigo, assine a minha newsletter. Ao fazer isso, além de ter acesso ao projeto, você receberá um e-mail toda semana sobre o artigo publicado e ficará sabendo também em primeira mão sobre o artigo da próxima semana, além de receber dicas “bônus” que eu só compartilho por e-mail. Inscreva-se utilizando o formulário no final do artigo.
Até a próxima!
André Lima
Photo by Peter Shanks used under Creative Commons
https://pixabay.com/en/startup-start-up-notebooks-creative-593327/
Song Rocket Power Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 3.0 License
http://creativecommons.org/licenses/by/3.0/
Calculando o hash de arquivos para verificação de integridade com C# e VB.NET Utilizando a API do Google Drive no C# e VB.NET
Muito bom Andre ! show !
Valeu Claudionor! Abraço!
André Lima
Excelente.No hablo portugues, pero tu ejemplo….excelente
Olá Ruben, muito obrigado pelo comentário! Fico feliz que você tenha gostado do tutorial.. :)
Um forte abraço!
André Lima
Andre ! tenho um projeto ASP.NET MVC 5 no Visual Studio 2017, estou utilizando no meu MODEL, as tabelas via LINQ TO SQL. To tendo dificuldades tem passar os dados pro REPORT VIEWER.
Voce pode me ajudar ! Desde já lhe agradeço !
Olá Claudionor!
O seu relatório já está pronto (e você só está tendo dificuldades em passar os dados) ou você está tendo problemas já na criação do relatório? Me explica melhor em qual etapa você está tendo dificuldades para que eu consiga te ajudar melhor..
De qualquer forma, eu sugiro que você dê uma olhada neste outro artigo, talvez ele te ajude:
Gerando relatórios do Report Viewer com Entity Framework
Abraço!
André Lima
Excelente tutorial, achei muito legal a sua disposição em dar continuidade a biblioteca.
Depois de muitas tentativas e erros funcionou no Visual Studio 2017 ASP.MVC5, mas tive que usar a versão do Microsoft.SqlServer.Types 14.0.314.76, não sei porque não funcionava na versão 11.0.0.
Olá mais uma vez Pablo!
Que estranho hein.. Era para ter funcionado com a outra versão do SqlTypes.. De qualquer maneira, obrigado por ter voltado aqui e postado a solução para o seu problema.. :)
Abraço!
André Lima
Muito obrigado, Pablo! Fico feliz que você tenha gostado..
Abraço!
André Lima
Você pretende disponibilizar as atualizações do biblioteca via NuGet?
Olá novamente, Pablo! Assim que eu conseguir um tempo para fazer isso, sim.. O problema é que atualmente o tempo está bem escasso, hehehe.. Então, por enquanto o jeito é copiar a dll compilada e adicionar a referência na mão mesmo..
Abraço!
André Lima
Gostaria de saber se tem algum jeito de gerar o relatório diretamente em PDF sem passar pela View do relatório!! se tiver como, coloca junto ao cometário
Olá Douglas!
Dá uma olhada neste outro artigo e veja se te ajuda:
Como podemos exportar relatórios do Report Viewer?
E tem também este outro artigo onde eu gero o PDF do Report Viewer através de uma Web API.. Talvez possa te ajudar também:
Expondo PDFs gerados pelo Report Viewer com Web API
Abraço!
André Lima
Is there any way to show a sort of please wiat message till the the time the report was loaded completly in UI
Hi!
Usually the Report Viewer control already displays a message “Loading data” while it is drawing.. Isn’t it working in your case?
André Lima
Legal!
Valeu, Rafael! Que bom que você gostou.. :)
Abraço!
André Lima
Hi,
I followed your tutorial and it works great. Then if I want to add a new report, it shows the report with no records. For instance, in the controller, when I fill de dataset I use Take(5).ToList() then in the report it shows the columns header and 5 blank records. I tried adding the new datatable to the existing DataSet and adding a new DataSet and both have the same behaviour. Can you imagine what is going on? Thanks in advance.
Hi Valentin!
This usually happens when the names of the properties (or columns) in the data source don’t match exactly the names of the columns in the report DataSet.. They have to match 100% exactly (they are case sensitive).. Did you check that already?
Regards,
André Lima
assinei como faco pra baixar o fonte?
Olá Ricardo!
Você deve ter recebido o link no e-mail de confirmação da inscrição.. Mas, de qualquer forma, eu acabei de mandar novamente o link no seu e-mail..
Abraço!
André Lima
Olá, adorei o seu post nem sabes o quanto ele foi util.
Estou com um probleminha, consegui gerar o relatorio mais a barra de ferramentas do relatorio aparece branca e sem os botões de gerar e imprimir o report.
Olá Eurico!
Você tem certeza que está utilizando a última versão da biblioteca? Isso acontecia em algumas versões atrás.. Você poderia enviar um screenshot mostrando essa situação?
Abraço!
André Lima
Bom dia Andre, ja fiz o screenshot mais o seu comentario não suporta ficheiro. Como faço? Envio pelo E-mail!
Olá Eurico!
Pode enviar no meu e-mail: contato [arroba] andrealveslima [ponto] com [ponto] br
Abraço!
André Lima
Boa noite Andre, eu baixei a dll da última release no seu github, funcionou perfeitamente para relatórios que não tem subrelatórios, mas eu não foi porque não aciona o evento LocalReport_SubreportProcessing, eu segui o seu exemplo.
Depois de fazer um monte de testes eu consegui, até clonei uma cópia do seu projeto no github e atualizei ela para as versões mais recentes das bibliotecas dependentes para ver se era esse o problema já que eu estou usando o Visual Studio 2017. Mas no final das contas o problema era que eu estava passando parâmetros para o subrelatório no relatório pai que não estava cadastrados no subrelatório.
Agora está funcionando perfeitamente.
Olá Pablo!
Que bom que você conseguiu encontrar o problema na passagem do parâmetro entre os relatórios.. Qualquer outra dificuldade, é só entrar em contato..
Abraço!
André Lima
Felicitaciones. Muy buen tutorial.
me ha servido mucho. Gracias por el aporte. Saludos
Muito obrigado pelo comentário, Freddy! Fico feliz por ter ajudado..
Abraço!
André Lima
Muito bom!!
Olá, Cláudio, muito obrigado pelo comentário!
Que bom que você gostou.. :)
Qualquer dificuldade, é só falar..
Abraço!
André Lima
Boa Tarde
o servidor de hospedagem tem que ter suporte para o reportView ?
Olá Denilson!
O servidor precisa ser Windows (IIS) com full trust.. Aí é só distribuir as dlls como eu mostrei neste vídeo:
Publicando sites com Report Viewer no Azure
Abraço!
André Lima
Olá André mesmo após a aplicar o comando SizeToReportContent = true; não consegui colocar o visualizador do relatório como full. Segue meu código.
DataTable dtDados = CertificadosBLL.RelatorioCerificadoSituacao(“”);
var viewer = new Microsoft.Reporting.WebForms.ReportViewer();
viewer.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Local;
viewer.LocalReport.ReportPath = Request.MapPath(Request.ApplicationPath) + @”Reports\Certificados\Report1.rdlc”;
viewer.LocalReport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource(“DataSetStatus”, dtDados));
viewer.SizeToReportContent = true;
viewer.Width = System.Web.UI.WebControls.Unit.Percentage(100);
viewer.Height = System.Web.UI.WebControls.Unit.Percentage(100);
viewer.LocalReport.Refresh();
Olá Dyego!
Cara, estranho hein.. Não sei o que pode estar acontecendo.. Nunca tive esse problema.. Você já tentou criar um projeto novo do zero para ver se o problema acontece também em um projeto zerado? Caso funcione em um projeto zerado, pode ser alguma coisa no seu layout, CSS ou coisa do tipo..
Abraço!
André Lima
Olá André
Tou com um projecto web com BD, e preciso que o sistema gere relatórios filtrados pela visão por exemplo trazer para o relatório registos com a mesma data.
Vi e tentei implementar uma dataView com o RowFilter como fizeste noutro exemplo com Windows Forms, mas o relatório não vem filtrado.
Podes me ajudar com isso?
Olá Alvim!
Vou repetir aqui o que eu te respondi no seu comentário lá no Youtube:
Era para ter funcionado com o DataView.. Como é que ficou o código? Você tentou debugar para ver se o conteúdo da DataView está sendo corretamente filtrado e se os dados estão sendo passados certinho para o relatório?
Outra opção seria tentar fazer o filtro através de parâmetro no relatório.. Você mandaria o valor do parâmetro para o relatório e filtraria o conteúdo com base nele..
Abraço!
André Lima