11 Oct 2006

Reporting Services Express Edition using host file redirect to connect to local database.

I had a few reports for an application that needed to be deployed to number of different report servers.  The report servers were Express edition of Reporting Services 2005 with the application database on the same server which helped with the connection limitation of Reporting Services 2005 Express. As the report servers were joined to a domain their computer names have to be unique, the only way application was going to get around this problem was to use host file redirect.  To help with deploying the report I was to going to try to use the host idea, so I added the server name to the localhost entry and tried to run the reports.  Unfortunately this would not work because it looks like the reporting services 2005 express checks the name of the computer, which it gets from the following path HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\ComputerName\ActiveComputerName, against the datasource within the connection if they don’t match then raises an error.

Report Viewer Customizing Printing for Local Report

We had a requirement to allow a front page, which was another local report, to be printed before the report within the report viewer was printed.  As both reports were local reports it was easy to create a print button which allowed us to meet the requirements, here is the code that we used:

   1:  if (this.printFrontingSheetCheckbox.Checked)
   2:  {
   3:   LocalReport frontsheet = front.reportViewer1.LocalReport;
   4:   Export(frontsheet, 8.27f, 11.69f, 0f, 0f, 0f, 0f);
   5:   m_currentPageIndex = 0;
   6:   Print(false);
   7:   
   8:   foreach (Stream s in m_streams)
   9:   {
  10:    s.Close();
  11:   }
  12:   front = null;
  13:  }
  14:   
  15:  LocalReport report = reportViewer.LocalReport;
  16:  Export(report, 11.69f, 8.27f, 0f, 0f, 0f, 0f);
  17:  m_currentPageIndex = 0;
  18:   
  19:  Print(true); foreach (Stream s in m_streams)
  20:  {
  21:   s.Close();
  22:  }
  23:   
  24:  private void Print(bool landscape)
  25:  {
  26:   if (m_streams == null || m_streams.Count == 0)
  27:    return;
  28:   PrintDocument printDoc = new PrintDocument();
  29:   PrinterSettings ps = new PrinterSettings();
  30:   ps.PrinterName = printDialog1.PrinterSettings.PrinterName;
  31:   ps.DefaultPageSettings.Landscape = landscape;
  32:      ps.DefaultPageSettings.PrinterSettings.DefaultPageSettings.Landscape = landscape;
  33:   printDoc.PrinterSettings = ps;
  34:   
  35:   if (!printDoc.PrinterSettings.IsValid)
  36:   {
  37:    string msg = String.Format("Can't find printer \"{0}\".", printDialog1.PrinterSettings.PrinterName);
  38:    MessageBox.Show(msg, "Print Error");
  39:    return;
  40:   }
  41:   printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
  42:   printDoc.Print();
  43:  } 
  44:   
  45:  /// <summary>
  46:  /// Export the given report as an EMF (Enhanced Metafile) file.
  47:  /// </summary>
  48:  private void Export(LocalReport report, float PageWidth, float PageHeight, float MarginTop, float MarginLeft, float MarginRight, float MarginBottom)
  49:  {
  50:   StringBuilder deviceInfosb = new StringBuilder();
  51:   deviceInfosb.Append("<DeviceInfo>");
  52:   deviceInfosb.Append("<OutputFormat>EMF</OutputFormat>");
  53:   deviceInfosb.Append(string.Format("<PageWidth>{0}in</PageWidth>", PageWidth)); 
  54:   deviceInfosb.Append(string.Format("<PageHeight>{0}in</PageHeight>", PageHeight));
  55:   deviceInfosb.Append(string.Format("<MarginTop>{0}in</MarginTop>", MarginTop));
  56:   deviceInfosb.Append(string.Format("<MarginLeft>{0}in</MarginLeft>", MarginLeft));
  57:   deviceInfosb.Append(string.Format("<MarginRight>{0}in</MarginRight>", MarginRight));
  58:   deviceInfosb.Append(string.Format("<MarginBottom>{0}in</MarginBottom>", MarginBottom));
  59:   deviceInfosb.Append(string.Format("</DeviceInfo>"));
  60:   string deviceInfo = deviceInfosb.ToString();
  61:   Microsoft.Reporting.WinForms.Warning[] warnings;
  62:   m_streams = new List<Stream>();
  63:   report.Render("Image", deviceInfo, CreateStream, out warnings);
  64:   foreach (Stream stream in m_streams)
  65:   {
  66:    stream.Position = 0;
  67:   }
  68:  }
  69:   
  70:  /// <summary>
  71:  /// Handler for PrintPageEvents
  72:  /// </summary>
  73:  private void PrintPage(object sender, PrintPageEventArgs ev)
  74:  {
  75:   Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);
  76:   ev.Graphics.DrawImage(pageImage, ev.PageBounds);
  77:   m_currentPageIndex++;
  78:   ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
  79:  } 

Then a new requirement came that we needed to get the report viewer print button to be the same as our print button.  At first I didn’t think it was possible because the button was within the report viewer control, but after looking through all the properties, methods and events we found the print event, which according to the object help, fires after the user prints a report.  This would help because at least we would be able to detect a print event and then print the front page at the end of printing the report.  But a collogue played around with the code and found that the event gets fired first before the printing happens and setting the cancel variable to true stops the report viewer doing the printing then by calling our printing code this allowed us to meet all the requirements.