Building Report-enabled Applications with the New ReportViewer Controls (Part 2 of 2)

n the first part of this article, you saw how to use the Windows Forms version of the ReportViewer control. This article walks you through the differences and discusses the process for using the Web version of the control.

Comparing the Report Viewers
To minimize the learning curve, the Report Services (RS) team has gone to great lengths to unify the appearance and programming interfaces of the WinForms and Web report viewers. Still, there are some notable discrepancies because they target different platforms.

You’ll find the Web ReportViewer programming model very similar (but not identical) to the WinForms ReportViewer. For example, both controls expose the same set of properties to control the processing mode and toolbar. Similarly, you can add the Web ReportViewer control to a Web form by dragging it from the Data section of the VS.NET Toolbox and dropping it on the form. Both controls have the same look and feel, support remote and local processing modes, and expose similar object models.

Naturally, there are architectural differences between the two report viewers that reflect the constraints of the underlying technology. For example, the WinForms ReportViewer is responsible for both requesting and rendering the report, while the Web ReportViewer delegates report rendering to the browser. From a deployment standpoint, you need to distribute the WinForms ReportViewer to each computer that will run your WinForms application. In comparison, the Web ReportViewer requires zero client deployment because you need to install the control on the Web server only.

?
Figure 1. Opening WebReporter: Open the ASP.NET project as a Web site from the local IIS server.

Another noticeable difference is that the default presentation format of the WinForms ReportViewer is GDI (through the new RGDI extension) renderable by any WinForm-based .NET 2.0 client. In contrast, the Web ReportViewer renders reports in HTML (see this MSDN page for more information about browser support). Finally, the WinForm ReportViewer uses the .NET framework for report printing, while the Web ReportViewer performs this task by downloading an ActiveX control from the server.

Because of their similarities, discussing the Web ReportViewer in detail would be redundant. Instead, this article demonstrates both processing modes by emphasizing the architectural and integration differences.

You can find the code samples accompanying this article in the WebReporter folder created by unzipping the downloadable WebReporter sample project. To test the security scenarios discussed in this article, make sure to open the sample Web application as a Web site in order to execute the code under IIS. To do so, create an IIS virtual folder named WebReporter) that points to the WebReporter physical folder. Next, open VS.NET 2005 and open the application straight from IIS by choosing File ?> Open ?> Web site (see Figure 1). If you open the project from the file system (a new capability with VS.NET 2005), you’ll find that the Windows security samples don’t work as expected. That’s because, in File System mode, VS.NET always executes the application under your identity. For your convenience, the download contains a VS.NET solution (WebReportReviewer.sln) that hosts both the WebReporter Web site and the sample reports in one solution.

Remote Mode
As you may recall from the Part 1 of this article, in remote mode, the ReportViewer control acts as a presentation layer to the Report Server. Figure 2 shows the architectural view of the remote processing mode with Web applications. The important point here is that the Web ReportViewer submits the report request on the server side of the application. The client (Web browser) never accesses the server directly. Instead, report processing follows these steps:

?
Figure 2. Remote Mode: In remote mode, the Web Report Viewer submits report requests to the Report Server.
  1. Server-side ASP.NET code configures the control to request a given report.
  2. The Web ReportViewer calls the Report Server to generate the report.
  3. The Web ReportViewer streams the report payload to the browser that renders the report.

Developers who have implemented server-side report generation with RS 2000 are aware of the complexities surrounding this integration scenario. For example, extra steps were required to handle report images and correlate report requests with Report Server sessions. In addition, the report interactive features didn’t work. These limitations simply disappear with the Web ReportViewer. How is this possible?

The ReportViewer HttpHandler
When you add the ReportViewer control to your form, it automatically registers a special ASP.NET HttpHandler (Reserved.ReportViewerWebControl.axd), as you can see by examining the application Web.config file. The HttpHandler is an integral part of the Web ReportViewer control. You must not remove or unregister it even if the report doesn’t require images or interactive features. In addition,?ASP.NET session state must be turned on. If this conflicts with the operational requirements of your application, note that the HttpHandler supports a certain degree of customization (see the MSDN document “Web.config Settings for ReportViewer“?for more details).

The main responsibilities of the HttpHandler include handling images, exporting reports to other report formats, supporting report sessions and interactive features. For example, if a report uses an embedded image, the browser submits an HTTP-GET request to the HttpHandler to fetch the image. The ReportViewer HttpHandler interfaces are not documented and are for internal use only. However, rest assured that the Web ReportViewer doesn’t send the report path or report parameters. The only Report Server-specific parameter is the session identifier used to correlate the report request with the client.

?
Figure 3. Requesting Reports: The Web Report Viewer demonstrates requesting reports in remote and local processing modes.

The Web Report Viewer Demo
Similar to its WinForms counterpart, the Web Report Viewer sample application demonstrates the remote and local processing modes (see Figure 3). When the end user clicks on the “Run Report” button, the page posts back to itself and invokes the RunRemote function.

   private void RunRemote()     {      reportViewer.ProcessingMode =         Microsoft.Reporting.WebForms.ProcessingMode.Remote;       // Get the Report Server endpoint from        // the config file       reportViewer.ServerReport.ReportServerUrl = new Uri(          ConfigurationManager.AppSettings[          "ReportServerEndPoint"]);       reportViewer.ServerReport.ReportPath =           "/Prologika/Customer Orders";   }

The code configures the Web ReportViewer in remote mode. Then, it sets the ServerReport.ReportServerUrl property to the Report Server URL. Finally, it tells the Web ReportViewer which report to render by setting its ReportPath property. As with the WinForms ReportViewer, the Web ReportViewer automatically generates a toolbar to handle common reporting tasks. This is the same toolbar you will see when running a report in the Report Manager, which uses the Web ReportViewer behind the scenes.

Author’s Note: There is an annoying bug with the initial release of the Web ReportViewer when using absolute positioning and multi-value parameters. Because multi-value parameters use absolute positioning, placing the Web ReportViewer at absolute CSS coordinates upsets the parameter handling logic?specifically, trying to expand the parameter results in a page postback instead of showing the parameter values. As of the time of this writing, the only workaround is to use flow positioning for the control.

Handling Report Parameters
Report parameters are handled automatically by the control. If a parameter is required, the end user can enter the parameter value and click the “View Report” button. This causes the page to post pack. If your requirements call for more involved parameter handling logic, the application can collect and pass the parameters to the control just like you can do so with the WinForms ReportViewer.

   private void SetParameters()    {      ReportParameter[] parameters = new            ReportParameter[2];      parameters[0] = new ReportParameter("Date",          "1/1/2003");      parameters[1] = new ReportParameter("CustomerID",          new string[] { "14335", "15094" });      reportViewer.ServerReport.SetParameters(parameters);   }

One welcome feature is the ability to export the report inline and bypass the Internet Explorer standard conformation dialog to save the file. To try this feature, set the ExportContentDisposition control property to AlwaysInline and export a report to a format of your choice. Another frequently requested feature was the ability to target a specific frame with URL navigation (Hyperlink action). Use the HyperlinkTarget property to specify the target window (e.g. _top or enter the frame name). Finally, the Web ReportViewer supports a cornucopia of properties to change its appearance (check the Appearance category in the VS.NET Properties window) or apply an ASP.NET skin (SkinID property).

Handling Security
Report-enabling Web applications brings additional challenges, the first and foremost being security. From a deployment standpoint, most Web applications can be categorized as intranet or Internet applications. You can secure the Web ReportViewer to address either of these deployment scenarios.

Intranet Reporting
Intranet applications are deployed and used in an isolated and secured intranet environment. Access to this type of application is restricted to a limited group of authorized users, such as employees who belong to a domain. Figure 4 depicts a typical intranet-based deployment that uses the Web ReportViewer for report delivery.

?
Figure 4. Intranet-based Deployment: Intranet reporting favors Integrated Windows authentication.

From a security standpoint, intranet applications should leverage the Windows Active Directory whenever possible where users are authenticated and authorized by the Report Server based on their domain accounts. For example, in Figure 4, Terri is logged to the AW domain as AW/Terri. Terri then uses the Web Reporter Viewer application to request a report. The Web Report Viewer passes Terri’s credentials to the Report Server. The report administrator can enforce restricted access to the report catalog by assigning the Terri’s Windows account (or Windows groups Terri belongs) to predefined or custom security roles.

Table 1. Configuration Settings: The table shows the configuration settings used for Integrated Windows Authentication.

Application virtual root (vroot) ASP.NET ApplicationWeb.config Report Viewer Report Server
Integrated Windows Authentication DefaultCredentials (default configuration) Windows security (default configuration)

Table 1 outlines the configuration settings to set up intranet security. The ASP.NET application virtual root in IIS is configured for Integrated Windows Authentication. This causes the IIS to initiate a challenge/response during the initial handshake with the browser to authenticate the user using NTLM.

The ASP.NET application must impersonate the user to flow the user credentials to the Report Server. If the Report Server and the ASP.NET application are on the same machine, this could be as easy as changing the application Web.config file (). You don’t need to do anything special to set up the ReportViewer because it will pass the user identity with the Web service call by default (DefaultCredentials=True).

Unfortunately, impersonating the user won’t work if the Report Server and the application are installed on different servers. Besides impersonation, this scenario requires delegation because of the double hop between the application server and report server. To enable cross-machine Kerberos delegation, you need to take additional (not so simple) steps (see Resources). If Kerberos delegation is not an option, the Report Server can be configured for Basic or custom security.

Internet Reporting
In general, Windows Integrated security is not an option for Internet-facing application. An Intranet Web application is typically configured for anonymous access and the user is required to log in with user name and password. Upon login, the application verifies the credentials against the user profile store (e.g. a SQL Server database).

As noted before, if the Web ReportViewer is used for report delivery, the reports are generated on the server side of the application and the browser never accesses the Report Server directly. Therefore, the Report Server doesn’t have to be configured for Internet access (it can remain on the private subnet). As a result, you can consider various security strategies for securing an Internet-facing Web application, including trusted subsystem or custom security.

Author’s Note: No matter the security model chosen, if your reports contain sensitive information, you should secure the data transfer by using the Secure Sockets Layer (SSL) protocol.

Trusted Subsystem
With the trusted subsystem approach, the Report Viewer submits all requests to the Report Server under a single “trusted” Windows account (see Figure 5).

?
Figure 5. Trusted Subsystem: With the trusted subsystem, the Report Server cannot differentiate the Web users.

The application authenticates and authorizes the users as it deems necessary (e.g. using Forms Authentication). When the user requests a report, the ReportViewer submits the request under the same trusted account.

Table 2: Configuration settings for trusted subsystem.

Application vroot ASP.NET ApplicationWeb.config Report Viewer Report Server
Anonymous (typically) or custom application security DefaultCredentials (default configuration) Windows security(default configuration)

The advantage of the trusted subsystem approach is that it is fairly easy to set up. By default, the application will pass the Windows identity it runs under to the Report Server. This will be the ASP.NET process identity (IIS 5.0) or the application pool identity (IIS 6.0).

Tip: If the application runs under IIS 6 (Windows Server 2003), you can change the identity of the application pool, e.g. to use a domain account. As a prerequisite, make sure to add the Windows account that will be used for the pool identity to the Windows 2003 IIS_WPG group. With IIS 5.0 (Windows XP or Windows 2000) you can change the ASP.NET process identity in machine.config, as explained in more detail here. Alternatively, with IIS 5.0, you can change the IIS application protection mode to High and use Component Services to set the identity of the COM+ Application.

When trusted subsystem is used, the Report Server sees all requests coming under the same account as though they come from the same user. In other words, the Report Server won’t be able to differentiate the users. As a result, the users cannot use the My Reports feature. In addition, the report author controls security by using User!UserID property, for example, to pass the user identity to the report data source to restrict the data shown on the report per user. If you need the user identity in your reports, you need to use custom security.

Custom security
Custom security is more flexible than trusted subsystem but it is more difficult to implement and configure because it requires writing a custom security extension. Consider custom security when you need to get the best of both worlds?application based security to authenticate and authorize the users with the ability to pass the user identity to the report server. With custom security, the Web application handles the user authentication and authorization as usual. At some point (e.g. when the user log in), the application calls the LogonUser SOAP API to authenticate the user against the Report Server and obtain an authentication ticket in the form of a cookie. For more information about custom security, read the article “Harden MS Reporting Services Using Custom Extensions.”

Tip: If the Web application uses the ASP.NET Forms Authentication, it is possible to reuse the authentication ticket by following the instructions in the Forms Authentication Across Applications article. This is the approach I followed in the WebReporter demo. When testing the application on your local computer, make sure to launch your application using the machine name, e.g. http:///WebReporter/default.aspx. If you use localhost, the browser will not pass the cookie to the Report Server). This easy-to-overlook gotcha can cause you countless hours of debugging and head scratching.

After setting the Report Server up for custom security, follow these steps to re-configure the WebReporter demo:

In the application Web.config file, comment the and elements to disable Windows authentication.

Again in Web.config, enable Forms Authentication by enabling the settings in the Custom Security block (authentication, identity, and machineKey). After you enable these settings, the application will automatically redirect you to the Login.aspx page when you request the default.aspx page.

In the default.aspx code-behind page, enable the following line

   reportViewer.ServerReport.ReportServerCredentials =       new MyReportServerCredentials();

The Web ReportViewer handles security somewhat differently than the WinForms ReportViewer. Specifically, you need assign an instance of a class that implements the Microsoft.Reporting.WebForms.IReportServerCredentials interface to the ReportServerCredentials property. The IReportServerCredentials interface defines two properties and one method whose purpose is explained in Table 3.

Table 3. IReportServerCredentials Interface: The table lists the properties and methods of the IReportServerCredentials interface.

Property/Method Returns Use When
ImpersonationUser property WindowsIdentity or null to ignore You need to programmatically impersonate the user request to go under a specific Windows account, e.g. when you need more control when implementing the trusted subsystem scenario.
NetworkCredentials property ICredentials or null to ignore Similar to the ReportServerCredentials.NetworkCredentials of the WinForms ReportViewer, use this property for Basic authentication.
GetFormsCredentials method Authentication ticket (cookie) oruser/password/domain You need to configure the ReportViewer with custom security.

Based on your security requirements, you may need to implement only one IReportServerCredentials property (method). For example, if you need to integrate the Web ReportViewer with custom security, you need to implement GetFormsCredentials only; ImpersonationUser and NetworkCredentials should return null. As with the WinForms ReportViewer, for optimum performance, the Web ReportViewer caches the IReportServerCredentials results. For example, if you use custom security, the Web ReportViewer invokes GetFormsCredentials the first time it’s initialized. Behind the scenes, the control will invoke LogonUser and cache the authentication ticket. Subsequent report requests on the same page, such as those stemming from interactive features will use the cached authentication ticket.

If your application uses ASP.NET Forms Authentication, implementing GetFormsCredentials is remarkably simple.

   public bool GetFormsCredentials (out Cookie authCookie,       out string user, out string password, out string       authority)   {      user = password = authority = null;         // The cookie name is specified in the        element in Web.config (.ASPXAUTH by default)      HttpCookie cookie = HttpContext.Current.         Request.Cookies[".ASPXAUTH"];      if (cookie == null)          HttpContext.Current.Response.         Redirect("login.aspx");      Cookie netCookie = new Cookie(         cookie.Name, cookie.Value);      if (cookie.Domain == null) {         netCookie.Domain = HttpContext.Current.Request.         ServerVariables["SERVER_NAME"].ToUpper();      }      netCookie.Expires = cookie.Expires;      netCookie.Path = cookie.Path;      netCookie.Secure = cookie.Secure;      authCookie = netCookie;      return true;    }

First, the code sets the user, password, and authority output arguments to null because we will use the authentication ticket returned by the ASP.NET Forms Authentication infrastructure. Alternatively, if you prefer to work with user credentials, you could set the authCookie argument to null and use the user credentials for authentication. As I mentioned in the first part of this article, caching the user credentials may present a security risk and it should be avoided whenever possible.

Next, the code assumes that the user has already logged in to the application and the ASP.NET Forms authentication ticket is already generated. If this is not the case, the code redirects the user to the login page. If the cookie is present, the only task left is to convert the cookie to a System.Net.Cookie and pass it back to the ReportViewer.

Author’s Note: Passing the authentication ticket from the Web application to the Report Server could be more involved. For example, if both applications are on different domains, the browser will refuse to pass the cookie for security reasons. Trying to change the cookie domain name in GetFormsCredentials won’t help in this case. One workaround is to make the LogonUser call from a page on the Report Server machine so the authentication ticket is bound to the Report Server domain.

Local Mode
The local processing mode of the Web ReportViewer is almost identical to the WinForms ReportViewer, so porting the code from the first part of this article was trivial. There are only a few things worth mentioning.

First, since the external images now reside on the server (not on the local hard drive), you need to set the Value property of the image to its URL address. For example, the URL address of the logo image in the Customer Orders report is http://localhost/WebReporter/Reports/AWC.jpg. To implement this, I changed the GetAppPath embedded function inside the report, as follows:

   Public Function GetAppPath() As String      return  String.Format("http://{0}{1}/",          System.Web.HttpContext.Current.Server.MachineName,          System.Web.HttpContext.Current.         Request.ApplicationPath)   End Function 

As a prerequisite, I had to reference the System.Web.dll in the report properties. In addition, I had to configure the Web ReportViewer to trust this assembly by adding the following line in the RunLocal function:

   reportViewer.LocalReport.      AddTrustedCodeModuleInCurrentAppDomain(      "System.Web, Version=2.0.0.0, Culture=neutral," +       "PublicKeyToken=b03f5f7f11d50a3a");

Finally, due to the different targeted platform, the Web ReportViewer supports a somewhat different set of events. The most noticeable missing event is the Hyperlink event. To implement a similar functionality, I had to change the “Jump to URL” link of the Customer field in the Customer Orders report.

   =Code.GetAppPath() & "default.aspx?customerId="       & Fields!CustomerID.Value

In my case, I wanted the page to post back and pass the customer identifier as a query string when user clicks on the customer field. The Page.Load event reacts to this condition by calling the ReportHyperlink, which can then handle the event any way it deems necessary.

The Web ReportViewer can help you tremendously to report-enable your custom ASP.NET 2.0 applications. You should definitely consider it to reduce the amount of plumbing code required to integrate with Reporting Services. Intranet applications should leverage the Windows security infrastructure already in place. If Internet-facing applications don’t need to pass the user identity to the Report Server, consider the trusted subsystem approach. If this is not the case, configure the Report Server and the ReportViewer for custom security.

I hope that this two-part article gave you a good understanding of how the ReportViewer controls work. From here, I suggest you review the resources available on the ReportViewer Web site. Also, make sure to check the ReportViewer newsgroup on MSDN where you can post questions and get feedback from the technical community.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: