views:

635

answers:

1

I am unsure how to go about exporting my ActiveReports report document to XLS in my asp.net mvc app.

My concept so far is to have a dropdown of export types and a submit button that submits that value to my controller. When I'm on the controller, I regenerate the report and pass it to my Export method. I'm not sure what to have this Export method return. I'm also getting an out of range error on the actual xlsExport.Export method. Below is my Export method. Also to note, reportBase.Report is an ActiveReport3 object.

private ActionResult Export(ReportBase reportBase)
     {
      Response.ClearContent();
      Response.ClearHeaders();

      var exportType = Request.Form["exportType"];

      switch (exportType)
      {
       case "RTF":
        Response.ContentType = "application/octet-stream";
        Response.AddHeader("Content-Disposition", "attachment;filename=report.rtf");
        var rtfExport = new RtfExport();
        rtfExport.Export(reportBase.Report.Document, Response.OutputStream);
        break;
       case "TIFF":
        Response.ContentType = "image/tiff";
        Response.AddHeader("Content-Disposition", "attachment;filename=report.tif");
        var tiffExport = new TiffExport();
        var filePath = System.IO.Path.GetTempFileName();
        tiffExport.Export(reportBase.Report.Document, filePath);

        var fileStream = System.IO.File.Open(filePath, System.IO.FileMode.Open);
        var bufferLength = (int)fileStream.Length;
        var output = new byte[bufferLength];
        var bytesRead = fileStream.Read(output, 0, bufferLength);

        Response.OutputStream.Write(output, 0, bytesRead);
        System.IO.File.Delete(filePath);
        break;
       case "XLS":
        Response.ContentType = "application/octet-stream";
        Response.AddHeader("Content-Disposition", "attachment;filename=report.xls");
        var xlsExport = new XlsExport();
        xlsExport.Export(reportBase.Report.Document, Response.OutputStream);
        break;
      }

      Response.Flush();
      Response.End();

      return View("Display", reportBase);

     }
+4  A: 

I don't have an answer for your issue. Including the full exception message would be helpful. There's not enough information for me to help you, but I'd check to make sure reportBase.Report.Document isn't null.

However, I do want to comment on your code in general. Your controller action isn't following the conventions of ASP.NET MVC. It shouldn't be writing directly to the reponse stream. Firstly, it's hard to unit test. Second, it tends to make your action explode in responsibility (it's already about 4 times larger than I prefer my largest controllers to be) The Response.End is cutting the action short and the "return View()" does nothing. I would do something like:

var exportType = Request.Form["exportType"];
switch (exportType)
{
  case "RTF":
    return new RtfExportResult(reportBase.Report.Document);
  case "TIFF":
    return new TiffExportResult(reportBase.Report.Document);
  case "XLS":
    return new XlsExportResult(reportBase.Report.Document);
}

return View("Error"); // unsupported export type

Then your XlsExportResult would look like:

public class XlsExportResult : ActionResult
{
    private readonly Document document;

    public XlsExportResult(Document document)
    {
        this.document= document;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        var response = context.HttpContext.Response;
        response.ContentType = "application/octet-stream";
        response.AddHeader("Content-Disposition", "attachment;filename=report.xls");
        var xlsExport = new XlsExport();
        xlsExport.Export(this.document, response.OutputStream);
    }
}

You could then write tests to exercise only the XlsExport part more easily. (I'd also find a way to hide XlsExport behind an interface.) With some creativity (adding additional prperties for things like file name, etc) you'll be able to reuse the *Result classes across your project.

Talljoe
Thanks Talljoe! Not only did this make my code look much nicer, it solved the problem. I wasn't sure how to manipulate the response the MVC way. Thanks for the help!
Aaron Palmer