Hi,

In this discussion I will explain how to download any SSRS report from the Report Server by using c# and javascript code. This implementation code is universal and can be used easily to download any report.

1. First step

You need add two endpoints /ReportExecution2005.asmx" and /.../ReportService2010.asmx"; to WebServiceReference.

2. Second step

You need create custom action in CRM  new_GetReport with three input parameters: LinkReport (type string), FileExtension (type string), ReportParameters (type string) and two output parameters:(OutputEncodedFile (type string), FileName (type string)) . In step 3 all these parameters are explained how to use it.

You have to create plugin with C# code below (paste it in Your .cs file)  which is registered on action new_GetReport (Post Operation).

using ProjectPlugins.datamodel;
using ProjectPlugins.RSExec;
using Microsoft.Xrm.Sdk;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Services.Protocols;

namespace ProjectPlugins
{

public class new_GetReport_PostOp : IPlugin
{


/// <summary>
///
/// </summary>
/// <param name="reportLink"></param>
/// <param name="p_reportParameters"></param>
/// <returns></returns>
static byte[] GetReport(string reportLink, string p_reportParameters,string fileExtension,
Guid usernameId, Guid organizationID)
{
Byte[] results;

try
{
RSExec.ReportExecutionService rsexec = new RSExec.ReportExecutionService();
rsexec.Credentials = new System.Net.NetworkCredential(@"username", "password", "domain");
rsexec.Url = "">xx.xxx.x.xxxx/.../ReportExecution2005.asmx";

RS2010.ReportingService2010 rs = new RS2010.ReportingService2010();
rs.Credentials = new System.Net.NetworkCredential(@"username", "password", "domain");
rs.Url = "">xx.xxx.x.xxxx/.../ReportService2010.asmx";


string historyID = null;
string deviceInfo = null;
string format = null;

switch (fileExtension.ToUpper())
{
case "PDF":
format = "PDF";
break;
case "DOCX":
format = "WORDOPENXML";
break;
default:
format = "WORDOPENXML";
break;
}

string encoding = String.Empty;
string mimeType = String.Empty;
string extension = String.Empty;

RSExec.Warning[] warnings = null;

string[] streamIDs = null;

string _reportName = reportLink;
string _historyID = null;
bool _forRendering = false;

RS2010.ParameterValue[] _values = null;
RS2010.DataSourceCredentials[] _credentials = null;
RS2010.ItemParameter[] _parameters = null;

RS2010.DataSource[] datasources = rs.GetItemDataSources(_reportName);
_parameters = rs.GetItemParameters(_reportName, _historyID, _forRendering, _values, _credentials);
RSExec.ExecutionInfo ei = rsexec.LoadReport(_reportName, historyID);


// Place to include the parameter.
if (_parameters!=null && _parameters.Length > 0)
{
RSExec.ParameterValue[] parameters =
new RSExec.ParameterValue[_parameters.Length];

string[] arrParams = !string.IsNullOrWhiteSpace(p_reportParameters)?p_reportParameters.Split(';'):null;

for (int i = 0; i < _parameters.Length; i++)
{
string f_arrayparam = null;

if (arrParams != null) {
f_arrayparam = arrParams.Where(x => x.Split(':')[0] == _parameters[i].Name).FirstOrDefault();
}

if (f_arrayparam!=null)
{

string[] param_Parts = f_arrayparam.Trim().Split(':');
parameters[i] = new RSExec.ParameterValue();
parameters[i].Name = param_Parts[0].Trim();
parameters[i].Value = param_Parts[1].Trim();

}
else
{
try
{
parameters[i] = new RSExec.ParameterValue();
parameters[i].Name = _parameters[i].Name;
parameters[i].Value = _parameters[i].DefaultValues.FirstOrDefault();
}
catch (ArgumentNullException argnullexc)
{
throw new ArgumentNullException("ArgumentNullException,Default value error for parameter \"" + parameters[i].Name + "\", " + argnullexc.Message);
}
catch (Exception exc)
{
throw new Exception("Generic Exception Default value error:" + exc.Message);
}

}
}

}

// Set DataSource Credentials
// the user name is your userid and the password is the id of the organization
// get more info here
// ronaldlemmen.blogspot.com/.../log-in-name-and-password-required-by.html
DataSourceCredentials datasetCredential = new DataSourceCredentials();
datasetCredential.DataSourceName = datasources[0].Name;
datasetCredential.UserName = usernameId.ToString().Replace("{", "").Replace("}", "");
datasetCredential.Password = organizationID.ToString().Replace("{", "").Replace("}", "");
DataSourceCredentials[] credentials = new DataSourceCredentials[1];
credentials[0] = datasetCredential;
rsexec.SetExecutionCredentials(credentials);

// Sets and validates parameter values associated with the current report execution.
// if report parameters are read-only do not execute SetExecutionParameters
//rsExec.SetExecutionParameters(parameters, "en-us");

results = rsexec.Render(format, deviceInfo, out extension, out encoding, out mimeType, out warnings, out streamIDs);

if (results==null)
{
throw new ArgumentNullException("Report has returned null");
}
}
catch (SoapException soapexc)
{
throw new InvalidPluginExecutionException(soapexc.Message+
", Actor:"+soapexc.Actor+", Detail:"+soapexc.Detail.ToString()+
", Inner exception: "
+(soapexc.InnerException!=null?soapexc.InnerException.ToString():"")+
".");
}
catch (ArgumentNullException argnullexc)
{
throw new InvalidPluginExecutionException(argnullexc.Message);
}
catch (Exception exc)
{
throw new InvalidPluginExecutionException(exc.Message);
}
return results;
}

public void Execute(IServiceProvider serviceProvider)
{
#region Initializing
//Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));

// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));

// Obtain the organization service reference.
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
#endregion

if (context.MessageName.ToLower() == "new_GetReport".ToLower())
{
string reportLink = context.InputParameters["LinkReport"] as string;
string fileExtension = context.InputParameters["FileExtension"] as string;
string reportParameters = context.InputParameters["ReportParameters"] as string;


byte[] data_report = GetReport(reportLink, reportParameters, fileExtension, context.UserId, context.OrganizationId);

context.OutputParameters["OutputEncodedFile"] = Convert.ToBase64String(data_report);
context.OutputParameters["FileName"] = Guid.NewGuid().ToString()+"."+fileExtension.ToLower();
}
}
}

}

3. Third Step

You have to paste javascript below in .js webresource.

This are three input parameters (LinkReport, FileExtension, ReportParameters) and two output parameters (OutputEncodedFile, FileName).

 - Input parameters

  • LinkReport - link on report
  • FileExtension - DOCX or PDF
  • ReportParametersPart of code which is brushed by green (it is assigning the values to the report parameters) must be in format "name1:value1;name2:value2;name3:value3". Get the splitters both : and ;

- Output parameters

  • OutputEncodedFile - base64 string encoded file format
  • FileName - filename with extension (the file is genereted by format xxxx.pdf or xxxxx.docx)

//Javascript code

function fn_DownloadReport() {

var value1="9d06b872-37a5-447d-aa24-4780380b79f6";

var value2="11111";

var value3="222222";


Process.callAction("new_GetReport",
[{
key: "LinkReport",
type: Process.Type.String,
value: "/XXXXXX_MSCRM/XXXXXXXX/XXXXXX" //Report Link
},
{
key: "FileExtension",
type: Process.Type.String,
value: "DOCX"
},
{
key: "ReportParameters",
type: Process.Type.String,
value: "ReportParameterName1:"+value1 + ";" +
"ReportParameterName2:" + value2 + ";" +
"ReportParameterName3:" + value3

}
],
function (params) {

var a = document.createElement("a");
a.href = "data:application/octet-stream;base64," + params.OutputEncodedFile;
a.download = params.FileName;
a.click();

},
function (e, t) {
alert("Error " + e + " , " + t);
console.log(e + " , " + t);
});
}

4. Fourth step

Call javascript function fn_DownloadReport and the file is downloaded.  Also, we can call  action new_GetReport from another action and that another action call from javascript. Enjoj :) .

Best Regards, Elvis