Introduction
I recently had a requirement to generate a SSRS report from a MVC 6 application. What seemed like a trivial easy to do task turned into one of those jobs passed from junior developer to junior developer without any real success or progress. The initial code review showed an attempt to request a SSRS report by doing a http POST and passing the required parameters to the report server which resulted in a 401 http response.
Please note: This approach may work for certain report server configurations.
Microsoft does, however, provide an endpoint to generate a SSRS report and using this endpoint should be seen as the correct way of generating a report from an application external to SSRS.
Why was the SSRS report service not used?
When I did my own research it became apparent that the available articles on this subject could easily confuse junior developers for the following reasons:
- SSRS is providing two service endpoints, each one with it's own uses. Which one of these two enpoints is used to generate reports?
- The younger generation of developers are used to RESTFUL web services and very few have knowledge of older web service technologies such as SOAP.
The SSRS report service endpoint
The endpoint to generate a SSRS report is
[Your report server host name]/ReportServer/ReportExecution2005.asmx
Also note that SSRS provides a second endpoint to perform other report server related tasks
[Your report server host name]/ReportServer/ReportExecution2010.asmx
Building the SSRS report service wrapper class
To make use of the report service endpoint provided by SSRS we have to add a web reference.
Very Important: The new ASP.NET 5/Core project types do not provide functionality to add web references. The only way around this is to create a .NET 4.5.1 class library project which will compile to a .dll file which can still be imported by your ASP.NET 5/Core applications.
Click on the File > New > Project menu
Select the Class Library project template and name your project SsrsWrapper
Right click on References and click on the Add Service Reference menu item
Very Important: I initially added a service reference which did not work, make sure that you add a web reference by following the steps I outline below.
Click on the Advanced... button
Click on the Add Web Reference... button
Enter the SSRS report service enpoint and click on the arrow button
Enter the username and password for the report server and click on the Ok button
Name the web reference SsrsReportService and click on the Add Reference button
Please note: The authentication modal popped up multiple times prompting me for a username and password, only enter your credentials once and click on the Cancel button subsequent to that.
In Solution Explorer you will notice a new Web References folder
Writing the ReportManager class
We now have an endpoint available that we can use to generate reports. Let's write a ReportManager
class
Rename Class1.cs to ReportManager.cs
Paste the following code into the ReportManager
class to create a manager class with two Render
methods, one that will return the report as a byte array and another to save a physical file to disk.
using System.IO;
using System.Net;
using SsrsWrapper.SsrsReportService;
namespace SsrsWrapper
{
public class ReportManager
{
private readonly ReportExecutionService _reportServerExecutionService;
public ReportManager
(
string reportServerWsdlUrl,
string username,
string password,
string domain)
{
_reportServerExecutionService = new ReportExecutionService
{
Url = reportServerWsdlUrl,
Credentials = new NetworkCredential(username, password, domain)
};
}
public byte[] Render
(
string reportDirectory,
string reportName,
string reportFormat,
ParameterValue[] parameters
)
{
_reportServerExecutionService.ExecutionHeaderValue = new ExecutionHeader();
_reportServerExecutionService.SetExecutionParameters(parameters, "en-us");
string encoding;
string mimeType;
string extension;
Warning[] warnings;
string[] streamIds;
var result = _reportServerExecutionService.Render(reportFormat, @"<DeviceInfo><Toolbar>False</Toolbar></DeviceInfo>", out extension, out encoding, out mimeType, out warnings, out streamIds);
return result;
}
public void Render
(
string reportDirectory,
string reportName,
string reportFormat,
ParameterValue[] parameters,
string destinationPath
)
{
var result = Render(reportDirectory, reportName, reportFormat, parameters);
var stream = File.Create(destinationPath, result.Length);
stream.Write(result, 0, result.Length);
stream.Close();
}
}
}
How to use the ReportManager class
Now that we have a wrapper class for the provided SSRS report service endpoint, we can use it to generate a SSRS report from a variety of c# applications such as
- Desktop applications
- Console applications
- Windows service applications
- Web applications such as classic ASP, MVC and Web API
Create a new instance of the ReportManager
class and call one of the Render
methods
var reportManager = new ReportManager
(
[The report server host name],
[The report server username],
[The report server password],
[The domain]
);
reportManager.Render
(
[The directory the report was published to on the server],
"My Report",
"PDF",
[The report parameters],
"c:\Test\MyReport.pdf"
);
How to configure the added web reference in user applications
Keep in mind that you can't reference and use the .dll file containing the ReportManager without providing the XML configuration of the SSRS resport service endpoint that was added as a web reference. For non ASP.NET 5/Core applications add the SsrsWrapper.Properties.Settings
configuration to the app\web.config file.
For ASP.NET 5/Core applications create a ReportManagerConfig.xml file in the root folder of the project containing the exact same XML configuration as seen in the image above and import the file in the Configure
method of the Startup.cs class by adding the following line of code
XmlConfigurator.Configure(new FileInfo(Path.Combine(env.ApplicationBasePath, "ReportManagerConfig.xml")));