Embedding SSRS 2016 reports into another webpage without iFrame? - reporting-services

Reporting-services 2016 (currently only available as a technical preview) comes with big-upgrades including HTML5 rendering and compliance. See: https://msdn.microsoft.com/en-us/library/ms170438.aspx
My desire is to embed SSRS 2016 reports into another webpage using native mode (no Sharepoint or aspx, just pure HTML5).
The traditional fashion to do this is to use an iFrame.
This is an half-way okay method as it's possible to remove the toolbar, hide parameters etc but still you end up losing a lot of control over the document. This is a cross-site implementation from a different domain so I can't manipulate the contained iFrame document as I please.
Does there exist an official way to embed the report element 'natively'?
I could envision a URL parameter option like rs:Format=REPORTDIV which serves me a html element.
I also tried fetching the report as an image (rs:Format=IMAGE&rc:OutputFormat=PNG) but the resulting PNG has a huge white frame (even when setting background to transparent in Report Builder) around the report element which is a no-go.

This should work. It should work outside of the environment as well as it embeds the images from memory instead of fetching them from the database
// Create service instance
ReportExecutionServiceSoapClient rsExec = new ReportExecutionServiceSoapClient(binding, endpoint);
rsExec.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
rsExec.ChannelFactory.Credentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
ReportingServices.Extension[] extentions = null;
ReportingServices.TrustedUserHeader trustedUserHeader = new ReportingServices.TrustedUserHeader();
rsExec.ListRenderingExtensions(trustedUserHeader, out extentions);
string reportPath = "/Untitled";
ExecutionInfo execInfo = new ExecutionInfo();
ExecutionHeader execHeader = new ExecutionHeader();
ReportingServices.ServerInfoHeader serverInfo = new ReportingServices.ServerInfoHeader();
string historyID = null;
rsExec.LoadReport(trustedUserHeader, reportPath, historyID, out serverInfo, out execInfo);
//Get execution ID
execHeader.ExecutionID = execInfo.ExecutionID;
string deviceInfo = null;
string extension;
string encoding;
string mimeType;
ReportingServices.Warning[] warnings = new ReportingServices.Warning[1];
warnings[0] = new ReportingServices.Warning();
string[] streamIDs = null;
string format = "HTML5";
Byte[] result;
rsExec.Render(execHeader, trustedUserHeader, format, deviceInfo, out result, out extension, out mimeType, out encoding, out warnings, out streamIDs);
var report = Encoding.UTF8.GetString(result);
int streamIdCount = streamIDs.Length;
Byte[][] imageArray = new Byte[streamIdCount][];
String[] base64Images = new String[streamIdCount];
for (int i = 0; i <= streamIdCount - 1; i++)
{
Byte[] result2;
string streamId = streamIDs[i];
rsExec.RenderStream(execHeader, trustedUserHeader, format, streamId, deviceInfo, out result2, out encoding, out mimeType);
imageArray[i] = result2;
base64Images[i] = Convert.ToBase64String(result2);
string replace = string.Format("https://<reportserver>/ReportServer?%2FUntitled&rs%3ASessionID={0}&rs%3AFormat={1}&rs%3AImageID={2}", execInfo.ExecutionID, format, streamId);
string src = string.Format("data:{0};charset=utf-8;base64, {1}", mimeType, base64Images[i]);
report = report.Replace(replace, src);
}

Related

MFC: Using CHtmlView with memory string via about: or data:?

I am trying out CHtmlView to display html from memory variables. After having dealt with the various exceptions you get in debug mode, have it working for very small strings via the about: uri.
Example:
Navigate(_T("about:<html><head></head><body>Hello</body></html>"))
works for small items but not larger strings. Does anyone know the documented limitation for about: ?
Now I found a new item that supposed to be available for IE, the data: entry, but when I try
Navigate(_T("data:text/html, <html><head></head><body>Hello</body></html>"))
It doesn't work, comes up with the fancy webpage can't be displayed page. Does anyone know why CHtmlView doesn't support data: and if there is any other trick that can be used to use memory variable data for html display in CHtmlView?
One option for setting HTML content directly, is to read from memory using IStream
MFC's CHtmlEditCtrl uses a similar method to set document html content, except MFC uses CStreamOnCString.
You may need to set the content to UTF8 for compatibility. To use UTF8,
change CString to CStringA in the code below, and pass UTF8 string to the function SetHTMLContent(htmlview, u8"<html>...")
HRESULT SetHTMLContent(CHtmlView* htmlview, CString html)
{
if(!html.GetLength()) return E_FAIL;
CComPtr<IDispatch> disp = htmlview->GetHtmlDocument();
if(!disp)
{
//not initialized, try again
htmlview->Navigate(_T("about:"));
disp = htmlview->GetHtmlDocument();
if(!disp)
return E_NOINTERFACE;
}
CComQIPtr<IHTMLDocument2> doc2 = disp;
if(!doc2) return E_NOINTERFACE;
int charsize = sizeof(html.GetAt(0));
IStream *istream = SHCreateMemStream(
reinterpret_cast<const BYTE*>(html.GetBuffer()), charsize * html.GetLength());
HRESULT hr = E_FAIL;
if(istream)
{
CComQIPtr<IPersistStreamInit> psi = doc2;
if(psi)
hr = psi->Load(istream);
istream->Release();
}
html.ReleaseBuffer();
return hr;
}
Usage:
CString str = _T("<html><head></head><body>Hello</body></html>");
SetHTMLContent(m_chtmlview, str);

SSRS How do you increase the size of the text report parameter

I am trying to pass an image into a report via the text report parameter.However, it only seems to work when the image is small. The code I am using to call the report is along these lines:
private CustomerAttachment LoadFromReportServer(byte[] imgAsByte)
{
string mimeType, encoding, extension;
string[] streamids;
Warning[] warnings;
string base64String = Convert.ToBase64String(imgAsByte);
_reportParams = new List<ReportParameter>();
_reportParams.Add(new ReportParameter("p_farm_map", base64String));
var rptViewer = new ReportViewer();
rptViewer.ShowCredentialPrompts = false;
rptViewer.ShowParameterPrompts = false;
rptViewer.ProcessingMode = ProcessingMode.Remote;
_reportServerUrl = "http://MyReportServer.wesenergy.local/ReportServer";
_reportFolderPath = "/WcfReportTest/";
_reportName = "FarmMapReport";
rptViewer.ServerReport.ReportServerUrl = new Uri(_reportServerUrl);
rptViewer.ServerReport.ReportPath = _reportFolderPath + _reportName;
rptViewer.ServerReport.SetParameters(_reportParams);
//Fails on this line here
byte[] bytes = rptViewer.ServerReport.Render(_reportFormat, deviceInfo, out mimeType, out encoding, out extension, out streamids, out warnings);
return new CustomerAttachment(_customerId, _fileName,"application/pdf", bytes);
}
In the report p_farm_map is a Text report parameter.
The error I get on larger files is rsInvalidParameter error.
Is there a way to explicitly set the max size of the Text data type?
Due to lack of a response to this question and project time constraints the alternate solution was to save the image to a share; pass the file location through via the text field to the report and have the image use that text value as the source for the image. Not an ideal solution as I have to write and read from a disk (slow). Plus I now have to clean up these files as well.

F#: DataContractJsonSerializer.WriteObject method

I am new to programming and F# is my first language.
Here are the relevant parts of my code:
let internal saveJsonToFile<'t> (someObject:'t) (filePath: string) =
use fileStream = new FileStream(filePath, FileMode.OpenOrCreate)
(new DataContractJsonSerializer(typeof<'t>)).WriteObject(fileStream, someObject)
let dummyFighter1 = { id = 1; name = "Dummy1"; location = "Here"; nationality = "Somalia"; heightInMeters = 2.0; weightInKgs = 220.0; weightClass = "Too fat"}
let dummyFighter2 = { id = 2; name = "Dummy2"; location = "There"; nationality = "Afghanistan"; heightInMeters = 1.8; weightInKgs = 80.0; weightClass = "Just Nice"}
let filePath = #"G:\User\Fighters.json"
saveJsonToFile dummyFighter1 filePath
saveJsonToFile dummyFighter2 filePath
When I run "saveJsonToFile dummyFighter1 filePath", the information is successfully saved. My problem is this: Once I run "saveJsonToFile dummyFighter2 filePath", it immediately replaces all the contents that are already in the file, i.e., all the information about dummyFighter1.
What changes should I make so that information about dummyFighter2 is appended to the file, instead of replacing information about dummyFighter1?
Change the way you open a file setting FileMode.OpenOrCreate to FileMode.Append. Append means "create or append" :
use fileStream = new FileStream(filePath, FileMode.Append)
From MSDN (https://msdn.microsoft.com/fr-fr/library/system.io.filemode%28v=vs.110%29.aspx) :
FileMode.Append opens the file if it exists and seeks to the end of the file, or
creates a new file. This requires FileIOPermissionAccess.Append
permission. FileMode.Append can be used only in conjunction with
FileAccess.Write. Trying to seek to a position before the end of the
file throws an IOException exception, and any attempt to read fails
and throws a NotSupportedException exception.

Html e-mail not being updated fast enough for smtp

Is there a known issue with SMTP and timing? I have included some code below that basically sends a birthday greeting to someone, along with a horoscope and other people that share their birthday (for fun).
I use Regex replace to get both elements, horoscope and other people, from other methods and insert them into the HTML document between a pair of "p" tags. I am positive that those methods work, and I am positive that the HTML document is being properly reformatted (according to the console, which prints out my new HTML document in another test of mine). I am thinking that maybe my problem is that the e-mail is sent off before the replacement has a chance to happen, but I could very easily be was off base. If anyone has had this issue before or knows the cause of it, I would be very appreciative. TIA.
public void formatHTMLTest()
{ using (StreamReader reader = File.OpenText("../../BirthdayMessage.htm"))
{
//Format the body
//Format the Famous People
string html = reader.ReadToEnd();
string replacePattern1 = "<!--INJECT FAMOUS PEOPLE HERE-->";
List<string> famousPeople = new List<string>();
famousPeople.Add("test1");
famousPeople.Add("test2");
famousPeople.Add("test3");
StringBuilder famousSB = new StringBuilder();
foreach (string person in famousPeople)
{
famousSB.Append(person + ", ");
}
int length = famousSB.Length;
famousSB.Remove(length - 2, 2);
string famousString = famousSB.ToString();
string html1 = Regex.Replace(html, replacePattern1, famousString);
//Format the Horoscope
string horoscope = "FOO.";
string replacePattern2 = "<!--INJECT HOROSCOPE HERE-->";
string html2 = Regex.Replace(html1, replacePattern2, horoscope);
//Configuring the SMTP client
SmtpClient smtp = new SmtpClient();
smtp.Port = 25;
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.UseDefaultCredentials = false;
smtp.Credentials = new NetworkCredential("barfoo#sender.com", "senderPass");
smtp.Host = "mysmtp";
//Set up email that is sent to the client
MailMessage clientEmail = new MailMessage();
clientEmail.From = new System.Net.Mail.MailAddress("barfoo#sender.com");
clientEmail.To.Add(new MailAddress("foobar#recipient.com"));
clientEmail.Subject = "Happy Birthday!";
clientEmail.IsBodyHtml = true;
clientEmail.Body = html;
//using (smtp as IDisposable)
{
smtp.Send(clientEmail);
clientEmail.Dispose();
}
}
}
I guess this goes without saying since I was able to get an e-mail, but just for clarity's sake, the SMTP has no issues also. I am fully able to receieve e-mails. The issue is that they do not contain the replaced html that appears in my console for other tests.
Also, any other things you see wrong with this code (optimizations, etc), don't hesitate to comment. I'm always willing to learn! Thanks
You are injecting the string html into the body. It should be html2?

SSRS 2008 Export Report to Image Only Exports First Page

Ok, so i am working on exporting my SSRS 2008 Reports to an image. What I would like to do is Export each individual page as an image. From my code, I can only get it to export the first page of the report. Any help would greatly be appreciated.
Dim warnings As Microsoft.Reporting.WebForms.Warning()
Dim streamids As String()
Dim mimeType, encoding, extension As String
Dim deviceInfo As XElement = _
<DeviceInfo>
<OutputFormat>JPEG</OutputFormat>
</DeviceInfo>
Report.ServerReport.SetParameters(Parameters)
Dim bytes As Byte() = Report.ServerReport.Render("Image", deviceInfo.ToString(), mimeType, encoding, extension, streamids, warnings)
Dim FileStream As New MemoryStream(bytes)
Dim ReportImage As New System.Drawing.Bitmap(FileStream)
ReportImage.Save(Server.MapPath("/Testing.jpg"), System.Drawing.Imaging.ImageFormat.Jpeg)
in one of my projects I use the following code to obtain one stream per page. Unfortunately I don't use VB.NET, but you should be able to translate this from C# to VB. Note: This works on SSRS2005 - I'm not sure it also works for SSRS2008! Also, I'm using the code to directly print the report without having to use the report viewer, so I'm creating an EMF device info - you might have to change this.
This base code was found somewhere on the Web after Googling for hours - I'd like to credit the author, but I didn't bookmark the link - sorry.
CultureInfo us = new CultureInfo("en-US");
string deviceInfo = String.Format(
"<DeviceInfo>" +
" <OutputFormat>EMF</OutputFormat>" +
" <PageWidth>{0}cm</PageWidth>" +
" <PageHeight>{1}cm</PageHeight>" +
" <MarginTop>{2}cm</MarginTop>" +
" <MarginLeft>{3}cm</MarginLeft>" +
" <MarginRight>{4}cm</MarginRight>" +
" <MarginBottom>{5}cm</MarginBottom>" +
"</DeviceInfo>",
Math.Round(m_pageSize.Width, 2).ToString(us),
Math.Round(m_pageSize.Height, 2).ToString(us),
Math.Round(m_marginTop, 2).ToString(us),
Math.Round(m_marginLeft, 2).ToString(us),
Math.Round(m_marginRight, 2).ToString(us),
Math.Round(m_marginBottom, 2).ToString(us));
m_reportStreams = new List<Stream>();
try
{
// Tell SSRS to store one stream per page on server
NameValueCollection urlAccessParameters = new NameValueCollection();
urlAccessParameters.Add("rs:PersistStreams", "True");
// Render first page
Stream s = viewer.ServerReport.Render("IMAGE", deviceInfo, urlAccessParameters, out mime, out extension);
m_reportStreams.Add(s);
// Loop to get other streams
urlAccessParameters.Remove("rs:PersistStreams");
urlAccessParameters.Add("rs:GetNextStream", "True");
do
{
s = viewer.ServerReport.Render("IMAGE", deviceInfo, urlAccessParameters, out mime, out extension);
if (s.Length != 0) m_reportStreams.Add(s);
}
while (s.Length > 0);
// Now there's one stream per page - do stuff with it
}
finally
{
foreach (Stream s in m_reportStreams)
{
s.Close();
s.Dispose();
}
m_reportStreams = null;
}
EDIT
Forgot to mention that viewer is a programmatically created instance of the ReportViewer control initialized to render the report that you're trying to print/save.