I am working on SSRS report. I am accessing report using web services (using web refrences)
I am using ReportExecutionService class to render report in the html 4.0 format and finaly I attach rendered HTML to my page DIV. Report is rendering very fine in HTML format but the images on that is not rendering properly because of missing authentication for images
for that I just replace the src attribute of the img tag in the response returned from the SSRS report execution service with the url to this location below is code for render report:-
public string Render(string reportDirectory,string reportName,string reportFormat, ParameterValue[]parameters )
{
_reportServerExecutionService.ExecutionHeaderValue = new ExecutionHeader();
_reportServerExecutionService.TrustedUserHeaderValue = new TrustedUserHeader();
_reportServerExecutionService.LoadReport("/GES-MVC/GES_FWCR",null);
_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);
//Here is logic for image replcaement
string html = string.Empty;
html = System.Text.Encoding.Default.GetString(result);
html = GetReportImages(_reportServerExecutionService, _reportServerExecutionService.ExecutionHeaderValue, _reportServerExecutionService.TrustedUserHeaderValue, reportFormat, streamIds, html);
return html;
}
and function (code) for image replacement
public string GetReportImages(ReportExecutionService _reportServerExecutionService, ExecutionHeader executionHeaderValue, TrustedUserHeader trustedUserHeaderValue, string reportFormat, string[] streamIds, string html)
{
if (reportFormat.Equals("HTML4.0") && streamIds.Length > 0)
{
string devInfo;
string mimeType;
string Encoding;
string fileExtension = ".jpg";
string SessionId;
Byte[] image;
foreach (string streamId in streamIds)
{
SessionId = Guid.NewGuid().ToString().Replace("}", "").Replace("{", "").Replace("-", "");
string reportreplacementname = string.Concat(streamId, "_", SessionId, fileExtension);
html = html.Replace(streamId, string.Concat(#"Report\GraphFiles\", reportreplacementname));
devInfo = "";
image= _reportServerExecutionService.RenderStream(reportFormat, streamId, devInfo, out Encoding, out mimeType);
System.IO.FileStream stream = System.IO.File.OpenWrite(HttpContext.Current.Request.PhysicalApplicationPath + "Report\\GraphFiles\\" + reportreplacementname);
stream.Write(image, 0, image.Length);
stream.Close();
mimeType = "text/html";
}
}
return html;
}
but issue is that image is saved into folder and also src tag is replaced into html ,still image is not display on report Can anybody have solution for this or any related code for same
Thanks In Advance
This is close to being correct. There is one small part you are missing.
Not only do you have to intercept the streams and save each to a temp location that is accessible to your app, you also have to let SSRS know that the renderer should source the dynamic images to your new location.
The way to let the renderer know about the new location is to override the DeviceInfo.StreamRoot passed into the Render() method.
string thisReportInstanceID = Guid.NewGuid();
string thisReportInstanceTempFolder = Path.Combine("Temp",thisReportInstanceID );
string physicalTempFolder = Path.Combine(<YourPhysicalWebRoot>,thisReportInstanceTempFolder );
string virtualTempFolder =<YourVirtualWebRoot>+"/Temp/"+thisReportInstanceID );
Directory.Create(physicalTempFolder );
StringBuilder devInfo = new StringBuilder();
if (format.ToUpper().StartsWith("HTML"))
{
devInfo.Append("<DeviceInfo>");
//StreamRoot should be your fully qualified domain name + temp folder for this report instance.
devInfo.Append("<StreamRoot>" + virtualTempFolder+ "</StreamRoot>");
devInfo.Append("</DeviceInfo>");
}
var result = _reportServerExecutionService.Render(reportFormat, devInfo.ToString(),out extension, out encoding, out mimeType, out warnings, out streamIds);
After the render, the byte[] should contain your report and once it has been displayed on a web page the embedded images should now be sourced to your temp location that is accessible to your web app.
EDIT :
Also, I noticed that you are trying to do some sort of post processing to the content that is returned from Render(). You do not have to touch that at all. Since you told SSRS to replace the image sources via the StreamRoot property then the renderer can handle it from there.
The only steps needed to re-path your report's assets:
Let SSRS know where you plan to place the assets it will be referencing in the report.
Intercept the report streams and save to an accessible location specified in the step above.
NOTE :
Here are some ways to get a virtual and physical temp folder from the context of your web app..
//Virtual Temp Folder - MVC
System.Web.HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) + Url.Content("~/Temp/");
//Virtual Temp Folder - Non-MVC
VirtualPathUtility.ToAbsolute("~/Temp/");
//Physical Temp Folder
AppDomain.CurrentDomain.BaseDirectory + #"Temp\";
Below isway I achieve render report using reporting services (ReportExecutionSerivce class and webrefrence of SSRS)
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)
};
}
public string Render(string reportDirectory, string reportName, string reportFormat, ParameterValue[] parameters)
{
_reportServerExecutionService.ExecutionHeaderValue = new ExecutionHeader();
_reportServerExecutionService.LoadReport("/GES-MVC/"+reportName, null);
_reportServerExecutionService.SetExecutionParameters(parameters, "en-us");
string encoding;
string mimeType;
string extension;
Warning[] warnings;
string[] streamIds;
var result = _reportServerExecutionService.Render(reportFormat, #"<DeviceInfo><StreamRoot>/</StreamRoot><HTMLFragment>True</HTMLFragment></DeviceInfo>", out extension, out encoding, out mimeType, out warnings, out streamIds);
//Here is logic for image replcaement
string html = string.Empty;
html = System.Text.Encoding.Default.GetString(result);
html = GetReportImages(_reportServerExecutionService, reportFormat, streamIds, html);
return html;
}
public string GetReportImages(ReportExecutionService _reportServerExecutionService, string reportFormat, string[] streamIds, string html)
{
if (reportFormat.Equals("HTML4.0") && streamIds.Length > 0)
{
string devInfo;
string mimeType;
string Encoding;
string fileExtension = ".jpg";
string SessionId;
Byte[] image;
foreach (string streamId in streamIds)
{
SessionId = Guid.NewGuid().ToString().Replace("}", "").Replace("{", "").Replace("-", "");
string reportreplacementname = string.Concat(streamId, "_", SessionId, fileExtension);
html = html.Replace(streamId, string.Concat(#"Report\GraphFiles\", reportreplacementname));
devInfo = "";
image = _reportServerExecutionService.RenderStream(reportFormat, streamId, devInfo, out Encoding, out mimeType);
System.IO.FileStream stream = System.IO.File.OpenWrite(HttpContext.Current.Request.PhysicalApplicationPath + "Report\\GraphFiles\\" + reportreplacementname);
stream.Write(image, 0, image.Length);
stream.Close();
mimeType = "text/html";
}
}
return html;
}
and here I pass required parameters to class
string rprwebserviceurl = exceservice;
string ReportDirName = "GES-MVC";
string ReportName = "GES_FWCR";
string RptFormat = "HTML4.0";
ParameterValue[] parameters = new ParameterValue[5];
parameters[0] = new ParameterValue();
parameters[0].Name = "PlantID";
parameters[0].Value = PlantID;
parameters[1] = new ParameterValue();
parameters[1].Name = "FromDateTime";
parameters[1].Value = Convert.ToString(fromDate); // June
parameters[2] = new ParameterValue();
parameters[2].Name = "ToDateTime";
parameters[2].Value = Convert.ToString(Todate);
parameters[3] = new ParameterValue();
parameters[3].Name = "ClientID";
parameters[3].Value = ClientID;
parameters[4] = new ParameterValue();
parameters[4].Name = "SelectedFeeders";
parameters[4].Value = SelectedFeeders;
ReportManager rpt = new ReportManager(rprwebserviceurl,RptUserName,RptPassword, "localhost");
res = rpt.Render(ReportDirName, reportName, RptFormat, parameters);
Related
returning a workbook via an httpresponse in a get call, the method used for an older version of ClosedXML, now returns an empty workbook - workbook tabs are created and correctly named, but are empty.
Sample code - trimmed down for basic response
public HttpResponseMessage Get([FromUri]ControlReportsView model)
{
string client = "EU";
ClosedXML.Excel.XLWorkbook workbook = CreateWorkbook(model, client);
MemoryStream stream = new MemoryStream();
workbook.SaveAs(stream);
stream.Position = 0;
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StreamContent(stream);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition.FileName = string.Format("{0}_{1:yyyyMMdd hhmmtt} to {2:yyyyMMdd hhmmtt}.xlsx", model.Type.ToString(), model.StartDate, model.EndDate);
response.Headers.CacheControl = new CacheControlHeaderValue()
{
Private = true,
MaxAge = TimeSpan.FromSeconds(300)
};
return response;
}
private static ClosedXML.Excel.XLWorkbook CreateWorkbook(ControlReportsView model, string client)
{
using (var workbook = new ClosedXML.Excel.XLWorkbook())
{
CreateTestTab(model, client, workbook);
return workbook;
}
}
private static void CreateTestTab(ControlReportsView model, string client, XLWorkbook workbook)
{
var worksheet = workbook.Worksheets.Add("Sample Sheet");
var firstRow = worksheet.FirstRow();
firstRow.Cell("A").Value = "Hello World!";
}
public class ControlReportsView
{
public enum ControlReportType
{
[Description("R")]
Inbound,
[Description("S")]
Outbound
}
public ControlReportType Type { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
I suspect there's a more elegant tool to do the response now, of which I'm unaware.
I have another file I'm returning successfully via another method, but I'm loath to make this big a change to the set up of the current file:
var stream = new MemoryStream();
workbook.SaveAs(stream);
byte[] fileArray = stream.ToArray();
//build file name
DashObject FarmInfo = (DashObject)MySession.Info;
string ProjName = FarmInfo.ProjectName;
string datemade = DateTime.Now.ToString("yyyyMMdd-HHmmss");
string docName = String.Format("Subscribers_{0}_{1}.xlsx", ProjName, datemade);
Response.ContentType = "application/octet-stream";
string attachVal = "attachment; filename=" + docName;
Response.AppendHeader("Content-Disposition", attachVal);
Response.BinaryWrite(fileArray);
Response.End();
Wow, that was weird.
The data was never making it into the worksheets, even tho they were getting created.
Removing the Using clause somehow sorted it:
private static ClosedXML.Excel.XLWorkbook CreateWorkbook(ControlReportsView model, string client)
{
ClosedXML.Excel.XLWorkbook workbook = new ClosedXML.Excel.XLWorkbook();
CreateTestTab(model, client, workbook);
return workbook;
}
I suspect somehow the worksheet in the using didn't pass back and forth properly for some reason - can anyone confirm?
Hello thanks for looking.
I have some .net code that uses the SSRS Report Execution Service to download a report for the user as an xlsx file.
It works & everything in the report is present & accounted for.
One annoying thing though. When opened in Excel 365 it gives a popup saying:
We found a problem with some content in "theReport.xlsx" Do you want us to try to recover as much as we can? If you trust the source of this workbook click yes
When I click yes then it indicates that the workbook was repaired and the report looks normal.
It does not give any indication what it repaired in the log file, just that it was repaired.
Please take a look at my code. Perhaps there is something small I can change to get rid of the error when the Excel sheet is opened.
private void DownloadQuoteExport()
{
string reportName = "reportName";
string fileName = "filename";
//create web services instance
ReportExecutionService rs = getService();
//render report 1st parameter
ParameterValue param1 = new ParameterValue();
param1.Name = "QuoteID";
param1.Value = quoteId.ToString();
try
{
executeReport(reportName, new ParameterValue[] { param1 }, "EXCELOPENXML", fileName, rs);
}
catch (Exception ex)
{
Response.Write(ex.Message + "<br>" + ex.StackTrace.ToString());
}
}
private void executeReport(String reportName, ParameterValue[] rptParams, String rptFormat, string strRptFileName, ReportExecutionService service)
{
string encoding;
string mimeType;
string extension;
Warning[] warnings = null;
string[] streamIDs = null;
string historyID = null;
ExecutionInfo execInfo = new ExecutionInfo();
ExecutionHeader execHeader = new ExecutionHeader();
service.ExecutionHeaderValue = execHeader;
execInfo = service.LoadReport(reportName, historyID);
service.SetExecutionParameters(rptParams, "en-us");
String SessionId = service.ExecutionHeaderValue.ExecutionID;
byte[] result = service.Render(rptFormat, null, out extension, out encoding, out mimeType, out warnings, out streamIDs);
Response.ClearContent();
if (rptFormat == "EXCELOPENXML")
{
Response.AppendHeader("content-disposition", "attachment; filename=" + strRptFileName + ".xlsx");
Response.ContentType = "application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
Response.BinaryWrite(result);
Response.Flush();
}
This is finally what worked.
private void executeReport(String reportName, ParameterValue[] rptParams, String rptFormat, string strRptFileName, ReportExecutionService service)
{
string encoding;
string mimeType;
string extension;
Warning[] warnings = null;
string[] streamIDs = null;
string historyID = null;
ExecutionInfo execInfo = new ExecutionInfo();
ExecutionHeader execHeader = new ExecutionHeader();
service.ExecutionHeaderValue = execHeader;
execInfo = service.LoadReport(reportName, historyID);
service.SetExecutionParameters(rptParams, "en-us");
String SessionId = service.ExecutionHeaderValue.ExecutionID;
byte[] result = service.Render(rptFormat, null, out extension, out encoding, out mimeType, out warnings, out streamIDs);
Response.ClearContent();
Response.Clear();
if (rptFormat == "EXCELOPENXML")
{
Response.AppendHeader("content-disposition", "attachment; filename=" + strRptFileName + ".xlsx");
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
Response.BinaryWrite(result);
Response.Flush();
Response.SuppressContent = true;
try
{
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
catch (ThreadAbortException ex)
{
//ignore
}
}
I want to export a paginated report from SSRS 2016 with a custom name from code. I can do it if I use the old 2005 control, but when I use the new URL access it either prompts me (if I'm in Edge) but defaults to the name of the report or in Chrome it just downloads with no prompting.
The report name, for example, is MyTestReport with several parameters passed to it. I'd like to be able to use those parameters to set the filename.
http://localhost/ReportServer/Pages/ReportViewer.aspx?/Finance/MyTestReport&i_entityID=98&i_sy=2016&i_runType=3&i_isPreview=true&rs:Format=PDF
That URL would ideally create a filename of 2016_Preview_Report.pdf if possible. I've searched through the SSRS documentation but can't find anything on how to go about doing so. A section of the code I'm using to export to PDF using the old 2005 control is below:
IReportServerCredentials irsc = new CustomReportCredentials(userid, password, domain);
var parametersCollection = new List<ReportParameter>();
parametersCollection.Add(new ReportParameter("i_sy", SY.ToString(), false));
parametersCollection.Add(new ReportParameter("i_entityID", LEA.ToString(), false));
parametersCollection.Add(new ReportParameter("i_runType", runtype.ToString(), false));
parametersCollection.Add(new ReportParameter("i_isPreview", isPreview.ToString(), false));
ReportViewer rv = new Microsoft.Reporting.WebForms.ReportViewer();
rv.ProcessingMode = ProcessingMode.Remote;
rv.ServerReport.ReportServerCredentials = irsc;
rv.ServerReport.ReportPath = REPORT_PATH;
rv.ServerReport.ReportServerUrl = new Uri(SSRS_REPORT_SERVER);
rv.ServerReport.SetParameters(parametersCollection);
rv.ServerReport.Refresh();
byte[] streamBytes = null;
string mimeType = "";
string encoding = "";
string filenameExtension = "PDF";
string[] streamids = null;
Warning[] warnings = null;
FileContentResult ReturnFile = null;
filenameExtension = ExportType;
mimeType = "application/pdf";
streamBytes = rv.ServerReport.Render("PDF", null, out mimeType, out encoding, out filenameExtension, out streamids, out warnings);
ReturnFile = File(streamBytes, mimeType, filename + "."+filenameExtension);
return ReturnFile;
This is how I did it:
public ActionResult GetPDFReport(int? id)
{
string filename = "Generate Filename Here"
NetworkCredential nwc = new NetworkCredential("username", "password");
WebClient client = new WebClient();
client.Credentials = nwc;
string reportURL = "http://servername//ReportServer?PO&rs:Format=PDF&rs:ClearSession=true&Param1=" + id;
return File(client.DownloadData(reportURL), "application/pdf", filename);
}
I have used two web references of ssrs reporting execution service to generate the report. I am using quartz.net windows service for scheduling ssrs reports. My Windows service is working when I use the StdSchedulerFactory.GetDefaultScheduler() but as I execute my job in a Quartz service remotely and use GetScheduler() , it's not working.
public void Execute(IJobExecutionContext context)
{
RS2005.ReportingService2005 rs;
RE2005.ReportExecutionService rsExec;
// Create a new proxy to the web service
rs = new RS2005.ReportingService2005();
rsExec = new RE2005.ReportExecutionService();
// Authenticate to the Web service using Windows credentials
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
rsExec.Credentials = System.Net.CredentialCache.DefaultCredentials;
rs.Url = "http://127.0.0.1:7001/ReportServer/reportservice2005.asmx";
rsExec.Url = "http://127.0.0.1:7001/ReportServer/reportexecution2005.asmx";
string historyID = null;
string deviceInfo = null;
string format = "PDF";
Byte[] results;
string encoding = String.Empty;
string mimeType = String.Empty;
string extension = String.Empty;
RE2005.Warning[] warnings = null;
string[] streamIDs = null;
// Path of the Report - XLS, PDF etc.
string fileName = "samplereport.pdf";
// Name of the report - Please note this is not the RDL file.
string _reportName = #"/reports_Debug/reportname";
string _historyID = null;
bool _forRendering = false;
RS2005.ParameterValue[] _values = null;
RS2005.DataSourceCredentials[] _credentials = null;
RS2005.ReportParameter[] _parameters = null;
try
{
_parameters = rs.GetReportParameters(_reportName, _historyID, _forRendering, _values, _credentials);
RE2005.ExecutionInfo ei = rsExec.LoadReport(_reportName, historyID);
RE2005.ParameterValue[] parameters = new RE2005.ParameterValue[8];
if (_parameters.Length > 0)
{
parameters[0] = new RE2005.ParameterValue();
parameters[0].Name = "FromDate";
parameters[0].Value = "1/1/2016";
parameters[1] = new RE2005.ParameterValue();
parameters[1].Name = "ToDate";
parameters[1].Value = "1/21/2016"; // June
}
rsExec.SetExecutionParameters(parameters, "en-us");
results = rsExec.Render(format, deviceInfo,
out extension, out encoding,
out mimeType, out warnings, out streamIDs);
using (FileStream stream = File.OpenWrite(fileName))
{
stream.Write(results, 0, results.Length);
}
}
catch (Exception ex)
{
throw ex;
}
}
My purpose of this is to render string into view. This is what i have done:
public string RenderRazorViewToString(string viewName, object model, string controllerName)
{
ViewData.Model = model;
Type controllerType = Type.GetType(controllerName + "Controller");
object controller = Activator.CreateInstance(controllerType);
RouteData rd = new System.Web.Routing.RouteData();
rd.Values.Add("controller", "Account");
((ControllerBase)(controller)).ControllerContext = new ControllerContext(HttpContext, rd, (ControllerBase)controller);
ControllerContext cc = ((ControllerBase)(controller)).ControllerContext;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindView(cc, viewName, null);
var viewContext = new ViewContext(cc, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(cc, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
Basically what this code does is to render a view file that is found in :
var viewResult = ViewEngines.Engines.FindView(cc, viewName, null);
And renders it in :
viewResult.View.Render(viewContext, sw);
What i want is not finding view file, but i want to render view that is stored in my database as string. So what i need is:
Getting database view string
Render the database view string
Output it as string after render
How can i achieve this?
You can simply use
#Html.Raw(mystring)
mystring will be the view content stored in database