Posts

When Security and Developers Collide

One of the most outstanding SQL Server 2005 feature is CLR stored procedures. A CLR stored procedure can encapsulate complex .NET code, process data, and pipe the results back to your report. The advantage of using CRL stored procedures is that from a reporting perspective things are very simple. The report just needs to call the CLR stored procedure, as it would call a regular SQL Server stored procedure.


One of my reporting requirements called for passing some XML metadata in the form of a serialized-to-XML object. The stored procedure had to deserialize the object before it can use it. In my case, the object used a custom XML serialization/deserialization by implementing IXmlSerializable interface. My first attempt to deserialize the object from the CLR stored procedure failed abysmally with the following exception:


Cannot load dynamically generated serialization assembly. In some hosting environments assembly load functionality is restricted, consider using pre-generated serializer. Please see inner exception for more information. —> System.IO.FileLoadException: LoadFrom(), LoadFile(), Load(byte[]) and LoadModule() have been disabled by the host.


Initially, I couldn’t understand what was going on since I’ve given my assembly UNSAFE rights, which means that it should be able to do anything. Luckily, googling on this exception brought me to the Vineet’s post which hinted that for security and reliability reasons, SQL Server does not support loading assemblies dynamically. After some experimenting, I was able to fix the issue by following these steps:


1. Sgen the object assembly to produce a pre-generated XmlSerializers assembly.
2. Deploy both the object and XmlSerializers assembly to SQL Server with UNSAFE access. Strangely, I had to deploy also System.Drawing .NET assembly because SQL Server was asking for it.
3. In my CLR database project in VS.NET, add a reference to both the object assembly and the XmlSerializers assembly.
4. Inside the CLR stored procedure, instead of deserializing the object directly, I had to use the XML serializer from the XmlSerializers assembly.


    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void csp_MyStoredProcedure(SqlXml metadata)
    {
       
// Deserialize the object using the XmlSerializers serializer
        FooSerializer serializer = new FooSerializer ();
        Foo f = (Foo)serializer.Deserialize(metadata.CreateReader());
        . . .
    }


So, you need to go through a few development, deployment, and management hoops just to deserialize an object in a CLR stored procedure. Not sure if security is a good justification for this effort though. Moreover, reflecting on the XmlSerializers assembly revealed that it is just a thin wrapper on top of the object assembly. One would say that you never have too much secuirty although, in this case, it certainly feels that way. Are we getting paranoid with security?

Into the Multi-dimensional Space

Lately, I’ve run into a few “multi-dimensional” posts in the public SSRS newsgroup. It seems like more and more people target SSAS 2005 cubes as a reporting source. It looks like I am not the only one who have noticed this trend. Brian Welcker has recently commented about the SSRS-SSAS integration in his Fingerpops blog. Here are some notes based on my experiments with the MDX Query Designer.


Limitations
The promise of the MDX Query Designer (implemented by the SSAS team) is giving the report author a tool to produce easily SSAS-based reports without requiring MDX knowledge. Unfortunately, the MDX Query Designer and SSRS integration has left a substantial ground for improvement. For example, it should allow dropping levels of a parent-child dimension on rows to produce the report similar to this one.


I can produce this report in the SSAS cube browser (or another OLAP browser) in seconds. However, the MDX Query Designer doesn’t allow me to request dimension levels side-by-side. I understand that the SSRS can consume only flattened datasets but this doesn’t explain why the MDX Query Designer lacks behind the cube browser which uses OWC to display the results in a two-dimensional format as well. So, my SSAS-SSRS wish #1 is to see the MDX Query Designer support the same functionality as the SSAS cube browser.


Aggregates
There are two ways to request data from an SSAS cube – cellset (hierarchical) and rowset (two-dimensional). SSRS uses the second format which is, of course, more natural for relational reporting. SSRS is not an OLAP browser and it should be viewed as such. Unfortunately, as a result of flattening the data, the SSAS aggregates (All and level aggregates) are lost. You may wonder why on earth you may need the SSAS aggregates instead of re-calculating them using the SSRS Sum(), Avg(), etc. functions. Well, the short answer is that SSAS may go far beyond the standard aggregate functions. For example, the Account dimension in the report above uses custom operators to roll up account categories. For example, income categories add up while expenses subtract. This is why the Balance Sheet Total in the report is $0. Using account charts is a cornerstone of financial reporting. If you can’t bring the SSAS precious aggregates, you have no other choice but to re-invent SSAS with relational reporting which is something you should avoid.
The good news is that SSRS can ask SSAS for the “lost” aggregates. If this is the case, the Aggregates element of the MdxQuery element in the report RDL file won’t be empty, e.g.:
<Aggregates><Aggregate><Levels /></Aggregate></Aggregates>


Here is a trick to make SSRS ask for aggregates:



  1. Use the graphical MDX Query Designer to produce interactively the report dataset.
  2. Switch to the Layout tab and author your report.
  3. In a texbox inside the report Group, enter the expression =Aggregate(Fields!<FieldName>.Value), where FieldName is the field that you need to aggregate.
  4. Save the report.

If all is well, the Aggregates element will be populated and the Aggregate function will return the SSAS aggregate value. However, the problem in the aggregate story is that:



  • Sometimes SSRS refuses to ask for these aggregates.
  • It is not clear what you could do on your part to help it out.
  • The Aggregates RDL syntax is not documented and you don’t know how to force the MDX query to bring the aggregates.

For example, I attempted to produce the above report by manually creating the MDX statement. While I succeeded to some degree, I wasn’t able bring the aggregates. Neither I was able to produce the sample report with the groups I wanted.


In conclusion, SSAS and SSRS could be a winning combination for OLAP and relational reporting. I hope that future service packs and releases will improve the SSRS and SSAS integration and preserve the fidelity of the cube data.

Web ReportViewer and Multi-value Parameter Bug (or how I spent my weekend)

This weekend, I was working on the second part of my Report Viewers article for DevX. As usual, it all started with an innocent idea which turned out into a whole-day affair. I wanted to demonstrate how to integrate the VS.NET 2005 web ReportViewer with a server report that takes a multi-value parameter. Of course, to save time to lay out the presentation layer, I decided to use absolute positioning for my web controls. Much to my surprise, the ReportViewer wouldn’t expand the multi-value parameter. It would helplessly repost the page each time I would click on a report parameter.


So, I got on an ambitious and arduous quest to find out what I am doing wrong. The most puzzling finding was that the Report Manager (which behind the scenes uses the web Report Viewer) would render the report just fine. This left me utterly perplexed and convinced that I am doing something terribly wrong.  And I’ve started changing stuff around. I fixed a bunch of other issues, including some mysterious DCOM events that were logged in the Event Viewer, but the ReportViewer won’t budge.


Finally, I created a new page, dropped the ReportViewer, and configured at design time, and sure it rendered the report just fine. It turned out that there is a bug with the ReportViewer and multi-value parameters because they use absolute positioning as well. As far as I know, the only workaround for now is to change the hosting page layout to use flow positioning instead.


So, stay away from absolute positioning until this ugly bug is fixed.

RS 2005 RDL Available

In his blog, Brian Welcker (Group Program Manager for Reporting Services) announced yesterday the arrival of the much anticipated RDL 2005 specification.

RS 2005 Tips and Tricks Code Available

The code samples for my web seminar “Reporting Services 2005 Tips and Tricks” can be found here. They include:



  • Using external images (URL and web service)
  • Expression-based connection strings
  • XML extension to render ADO.NET datasets streamed from a web service
  • OLAP report from SSAS
  • CLR stored procedure integration
  • ASP.NET Handler to echo in the incoming URL and SOAP requests to the Report Server
  • WinReporter demo that demonstrates the WinForms ReportViewer in remote and local mode.

Great Plains Report Pack


Microsoft has come up with a new Report Pack for Great Plains which uses SQL Server Reporting Services and comes with a number of report templates.

Using SQL Reporting Services 2005 and Forms Authentication with the Whidbey/2.0 SQLMembershipProvider

As you probably know, when the RS Windows-based security doesn’t meet your requirements, you can replace it with custom security. Not many products out there allow you do this. In hist blog, Russell Christopher explains how you can use the Whidbey/2.0 SQLMembershipProvider with custom security.

My Top 10 RS Wish List

In the spirit of the season, I compiled a list of the top 10 things that I would love Santa to implement in the next release of Reporting Services (although it may look like this won’t happen next year :-). I purposely excluded enhancements to the RS data regions since it should be relatively easily to compile a list of the feature most folks complain about in the public ng. 


  1. Exposing the intrinsic RDL object model to manipulate data regions and items programmatically. It will be great if this works similar to the ASP.NET user controls where controls can be added, changed, or removed at runtime. For example, custom code should be able to reference a table region to add, remove, and bind columns at runtime.
  2. Server-side events, e.g. OnReportRender, OnBodyRender, OnPrint, OnRegionRender, etc.
  3. A supported way to maintain state in custom code.
  4. Exposing the report datasets to custom code to allow programmatic navigation and data retrieval, e.g. looping through the dataset rows.
  5. Decoupling the Report Builder Designer and exposing it as a reusable .NET control which can be embedded in applications. Ideally, a developer should be able to pass the semantic model (or metadata described in a different format) the designer. The output of the WYSWIG manipulation should be returned in the form of RDL.
  6. Enhancing the Report Builder Designer to support custom code and plugging in custom function libraries.
  7. Simplifying CAS security to the three levels supported by SQL Server and SSAS – Safe, External Access, and Unsafe.
  8. Binding server-side reports to ADO.NET datasets.
  9. A conditional page break.
  10. The XML extension should support XML schemas and cast the column types to data types according to the schema.

Please feel free to add to the list and happy holidays!

RS 2005 ASP.NET Report Viewer and Custom Assemblies

There was an interesting post on the Reporting Services public newsgroup about an issue with the RS 2005 ASP.NET Report Viewer and custom assemblies. In a nutshell, the issue was that if you want to invoke a custom assembly from the ASP.NET Report Viewer, you need to deploy it to GAC.


Because of a bug in the RTM version, copying custom assemblies to the web app bin folder will not work. This bug will be fixed in a service pack. Currently, for web applications, you have to copy custom assemblies to GAC. This issue doesn’t apply to the WinForm version of the Report Viewer. In the case of WinForms apps, custom assemblies can be in the same directory as the application’s .EXE file; no need to copy to GAC.


An example of how the WinForm version of the Report Viewer can be configured to work with custom assemblies can be found on the Report Viewer home page. This page is maintained and monitored by the Rajeev Karunakaran, a Program Manager for the Report Viewer controls.

Configuration error with stylesheets and RS 2005

If you install RS 2005 and the default web site has a web.config file that uses the new ASP.NET 2.0 themes feature, when you attempt to run the Report Manager, you will get:


Theme <theme name> cannot be found in the application or global theme directories


The reason for this error is that the styleSheetTheme element in the root web.config is automatically inherited by the nested web.config files. This error is not RS-specific. It happens with any nested web site because ASP.NET attempts to located that folder and apply it to the nested web site. To fix the error, break the inheritance chain by changing the styleSheeTheme in the nested Report Manager web.config file, as follows:


<pages validateRequest=”false” styleSheetTheme=””/>