none
Tutorial: How to Render reports with no GUI in any app. RRS feed

  • General discussion

  • I've got a nice little way to render reports, for example from a console application as i am now. I'm posting the code to help anyone out trying to do the same or similar without the need to display it.

    You'll have to modify some stuff (probably the Zip support I added may need to be removed.)

     

    LogAndWrite() is missing here.. it just appends to a log text file and writes to the screen in one sub.

    also some of the imports may be un necessary, i forget wich ones right now.

    In my project reports are copied to the output folder in a Reports folder. This makes it easy to update later.

     

    If you have anything to add or fix, you're welcome to... just post what you have here that way we can all benefit.

     

    TIP: if you see a ("Report Definition is invalid for "Main Report") exception look into the inner exceptions a couple levels deep... I made the mistake of not looking all the way in and seeing that it was a missing report assembly that i had included in my array.

     

    I really wish there was a nice simple function like this built right into the report viewer... with verbose console output and all.

     

    Does anyone know how to switch between embedded reports?? I can't seem to get that part to work, this is why i copy to output folder, although convenient.

     

    -Kanaida

     

    Code Snippet

    Imports System.ConsoleColor

    Imports System.Collections.ObjectModel

    Imports System.Diagnostics

    Imports System.Diagnostics.Process

    Imports System.Diagnostics.EventLogEntryType

    Imports System.IO

    Imports Microsoft.Reporting.WinForms

    Imports ProjectName.ReportFormat

     

    Public Structure ReportFormat

    CSV

    ZIP_CSV

    Excel

    ZIP_EXCEL

    PDF

    ZIP_PDF

    XML

    ZIP_XML

    End Structure

     

    Public Function GenerateReport_New(ByVal FileName As String, ByVal Report As String, ByVal DataSetName As String, ByVal Table As DataTable, ByVal OutputFormat As ReportFormat, ByVal OpenAfterRender As Boolean, Optional ByVal Parameters() As ReportParameter = Nothing, Optional ByVal TrustedModules As ArrayList = Nothing) As String

     

    Dim RESULT As String = ""

    Dim i As New ReportViewer

    i.ProcessingMode = ProcessingMode.Local

    i.LocalReport.EnableExternalImages = True

    i.LocalReport.EnableHyperlinks = True

     

    i.LocalReport.ReportPath = My.Application.Info.DirectoryPath & "\Reports\" & Report & ".rdlc"

     

    Dim R As ReportParameterInfoCollection = i.LocalReport.GetParameters()

    For Each Parameter As ReportParameterInfo In R

    Console.WriteLine("REQUIRED PARAMETER: " & Parameter.Name)

    Next

     

    i.LocalReport.DataSources.Add(New ReportDataSource(DataSetName, Table))

     

    If Not Parameters Is Nothing Then

    For Each Param As ReportParameter In Parameters

    If Param.Values.Count > 0 Then

    Console.WriteLine("PARAMETER: " & Param.Name & " = " & Param.Values.Item(0))

    End If

    Next

    i.LocalReport.SetParameters(Parameters)

    End If

     

    If Not TrustedModules Is Nothing Then

    For Each _Module As String In TrustedModules

    i.LocalReport.AddTrustedCodeModuleInCurrentAppDomain(_Module)

    Next

    End If

     

    Dim FormatCode As String = ""

    Select Case OutputFormat

    Case CSV : FormatCode = "CSV"

    Case ZIP_CSV : FormatCode = "CSV"

    Case Excel : FormatCode = "EXCEL"

    Case ZIP_EXCEL : FormatCode = "EXCEL"

    Case PDF : FormatCode = "PDF"

    Case ZIP_PDF : FormatCode = "PDF"

    Case XML : FormatCode = "XML"

    Case ZIP_XML : FormatCode = "XML"

    End Select

     

    'Export to Specified Format. Get binary content.

    Dim ReportFileName As String = FileName

    Dim Content As Byte() = i.LocalReport.Render(FormatCode, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing)

    My.Computer.FileSystem.WriteAllBytes(FileName, Content, False)

     

    If OutputFormat = ZIP_CSV Or ZIP_EXCEL Or ZIP_PDF Or ZIP_XML Then

    Dim File As FileInfo

    Dim Dir As DirectoryInfo

    Dim Path As String = ""

    Dim ZipFile As String = ""

     

    Try

    File = New FileInfo(FileName)

    Dir = File.Directory

    Path = Dir.FullName

    ZipFile = File.Name & ".Zip"

    RESULT = Zip(ReportFileName, ZipFile, Path) 'Create Zip File

     

    'Delete original Report, keeping the Zip File

    My.Computer.FileSystem.DeleteFile(MAIL_PICKUP & "\" & File.Name)

    Catch ex As Exception

    LogAndWrite([Error], Failure, "Error Creating Directory Information Object.", ex.Message, Red)

    Finally

    File = Nothing

    Dir = Nothing

    Path = Nothing

    End Try

    Else

    RESULT = FileName

    End If

     

    i.Dispose()

    'Some extra Cleanup of variables can go here...

     

    'Open Report

    If OpenAfterRender Then Start(FileName)

    Return RESULT

    End Function

     

     

    Monday, September 10, 2007 9:01 PM

All replies

  •  

    >>Does anyone know how to switch between embedded reports??

     

    Yes <s>.  I don't have any trouble with this.  What have you tried that doesn't work, maybe I can spot/fix the syntax?

     

    >L<

    Thursday, September 13, 2007 2:45 AM
  • I don't have an example right now...
    would you happen to have one?  

    say i made Report1.rdlc and Report2.rdlc
    I drop in a reportviewer and set the default via the gui to Report1.rdlc
    It sets some embedded property... a string with the name of the report.

    'do data work to fill dataset

    this renders fine on startup

    now i want to change to report2.rdlc.

    I would do a reportviewer.reset
    set processing mode to local

    and set the embedded report path/name to "report2.rdlc"
    (this is where i think my syntax was wrong...")

    what is the proper syntax?
    Saturday, September 15, 2007 5:11 PM
  • Of course you have "an example".  You have whatever it is you tried <s>.

     

    And here it is in your message:

     

    >>and set the embedded report path/name to "report2.rdlc"

     

    ... which, as you say, does not work for an embedded resource.  It would be "DLLName.report2.rdlc" or "EXEName.report2.rdlc".  And just btw this has nothing to do with reports or rdlc in particular!   It is true of other types of embedded resources as well.

     

    [editing message, somewhat later]

     

    >>would you happen to have one?  

    And BTW thanks for the kick in the pants, I have been meaning for quite a while to post a walkthrough of exactly how I do this and a bunch of related work... so here it is ... http://spacefold.com/lisa/post/Dynamically-loading-reports-in-ReportViewers.aspx

     

    HTH,

     

    >L<

     

     


     

     

     

     

    Sunday, September 16, 2007 2:01 PM
  •  

    that's what i was trying to get at... so it's the dllName.EmbeddedResourceName

    I had never used them before, well not without the gui doin it for me.

     

    I will try it. What i had meant was that i didnt have an example in front of me because i forget what project name i had tried it in.

     

    thanks.

    Tuesday, September 18, 2007 9:15 PM
  • Is there a reason why you are creating a ReportViewer object, rather than just directly instantiating a LocalReport object? Is the ReportViewer needed for something?

     

    Thanks,

    --kaburke

    Thursday, September 20, 2007 6:05 AM
  • Yes of course it is "needed for something".  Take a look at the form in the screenshot in the walkthrough.

     

    Here is another screenshot (taken from the RDLDocumenter/XMLRSDocs docs, which are here http://spacefold.com/articles/XMLRSDocs.aspx  -- this link is also in the walkthrough), after an RDL has been parsed to a .docRDLXML:

     

    http://spacefold.com/articles/XMLRSDocs_images/TestHarnessUI1.png

     

    ... or when multiple reports' docRDL have been loaded to a database server

     

    http://spacefold.com/articles/XMLRSDocs_images/TestHarnessUI2.png

     

    What do you see in the bottom half of the form <s>?

     

    >L<

     

    Thursday, September 20, 2007 11:59 AM
  • The original post was concerning rendering RDLC files in console apps with no GUI. In the orignal code, there are no forms. In that situation, is there a need for a ReportViewer?

     

    Thanks,

    --kaburke

    Thursday, September 20, 2007 1:20 PM
  • No in that case there isn't any need for the viewer -- as you'll easily see in the very nice demo of how to do it if you need printing as one of your output targets, here http://gotreportviewer.com/ (see the print from a console app example there).

     

    On server mode reports there isn't any need for the viewer (if you don't want the viewer, you just want to render the report to your target-of-choice) either...

     

    >L<

     

     

     

    Thursday, September 20, 2007 1:47 PM
  •  

    you guys bring up a good point, I was unaware of the LocalReport object.

     

    I'll do some tests, hopefully it still has all the functions that I need to allow trusted assemblies that make my barcode images etc...

     

    maybe I'll even get a nice little speed boost and even smaller memory footprint Smile

     

    Friday, September 28, 2007 8:26 PM
  • Thanks for your  code example.

    but when i implemented it with my code and tried export CSV or MHTML file it is showing error.

    System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
    Parameter name: format

     

    My Code:

    string mimeType;

            string encoding;

            string fileNameExtension;

            string[] streams;

            byte[] pdfContent;

            string path;

            Microsoft.Reporting.WebForms.Warning[] warnings;

     

                       pdfContent = repviewer.LocalReport.Render("CSV", null, out mimeType, out encoding, out fileNameExtension, out streams, out warnings);

     

    similarly for MHTML

     

    Pease help me out to solve this problem.

    Thursday, October 25, 2007 6:33 AM
  • I'm having exactly the same situation when I try to render any HTML format. I can get PDF to work just fine.

     

    I've tried using format: "HTML", "HTML 4.0", "HTML4.0", and "MSHTML".  I have to be missing something. I've tried this with and without device info. I still get the ArgumentOutOfRange exception every time.

    System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
    Parameter name: format

     

    Any ideas?

     

    Code Block

       Warning[] warnings;
       string[] streamids;
       string mimeType;
       string encoding;
       string extension;

     

       StringBuilder deviceInfo = new StringBuilder("<DeviceInfo>");
       deviceInfo.Append("<HTMLFragment>true</HTMLFragment>");
       deviceInfo.Append("</DeviceInfo>");

     

       byte[] bytes = report.Render(
         "MHTML", deviceInfo.ToString(), out mimeType, out encoding,
          out extension,
         out streamids, out warnings);

     

       return System.Text.Encoding.UTF8.GetString(bytes);

     

     

     

    Thursday, November 1, 2007 7:41 PM
  • I think the problem is that they decided to castrate the exportable formats. I've only seen PDF and Excel work.
    I believe that somwhere I read that using the local reports, those formats are not available. 
    I really had wished for an error Like "Sorry, that format is only available in remote processing mode. It's a business reason."
    You'd have to confirm that though.

    It's beyond me why they would limit html. maybe they're afraid someone will make a web page generator or something out of it, who knows...
    Thursday, November 1, 2007 7:48 PM
  • That's what I'm reading. I just found the online doc for the Render() method. In the format parameter it says it only supports, PDF, XLS and Image.

    bummer.

    http://msdn2.microsoft.com/en-us/library/ms251839(VS.80).aspx
    Thursday, November 1, 2007 8:01 PM
  • It doesen't matter though, I make html all the time in a nice easy way for reports. try this:

    add an html file to your project and call it ReportTemplate.html or something like that.
    Drag and drop a table or two, change colors, fonts etc...

    you need 3 basic things:

    Table columns the way you want them to look, with the column names typed in.
    Where the data goes type in some simple variable names as text with dollars before and after, like:  $ADDRESS1$

    next, add a single blank row filled with variables to your table
    eg.   $ORDER_NO$ | $DATE$ | $PRODUCT_NAME$

    Lastly below the table add any footer type message:


    this should take you a couple minutes, and believe me it's much easier than typing html and learning tags.

    if you view the code for this html page, scroll down to find your row variables your code block may look something like this:

    <tr>
    <td style="border-right: lavender thin solid; padding-right: 0px; border-top: lavender thin solid;
    padding-left: 0px; padding-bottom: 0px; border-left: lavender thin solid; width: 136px;
    padding-top: 0px; border-bottom: lavender thin solid; font-family: Arial; text-align: center">
    $ORDER$</td>
    <td style="border-right: lavender thin solid; padding-right: 0px; border-top: lavender thin solid;
    padding-left: 0px; padding-bottom: 0px; border-left: lavender thin solid; width: 324px;
    padding-top: 0px; border-bottom: lavender thin solid; font-family: Arial; text-align: center">
    $AMOUNT$</td>
    <td style="border-right: lavender thin solid; padding-right: 0px; border-top: lavender thin solid;
    padding-left: 0px; padding-bottom: 0px; border-left: lavender thin solid; width: 324px;
    padding-top: 0px; border-bottom: lavender thin solid; font-family: Arial; text-align: center">
    $PERIOD$</td>
    </tr>

    Copy that text into My.Settings.RowTemplate (you have to create the setting)

    Next, copy everything before the row code to (My.Settings.HeaderTemplate)

    Now do the same with the footer code.

    Now make 3 functions
    HTML_Footer, HTML_Row, HTML_Header
    in these functions just do this (of course putting in all your variables that you chose in each template:


    Public Function HTML_Row(ByVal Order As String, ByVal ApprovedAmount As String, ByVal ShipPeriod As String) As String
    Dim Result As String = My.Settings.ReportRow

    Result = Replace(Result, "$ORDER$", Order)
    Result = Replace(Result, "$AMOUNT$", ApprovedAmount)
    Result = Replace(Result, "$PERIOD$", ShipPeriod)
    Return Result
    End Function


    Last step is do this:

    Dim OutputHTML as string

    OutputHTML += HTML_Header()

    'Do your code here to figure stuff out and whenever you need to write a row just use: (this can be done as many times as you want)
    OutputHTML += HTML_Row(YourVar1,YourVar2,YourVar3, etc...)

    OutputHTML += HTML_Footer()

    then do whatever you want with the html!

    it's fast, and works excellent.




    Thursday, November 1, 2007 8:17 PM
  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
    <title>Untitled Page</title>
    </head>
    <body>
    <table style="width: 480px; font-family: Aria; border-right: lavender thin solid; padding-right: 0px; border-top: lavender thin solid; padding-left: 0px; padding-bottom: 0px; margin: 0px; border-left: lavender thin solid; padding-top: 0px; border-bottom: lavender thin solid;">
    <tr>
    <td colspan="3" style="color: #ffffff; font-family: Arial; background-color: #ff3300;
    text-align: left">
    <span style="color: #ffffff"><strong>NOTIFICATION OF SOME KIND</strong></span></td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: right; width: 136px;">
    <strong>Company:</strong></td>
    <td style="font-family: Arial;" colspan="2">
    $COMPANY_NAME$</td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: right; width: 136px;">
    <strong>CIT Account:</strong></td>
    <td style="font-family: Arial;" colspan="2">
    $CIT$</td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: right; width: 136px;">
    <strong>Customer:</strong></td>
    <td style="font-family: Arial;" colspan="2">
    $CUST_ID$</td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: right; width: 136px;">
    </td>
    <td colspan="2" style="font-family: Arial">
    $CUST_NAME$</td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: right; width: 136px;">
    </td>
    <td colspan="2" style="font-family: Arial">
    $ADDR1$</td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: right; width: 136px;">
    </td>
    <td colspan="2" style="font-family: Arial">
    $ADDR2$</td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: right; width: 136px;">
    </td>
    <td colspan="2" style="font-family: Arial">
    $ADDR3$</td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: right; width: 136px;">
    </td>
    <td colspan="2" style="font-family: Arial">
    </td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: right; width: 136px;">
    Phone #:</td>
    <td colspan="2" style="font-family: Arial">
    $PHONE$</td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: right; width: 136px;">
    Fax #:</td>
    <td colspan="2" style="font-family: Arial">
    $FAX$</td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: right; width: 136px;">
    Buyer:</td>
    <td colspan="2" style="font-family: Arial">
    $BUYER$</td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: right; width: 136px;">
    </td>
    <td colspan="2" style="font-family: Arial">
    </td>
    </tr>
    <tr>
    <td colspan="3" style="border-right: lavender thin solid; border-top: lavender thin solid;
    border-left: lavender thin solid; color: #ffffff; border-bottom: lavender thin solid;
    font-family: Arial; background-color: #cc0033; text-align: left">
    <strong>LISTING OF APPROVALS ON $TODAY$</strong></td>
    </tr>
    <tr>
    <td style="font-family: Arial; text-align: center; border-right: lavender thin solid; padding-right: 0px; border-top: lavender thin solid; padding-left: 0px; padding-bottom: 0px; border-left: lavender thin solid; width: 136px; padding-top: 0px; border-bottom: lavender thin solid;">
    <strong>
    Order #</strong></td>
    <td style="font-family: Arial; text-align: center; border-right: lavender thin solid; padding-right: 0px; border-top: lavender thin solid; padding-left: 0px; padding-bottom: 0px; border-left: lavender thin solid; width: 324px; padding-top: 0px; border-bottom: lavender thin solid;">
    <strong>
    Amount Withdrawn</strong></td>
    <td style="border-right: lavender thin solid; padding-right: 0px; border-top: lavender thin solid;
    padding-left: 0px; padding-bottom: 0px; border-left: lavender thin solid; width: 324px;
    padding-top: 0px; border-bottom: lavender thin solid; font-family: Arial; text-align: center">
    <strong>Shipping Period</strong></td>
    </tr>
    <tr>
    <td style="border-right: lavender thin solid; padding-right: 0px; border-top: lavender thin solid;
    padding-left: 0px; padding-bottom: 0px; border-left: lavender thin solid; width: 136px;
    padding-top: 0px; border-bottom: lavender thin solid; font-family: Arial; text-align: center">
    $ORDER$</td>
    <td style="border-right: lavender thin solid; padding-right: 0px; border-top: lavender thin solid;
    padding-left: 0px; padding-bottom: 0px; border-left: lavender thin solid; width: 324px;
    padding-top: 0px; border-bottom: lavender thin solid; font-family: Arial; text-align: center">
    $AMOUNT$</td>
    <td style="border-right: lavender thin solid; padding-right: 0px; border-top: lavender thin solid;
    padding-left: 0px; padding-bottom: 0px; border-left: lavender thin solid; width: 324px;
    padding-top: 0px; border-bottom: lavender thin solid; font-family: Arial; text-align: center">
    $PERIOD$</td>
    </tr>
    </table>
    <br />
    <span style="font-size: 10pt; color: #0000ff; font-family: Century Gothic"><span
    style="color: blue">Thanks for your business,<br />
    Some company. Etc..</span></span>

    </body>
    </html>



    Thursday, November 1, 2007 8:20 PM
  • add a new html file to your project and overwrite source with what i had in my last message. then view in designer mode.
    Thursday, November 1, 2007 8:22 PM
  • Yeah I've done something like that before for other situations.

    The problem is, some of the reports I'm working with right now are somewhat intricate, and we want to use the same report definition for all formats and venues of the report. We're actually hard coding the definition into a resource of an assembly so we can deploy it over web or on a windows client or in a windows service, etc.

    I like your idea; I've used that before. It might be that we have to just do that for this situation, but I'm definitely still open to finding other ways to use the report definition and a data source to generate output in any format we need. I may just need to create my own ReportExtension to generate a simplified HTML output or something like that.  It might be a little over kill at the moment though.

    Thanks!
    Nathan
    Thursday, November 1, 2007 9:05 PM
  • >>I'm definitely still open to finding other ways to use the report definition and a data source to generate output in any format we need.

     

    Then I think you should give XSLT on top of the data output a try...

     

    http://spacefold.com/lisa/post/Changing-the-Sheet-names-in-SQL-Server-RS-Excel-QnD-XSLT.aspx

     

    ... and if you can allow for programmatic wrapping of the pull (where you apply the XSLT yourself instead of the "automagic" assignment) please read the followup here...

     

    http://spacefold.com/lisa/post/After-you-learn-to-walk%2c-you-can-run-a-postscript-to-the-QnD-XSLT-walkthrough.aspx

     

    In this example I was resolving a simple and common question about dealing with Excel output, but in reality you can do pretty much anything you want, and you can have one XSLT be very generic, with or without some extra metadata "hints".

     

    By "hints" I mean that you include some data regions in the report whose purpose is to provide extra instructions, such as (for example) the friendly column names you'd like to use for any and all columns that might appear in the output, and/or the current values of all parameters.

     

    I know people think I'm daft on this subject, but really. 

     

    >L<

    Thursday, November 1, 2007 9:21 PM
  • I remember when I was going nuts almost making my own data provider lol...  let me know if you actually make an html renderer, but I have just one tip.  make a dummy one first and make sure it works in local processing mode. they seem to have drastically reduced many things out of it, and as much as I like using it... sometimes it just becomes useless when it's missing basic features like export, oh yeah and the print button. I mean come on... the print button!!?? that's a slap in the face
    Thursday, November 1, 2007 9:31 PM
  • Hi,

    If I take format as HTML4.0 or HTML3.2 images are not loading from SSRS 2005.
    How can I load images into html file?

    -Thanks

    Thursday, May 7, 2009 10:52 AM