« Simplify Authorization for Team Project Creation | Main | Elimination of ADAM from TFS »

May 09, 2005

Eliminate ctl00oReportCell error in Team System Project Portal

Visual Studio Team System includes a Project Portal site built on Windows Sharepoint Services (WSS). The Project Portal provides a convenient snapshot of the project's health and can be shared by everyone involved.

Unfortunately, the Beta 2 release contains a very annoying bug when displaying any of the reports in the Project Portal. Each report on the page pops up a message box stating "Unable to locate control: ctl00oReportCell". For the default home page, that means three message boxes everytime you load it.

I've been working on a review of Team System for one of my clients and didn't want to interrupt the presentation with these constant error dialogs. And, quite frankly, I was tired of clicking on them myself. I tried a number of tricks and came up a change to the report url didn't cause the error, but nothing was really satisfactory. So, I sat down today and fixed the problem at the source.

If you're not interested in the technical details and are not concerned about modifying the default security permissions of SQL Reporting Services (in other words, "If you trust me!"), just download this zip file and save it as: %ProgramFiles%\Microsoft SQL Server\MSSQL.3\Reporting Services\ReportServer.zip then rightt click on the file and select 'Extract All...', 'Next', 'Next', 'Yes to All', and 'Finish'.

Otherwise, read on....

The error dialog displayed in the Project Portal is caused by a bug in the SQL Reporting Services April CTP page rendering when the report toolbar is not displayed. A bit of javascript is emitted before the table that the script references. IE tries to execute the script before the table containing the cell name 'ctl00oReportCell' is created, the script fails, and the error dialog is displayed.

The bug can be patched by wrapping the ASP.NET control responsible for generating the report and overriding its protected Render method.

  1. Create a new C# 'Class Library' project in Visual Studio and paste in the following code:

    using System;
    using System.IO;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Web.UI;
    using Microsoft.ReportingServices.WebServer;

    namespace Amaxo.ReportingServices.ReportViewerHostExtension
    {
      public class HostExtension : ReportViewerHost
      {
        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
          if ( ! base.ShowToolBar)
           {
            StringBuilder stringBuilder = new StringBuilder();
            StringWriter stringWriter = new StringWriter(stringBuilder);
            HtmlTextWriter htmlTextWriter = new HtmlTextWriter(stringWriter);

             // Get the HTML for the report
            base.Render(htmlTextWriter);

            // Move the <script> element to the end
            string modifiedHtml = Regex.Replace(
                stringBuilder.ToString(),
            "(?<badScript><script>[^<]*</script>)(?<rest>.*)",
               "${rest}${badScript}",
               RegexOptions.Singleline);

            // Send the modified HTML to the browser
             writer.Write(modifiedHtml);
          }
        else
           base.Render(writer);
        }
      }
    }
  2. Add a reference to System.Web and to the ReportingServicesWebServer.dll assembly. It's located in the %ProgramFiles%\Microsoft SQL Server\MSSQL.3\Reporting Services\ReportServer\bin directory on the TFS server.
  3. Generate your own public/private key pair and use it to assign a strong name to the project, then build it.
  4. Copy the resulting dll to the same directory as the dll that you referenced in step 2.
  5. Now, we need to make the report server use the wrapper assembly.
    Make a backup copy of %ProgramFiles%\Microsoft SQL Server\MSSQL.3\Reporting Services\ReportServer\Pages\ReportViewer.aspx and replace the original with the following ASP code:

    <%@ Register TagPrefix="RS"
        Namespace="Amaxo.ReportingServices.ReportViewerHostExtension"
      Assembly="ReportViewerHostExtension" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <title>Report Viewer</title>
      </head>
      <body style="margin: 0px; overflow: auto">
        <form runat="server" ID="ReportViewerForm">
        <RS:HostExtension runat="server" />
        </form>
      </body>
    </html>
  6. We need to make sure that the wrapper assembly is included as a reference when the ASP.NET page is compiled, so we need to add the following element to the web.config file at %ProgramFiles%\Microsoft SQL Server\MSSQL.3\Reporting Services\ReportServer\web.config

    <compilation defaultLanguage="c#" debug="false">
      <assemblies>
        <clear />
        <add assembly="ReportingServicesWebServer" />
        <add assembly="ReportViewerHostExtension" />
      </assemblies>
    </compilation>
  7. If you try to access the Report Server now, you'll get an error because your new assembly isn't trusted. We'll need to edit the security permissions by adding the following element to the Report Servers configuration policy file at %ProgramFiles%\Microsoft SQL Server\MSSQL.3\Reporting Services\ReportServer\rssrvpolicy.config. Add it immediately after the element for Report_Server_Strong_Name.

    <CodeGroup
        class="UnionCodeGroup"
        version="1"
        PermissionSetName="FullTrust"
        Name="Amaxo_Strong_Name"
        Description="This code group grants Amaxo code full trust.">
      <IMembershipCondition
        class="StrongNameMembershipCondition"
        version="1"
        PublicKeyBlob="your public key blob"
      />
    </CodeGroup>
  8. Now since you don't trust me, you'll need to get the PublicKeyBlob for your new assembly. Run the following command from a Visual Studio 2005 command prompt:

    secutil.exe -hex -s <your assembly>
  9. Copy the value of the 'Public Key' in place of the "your public key blob" text in the policy file.
  10. Restart IIS.

You should now be able to refresh the project portal without any unsightly error dialogs.

Posted by Mike Attili at May 9, 2005 10:16 PM

Comments

Thanks for posting this! Just a couple of points I ran into when doing these steps:

When compiling your code above on a clean Beta 2 machine, I get the following errors:

Error 1 The type or namespace name 'UI' does not exist in the namespace 'System.Web' (are you missing an assembly reference?) C:\Projects\AmaxoReportViewerHostExtension\AmaxoReportViewerHostExtension\Class1.cs 5 18 AmaxoReportViewerHostExtension

Error 2 The type 'System.Web.UI.WebControls.CompositeControl' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. C:\Projects\AmaxoReportViewerHostExtension\AmaxoReportViewerHostExtension\Class1.cs 10 15 AmaxoReportViewerHostExtension

Error 3 The type 'System.Web.UI.IPostBackEventHandler' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. C:\Projects\AmaxoReportViewerHostExtension\AmaxoReportViewerHostExtension\Class1.cs 10 15 AmaxoReportViewerHostExtension

Error 4 The type or namespace name 'UI' does not exist in the namespace 'System.Web' (are you missing an assembly reference?) C:\Projects\AmaxoReportViewerHostExtension\AmaxoReportViewerHostExtension\Class1.cs 12 45 AmaxoReportViewerHostExtension


To fix that, I did exactly that, went to the References dialog and added "System.Web 2.0.0.0". Everything built/compiled fine.

Also ended up having to create a private/public key, signing the assembly and then using the secutil program. The secutil kept throwing an exception about the assembly not having a strong name.

Posted by: Michael Shorten at May 10, 2005 12:35 PM

Michael, I've updated steps 2 and 3 to be more explicit. Thanks for the feedback.

Posted by: Mike at May 10, 2005 12:59 PM

I patched the report serverice with the ReportServer.zip file but the report service can't start.
The log file :ReportingServicesService!servicecontroller!4!5/14/2005-22:08:31:: e ERROR: Exception caught loading and setting code permissions policy level: System.Security.XmlSyntaxException: Invalid syntax.
at System.Security.SecurityDocument.InternalGetElement(Int32& position, Boolean bCreate)
at System.Security.SecurityDocument.GetElement(Int32 position, Boolean bCreate)
at System.Security.Util.Parser.GetTopElement()
at System.Security.Policy.PolicyLevel.Load(Boolean quickCacheOk)
at System.Security.Policy.PolicyLevel.IndividualCheckLoaded(Boolean quickCacheOk)
at System.Security.Policy.PolicyLevel.CheckLoaded(Boolean quickCacheOk)
at System.Security.SecurityManager.LoadPolicyLevelFromFile(String path, PolicyLevelType type)
at Microsoft.ReportingServices.Library.ServiceController.SetAppDomainPolicy()
ReportingServicesService!servicecontroller!4!5/14/2005-22:08:31:: Error Starting Service: System.Security.XmlSyntaxException: Invalid syntax.
at System.Security.SecurityDocument.InternalGetElement(Int32& position, Boolean bCreate)
at System.Security.SecurityDocument.GetElement(Int32 position, Boolean bCreate)
at System.Security.Util.Parser.GetTopElement()
at System.Security.Policy.PolicyLevel.Load(Boolean quickCacheOk)
at System.Security.Policy.PolicyLevel.IndividualCheckLoaded(Boolean quickCacheOk)
at System.Security.Policy.PolicyLevel.CheckLoaded(Boolean quickCacheOk)
at System.Security.SecurityManager.LoadPolicyLevelFromFile(String path, PolicyLevelType type)
at Microsoft.ReportingServices.Library.ServiceController.SetAppDomainPolicy()
at Microsoft.ReportingServices.Library.ServiceController.StartService()

Posted by: jackie at May 14, 2005 11:35 AM

Thanks for your patch.But when I applied the patch,the report server service can't start.

Posted by: jackie at May 15, 2005 10:36 AM

Thanks, Mike! That's a much better fix than hacking the URLs in the web parts for each new project that's made.

Posted by: Carl Daniel at May 16, 2005 12:02 AM

Jackie,
Sorry for the delay responding. I have comment moderation turned on and don't always get notifications when a new comment is posted.

The original upload contained a bad encoding in the rssrvpolicy.config file. This caused ReportingServices to throw an exception when it tried to load the file on service startup.

I've corrected the problem. If you download and unzip the files again, you should be good to go. My apologies for the screw up.

Posted by: Mike at May 17, 2005 12:50 AM

this is the error when a form authentication example so pls help me how to solve my problem
when i type http:\\localhost\reportserver it is giving me the error as follows

Server Error in '/ReportServer' Application.
--------------------------------------------------------------------------------

Invalid syntax on line 174 - Unexpected end of file..
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Security.XmlSyntaxException: Invalid syntax on line 174 - Unexpected end of file..

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:


[XmlSyntaxException: Invalid syntax on line 174 - Unexpected end of file..]
System.Security.Util.Parser.ParseContents(SecurityElement e, Boolean restarted) +2607
System.Security.Util.Parser..ctor(Tokenizer t) +67
System.Security.SecurityManager.LoadPolicyLevelFromString(String str, PolicyLevelType type) +115
System.Web.HttpRuntime.CreatePolicyLevel(String configFile, String appDir, String binDir, String strOriginUrl) +475
System.Web.HttpRuntime.SetTrustLevel() +201
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +403

[HttpException (0x80004005): ASP.NET Initialization Error]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +928
System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr) +128


--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:1.1.4322.573; ASP.NET Version:1.1.4322.573

Posted by: jagan at May 30, 2005 08:20 AM

Post a comment




Remember Me?