Come esportare il contenuto di una istanza di Reporting Services

Migrare reporting services e' una operazione ben documentata. Oggi vedremo come, con poche righe di codice, sia possibile esportare una istanza di reporting services su file system. Non entrero' nel dettaglio di come collegarsi e utilizzare il web service di reporting services (per dettagli vedere qui: http://msdn.microsoft.com/en-us/library/bb522713.aspx). Mi limitero' a utilizzare questi due metodi che fanno al caso nostro:

  1. ReportingService2010.FindItems Method
  2. ReportingService2010.GetItemDefinition Method

Il primo metodo e' in grado di restituire tutti gli oggetti di una istanza di RS, il secondo estrae il contenuto come array di bytes. Salvando su file system il contenuto noteremo che si tratta dello stesso XML (o meglio, RDL) che compone il report.

Il codice a questo punto e' molto semplice (qui sotto ne pubblico uno spunto per una eventuale implementazione):

             RS2010.ReportingService2010SoapClient svc = new RS2010.ReportingService2010SoapClient();
            svc.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
            svc.Endpoint.Address = new System.ServiceModel.EndpointAddress(args[0]);

            RS2010.TrustedUserHeader tuh = new RS2010.TrustedUserHeader();

            RS2010.CatalogItem[] items = null;
            
            // Lettura di tutti gli oggetti del server
            svc.FindItems(tuh, "/", RS2010.BooleanOperatorEnum.And,
                new RS2010.Property[] { new RS2010.Property() { Name = "Recursive", Value = "true" } },
                new RS2010.SearchCondition[] { },
                out items);

            #region Extract all
            if (fExtractAll)
            {
                Console.WriteLine("Extracting all items");

                byte[] bBuffer2;
                for (int i = 0; i < items.Length; i++)
                {
                    if (items[i] is RS2010.CatalogItem)
                    {
                        RS2010.CatalogItem ci = (RS2010.CatalogItem)items[i];
                        if (ci.TypeName == "Folder")
                            continue;

                        try
                        {
                            Console.WriteLine("Extracting " + ci.Path);

                            // Estrazione definizione dell'oggetto
                            svc.GetItemDefinition(tuh, ci.Path, out bBuffer2);

                            int idx = ci.Path.LastIndexOf('/');
                            string strPath = ci.Path;
                            if (idx > 0)
                            {
                                strPath = strPath.Substring(0, idx);
                                strPath = strPath.Replace('/', System.IO.Path.DirectorySeparatorChar).Substring(1);
                            }
                            else
                            {
                                strPath = "";
                            }

                            System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(
                                strBaseDirectory + System.IO.Path.DirectorySeparatorChar +
                                strPath);
                            if (!di.Exists)
                                di.Create();

                            string strFileName = di.FullName + System.IO.Path.DirectorySeparatorChar + ci.Name;
                            if (ci.TypeName == "Report")
                                strFileName += ".rdl";
                            else
                                strFileName += ".xml";

                            using (System.IO.FileStream fs = new System.IO.FileStream(
                                strFileName,
                                System.IO.FileMode.Create,
                                System.IO.FileAccess.ReadWrite,
                                System.IO.FileShare.Read))
                            {
                                fs.Write(bBuffer2, 0, bBuffer2.Length);
                            }
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.ToString());
                        }
                    }
                }
            }
            #endregion

Un paio di note: 

  1. Ricordatevi di alzare il valore maxReceivedMessageSize del binding al WS.
  2. Per usare l'autenticazione integrata impostate security mode="TransportCredentialOnly " e transport clientCredentialType="Windows".
  3. Benche' sia possibile esportare anche i shared data sources, fate attenzione perche' le password non verranno esportate.

Happy coding,

Francesco Cogno