none
Generar y guardar PDF automaticamente RRS feed

  • Pregunta

  • hola,

    estoy generando un reporte desde Report Viewer sin problemas, el reporte se genera correctamente y muestra la información deseada. Sin embargo, necesito que al momento de generarlo a PDF este lo haga automáticamente y se guarde automáticamente  en una carpeta de mi pc .

    martes, 21 de febrero de 2017 22:12

Respuestas

  • Ojo, una distinción importante: ¿Traes la información del reporte y lo ensamblas localmente, o generas el reporte en remoto y te traes el reporte generado (usando Reporting Services)? La primera opción es un reporte local (aunque los datos vengan de remoto). La segunda opción es un reporte remoto (con independencia de cuál sea la procedencia de sus datos).

    Si el reporte es local, entonces el código que estás usando es correcto, y lo único que pasa es que tus variables son null, probablemente porque las estás llamando antes de haberlas inicializado (o estás llamando a otra instancia y no la que inicializaste).

    Si el reporte es remoto, entonces las cosas son más complicadas. Yo lo que hago es conectarme al webservice de Reporting Services y darle los comandos para que me descargue un array de bytes con el reporte en PDF. Son como unas 20 o 30 líneas de código. Te podría buscar un ejemplo, pero antes de perder el tiempo en buscarlo asegúrate de que tu reporte es efectivamente remoto y conoces los datos de conexión al SSRS. Si es un reporte local, no sirve de nada lo de la conexión remota.

    Otra forma de comprobarlo: examina el archivo que tiene la definición del informe. Si es .rdlc es local, si es .rdl es remoto.

    jueves, 23 de febrero de 2017 7:49

Todas las respuestas

  • Hola,

    Con el método LocalReport.Render() podés transformar el reporte a un conjunto de bytes, y luego con un objeto FileStream podés transformar ese conjunto de bytes en un archivo PDF en tu disco duro.

    Método Render(): https://msdn.microsoft.com/es-es/library/ms251837.aspx

    Sobrecargas del método: https://technet.microsoft.com/es-es/library/microsoft.reporting.winforms.localreport.render(v=vs.100).aspx

    byte[] bytes = reportViewer.LocalReport.Render("PDF");
    
    using (FileStream fs = new FileStream("Nombre_del_Reporte.pdf", FileMode.Create))
    {
        fs.Write(bytes, 0, bytes.Length);
    }

    Saludos.

    miércoles, 22 de febrero de 2017 4:20
  • Es más, te puedes incluso ahorrar el FileStream y hacerlo todo "de golpe" en una sola línea usando la clase System.IO.File:

    File.WriteAllBytes(@"c:\ruta\fichero.pdf", reportViewer1.LocalReport.Render("PDF"));


    miércoles, 22 de febrero de 2017 7:41
  • tengo una pregunta para que utilizas el "@" que llamas ahí ??

    File.WriteAllBytes(     @  "c:\ruta\fichero.pdf", reportViewer1.LocalReport.Render("PDF"));

    miércoles, 22 de febrero de 2017 15:30
  • tengo una pregunta para que utilizas el "@" que llamas ahí ??

    Sirve para quitarles el significado especial a las "\".

    Si en una cadena pones por ejemplo, "c:\ruta", el compilador entiende que quieres decir C: seguido de un retorno de carro (representado por \r) y luego las letras "uta". Hay dos formas de evitarlo, una es duplicar las barras: "c:\\ruta" y la otra es anteponer una @:  @"c:\ruta":

    miércoles, 22 de febrero de 2017 19:30
  • mira al momento de correrlo no me funciona  
    miércoles, 22 de febrero de 2017 20:14
  • NullReferenceException indica que alguna de las variables es null. Y en esa sentencia, hay dos cosas que pueden ser null: reportViewer1 y localReport. Si es reportViewer1, quiere decir que no está bien inicializada la clase (¿estás llamando a la instancia correcta?) Y si es LocalReport quiere decir una de dos: o que no está bien inicializada esa instancia, o que el reporte no es local sino remoto. Si estás usando el reportViewer1 para llamar a un informe remoto en SSRS, entonces la forma de extraer el PDF es distinta.
    miércoles, 22 de febrero de 2017 21:30
  • Traigo la información  del reporte  de una base de datos en remoto,  y si es asi como seria el código y en que evento lo tendria q poner ?

    miércoles, 22 de febrero de 2017 22:52
  • Ojo, una distinción importante: ¿Traes la información del reporte y lo ensamblas localmente, o generas el reporte en remoto y te traes el reporte generado (usando Reporting Services)? La primera opción es un reporte local (aunque los datos vengan de remoto). La segunda opción es un reporte remoto (con independencia de cuál sea la procedencia de sus datos).

    Si el reporte es local, entonces el código que estás usando es correcto, y lo único que pasa es que tus variables son null, probablemente porque las estás llamando antes de haberlas inicializado (o estás llamando a otra instancia y no la que inicializaste).

    Si el reporte es remoto, entonces las cosas son más complicadas. Yo lo que hago es conectarme al webservice de Reporting Services y darle los comandos para que me descargue un array de bytes con el reporte en PDF. Son como unas 20 o 30 líneas de código. Te podría buscar un ejemplo, pero antes de perder el tiempo en buscarlo asegúrate de que tu reporte es efectivamente remoto y conoces los datos de conexión al SSRS. Si es un reporte local, no sirve de nada lo de la conexión remota.

    Otra forma de comprobarlo: examina el archivo que tiene la definición del informe. Si es .rdlc es local, si es .rdl es remoto.

    jueves, 23 de febrero de 2017 7:49
  • si, efectivamente el reporte es local, ya me funciono Muchas Gracias, lo estaba llamando en el evento que no era, 

    pero ahora tengo otro caso al momento que  el pdf se me guarda en el computador , cada vez que genero un reporte  este se me reemplaza, es decir  me crea uno sobre otro ..no me queda guardado el anterior sino el ultimo que se me genero y necesito  guardar todos los reportes(PDF) que  genere . 

    jueves, 23 de febrero de 2017 14:26
  • Bueno, no tienes mas que ir cambiando el nombre del archivo. Fijate donde el ejemplo ponia File.WriteAllBytes(@"c:\ruta\fichero.pdf", ...

    Evidentemente ese "C:\ruta\fichero.pdf" no es mas que un ejemplo. La funcion WriteAllBytes admite como parametro un String, y el string lo puedes ensamblar concatenando lo que quieras, por ejemplo un numero consecutivo, o la fecha y hora, o un nombre de fichero que le preguntas al usuario...

    jueves, 23 de febrero de 2017 15:22
  •  si , bueno quiero tener la base de datos de  los registros que me  genere y tengo un codigo que  me los genera, quiero saber si estos los puedo guardar con un textbox?
    jueves, 23 de febrero de 2017 15:38
  • Fíjate que cuando llamas a reportViewer1.LocalReport.Render("PDF"), lo que te devuelve es un array de bytes que dentro tiene todos los datos del PDF. En el ejemplo, estábamos pasando ese array a la función File.WriteAllBytes para que lo grabe en disco. Pero perfectamente puedes pasarlo a una variable:

    byte[] misDatos = reportViewer1.LocalReport.Render("PDF"));

    Una vez que tienes los bytes en esa variable, puedes salvarlos en donde quieras. A partir de aquí olvídate de que provienen de un Report y olvídate de que es un PDF. Simplemente son bytes, y los puedes salvar en donde quieras (en un fichero, en base de datos, con nombre fijo, con nombre variable, guardando un histórico... lo que quieras) de la misma manera que normalmente suelas utilizar para salvar cualquier otro contenido tal como por ejemplo una imagen, no hay que hacer nada en especial ni distinto por el hecho de que provenga del ReportViewer.

    jueves, 23 de febrero de 2017 19:16
  • Me sale este error ne Byte[] , y quiero saber si ...en el codigo  cuando te refieres a mis datos 

    byte[] misDatos = reportViewer1.LocalReport.Render("PDF"));

     te estas refiriendo al lugar donde van a quedar guardados mis pdf ..en este caso el disco  de mi computador.

    jueves, 23 de febrero de 2017 21:09
  • Agh, tu código está en Visual Basic, y to te puse el ejemplo en C#. En VB es así:

    Dim loquesea as Byte() = reportViewer1.LocalReport.Render("PDF"))

    El lugar en donde quieres guardar los datos tienes que decidirlo. Si los quieres en disco, puedes usar File.WriteAllBytes y pasarle la variable con los bytes, igual que hicimos en el ejemplo anterior (solo que en ese caso lo hicimos de golpe sin poner una variable intermedia, pero el efecto es el mismo). Recuerda que el nombre del archivo es un string, que puedes tomar y construir como quieras (por ejemplo, preguntándoselo al usuario). Pero en una pregunta anterior decías que querías hacer más cosas ("tengo en la base de datos los registros..."). Si quieres guardarlo en base de datos o algo así, entonces hay que hacer otras cosas.

    jueves, 23 de febrero de 2017 21:25
  • si de hecho con el primer código que me diste me funciono super bien , lo que te preguntaba era que ...como hacia por que en el momento que se guardaban los pdf ...  en mi disco... no me quedaban  , es decir se me reemplaza por el ultimo  que genero y pues quiero tener una base de datos de los PDF  que genere y pues tengo un codigo que es el que me los genera y quiero saber si estos los puedo guardar con un texbox?
    jueves, 23 de febrero de 2017 22:20
  • Claro que puedes, si precisamente eso es lo que te decía, que el nombre del fichero es un String, y el String puede venir de cualquier parte donde tengas un String. "Cualquier parte", obviamente, incluye el .Text de un TextBox, que te devuelve un String.

    File.WriteAllBytes(TexBox1.Text, reportViewer1.LocalReport.Render("PDF"));

    Por cierto, lo de la "@" que te respondí en un mensaje anterior es de C# (porque en ese momento estaba pensando que programabas en C#, ya que todavía no habías mencionado nada al respecto). En VB no se aplica la @.

    jueves, 23 de febrero de 2017 22:57
  • hola, discúlpame formule mal mi pregunta :( 

    lo que quería saber,era  como hacer para el momento en el que guarde mis pdfs todos me queden guardados con el nombre de una variable que en este caso  seria como el serial de mi numero de factura , quiero que me quede guardada como mi base de datos local  de todos los pdfs que genere ... 

     esa variable la va a tomar un textbox  el cual trae el código de la factura .

    viernes, 24 de febrero de 2017 14:05
  • Bueno, y si ya tienes tu serial en una variable, ¿por qué no usas esa misma variable para formar el nombre del fichero? ¿Cuál es el problema?
    viernes, 24 de febrero de 2017 15:28
  • si, mira tengo un txtbox  con los números de serial  , pero no sabria como hacer el codigo para que este  se me genere 

    me podrías dar un ejemplo ?

    viernes, 24 de febrero de 2017 15:33
  • El ejemplo ya estaba puesto en una respuesta anterior. Si en el textbox ya existe el serial que quieres grabar, y quieres que el fichero tenga el mismo nombre que hay escrito en el textbox, puedes generarlo asi:

    File.WriteAllBytes(TexBox1.Text, reportViewer1.LocalReport.Render("PDF"));

    Recuerda (una vez más) que el primer parámetro es un string, por lo que puedes hacer con él cualquier operacion que se haga con strings, como por ejemplo concatenarles texto. Asi que si quieres añadir un prefijo o una ruta y una extension, no tienes que hacer nada más que concatenarlas:

    File.WriteAllBytes("c:\carpeta\" & TexBox1.Text & ".pdf", reportViewer1.LocalReport.Render("PDF"));

    viernes, 24 de febrero de 2017 15:43
  • Agradezco tu colaboración, ya me funciono todo a la perfección !  :D
    viernes, 24 de febrero de 2017 16:41
  • El ejemplo ya estaba puesto en una respuesta anterior. Si en el textbox ya existe el serial que quieres grabar, y quieres que el fichero tenga el mismo nombre que hay escrito en el textbox, puedes generarlo asi:

    File.WriteAllBytes(TexBox1.Text, reportViewer1.LocalReport.Render("PDF"));

    Recuerda (una vez más) que el primer parámetro es un string, por lo que puedes hacer con él cualquier operacion que se haga con strings, como por ejemplo concatenarles texto. Asi que si quieres añadir un prefijo o una ruta y una extension, no tienes que hacer nada más que concatenarlas:

    File.WriteAllBytes("c:\carpeta\" & TexBox1.Text & ".pdf", reportViewer1.LocalReport.Render("PDF"));

    Alberto buen dia.

    Lei en el hilo que tambien lo podemos hacer usando Reporting Services, realmente no tengo problemas con los informes pero cuando envio un informe por primera vez demora mucho en la coneccion con el servidor de reportes. Mi idea es solicitar un informe en segundo plano para que esta primera vez ya no se sienta muy demorada por partes del usuario. Si tienes otra idea por favor me comentas.

    Saludos,

    Jaime.


    saludos.

    sábado, 6 de octubre de 2018 21:01
  • Sí, si quisieras podrías pedir el informe en un hilo de background para que se vaya preparando... pero normalmente no hace falta. Eso ya lo sabe hacer Reporting Services si lo configuras adecuadamente. Puedes configurar los informes para que se ejecuten a la hora que quieras y se cachee el resultado, de forma que cuando un usuario lo pida se devuelva inmediatamente. Léete primero la documentación de SSRS a ver si te sirve alguna de las opciones que tiene, no vaya a ser que te pongas a programar por tu cuenta en el código cliente algo que ya existe en la herramienta y que basta con activarlo desde el Report Manager.
    domingo, 7 de octubre de 2018 8:06