When I want to have a great deal of control of what prints out I use the ReportViewer control and report designer that comes with Visual Studios (you can also download the viewer for Visual Web Developer 2005: http://www.microsoft.com/downloads/details.aspx?familyid=8a166cac-758d-45c8-b637-dd7726e61367&displaylang=en). Because the report viewer can create a PDF document, you have a great deal of control over how the document.
You create a datatable thatholds all of the dynamic data, then load it in code, and use that for the report viewer datasource. If you just drop the report viewer control on the page and wire it up simply, the user will see a copy of the data and have the option to export to either of Excel of PDF (there are "hacks" to get other formats, if you want to serach for them).
If you want to go the extra mile, you can just use the report view in code and server up a PDF (or whatever) without having to mess with the UI of the report viewer. Yor code would look something lihe the following:
Dim report As LocalReport = New LocalReport
report.ReportPath = Server.MapPath("~/" + rdlcPath)
Dim rptDS As ReportDataSource = Nothing
Dim Ps As New System.Collections.Generic.List(Of ReportParameter)
Ps.Add(New ReportParameter("AnyNeededParam",paramValue))
report.SetParameters(Ps)
Select Case reportSelect
Case "NormalReport"
Using ta As New StudentInspectorTableAdapters.SIFInformationTableAdapter
rptDS = New ReportDataSource("neededDataSource", ta.GetData())
End Using
Case Else
End Select
report.DataSources.Add(rptDS)
Dim deviceInfo As String = _
"<DeviceInfo>" & _
" <OutputFormat>PDF</OutputFormat>" & _
" <PageWidth>11in</PageWidth>" & _
" <PageHeight>8.5in</PageHeight>" & _
" <MarginTop>1in</MarginTop>" & _
" <MarginLeft>1in</MarginLeft>" & _
" <MarginRight>1in</MarginRight>" & _
" <MarginBottom>1in</MarginBottom>" & _
"</DeviceInfo>"
Dim Warnings As Warning() = Nothing
Dim streams As String() = Nothing
Dim mimeType As String = Nothing, encoding As String = Nothing, fileNameExtension As String = Nothing
Dim renederedBytes As Byte() = report.Render(Request("m"), deviceInfo, mimeType, encoding, fileNameExtension, streams, Warnings)
Response.Clear()
Response.ContentType = mimeType
Response.AddHeader("content-disposition", "attachment; filename=Report." + fileNameExtension)
Response.BinaryWrite(renederedBytes)
Response.End()
Some of the variables above need to be defined in your code (e.g. rdlcPath), but what it's looking for shouldn't be cryptic. This code could go anywhere from Load to Prerender, just remember to buffer the output and do not flush any data (you can not change, or add, headers after you start flushing data... which would be problematic).
Failure is always an option. Avoid situations where it is the only option.