Skip to content

Tag: SharePoint

Working With Power BI, Office 365 and File Size Limits

Note – this article was written during the preview cycle of Power BI, and certain behaviours and screens may change by final release.

Quick, what’s the biggest file that you can upload into SharePoint? As with anything SharePoint, of course it depends. This article explains some of the file size boundaries in SharePoint and Office 365, how they impact Power BI, how to take advantage of the storage changes that Power BI provides, and some of the intricacies of using the xVelocity model with Power BI.

The maximum file upload size is 250 Mb by default with SharePoint 2013, and 50 with prior versions. This setting can be changed on an application by application basis within Central Administration, and once set, is a hard limit. If your file exceeds it, you won’t be able to upload it into SharePoint.

If you use Excel Services, you may also note that the default maximum size for an Excel workbook is 10 Mb. This too can be changed in Central Administration (it’s a property of trusted file locations). If you upload a workbook that exceeds this limit, Excel Services won’t be able to render it, and you’ll need to use the Excel client. Depending on performance limitations, I often like to adjust this setting to match the maximum file upload size to avoid end user confusion.

SharePoint Online in Office 365 works a little bit differently. Until recently, the default upload limit was unchangeable. Recently however, SharePoint Online removed the upload limit altogether, so now the maximum file upload size is 2 Gb, which represents the maximum file size that SharePoint can store. For Excel Services Online there are settings that can be adjusted, but the maximum workbook size isn’t one of them. With Excel Services in Office 365, the maximum workbook size is 10 MB. Period.

If you use Power Pivot to do analysis, data is brought into the data model that is embedded within the workbook. That workbook is then stored in SharePoint, and on first use of the model (clicking a slicer, expanding a dimension, or anything requiring the retrieval of data from the model), an instance of the model is created in a backing Analysis Services engine by Excel Services.

Given that all of this is wrapped up into a single workbook file (xlsx), 10 MB would seem to be pretty constraining for data storage, and it is. The data model is very efficient, and data is highly compressed, but 10MB is simply too small for most involved analyses. This isn’t a problem on premises, where additional resources can be allocated and the limit increased, but in Office 365, you’re simply stuck with the 10 MB limit.

Enter BI Sites, the recently announced Office 365 based Business Intelligence app that is part of the Power BI application suite. BI Sites is a SharePoint app that provides additional capability to workbooks with embedded models stored in SharePoint Online libraries. BI sites allows for data models as large as 250MB. The BI Sites app doesn’t actually store content, it just renders it, and provides additional capability such as automatic data refresh. BI Sites also relies on Excel Services to render the content, so does a Power BI subscription increase that workbook limit to 250 Mb? Nope – that limit is still firmly in place. So how does it get around this limit?

As mentioned above, when a model is accessed by a user by forcing a data retrieval from the model, Excel Services creates an instance of the model in the backing Analysis Services instance, if it hasn’t already been created. Subsequent calls just utilize the backing version. What Power BI does is it preloads this model, and then drops the model from the workbook (it is reconstituted on download). Given that the model is the large part of the workbook this drops the file size considerably, allowing it to work within the limits imposed by Excel Services.

Notice that the limit of 250 Mb above is specified for the model, NOT for the workbook. The workbook limit is still 10 Mb, and this is quite visible if you do things in the wrong order, at least in the Power BI preview. To demonstrate we will work with a model that is similar to the one that I created in this article, which is a rudimentary budget analysis with Great Plains data. There are three versions of the analysis file for demonstration purposes.

image 

In the first version, the data was first imported into Excel worksheets using Power Query, and then loaded into the model before the model was edited. It is obviously the largest of the 3, as it contains both the original data, and the more optimized model. In the second file, the data was loaded directly into the model with Power Query. After model edits, the analysis was created using a simple pivot table and pivot chart. It is the smallest of the three, as the data is contained exclusively within the optimized model. In the last version of the file, the data was imported into Excel worksheets using Power Query. Take note of the fact that the file is 12 MB, 50% larger that the model only version, and all of which is counted when considering the Excel Services limit.

After uploading these three files to an Office 365 site, Only the EnbGPDataModelOnly file can be accessed via Excel Services directly. This makes sense because the other two are larger than the 10 MB limit, and Excel Services can’t do anything with them at all, resulting in the error below:

Sorry, we can't open your workbook in Excel Web App because it exceeds the file size limit. You'll need to open this in Excel.

If we now navigate into the Power BI application, We will see a warning symbol on the tiles for our workbooks. This is because they have not yet been optimized for viewing on the web. What does that mean? It means that the model has not yet been extracted from the workbook, and attached to the Analysis Services engine.

image

To do this, click the ellipsis on the tile, and then select Enable. After confirming, the model will be extracted, and you receive a confirmation. In our case, the only one that will be successfully enabled is our EnbGPDataModelOnly file, but the reason is different for the other two files. In the case of EnbGPExcelOnly, the data model was never populated, and results in “This Workbook could not be enabled for web viewing because it does not contain a data model”.

image

This makes perfect sense, but it does mean that all of the features available through the BI Sites feature are unavailable to workbooks that don’t use data models. There is one exception to this however. The Power BI app for Windows 8 and iOS can render workbooks without models, provided that they are within the 10MB limit.

If we try to enable the EnbGPDataModelandExcel file, which does contain a data model, we get the error “This workbook could not be enabled in Power BI for Office 365 because the worksheet contents (the contents of the workbook that are not contained in the data model) exceed the allowed size.

image

If we look at the file size with only the model, it’s about 8.7 MB. The file without the model is 12 Mb, so even with the model extracted, the limit is exceeded, and the enablement process detects this.

On a side note, I think that these error messages have some interesting language. They make reference to “Power BI for Office 365”. This implies, to my mind at least, that there may be a version coming that isn’t for Office 365. No on premises version of Power BI has ever been mentioned by Microsoft, but this may hint at it.

When complete, the failed and successful enablements are easy to spot.

image

Clicking on the middle tile will successfully render the workbook.

Next, let’s work with a file that can benefit from these new features. I created a model that’s identical to the “model only” version with the only difference that I import all of the data from the 3 tables, not just the selected columns. The resultant file (named EnbGPBigModel.xlsx) is 54 MB on disk – well above the 10 MB Excel Services limit, but below the 250 MB Power BI limit. However, Once uploaded, clicking on it directly in the library gives the “file size exceeded” error message. What’s up with that?

The reason is that Excel Services just sees that it is too big, and gives up. In order to extract the model, we must first enable it in Power BI before we can work with it in Excel Services. To do that, we simply repeat the above process by navigating to the Power BI app, and enabling it.

image

Once this has been done, the workbook can be accessed by clicking on it within the Power BI app here, in the Power BI mobile app, or by navigating back to the source library and using it directly with Excel Services.

image

image

Therefore, when building models, it is vitally important to distinguish between the size of the model, and the size of the rest of the workbook. While the model can grow to 250 MB, the sum of the rest of the content cannot exceed 10 MB. Note to Microsoft – we could really use a good term here, as opposed to “rest of the workbook”. Let’s call it the spreadsheets for our purposes right now.

So, how do we know the size of the model vs the size of the spreadsheets? Well, an Excel file (xlsx) is really just a zip file in disguise. In fact, if we rename the file to end in a .zip extension, we can crack it open with a ZIP viewer (or as a folder in Windows). If we do so with our file that contains both the spreadsheets and the model, open it up, and then drill down to the xlmodel folder we’ll see the file item.data.

image

This file is your data model. in this case, it is 7.8 MB in size. Subtract that value from the size of the overall xlsx file, and you have the size of your spreadsheets, which is the part that must fit within the 10 MB limit. When done, just rename the extension xlsx.

If we continue to have a problem, or as a matter of good practice, an excellent tool to use is the Workbook Size Optimizer tool from Microsoft – available here. This is (yet another) Excel add-in that will help to further optimize your model and to help reduce the file size. Just open your workbook, run the add in, and follow the prompts.

We can see that although the 250 MB model size in Power BI helps to make Office 365 a viable BI platform, it does still require a certain awareness on the part of users. The most important lesson to learn from this is to try to avoid importing data directly into Excel. Whenever possible, bring the data directly into the model, bypassing any Excel storage. This is a good idea in any event, but Power BI further underscores the need for it. When using Power Pivot, it’s fairly straightforward, but the data acquisition interface available in Power Query tends to prefer Data import. When using Power Query, care must be taken to avoid Excel import, and I’ll be posting another article on how to do this shortly. 

8 Comments

Office Web Applications In SharePoint 2013 – Bigger, Faster, Better?

At the same time that SharePoint 2010 was released, the Office team released the Office Web Applications. These browser versions of Word, Excel, and PowerPoint were tightly integrated with SharePoint and in fact originally required SharePoint to run. To install them, you would stand up a SharePoint server, and then install the web application bits on that server. Like a service pack or CU, you would then run PSCONFIGUI to integrate the bits into the farm, and install the relevant service applications. Simple enough.

However, there were some quirks associated with them. As noted here, removing the web applications from the server would actually remove the server from the farm. Simple enough to correct, but if you uninstalled the SharePoint bits before uninstalling the Office Web Application bits, you could be left with an effectively inoperable server.

During the 2010 release lifetime however, we started to see the Office Web Applications pop up elsewhere. Initially powering Facebook’s docs.com, they could also be seen as part of Windows Live. Obviously, when Office 365 was released, they were front and center. With this increasingly broad adoption, and requirement for scale, a reliance on SharePoint as a platform made less and less sense, and now, for 2013, we get a new architecture.

Standalone Web Applications Server

The big change is that Office Web Applications is no longer reliant on SharePoint. It installs and configures independently and it can serve any number of clients, SharePoint being one, and Exchange being another. In fact, it’s now positively hostile to SharePoint and other servers – you can’t install it on a machine where the SharePoint bits are installed at all. The same goes for Exchange, Lync, SQL Server, or anything really. The following is from the TechNet document “Plan Office Web Apps Server Preview”:

Servers that run Office Web Apps Server Preview must not run any other server application. This includes Exchange Server, SharePoint Server, Lync Server, and SQL Server. If you have hardware constraints, you can run Office Web Apps Server Preview in a virtual machine instance on one of these servers.

Do not install any services or roles that depend on the Web Server (IIS) role on port 80, 443, or 809 because Office Web Apps Server Preview periodically removes web applications on these ports.

Do not install any version of Office. You must uninstall Office before you install Office Web Apps Server Preview.

 

The Office Web Application Server really doesn’t play well with others. It pretty well demands that it is installed in isolation from other servers, which in reality means that a small SharePoint farm will consist of 3 servers – one SharePoint front end server, one SQL server, and one Office Web Applications server, and while virtualization makes this much more palatable, it may be a bit much for some smaller organizations to swallow.

Setting It Up

The official (pre-release)  document on planning and deploying the Office Web Application server can be found here and here respectively. Originally, I had planned on putting together a step by step walkthrough, but Steve Peschka from Microsoft published this article today that does precisely that.

Steve’s article is great because it describes the process of setting up the server with both http and https. Http is fine if all traffic is internal, but if you will have any external traffic, you must set it up with SSL (if security matters at all to you..), and the server will support only one zone, you cannot use both http and https. As you would expect, setting it up for SSL is more complex than for http.

All of the setup is done with Powershell. Powershell is fantastic, and highly useful, but I don’t think that anyone would claim that it’s easy to get started with, especially for small farm administrators,

I think that it can safely be concluded that it’s significantly harder to get the Office Web Applications installed with 2013 than it was with 2010.

Takeaways

Anyone running a two server SharePoint farm with the Office Web Applications on 2010 will wind up with a three server farm after upgrading to SharePoint 2013. This can be done via virtualization, or by standing up another physical box. Depending on the workload, the Office Web Application server doesn’t need to be particularly powerful, but no matter what, it introduces an added level of complexity. For those that heavily leverage the server, that’s a good trade-off, but for others, perhaps not.

The Office Web Applications are a fantastic set of tools, and they have been significantly improved in 2013. I am however concerned that the lack of a smooth architectural transition path from 2010 combined with the lack of a simple setup process may keep some (smaller) organizations away from it. Of course, those organizations will also have the option of moving to Office 365 where these services will already be set up and running.

Something tells me that this may just be the point.  

Leave a Comment

Setting Up Reporting Services 2012 With SharePoint 2013

In my last post, I discussed the changes in Excel and PowerPivot as they pertain to SharePoint 2013 and SQL Server. This post will walk through the steps required to set up SQL Server Reporting Services in Integrated mode with SharePoint 2013. As was the case with the new Excel data model, you will need at least SQL Server 2012 SP1 to get this to work as I describe (it’s currently available here as CTP 3).

Fundamentally, there are no real differences with how this installs when compared to installing SSRS 2012 on a SharePoint 2010 farm in SharePoint mode, so if you’ve landed here looking for 2010 information, it should be valid, but the screens will look a little different.

To start with, it’s important to understand that SSRS will install as a SharePoint service application. This obviously means that it must be installed on a machine that is part of the the SharePoint farm. What this does NOT mean is that you should install SharePoint on your SQL server and join it to the farm (please DON’T do that!). In a single SharePoint front end environment it is much better to add SSRS to your SharePoint server than it is to add SharePoint to your SQL server. Obviously, if you have a separate SharePoint application server, that’s the best place for it.

To install, obtain the SQL Server 2012 SP1 (or greater) media and mount it on tyour SharePoint server. Run the installer, choose new install and follow the prompts. Eventually you will get to the feature section screen, and assuming that machine has no prior SQL on it will look something like the following when completed.

image

You’ll notice that everything selected is under the Shared Features section, which means that it is not installed as part of a SQL instance. In fact, you’ll notice that we don’t have the data engine installed at all. The two Reporting Services options shown are the only items that are actually required for SSRS Integrated mode to work. As you can see, I’ve also selected SQL Server Data Tools (formerly BIDS) and Management Tools as well. I like to install these tools as a matter of course on SharePoint servers, as they can come in handy for connectivity testing or quick BI project building.

Follow the remaining prompts until the installation is complete.

Another thing that you should note is that the order of operations is important here. If you install Reporting Services – SharePoint prior to installing SharePoint on the farm, the option to create a Reporting Services application will not appear. That’s because it won’t be registered with the farm as a service application. If this happens, you can run the following PowerShell to register the Service Application

Install-SPRSService
Install-SPRSServiceProxy
 

Once registered, the service application can be created as below. If you install Reporting Service – SharePoint after the server has been joined to the farm, then the above steps are taken care of for you automatically.

The next thing that you need to do is to provision the service application. From Central Administration, navigate to Manage Service applications. Then, from the new menu, Select SQL Server Reporting Services Service Application.

image

Fill out the resulting form as appropriate, and select OK. Make sure that you navigate to the bottom of the form and select the applications to activate SSRS on.

image

Once the service application and proxy have been created, click on it to access the management screen.

image

You’ll want to access each of the sections and fill out the appropriate options for your installation. The instructions are fairly self-explanatory, so I won’t go into them here. At a minimum, you should back up your encryption key in the key management section, Set your unattended execution account (the default account to use when no credentials are available), and your email server settings if you want to be able to deliver reports via email. If you want to enable self service subscriptions and alerts, fill out that section, and it contains instructions for setting up the SQL agent service to support it.

The most important section is System Settings, which controls the bulk of how Reporting Services will run. Clicking on it accessed the service itself, and it’s the first place that you’ll see an error if you have configuration problems. In early builds, I have seen an error similar to the following:

The requested service, ‘http://localhost:xxxxx/SecurityTokenServiceApplication/securitytoken.svc/actas’ could not be activated

(xxxxx is a local port which varies from farm to farm)

This indicated a problem with the SecurityTokenService, which you can see by accessing IIS. After doing a little poking around, I tried to access the service directly in a browser via its base url:

http://localhost:xxxxx/SecurityTokenServiceApplication/securitytoken.svc

I was then presented with an error indicating that the server was too low on memory. The solution? Allocate more RAM. It was running with 4 GB and only SharePoint installed, but it did have most of the service applications activated. The lesson – if you want all the services to work, give your server enough memory. Bumping it to 8 GB did it in my case.

If you can access your system settings, then you should be good to go. The next step is to enable SSRS in you site collections, and I plan on doing a post on that in the very near future. Stay tuned.

Update – July 26 2012 – If you’re interested in trying out SSRS on SharePoint, or PowerPivot for SharePoint, you can use a pre-built environment that’s been set up on Cloudshare. Click here to sign up and access the environment.

33 Comments

How To Automate SharePoint Report Creation With SSIS and SSRS

If you’ve used SQL Server Reporting Services to any great extent, you’ve likely encountered the need to generate reports automatically. This requirement may be for for delivery purposes, archival purposes, or simply to reduce report rendering wait times for the end users. SSRS supports this requirement out of the box – a report administrator can set up a subscription, enter the required parameters, and the report will be generated and delivered on that schedule.

This approach is highly declarative, and puts the onus of subscription creation on the report administrator. To this end SSRS also supports data driven subscriptions, which allow the subscriptions to be looked up from a SQL table. How that table is maintained is up to the individual organization, but it does allow a measure of dynamism. With SQL Server Reporting Services 2012, this feature is made much more user friendly through the use of User Driven Subscriptions.

The down side to any of this dynamic behaviour is that in every case, it requires the Enterprise version of SQL Server (with SQL Server 2012, the BI SKU also has this capability). In addition, with SQL Server versions prior to 2012, the capability is somewhat less than user friendly.

In this post, I will outline a methodology that will allow you to provide SharePoint list based report subscriptions that will allow users to subscribe to published reports, and have them published to a SharePoint document library. The approach is not restricted to SharePoint – indeed it could be used with native mode to read through a list of possible parameter values, and email the resulting reports, or store them in a file system, but the SharePoint example is the one that I will be using below.

I should also point out that although the examples below use SQL Server 2012, the approach should work with versions back to SQL Server 2005.

The primary components of this solution are a SharePoint list that will be read to determine what reports to render (the subscription list), a SQL Server Integration Services (SSIS) package that will read through the subscription list and use the values therein to render the report, and finally, a SharePoint document library that will house the reports. Of course, we also need a report to be rendered, and in our case, this report is also stored in a SharePoint document library, as Reporting Services is running in SharePoint Integrated mode.

The good news, is that all of the constituent portions of this solution are either downloadable for free, or come with SQL server in any other edition besides Express. Therefore, the chances are that if you have SharePoint, then you already have all of the tools that you need.

Step 1 – Obtain the SharePoint List Source and Destination Project

Out of the box, SSIS doesn’t know how to talk to SharePoint data. Fortunately, there’s an excellent Codeplex project that adds the required capability. If you haven’t already done so, download the SharePoint List Source and Destination project from Codeplex. You will find a good blog post on working with this tool here. Once installed, you will be ready to build the solution. Of course, this step is only necessary if you want to use a SharePoint list as a subscription source.

Step 2 – Create your subscription and report library

In this solution, we will allow a user to enter a subscription request in our subscription list. The user can specify the URL of the report to be run, the parameters for the report, the file type that is to be produced, and the library where the report is to be stored. In order to support this, we’ll need at least one document library where the produced reports will be stored, and one custom list.

Create your document library, and note its URL. In our case below, our report library will be at http://home.nautilusinc.local/sites/nmarine/IT/Sandbox/ExpenseReportOutput. This URL will be used below. In this library, we don’t need to add any custom metadata properties, but you certainly may, should you wish to do so.

Next, create a custom list. In our case, the list will be named “Subscriptions” and will be created in the  “http://home.nautilusinc.local/sites/nmarine/IT/Sandbox” site. Where you create this list is not important, but what is important is the display name of the list, and the URL of its parent site.

For our use case, we want the user to be able to specify the Report to be rendered, the destination to place the rendered reports, the parameters to use for the rendered report, and the file type of the rendered report. To that end, we will add 4 additional columns to the list, as shown below.

image

You will also note that the “Title:” field has been renamed to “Subscription” on this list. This is purely for cosmetic purposes. Three of the new fields are simply single line text fields, while the Format field is choice. In our example, the options available for the choice field are WORDOPENXML, PDF, EXCELOPENXML, IMAGE, and NULL. You can allow any of the possible output types that Reporting services supports. I have outlined these types previously in another post here.

While it is outside the scope of this article, you will likely want to modify the form to display more user friendly names for the options than “WORDOPENXML”, etc, and automatically calculate the value for the subscription field. InfoPath would be an excellent tool to do this with, and there are other alternatives as well. For our purposes, we will work with the form as is.

Once done, you will want to add a couple of subscriptions. In our case, we’re working on a very simple report as shown below:
image

The report takes a single parameter, employee name, and renders the report filtered by that parameter. The subscription list item that we’ll create will look something like below:

image

The value for ReportURL is the full URL path to the report definition, in our case it is http://home.nautilusinc.local/sites/nmarine/finance/ReportsMarch22/ExpenseReports.rdl (you should be able to enter the URL into a browser and see the report), and the destination library is the full URL path to the destination library, in our case http://home.nautilusinc.local/sites/nmarine/IT/Sandbox/ExpenseReportOutput.

After adding two subscriptions, our subscription list appears as follows:

image

When our job runs (defined below) it will iterate through this list and create a corresponding PDF file and Word file in the destination library. Next, we create the SSIS package that will actually do the work.

Step 3 – Create a Reporting Services Web Service Proxy Class

In order to render the Reporting Services reports, we will need to call the Reporting Services web service from a SSIS Script task. In order to do that, we’ll need to use a proxy class. Luckily, we can just generate one using the WSDL.EXE generation tool available from the .Net 3.5 SDK. You run the tool with the following options:

wsdl.exe /language:[language choice] /out:ReportService.[language choice] http://[SPSiteURL]/_vti_bin/ReportServer/ReportService.asmx?WSDL

where:

  • [language choice] = VB or CS
  • [SPSiteURL] = URL of the SharePoint Site Collection

In our case, the precise command is:

wsdl.exe /language:VB /out:ReportService.vb http://home.nautilusinc.local/sites/nmarine/_vti_bin/ReportServer/ReportExecution2005.asmx?WSDL

If you don’t want to build your own, you can download the one that I created for this project (it’s Visual Basic). It was built using SSRS 2012, but should be backward compatible. Also, don’t forget to change the embedded server URLs.

Once you have the output file, make note of its location – we’ll use it below when creating the script task in SSIS.

Step 4 – Build the SSIS Package

I’m going to assume that most people reading this have little or no exposure to SSIS, so I’ll try to be as detailed as possible. You’ll need to start SQL Server Data Tools (if you’re using SQL Server 2012) or Business Intelligence Development Studio (for SQL versions prior to 2012).

image

You may notice that is has a striking resemblance to Visual Studio 2010. That’s because it is VS2010.  Select “New Project” then in the “Business Intelligence” section, select “integration Services Project”. Give the new project a name and location and click OK.

image

Once created, we’ll need to create a SharePoint List connection manager. From the Solution explorer, right click on “Connection Managers” and select “New Connection Manager”. Scroll down on the window, select “SPCRED” and click Add.

image

You will only see SPCRED if you completed Step 1 above. The Connection Manager will then prompt for a name and a set of credentials. Provide the name, and also provide it with an account that has access to the subscription list. If the SSIS service account has access, you can select “Use Credentials of Executing Process”, otherwise provide a service account with access.

image

We’ll be working within a Data flow task, so drag a Data Flow Task onto the design canvas.

image

Next, double click on the data flow task, or click on the Data Flow tab to bring up the Data Flow Task Editor. From there, drag a “SharePoint List Source” action onto the canvas. (Note: if the SharePoint List Source does not appear, there may have been a problem installing it. Consult the documentation for the SharePoint List Source and Destination project for troubleshooting steps.) Double Click on the List Source action to configure it. The first item to configure is the Connection Manager. Simply select it from the (hidden!!! ) drop down list. Click on the area beside “SharePoint Credential Conn…” to reveal the dropdown.

image

Next, click on the “ Component Properties” tab. Here, you perform the bulk of the action configuration. There are many options to choose from, but the ones that we’re concerned with here are SiteUrl and SiteListName. SiteURL is the absolute URL of the site that will contain our list, and SiteListName is the display name of the list. I stress display name as this is different than working with most other APIs for SharePoint, which tend to use the internal name. Also – it’s relatively easy for users to change the display name of the list. Doing so will break the package until it is reconfigured.

image

Next, drag a Script Component onto the canvas, below the data source. If prompted, choose “Transformation” for the script type. Next, connect the two actions by dragging the arrow from the  SharePoint List Source to the Script Component.

image

Next, double click on the script component to bring up the script component editor. From the left, select Input Columns and select all of the columns to use in this script. In our case, we’ll be working with the columns shown below:

image

Next, click on the Script section, choose the language that you want to work with, then click the “Edit Script” button.

image

Without getting into too much detail of how the script action works, what we are going to do is to add code that will run for each row of data that flows through the transformation. In our case, that will be for each configuration item. We’re going to use the values of the columns of each configuration item to render the reports. Therefore, the code that we will write will go into the “Input0_ProcessInputRow” sub.

Before we can do that however, we need to add some supporting items. Firstly, since we’ll be working with web services, we’ll need to reference the .Net System.Web.Services library. Right click on the project name in solution explorer, and select Add Reference. From the .Net tab, select System.Web.Services, and click OK.

image

Next, expand the “Imports” section and import the System.IO and the System.Net  namespace.

image

We now need to add our Reporting Services proxy class. The best way to do this is to first create a new class. Right click on the project in solution explorer, and select Add – Class.

image

Next, give the class a name. I like to match the name to the main class embedded, so the new name is ReportExecutionService.vb. Next, using Notepad, open the file that you created or downloaded in Step 3 above. Select all text, copy it into the clipboard, and then paste it into the newly created class, overwriting anything already there. Once done, save and close the class.

Next, I add a helper function to the script that helps to deal with URLs missing an ending slash. You can add it immediately above the “Input0_ProcessInputRow” sub. The code is below:

 Private Function CheckSlash(ByVal input As String) As String
        If input.EndsWith(Path.DirectorySeparatorChar) Then
            Return input
        Else
            Return input & Path.DirectorySeparatorChar
        End If
    End Function

As we saw below, the output format parameters aren’t the friendliest, and we will need to specify the extension for the output file. To allow this, I also wrote a small helper function to turn output format values into file extensions, and include it below. This also needs to be added to the script.

Private Function GetExt(format As String) As String
        Select Case format
            Case Is = "XML"
                Return "xml"
            Case Is = "Null"
                Return Nothing
            Case Is = "CSV"
                Return "csv"
            Case Is = "ATOM"
                Return "atom"
            Case Is = "PDF"
                Return "pdf"
            Case Is = "HTML4.0"
                Return "htm"
            Case Is = "RGDI"
                Return "gdi"
            Case Is = "MHTML"
                Return "mhtml"
            Case Is = "EXCEL"
                Return "xls"
            Case Is = "EXCELOPENXML"
                Return "xlsx"
            Case Is = "RPL"
                Return "rpl"
            Case Is = "IMAGE"
                Return "tiff"
            Case Is = "WORD"
                Return "doc"
            Case Is = "WORDOPENXML"
                Return "docx"
            Case Else
                Return Nothing
        End Select
    End Function

 

Finally, we’re ready to add code to the “Input0_ProcessInputRow” sub. The complete code listing is below:

  1. Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
  2.       '
  3.       Dim rs As New ReportExecutionService
  4.       rs.Url = "http://home.nautilusinc.local/sites/nmarine/_vti_bin/ReportServer/ReportExecution2005.asmx"
  5.       rs.Credentials = System.Net.CredentialCache.DefaultCredentials
  6.       Dim report As Byte() = Nothing
  7.       Dim deviceinfo As String = Nothing
  8.  
  9.       Dim ParameterPairs As String() = Row.Parameters.Split(";")
  10.       Dim parameters As ParameterValue() = New ParameterValue(ParameterPairs.Length – 1) {}
  11.       Dim CurrentPair As String()
  12.       For i As Integer = 0 To ParameterPairs.Length – 1
  13.           CurrentPair = ParameterPairs(i).Split("=")
  14.           parameters(i) = New ParameterValue
  15.           parameters(i).Name = CurrentPair(0)
  16.           parameters(i).Value = CurrentPair(1)
  17.       Next
  18.  
  19.       Dim historyID As String = Nothing
  20.       Dim credentials As DataSourceCredentials() = Nothing
  21.       Dim showHideToggle As String = Nothing
  22.       Dim extension As [String] = String.Empty
  23.       Dim encoding As [String] = String.Empty
  24.       Dim mimeType As [String] = String.Empty
  25.       Dim warnings As Warning() = Nothing
  26.       Dim reportHistoryParameters As ParameterValue() = Nothing
  27.  
  28.       Dim streamIDs As String() = Nothing
  29.       Dim execInfo As New ExecutionInfo()
  30.       Dim execHeader As New ExecutionHeader()
  31.  
  32.       rs.ExecutionHeaderValue = execHeader
  33.       execInfo = rs.LoadReport(Row.ReportURL, historyID)
  34.       rs.SetExecutionParameters(parameters, "en-us")
  35.       Dim destUrl As String = Row.DestinationLibrary
  36.       Dim destinationUrl As String = CheckSlash(destUrl) + Row.SubscriptionTitle + "." + GetExt(Row.Format)
  37.       Dim r As Byte()
  38.  
  39.       Try
  40.           report = rs.Render(Row.Format, deviceinfo, extension, mimeType, encoding, warnings, streamIDs)
  41.           Dim m_WC As WebClient = New WebClient
  42.           m_WC.Credentials = System.Net.CredentialCache.DefaultCredentials
  43.           r = m_WC.UploadData(destinationUrl, "PUT", report)
  44.       Catch ex As Exception
  45.  
  46.       End Try
  47.   End Sub

 

Again, without getting into too much detail, some explanation of the above code is in order.

Lines 3-5 initialize the web service, assign it a URL (Don’t forget to change this for your environment!!) and assign it the credentials to use when calling the web service.

When this  sub is called by SSIS, it is passed a row object. The row object contains column objects for each column that is used by the script (this was configured above). Therefore, to get the value for any given column, you simply need to refer to it as row.ColumnName. In our case, to get the value of the Parameters column, you use row.Parameters. Lines 9 through 17 get the value of the parameters column, split the value into an array of string objects using a semicolon as a value delimiter, then for each of these objects, separates them into name/value pairs using the equals sign as a delimiter, and them finally assigns them to a Reporting Services parameter collection.

Using this approach, we can use a single field to store all of the parameters for a report, and any report can have any number of parameters.

Lines 19-32 are  primarily used for initialization. Line 33 loads the report specified in the subscription (by calling row.ReportURL). Line 34, sets the parameters, and lines 35-36 set the destination variables.

Finally, Line 40 calls the web service to actually render the report into a byte stream, and line 43 uses the .Net WebClient object to upload the file directly into SharePoint. In this example, we don’t actually add any metadata to the SharePoint library, but if this was required, you could use the techniques outlined in this post. We are now ready to test the process.

Step 5 – Run the Package

Close the Script editor window and click the OK button. If all is well, your Script Component action should show no errors. When ready, click the run button to test your package. If all is well, after a short compilation period, you should see that 2 records were successfully read from the subscription list, an both steps should show green. If things don’t go well, the error messages are pretty good….

image

Navigating to the destination library, we see the two requested reports.

image

Next Steps

Obviously, every time that this package runs, the reports will be overwritten with the new report. This may be desired behaviour, but if not, you may want to turn on version control (each version will be stored as a version) or modify the script to change the file name on each run (date stamping is a common technique).

In addition, you will want the package to be run automatically without human intervention. To do this, you’ll want to deploy it to a SQL Server running SSIS , and to schedule it to run as an agent job. There is a wealth of information online for how to do that.

Conclusion

The example provided above covers a single use case, but with minor adjustment could be used to automate all sorts of reporting tasks. A common one would be to use the NULL renderer to refresh report caches on a server. If you find any unique uses of this approach, I would love to hear about it. Please post a comment!

Credits

In preparing this post, I found the following articles to be useful:

SSIS and Reporting Services Web Services

Uploading documents to WSS (Windows Sharepoint Services) using SSIS

SharePoint reporting services SOAP endpoint in CTP3

Upload document from Local Machine to SharePoint Library using WebService

Uploading files to the SharePoint Document Library and updating any metadata columns

8 Comments

How To Get A Comprehensive List of all E-Mail Enabled Libraries in SharePoint

I recently completed a multi-farm consolidation and upgrade from SharePoint 2007 to 2010 for a customer, collapsing three farms into one. The approach was to create a new farm, and to individually do dbattach upgrades of each of the 2007 databases into separate SharePoint applications. Everything went well, including Reporting Services subscriptions, but we ran into a problem with incoming email.

The problem is that while all of the incoming email settings for a library are properly migrated when doing a dbattach upgrade, all of the aliases are stored in the Farm Database (in the EmailEnabledLists table, if you’re interested in looking), and it remains empty. The resultant effect is that you inspect the library properties, and all looks good, and email is properly being delivered to the drop folder. Unfortunately, the incoming email service timer job is looking for emails that correspond to the entries in the EMailEnabledLists table, and there are none.

The solution is to simply turn off incoming email for the affected lists, and then turn it back on. A bit cumbersome maybe, but it does work. However, in our case, our customer had over 100 libraries and wasn’t sure where they all were. A bit of hunting around found a couple of ways to get a list of email enabled libraries through code (here and here).

However, I don’t like writing code if I don’t have to, and decided to have a look in the content databases. Don’t forget the first rule of playing around in the SharePoint content databases, which is don’t. However, reading from them isn’t so bad, and ultimately solves our problem. Enough information is in fact in there to construct a simple query:

SELECT
     Webs.FullUrl As LibraryURL,
     AllLists.tp_Title As LibraryTitle,
     AllLists.tp_EmailAlias As emailAlias
FROM
     AllLists
INNER JOIN
     webs on AllLists.tp_WebID = Webs.Id
WHERE
    AllLists.tp_EmailAlias IS NOT NULL
Opening up SQL Server Management Studio, and running this query on each content database will give you a comprehensive list of all e-mail enabled document libraries.
7 Comments