I am working on SSRS Report. I have a report with an external image embedded in it
This renders fine inside the report viewer.
but when I render report in HTML 4.0 format in my application via web url (without using report viewer).The report that comes back from all the data except the image is not in the html
see the image tag looks like the following:-
<img onerror="this.errored=true;" class="r1" src="http://ges-server-pc/ReportServer_SQLEXPRESS?%2FGES-MVC%2FGES_FWCR&rs%3ASessionID=vdpuofii3xtph545xelnym45&rs%3AFormat=HTML4.0&rs%3AImageID=1403af250c474da8a5f851b63a8a377b">
how can I render extrenal image on Report which is in format= HTML 4.0
Can Anybody have solution for the same It will be appreciable
Thanks in advance
Here is one way to ensure that your application can reliably display images dynamic rendered in a report by SSRS.
When you are using the report viewer control, a lot is done behind the scenes to keep an active session and allow access to all artifacts generated by reports requested by the user. When you are using the ReportExecution api directly there are some advanced reporting features that are just not supported. Interactive sorting, sizing, drilldown and this issue just to name a few.
Always ensuring dynamic images from reports are available to your client is pretty easy. I had to cross this hurdle a way back and I'll share the way I solved it.
In a nutshell, you are going to have to intercept the render, iterate the streams, and save each resource to a temp folder and tell ssrs to look for the image in your temp folder that is behind the web app that your end user has authenticated with.
DeviceInfo
The device info structure, mostly overlooked, is going to come in handy. In this structure you will find a StreamRoot property. You can find documents on this. It basically allows you to override the location from which SSRS will stream resources as needed. This is how you tell SSRS to look for your external images in a new location.
For each report rendered I create a temp folder using a guid prior to rendering. Also, prior to rendering you need to set the StreamRoot to this temp folder.
string physicalTempFolder = MakeNewTempFolderInTempOffOfWebRoot();
string virtualTempFolder = Path.Combine(yourWebRoot,"Temp",Path.GetDirectoryName(physicalTempFolder));
Now you have a physical and virtual pointer to your repo where the images will be saved for your report. Now update the StreamRoot in SSRS. This tells SSRS that we want to override the default location for dynamic images and whatnot.
StringBuilder devInfo = new StringBuilder();
if (YourRenderFormat=="HTML")
{
devInfo.Append("<DeviceInfo>");
devInfo.Append("<StreamRoot>" + virtualTempFolder+ "</StreamRoot>");
devInfo.Append("</DeviceInfo>");
}
With the needed device info structure build we can pass it into the render method.
string extension;
string mimeType;
string reportEncoding;
string[] streamIDs = null;
ReportExecution2005.Warning[] warnings = null;
ReportExecution2005.ExecutionHeader execHeader = new ReportExecution2005.ExecutionHeader();
ReportExecution2005.ExecutionInfo rpt = _execService.LoadReport(YourReportPath, null);
if(YourParamas!=null)
_execService.SetExecutionParameters(YourParams, "en-us");
_execService.ExecutionHeaderValue = execHeader;
_execService.ExecutionHeaderValue.ExecutionID = rpt.ExecutionID;
result = _execService.Render(format, devInfo.ToString(), out extension, out mimeType, out reportEncoding, out warnings, out streamIDs);
The render method returns the streamIDs out parameter and it is key here. Next after we call render, simply iterate all the streams that are images and call ssrs's RenderStream() method to get the images and save to your physical temp folder.
if (YourRenderFormat=="HTML"))
{
string imageEncoding = "";
// For each image stream returned by the call to render,
// render the stream and save it to the application root
string FilePath = physicalTempFolder;
byte[] image;
// For each image stream returned by the call to render,
// render the stream and save it to the application root
foreach (string streamID in streamIDs)
{
image = _execService.RenderStream("HTML4.0", streamID, null, out imageEncoding, out mimeType);
//All files are unique
File.WriteAllBytes(Path.Combine(physicalTempFolder,streamID),image);
}
}
return result;
Related
I am trying to create a solution to show dynamic images in SSRS reports. I have .NET process that generates Base64 strings that after decoding returned to the client. Here is C# code:
byte[] imageBytes = Convert.FromBase64String(image);
MemoryStream exportStream = new MemoryStream(imageBytes, 0, imageBytes.Length);
exportStream.Position = 0;
return Ok(exportStream);
where image is the Base64 string.
It works fine when a client is a Browser. But in the report it shows Red X when I am running it in the report builder. Published report shows nothing at all. Seems like the report doesn't fully understand the return format or something else. Please share any idea.
Thanks
Image properties:
For some reason, any document I upload to OneNote via the new REST API is corrupt when viewed from OneNote. Everything else is fine, but the file (for example a Word document) isn't clickable and if you try and open is shows as corrupt.
This is similar to what may happen when there is a problem with the byte array, or its in memory, but that doesn't seem to be the case. I use essentially the same process to upload the file bytes to SharePoint, OneDrive, etc. It's only to OneNote that the file seems to be corrupt.
Here is a simplified version of the C#
HttpRequestMessage createMessage = null;
HttpResponseMessage response = null;
using (var streamContent = new ByteArrayContent(fileBytes))
{
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data");
streamContent.Headers.ContentDisposition.Name = fileName;
createMessage = new HttpRequestMessage(HttpMethod.Post, authorizationUrl)
{
Content = new MultipartFormDataContent
{
{
new StringContent(simpleHtml,
System.Text.Encoding.UTF8, "text/html"), "Presentation"
},
{streamContent}
}
};
response = await client.SendAsync(createMessage);
var stream = await response.Content.ReadAsStreamAsync();
successful = response.IsSuccessStatusCode;
}
Does anyone have any thoughts or working code uploading an actual binary document via the OneNote API via a Windows Store app?
The WinStore code sample contains a working example (method: CreatePageWithAttachedFile) of how to upload an attachment.
The slight differences I can think of between the above code snippet and the code sample are that the code sample uploads a pdf file (instead of a document) and the sample uses StreamContent (while the above code snippet uses ByteArrayContent).
I downloaded the code sample and locally modified it to use a document file and ByteArrayContent. I was able to upload the attachment and view it successfully. Used the following to get a byte array from a given stream:
using (BinaryReader br = new BinaryReader(stream))
{
byte[] b = br.ReadBytes(Convert.ToInt32(s.Length));
}
The rest of the code looks pretty similar to the above snippet and overall worked successfully for me.
Here are a few more things to consider while troubleshooting the issue:
Verify the attachment file itself isn't corrupt in the first place. for e.g. can it be opened without the OneNote API being in the mix?
Verify the API returned a 201 Http Status code back and the resulting page contains the attachment icon and allows downloading/viewing the attached file.
So, the issue was (strangely) the addition of the meta Content Type in the tag sent over in the HTML content that's not shown. The documentation refers to adding a type=[mime type] in the object tag, and since the WinStore example didn't do this (it only adds the mime type to the MediaTypeHeaderValue I removed it and it worked perfectly.
Just changing it to this worked:
<object data-attachment=\"" + fileName + "\" data=\"name:" + attachmentPartName + "\" />
Thanks for pointing me in the right direction with the sample code!
My idea is to save the images which the user uploads outside the context path as follow:
D:\somefolder\myWeb\web-app\
D:\somefolder\imagesOutsideContextPath\
The code for that is the next (working locally):
String path = servletContext.getRealPath("/");
String parentFolder = new File(path).getParentFile().getParent();
String imagesFolder = parentFolder + "\\imagesOutsideContextPath";
Another idea (if this one doesn't work on server) would be to save the images in the current user's home folder as #HoàngLong suggested me.
But I'm not able to load the images from the view. I think this article from official documentation is not valid for that purpose. The next code desn't load anything:
<img src="D:\\somefolder\\imagesOutsideContextPath\\bestImageEver.jpg" alt="if I don't see this message, I'll be happier">
How could I use the real path instead the an url path to load these images?
There's a new plugin that makes this easy, check out http://grails.org/plugin/img-indirect
Create an action
def profileImage() {
String profilePicturePath = "${grailsApplication.config.profilePictureDirectoryPath}/${params.id}"
File file = new File(profilePicturePath)
response.contentType = URLConnection.guessContentTypeFromName(file.getName())
response.outputStream << file.bytes
response.outputStream.flush()
}
and then call this action with image name in params like:
<g:img uri="${grailsApplication.config.grails.serverURL}/controller/profileImage/${user?.profilePicture?.fileName}"/>
I have declared the image directory file in my config.groovy file like:
profilePictureDirectoryPath = '/opt/CvSurgeon/profileImages'
You can set the src to an action. With that your user will not know where your images are stored (security) and you can easily change your logic to display them.
In the action, just get your image and print the bytes. Example here.
Firstly, thank you for your reference.
It's insecure to load images using real path. The web browser should know nothing about how the pictures are saved on server, therefore not aware of the folder structure.
What I mean is that the system should use a specific URL for all your pictures, such as http://your_app/photo/user/{id}. Then to that URL, you can construct an action which gets id as a parameter, look up the photo in your file system(of course you must store the picture folder in configuration), and render the photo back.
Basically I have a reports server which contains loads of "My Reports" reports which I need to migrate to a new SSRS server.
Question:
Is their an easy way to obtain all the physical.RDL files without having to export the files one-by-one from the old server interface and then upload using the new servers interface?
Looking forward to your reply
Steven
There is a third party tool available here that will allow you to batch download / upload rdls.
http://sqldbatips.com/showarticle.asp?ID=62
You could write a small .NET app to retrieve them all, using the SSRS Web Service API. The article on the GetItemDefinition method has sample code to get a single file, here's a relevant snippet (copy/paste alert!):
ReportingService2010 rs = new ReportingService2010();
rs.Url = "http://<Server Name>/_vti_bin/ReportServer/ReportService2010.asmx";
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
string reportName = "http://<Server Name>/Docs/Documents"
+ "/AdventureWorks Sample Reports/Sales Order Detail.rdl";
byte[] reportDefinition = null;
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
try
{
reportDefinition = rs.GetItemDefinition(reportName);
MemoryStream stream = new MemoryStream(reportDefinition);
string myDocumentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
doc.Load(stream);
doc.Save(Path.Combine(myDocumentsFolder, "Sales Order Detail.rdl"));
}
If you write a little loop around (part of) this code you may be able to quickly grab all the files.
When you create a report using SQL Server Reporting Services 2008 (SP1), that uses .jpg images sometimes you get the following error when you export the report to word.
Index was outside the bounds of the array.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Exception: Index was outside the bounds of the array.
Having discussed this with Microsoft support (a helpful chap called Mikael Ljunghorn) it would appear to be related to whether the .jpg image you are using in your report is encoded using 'progressive' encoding.
To prevent this from occuring, try to avoid using progressive encoded .jpg images in your report.
Mikael also suggested that the following workaround to convert a jpg image to a png sidestepping the conversion problem in word:
1)
Add this custom code block through the Report > Report Properties > Code window.
Function ConvertToPNG(ByVal bytes As Byte()) As Byte()
Dim inStream As New System.IO.MemoryStream(bytes)
Dim bmp As New System.Drawing.Bitmap(inStream)
Dim outStream As New System.IO.MemoryStream()
bmp.Save(outStream, System.Drawing.Imaging.ImageFormat.PNG)
Return outStream.GetBuffer()
End Function
2)
Wrap the database image Value expression in this call: =Code.ConvertToPNG(Fields!ImageBlobField.Value)