Master Report from console application

Andrew Kazyrevich
 
Master Report solution we discussed in the previous post works great but it lacks automation: someone has to go and manually select the master and child templates in order to get the combined result.

But what if we needed to email a few dozens of such reports every day and didn’t want to hire a monkey?

Then we’d probably need a scheduled task which would run daily and generate those reports based on some input parameters and email them over. Seems like a hard one for SharpShooter? Not at all – read on for the solution!

High level solution.

So we create a new console app with Main like this:

   /// 
   /// Usage: [app.exe] /master:"path" /child:"path" /saveAs:"path"
   /// 
   static void Main(string[] args)
   {
      var masterPath = args[0].Replace("/master:", "");
      var childPath = args[1].Replace("/child:", "");
      var saveAsPath = args[2].Replace("/saveAs:", "");

      var generator = new ReportGenerator(masterPath, childPath, saveAsPath);
      generator.Run();
   }

Yes it lacks quite a bit of error checking but I’d leave it as an exercise to the reader ;)
 
Internally, the above ReportGenerator might seem a bit complicated as we’d have to solve one big problem there: how to generate a report without showing a windows form. Interested? Let’s look inside!

Implementation details.

We need a WinForm due to the asynchronous nature of SharpShooter: without a form it cannot properly operate its threads. However, it’s possible to create a hidden form just for the generation timespan, and close it immediately afterwards. That’s exactly the trick we’ll employ.

Below is the constructor of our generator:

   public ReportGenerator(string masterPath, string childPath, string resultPdfPath)
   {
      ApplyReport(_masterSlot, masterPath);
      ApplyReport(_childSlot, childPath);
      _resultPdfPath = resultPdfPath;

      var hiddenForm = new Form {
            FormBorderStyle = FormBorderStyle.FixedToolWindow,
            ShowInTaskbar = false,
            StartPosition = FormStartPosition.Manual,
            Location = new Point(-2000, -2000),
            Size = new Size(1, 1),
            Text = "Hidden form to generate reports from a console app"
      };
      _reportManager.OwnerForm = hiddenForm;
      _reportManager.Reports.AddRange(new[] { _masterSlot, _childSlot });
      _reportManager.ResolveSubReport += (sender, args) => {
            if (args.TemplateName.EndsWith("Master")) {
                  args.Template = _masterSlot.LoadReport();
            }
      };
   }

Above, we do a bunch of interesting things:

  • setup master and child report slots via ApplyReport method which is not important enough to show here
  • create a hidden Windows Form which becomes “owner form” for our report manager
  • setup ResolveSubReport so that it would correctly setup master template in case the child template requires it

So far so good, and now let’s look at the Run method:

   public void Run()
   {
      try {
         var filter = new PdfExportFilter();
         filter.Export(_childSlot.RenderDocument(), _resultPdfPath, false);
      }
      finally {
         if (_reportManager.OwnerForm != null) {
            _reportManager.OwnerForm.Close();
         }
      }
      //to test email sending, uncomment and update:
      //var message = new MailMessage("[email protected]", "[email protected]") {
      //    Subject = "Report",
      //    Body = "Please find the report pdf attached"
      //};
      //message.Attachments.Add(new Attachment(_resultPdfPath));
      //var emailClient = new SmtpClient("smtp.bar.com");
      //emailClient.Send(message);
   }

As you see, we export the generated report as a .pdf file and dispose the hidden form – voilà, job done! (If you want to test email sending, the feel free to uncomment and update appropriately the corresponding snippet above.)
 
Here’s how we use the whole thing:
 

 
And here’s the .pdf generated with the master/child templates from the previous post (the “Happy New Year” header comes from the master template, while the zipcode comes from the child one):
 

 

Summary.

Console applications can work with SharpShooter, too – you’re not constrained to WinForms interfaces.
 
Coding is slightly odd though, but using SharpShooter from a console app opens up a way to a throng of new usages, autonomous scripts which would generate reports, email them, send them over SFTP and do all sorts of things, all of which – potentially – completely automatically.
 
Feel free to browse source code of the solution, or download .zip archive – and, indeed, Happy New Year 2012! :)
 

December 26th, 2011

Leave a Comment