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);
As the title suggests, I am looking for a way to export a .NET MVC View to a PDF.
My program works like this:
Page 1
Takes in information
Page 2
Takes this information and heavily styles it with CSS etc
So basically I need to save page 2 after it has been processed and used the information from Page 1's model.
Thanks in advance!
To render a non-static page to a pdf, you need to render the page to a string, using a ViewModel, and then convert to a pdf:
Firstly, create a method RenderViewToString in a static class, that can be referenced in a Controller:
public static class StringUtilities
{
public static string RenderViewToString(ControllerContext context, string viewPath, object model = null, bool partial = false)
{
// first find the ViewEngine for this view
ViewEngineResult viewEngineResult = null;
if (partial)
{
viewEngineResult = ViewEngines.Engines.FindPartialView(context, viewPath);
}
else
{
viewEngineResult = ViewEngines.Engines.FindView(context, viewPath, null);
}
if (viewEngineResult == null)
{
throw new FileNotFoundException("View cannot be found.");
}
// get the view and attach the model to view data
var view = viewEngineResult.View;
context.Controller.ViewData.Model = model;
string result = null;
using (var sw = new StringWriter())
{
var ctx = new ViewContext(context, view, context.Controller.ViewData, context.Controller.TempData, sw);
view.Render(ctx, sw);
result = sw.ToString();
}
return result.Trim();
}
}
Then, in your Controller:
var viewModel = new YourViewModelName
{
// Assign ViewModel values
}
// Render the View to a string using the Method defined above
var viewToString = StringUtilities.RenderViewToString(ControllerContext, "~/Views/PathToView/ViewToRender.cshtml", viewModel, true);
You then have the view, generated by a ViewModel, as a string that can be converted to a pdf, using one of the libraries out there.
Hope it helps, or at least sets you on the way.
We are currently trying to create an action that returns a JsonResult and at certain times that action should also return some HTML inside it along with the other data. Is it possible to generate the HTML from another action that returns a PartialViewResult?
I think this is what you want to achieve.
Generate HTML from another action sounds strange.
You may get the same model from your repository and then render the same PartialView. You will need a method like the following.
// in a RenderingHelper class
public static string RenderViewToString(ControllerContext context, string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = context.RouteData.GetRequiredString("action");
ViewDataDictionary viewData = new ViewDataDictionary(model);
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
ViewContext viewContext = new ViewContext(context, viewResult.View, viewData, new TempDataDictionary(), sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
And then you will render the partial view accordingly:
string renderedHtml = RenderingHelper.RenderViewToString(this.ControllerContext, "~/Views/MyController/MyPartial", viewModel);
Where viewModel is the model used by "other action" too and "~/Views/MyController/MyPartial"is the partial view used by "other action" too.
I have an ASP.NET MVC 3 Controller Action that accepts an object as follows:
//// model.ReferenceNumber equals "-1"
public ActionResult EditApplication(EditApplicationViewModel model)
{
if (!ModelState.IsValid)
{
...
}
// Existing Applicant
model.ReferenceNumber = "";
var msg = this.RenderPartialViewToString("_ExistingApplication", model);
}
When the request is received, the "model.ReferenceNumber" equals "-1". Even after setting the property on the model to empty string "", still the results of "RenderPartialViewToString" shows the value of "-1" in the "Value" property of the "input" HTML field.
Any idea why this is happening?
This is the code used to render the partial view:
http://craftycodeblog.com/2010/05/15/asp-net-mvc-render-partial-view-to-string/
public static string RenderPartialViewToString(this Controller controller, string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = controller.ControllerContext.RouteData.GetRequiredString("action");
controller.ViewData.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
Thanks
When you modify the value of some model property in your controller qction make sure you remove it from the modelstate as well:
ModelState.Remove("ReferenceNumber");
model.ReferenceNumber = "new value";
var msg = this.RenderPartialViewToString("_ExistingApplication", model);
I'm trying to understand correct way to handle backslashes in urls within a string array that are returned via Json...I have commented the goal below
public JsonResult PhotosByListingId(int id)
{
var pics = _listingRepository.GetById(id).ListingPhoto.ToList();
List<string> l = new List<string>();
foreach(var p in pics)
{
//l.Add("albums\\/album1\\/" + p.PhotoName); //nope
//l.Add(#"albums\/album1\/" + p.PhotoName); //nope
l.Add("albums/album1/" + p.PhotoName); //????? nope
}
string[] s = l.ToArray();
return Json(s, JsonRequestBehavior.AllowGet);
//needs to be this..THE GOAL
// ["albums\/album1\/10k.jpg","albums\/album1\/10l.jpg","albums\/album1\/10y.jpg"]
//but is returning this?
// ["albums/album1/10k.jpg","albums/album1/10l.jpg","albums/album1/10y.jpg"]
}
You could try string.Replace:
public JsonResult PhotosByListingId(int id)
{
var pics = _listingRepository.GetById(id).ListingPhoto.ToList();
List<string> l = new List<string>();
foreach(var p in pics)
{
l.Add("albums/album1/".Replace("/", "\\/") + p.PhotoName);
}
string[] s = l.ToArray();
return Json(s, JsonRequestBehavior.AllowGet);
}
Because the javascript serialiser is converting the slashes, you could implement serialisation yourself and modify the generated JSON:
public string CustomSerialised()
{
string test = "/This/That/The other/";
List<string> arr = new List<string>();
arr.Add(test);
arr.Add(test);
arr.Add(test);
System.Web.Script.Serialization.JavaScriptSerializer s = new System.Web.Script.Serialization.JavaScriptSerializer();
return s.Serialize(arr).Replace("/","\\/");
}
This can be navigated to using the standard routing pattern when used within a controller.