public UsedRsDataSets(string RdlPath)
        {
            //all this code is just to call VBExpressionParser.ParseExpression which is a private class
            //that method required all sorts of other objects, not many of which we know what in the world they are for
            System.Reflection.Assembly assembly = System.Reflection.Assembly.Load("Microsoft.ReportingServices.ProcessingCore");
#if !YUKON
            Type type = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assembly.GetTypes()[0], "Microsoft.ReportingServices.RdlExpressions.VBExpressionParser");
#else
            Type type = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assembly.GetTypes()[0], "Microsoft.ReportingServices.ReportProcessing.VBExpressionParser");
#endif
            System.Reflection.ConstructorInfo constructor = type.GetConstructors(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[0];

            //create PublishingErrorContext
            Type typeErrorContext = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assembly.GetTypes()[0], "Microsoft.ReportingServices.ReportProcessing.PublishingErrorContext");
            System.Reflection.ConstructorInfo constructorErrorContext = typeErrorContext.GetConstructors(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)[0];
            object oErrorContext = constructorErrorContext.Invoke(new object[] { });

            //get ExpressionContext type and constructor
            Type typeExpressionContext = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assembly.GetTypes()[0], "Microsoft.ReportingServices.RdlExpressions.ExpressionParser+ExpressionContext");

            System.Reflection.ConstructorInfo constructorExpressionContext = typeExpressionContext.GetConstructors(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[0];

            //get InternalPublishingContext constructor
            Type typeInternalPublishingContext = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assembly.GetTypes()[0], "Microsoft.ReportingServices.ReportProcessing.PublishingContext"); //used to be ReportPublishing.InternalPublishingContext which doesn't exist anymore?
            System.Reflection.ConstructorInfo constructorInternalPublishingContext = null;
            foreach (System.Reflection.ConstructorInfo c in typeInternalPublishingContext.GetConstructors(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public))
            {
                if (c.GetParameters().Length == 8)
                {
                    constructorInternalPublishingContext = c;
                    break;
                }
            }
            if (constructorInternalPublishingContext == null)
            {
                throw new Exception("Couldn't find InternalPublishingContext constructor");
            }

            //get PreviewItemContext
            System.Reflection.Assembly assemblyReportPreview = System.Reflection.Assembly.Load("Microsoft.ReportingServices.ReportPreview");
            Type typeItemContext = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assemblyReportPreview.GetTypes()[0], "Microsoft.Reporting.PreviewItemContext");

            ////////////////////////////////////////
            //now run the main code to parse the RDL
            XmlDocument doc = new XmlDocument();
            doc.Load(RdlPath);

            XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
            nsmgr.AddNamespace("rs", doc.DocumentElement.NamespaceURI);

            //build list of all DataSets in report
            foreach (XmlNode nodeDataSet in doc.SelectNodes("/rs:Report/rs:DataSets/rs:DataSet", nsmgr))
            {
                RsDataSet ds = new RsDataSet();
                ds.ReportName  = System.IO.Path.GetFileNameWithoutExtension(RdlPath);
                ds.DataSetName = nodeDataSet.Attributes["Name"].Value;
                _dataSets.Add(ds.DataSetName, ds);
            }

            //build list of all objects such as tables that use the dataset
            foreach (XmlNode nodeDataSetRef in doc.SelectNodes("//rs:DataSetName", nsmgr))
            {
                if (_dataSets.ContainsKey(nodeDataSetRef.InnerText))
                {
                    if (!_dataSets[nodeDataSetRef.InnerText].Usages.Contains(GetPathForXmlNode(nodeDataSetRef)))
                    {
                        _dataSets[nodeDataSetRef.InnerText].Usages.Add(GetPathForXmlNode(nodeDataSetRef));
                    }
                }
            }

            //loop through all expressions and parse them
            foreach (XmlNode nodeExpression in doc.SelectNodes("//*[starts-with(text(),'=')]", nsmgr))
            {
                try
                {
                    //see if the surrounding table, for example, has already said it uses a particular DataSet. If so, we won't report it again
                    string  sDataSetUsedByParent = string.Empty;
                    XmlNode parentNode           = nodeExpression.SelectSingleNode("ancestor-or-self::*/rs:DataSetName", nsmgr);
                    if (parentNode != null)
                    {
                        sDataSetUsedByParent = parentNode.InnerText;
                    }

                    //create VBExpressionParser
                    object vbparser = constructor.Invoke(new object[] { oErrorContext });

                    //create PreviewItemContext
                    object itemContext = typeItemContext.GetConstructors(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)[0].Invoke(null);

                    //signature of this function call is: public InternalPublishingContext(ICatalogItemContext catalogContext, Microsoft.ReportingServices.ReportProcessing.ReportProcessing.CheckSharedDataSource checkDataSourceCallback, Microsoft.ReportingServices.ReportProcessing.ReportProcessing.ResolveTemporaryDataSource resolveTemporaryDataSourceCallback, DataSourceInfoCollection originalDataSources, IConfiguration configuration, IDataProtection dataProtection, bool traceAtomicScopes, bool isPackagedReportArchive)
                    object oInternalPublishingContext = constructorInternalPublishingContext.Invoke(new object[] { itemContext, null, null, null, null, null, null, null }); //last two params used to be: false, false

                    //create ExpressionContext
                    //signature of this function call is: internal ExpressionContext(ExpressionParser.ExpressionType expressionType, DataType constantType, LocationFlags location, ObjectType objectType, string objectName, string propertyName, string dataSetName, int maxExpressionLength, InternalPublishingContext publishingContext);
                    object expressionContext = constructorExpressionContext.Invoke(new object[] { ExpressionInfo.ExpressionType.General, 0x12, ExpressionInfo.LocationFlags.None, ExpressionInfo.ObjectType.Field, string.Empty, "Text", "DSN", int.MaxValue, oInternalPublishingContext });

                    //find and invoke ParseExpression method

                    int      iParseExpressionParamCount = 3;
                    object[] arrParseExpressionParams   = new object[] { nodeExpression.InnerText, expressionContext, 0 };

                    System.Reflection.MethodInfo methodParseExpression = null;
                    foreach (System.Reflection.MethodInfo method in type.GetMethods(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance))
                    {
                        if (method.Name == "ParseExpression" && method.GetParameters().Length == iParseExpressionParamCount)
                        {
                            methodParseExpression = method;
                            break;
                        }
                    }
                    if (methodParseExpression == null)
                    {
                        throw new Exception("Couldn't find VBExpressionParser.ParseExpression method");
                    }
                    object expressionInfo = methodParseExpression.Invoke(vbparser, arrParseExpressionParams);

                    //create a wrapper for the SSRS object then examine it recursively
                    ExpressionInfo info = new ExpressionInfo(expressionInfo);
                    RecurseExpressionInfo(info, nodeExpression, sDataSetUsedByParent);
                }
                catch (Exception ex)
                {
                    throw new Exception("Error while scanning...\r\nReport: " + RdlPath + "\r\nExpression: " + nodeExpression.InnerText, ex);
                }
            }
        }
Example #2
0
        public UsedRsDataSets(string RdlPath)
        {
            //all this code is just to call VBExpressionParser.ParseExpression which is a private class
            //that method required all sorts of other objects, not many of which we know what in the world they are for
            System.Reflection.Assembly assembly = System.Reflection.Assembly.Load("Microsoft.ReportingServices.ProcessingCore");
#if !YUKON
            Type type = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assembly.GetTypes()[0], "Microsoft.ReportingServices.RdlExpressions.VBExpressionParser");
#else
            Type type = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assembly.GetTypes()[0], "Microsoft.ReportingServices.ReportProcessing.VBExpressionParser");
#endif
            System.Reflection.ConstructorInfo constructor = type.GetConstructors(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[0];

            //create PublishingErrorContext
            Type typeErrorContext = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assembly.GetTypes()[0], "Microsoft.ReportingServices.ReportProcessing.PublishingErrorContext");
            System.Reflection.ConstructorInfo constructorErrorContext = typeErrorContext.GetConstructors(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)[0];
            object oErrorContext = constructorErrorContext.Invoke(new object[] { });

            //get ExpressionContext type and constructor
#if !YUKON
            Type typeExpressionContext = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assembly.GetTypes()[0], "Microsoft.ReportingServices.RdlExpressions.ExpressionParser+ExpressionContext");
#else
            Type typeExpressionContext = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assembly.GetTypes()[0], "Microsoft.ReportingServices.ReportProcessing.ExpressionParser+ExpressionContext");
#endif
            System.Reflection.ConstructorInfo constructorExpressionContext = typeExpressionContext.GetConstructors(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[0];

#if DENALI || SQL2014
            //get InternalPublishingContext constructor
            Type typeInternalPublishingContext = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assembly.GetTypes()[0], "Microsoft.ReportingServices.ReportPublishing.InternalPublishingContext");
            System.Reflection.ConstructorInfo constructorInternalPublishingContext = null;
            foreach (System.Reflection.ConstructorInfo c in typeInternalPublishingContext.GetConstructors(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public))
            {
                if (c.GetParameters().Length == 8)
                {
                    constructorInternalPublishingContext = c;
                    break;
                }
            }
            if (constructorInternalPublishingContext == null) throw new Exception("Couldn't find InternalPublishingContext constructor");
#endif

            //get PreviewItemContext
            System.Reflection.Assembly assemblyReportPreview = System.Reflection.Assembly.Load("Microsoft.ReportingServices.ReportPreview");
            Type typeItemContext = BIDSHelper.SSIS.ExpressionHighlighterPlugin.GetPrivateType(assemblyReportPreview.GetTypes()[0], "Microsoft.Reporting.PreviewItemContext");

            ////////////////////////////////////////
            //now run the main code to parse the RDL
            XmlDocument doc = new XmlDocument();
            doc.Load(RdlPath);

            XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
            nsmgr.AddNamespace("rs", doc.DocumentElement.NamespaceURI);

            //build list of all DataSets in report
            foreach (XmlNode nodeDataSet in doc.SelectNodes("/rs:Report/rs:DataSets/rs:DataSet", nsmgr))
            {
                RsDataSet ds = new RsDataSet();
                ds.ReportName = System.IO.Path.GetFileNameWithoutExtension(RdlPath);
                ds.DataSetName = nodeDataSet.Attributes["Name"].Value;
                _dataSets.Add(ds.DataSetName, ds);
            }

            //build list of all objects such as tables that use the dataset
            foreach (XmlNode nodeDataSetRef in doc.SelectNodes("//rs:DataSetName", nsmgr))
            {
                if (_dataSets.ContainsKey(nodeDataSetRef.InnerText))
                {
                    if (!_dataSets[nodeDataSetRef.InnerText].Usages.Contains(GetPathForXmlNode(nodeDataSetRef)))
                    {
                        _dataSets[nodeDataSetRef.InnerText].Usages.Add(GetPathForXmlNode(nodeDataSetRef));
                    }
                }
            }

            //loop through all expressions and parse them
            foreach (XmlNode nodeExpression in doc.SelectNodes("//*[starts-with(text(),'=')]", nsmgr))
            {
                try
                {
                    //see if the surrounding table, for example, has already said it uses a particular DataSet. If so, we won't report it again
                    string sDataSetUsedByParent = string.Empty;
                    XmlNode parentNode = nodeExpression.SelectSingleNode("ancestor-or-self::*/rs:DataSetName", nsmgr);
                    if (parentNode != null) sDataSetUsedByParent = parentNode.InnerText;

                    //create VBExpressionParser
                    object vbparser = constructor.Invoke(new object[] { oErrorContext });

                    //create PreviewItemContext
                    object itemContext = typeItemContext.GetConstructors(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)[0].Invoke(null);

#if DENALI || SQL2014
                    //signature of this function call is: public InternalPublishingContext(ICatalogItemContext catalogContext, Microsoft.ReportingServices.ReportProcessing.ReportProcessing.CheckSharedDataSource checkDataSourceCallback, Microsoft.ReportingServices.ReportProcessing.ReportProcessing.ResolveTemporaryDataSource resolveTemporaryDataSourceCallback, DataSourceInfoCollection originalDataSources, IConfiguration configuration, IDataProtection dataProtection, bool traceAtomicScopes, bool isPackagedReportArchive)
                    object oInternalPublishingContext = constructorInternalPublishingContext.Invoke(new object[] { itemContext, null, null, null, null, null, false, false });

                    //create ExpressionContext
                    //signature of this function call is: internal ExpressionContext(ExpressionParser.ExpressionType expressionType, DataType constantType, LocationFlags location, ObjectType objectType, string objectName, string propertyName, string dataSetName, int maxExpressionLength, InternalPublishingContext publishingContext);
                    object expressionContext = constructorExpressionContext.Invoke(new object[] { ExpressionInfo.ExpressionType.General, 0x12, ExpressionInfo.LocationFlags.None, ExpressionInfo.ObjectType.Field, string.Empty, "Text", "DSN", int.MaxValue, oInternalPublishingContext });
#elif KATMAI
                    //create ExpressionContext
                    object expressionContext = null;
                    if (constructorExpressionContext.GetParameters().Length == 8)
                    {
                        //SSRS2008 R2
                        //signature of this function call is: internal ExpressionContext(ExpressionParser.ExpressionType expressionType, DataType constantType, LocationFlags location, ObjectType objectType, string objectName, string propertyName, string dataSetName, int maxExpressionLength);
                        expressionContext = constructorExpressionContext.Invoke(new object[] { ExpressionInfo.ExpressionType.General, 0x12, ExpressionInfo.LocationFlags.None, ExpressionInfo.ObjectType.Field, string.Empty, "Text", "DSN", int.MaxValue });
                    }
                    else
                    {
                        //SSRS2008
                        //signature of this function call is: internal ExpressionContext(ExpressionParser.ExpressionType expressionType, DataType constantType, LocationFlags location, ObjectType objectType, string objectName, string propertyName, string dataSetName)
                        expressionContext = constructorExpressionContext.Invoke(new object[] { ExpressionInfo.ExpressionType.General, 0x12, ExpressionInfo.LocationFlags.None, ExpressionInfo.ObjectType.Field, string.Empty, "Text", "DSN" });
                    }
#elif YUKON
                    //create ExpressionContext
                    //signature of this function call is: internal ExpressionContext(ExpressionParser.ExpressionType expressionType, ExpressionParser.ConstantType constantType, LocationFlags location, ObjectType objectType, string objectName, string propertyName, string dataSetName, bool parseExtended)
                    object expressionContext = constructorExpressionContext.Invoke(new object[] { ExpressionInfo.ExpressionType.General, 0, ExpressionInfo.LocationFlags.None, ExpressionInfo.ObjectType.Field, string.Empty, "Text", "DSN", false });
#endif

                    //find and invoke ParseExpression method
#if !YUKON
                    int iParseExpressionParamCount = 3;
                    object[] arrParseExpressionParams = new object[] { nodeExpression.InnerText, expressionContext, 0 };
#else
                    int iParseExpressionParamCount = 2;
                    object[] arrParseExpressionParams = new object[] { nodeExpression.InnerText, expressionContext};
#endif
                    System.Reflection.MethodInfo methodParseExpression = null;
                    foreach (System.Reflection.MethodInfo method in type.GetMethods(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance))
                    {
                        if (method.Name == "ParseExpression" && method.GetParameters().Length == iParseExpressionParamCount)
                        {
                            methodParseExpression = method;
                            break;
                        }
                    }
                    if (methodParseExpression == null) throw new Exception("Couldn't find VBExpressionParser.ParseExpression method");
                    object expressionInfo = methodParseExpression.Invoke(vbparser, arrParseExpressionParams);

                    //create a wrapper for the SSRS object then examine it recursively
                    ExpressionInfo info = new ExpressionInfo(expressionInfo);
                    RecurseExpressionInfo(info, nodeExpression, sDataSetUsedByParent);
                }
                catch (Exception ex)
                {
                    throw new Exception("Error while scanning...\r\nReport: " + RdlPath + "\r\nExpression: " + nodeExpression.InnerText, ex);
                }
            }
        }