Avoid using HttpContext in your reports
On one of our internal mailing lists, someone was asking trying to retrieve some HTTP Headers that their internal application was submitting to the Report Server within the report. Someone else responded with a code snippet containing the custom code that you can put into an RDL expression to do just that.
This is a bad idea.
HttpContext has the interesting property of exposing per-request state via a static property. Inherently, there is nothing really wrong this approach. It allows access to data without having to plumb the data all of the way through every single API or object on the call stack. However, one gotcha here is that HttpContext is only available on the thread that received the request, and not on any asynchronous threads that may be spawned by that request. This can lead to subtle problems in your reports under the following conditions:
- When printing the report, the Report Server actually uses an asynchronous mechanism to render the report in order to return the first page quickly while continuing to render the additional pages in the background.
- In the case of a subscription delivery, there is actually no HTTP Request that initiated the request.
Additionally, in the future we will more than likely be making additional portions of report execution asynchronous to improve both perceived latency as well as taking advantage of multi-core processors during non-peak load.
That said, there are a couple of scenarios I can think of where you might be tempted to examine the HTTP Request during report execution. These are:
- You want to determine the path or location of the report, and you are doing so by examining the incoming request URL.
- Your application is passing some value to the report via an HTTP header.
For each of these, there are built-in supported mechanisms. For (1), there is a set of values exposed by the global collections which allow to get information about the report server and the context report. For example, there are Globals.ReportFolder, Globals.ReportName, and Globals.ReportServerUrl. You can leverage these variables in report expressions rather than trying to tease apart the HTTP Request.
In the case of passing data to the report via an HTTP Header, there is already a built-in mechanism for passing data to a report execution. They are called report parameters. They are useful for more than just providing query parameters! You can use them to also pass application-specific information that some of your custom code may require.
So what is the moral of the story? Be very careful when accessing static objects that are request-specific in the context of your report via custom code. Doing so exposes you to potential back-compat issues as we continue to bring the platform forward. Wherever possible we try to expose enough context through the supported report processing and rendering object models, and if there are additions you need we would love to hear about them.