I've read through multiple articles regarding this issue however they have all ended up with it not working, or are in vb.net.
What I currently have:
The reports are accessed via a URL which renders them as a PDF and saves them in the downloads folder when the user clicks on a button, these are given generic names such as OrderReport, OrderReport(1)... and so on.
var orderNum = 1;
"http://Server/ReportServer_Name/Pages/ReportViewer.aspx?%2fOrderReport&rs:Command=Render&OrderID=" + orderNum + "&rs:ClearSession=true&rs:Format=PDF"
What I am trying to acheive:
I would like to use C# to fetch this report if possible, and then specify a name for the PDF file and save it in the correct location.
so for example I would like to save this report in a temporary folder for now "C:\temp" with the name OrderID-1. I am using C#
I have added in a ServiceReference into the Project i am using called ReportTestings so the reference is
using ReportTestings;
and the Web Reference URL:
http://Server/ReportServer_Name/ReportExecution2005.asmx
(removed the actual names for security reasons)
so based on all of this information above could someone point me in the right direction or give an example part of code, Thankyou for all that read this post or help
using this code i get this error :(+ e
{"Access to the path 'C:\\Program Files (x86)\\IIS Express\\report1one.pdf' is denied."} System.Exception {System.UnauthorizedAccessException})
code:
ReportExecutionService rs = new ReportExecutionService();
rs.Credentials = new NetworkCredential("username", "password", "domain");
rs.Url = "http://Server/ReportServer_Name/reportexecution2005.asmx";
// Render arguments
byte[] result = null;
string reportPath = "/Invoice";
string format = "PDF";
string historyID = null;
string devInfo = #"<DeviceInfo><Toolbar>False</Toolbar></DeviceInfo>";
// Prepare report parameter.
ParameterValue[] parameters = new ParameterValue[3];
parameters[0] = new ParameterValue();
parameters[0].Name = "InvoiceID";
parameters[0].Value = "2";
DataSourceCredentials[] credentials = null;
string showHideToggle = null;
string encoding;
string mimeType;
string extension;
Warning[] warnings = null;
ParameterValue[] reportHistoryParameters = null;
string[] streamIDs = null;
ExecutionInfo execInfo = new ExecutionInfo();
ExecutionHeader execHeader = new ExecutionHeader();
rs.ExecutionHeaderValue = execHeader;
execInfo = rs.LoadReport(reportPath, historyID);
rs.SetExecutionParameters(parameters, "en-us");
String SessionId = rs.ExecutionHeaderValue.ExecutionID;
Console.WriteLine("SessionID: {0}", rs.ExecutionHeaderValue.ExecutionID);
try
{
result = rs.Render(format, devInfo, out extension, out encoding, out mimeType, out warnings, out streamIDs);
execInfo = rs.GetExecutionInfo();
Console.WriteLine("Execution date and time: {0}", execInfo.ExecutionDateTime);
}
catch (SoapException e)
{
Console.WriteLine(e.Detail.OuterXml);
}
// Write the contents of the report to an MHTML file.
try
{
FileStream stream = File.Create("report1one.pdf", result.Length);
Console.WriteLine("File created.");
stream.Write(result, 0, result.Length);
Console.WriteLine("Result written to the file.");
stream.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
The webservice URL you are using (ReportService2012) is for managing the report server objects.
If you need to render reports, you should be using the ReportExecution2005 webservice.
To get started, you should take a look at the Render method.
To specify credentials you can add the folowing line (I'm the same variable name used in your link: RS2005):
RS2005.Credentials = new System.Net.NetworkCredential("username", "password", "domain");
EDIT:
Your access denied error occurs when your application try to save the file with your web application, so you should use an absolute path or resolve it using Server.MapPath
I recommend an amazingly simple implementation that I found at Crafted For Everyone. The author shows how to add a Service Reference to the SSRS server, and then provides sample code that worked for me on the first try.
It saves the report to a local file, but it is easy to send the report in an email (not included in sample.
Related
I'm trying to create a scanning solution. Basically the user is physically scanning a page. The printer is making an API call, passing in the binary data of the scan in the body.
I'm trying to save this as a PDF on the server, but when I go to open the file, i'm getting an error "There is an error while reading a stream".
var bodyStream = new StreamReader(HttpContext.Current.Request.InputStream);
bodyStream.BaseStream.Seek(0, SeekOrigin.Begin);
var bodyText = bodyStream.ReadToEnd();
string pathToFiles = HttpContext.Current.Server.MapPath("~\\UploadedFiles\\WriteLines.pdf");
try
{
using (StreamWriter outputFile = new StreamWriter(pathToFiles, false))
{
outputFile.WriteLine(bodyText);
}
HttpContext.Current.Response.ContentType = "application/pdf";
}
catch (Exception ex)
{
throw (ex);
}
This is just testing something, and I have permissions etc for writing the file, it's just not creating a valid file.
Any thoughts on what I should use? I have looked into some libraries, but they don't seem to cover what i'm after
StreamReader.ReadToEnd convert bytes to string in particular encoding (UTF8 by default). I don't think this work for PDF.
You need copy bytes directly in the output file :
var bodyStream = HttpContext.Current.Request.InputStream;
bodyStream.Seek(0, SeekOrigin.Begin);
string pathToFiles = HttpContext.Current.Server.MapPath("~\\UploadedFiles\\WriteLines.pdf");
using (FileStream outputFile = File.Create(pathToFiles))
{
bodyStream.CopyTo(outputFile);
}
I am attempting to produce a c# program to run an SSRS report on any one of a number of identical databases, the target database to be specified at run-time. To this end, I create a solution and project, and in this project include an SSRS report. This report has a dataset LegislationData which invokes a stored procedure in a specimen database.
I am now trying to get this to run in the C# project. I create a form with a report viewer and a go button and attempt to set up the report. I envisaged some code along the following lines:-
MyReport my_report = new MyReport();
my_report.ConnectionString = "blah blah"; // or
my_report.DataSet.ConnectionString = "blah blah"; // or
my_report.LegislationData.ConnectionString = "blah blah"
and then
report_viewer.Report = my_report; // or
report_viewer.LocalReport = my_report; // or
report_viewer.SetReport(my_report);
but none of these things actually exist.
Can someone explain to me very slowly and in words of one syllable what I need to do here? I have looked at the answers to similar questions here and here but to be frank the answers make no sense.
The first thing you need to realise is that SSRS has to be added into your C# application as a web reference. There's a guide on how to do this here: https://msdn.microsoft.com/en-gb/library/ms169926.aspx. Basically it sounds worse than it is, and it should only take a few minutes to configure all this. I found that MSDN link was corrupted for me, so here's another place that discusses how to do this: https://sqluninterrupted.com/2012/03/04/adding-a-reporting-services-web-reference-to-net-application/.
Once you have your report running from a C# application you will need to decide what you want to do with the output, convert it to PDF, stream it to the screen, save it as Excel, etc.
I haven't done this before, but it looks as though you can embed a data source into your report that uses an expression based on a parameter. So you would pass in a parameter to run the report that would be a connection string. You would also need to pass in any other parameters you might have in your report.
So step 1 add the web reference for SSRS.
Step 2 add some code to run your report, e.g. here's an example that returns the report as a byte array in PDF format:
public byte[] RenderReport(ReportExecutionService rs, string reportName, int variant)
{
Console.WriteLine("Rendering " + reportName + "_" + variant.ToString("00"));
byte[] result = null;
string reportPath = "/Prototypes/Inheritance Letters/" + reportName;
const string format = "PDF";
const string devInfo = #"<DeviceInfo><Toolbar>False</Toolbar></DeviceInfo>";
//Prepare report parameters
var parameters = new ParameterValue[2];
parameters[0] = new ParameterValue { Name = "row_id", Value = variant.ToString() };
parameters[1] = new ParameterValue { Name = "bulk_run", Value = "1" };
rs.ExecutionHeaderValue = new ExecutionHeader();
rs.LoadReport(reportPath, null);
rs.SetExecutionParameters(parameters, "en-gb");
try
{
string encoding;
string mimeType;
string extension;
Warning[] warnings;
string[] streamIDs;
result = rs.Render(format, devInfo, out extension, out encoding, out mimeType, out warnings, out streamIDs);
rs.GetExecutionInfo();
return result;
}
catch (SoapException e)
{
Console.WriteLine(e.Detail.OuterXml);
return null;
}
}
Step 3 pass the connection string as one of the parameters, and use an expression in an embedded data source in your report to pick this up and use it.
Step 4 decide what to do with the rendered output. For example, here I render a report then save the output to a PDF:
byte[] result = new Render().RenderReport(rs, "ACQ_Welcome_Letter", i);
new Render().CreatePDF(i, "Welcome Letter", "ACQ_Welcome_Letter" + "_" + fuelType, result);
Here's the CreatePDF method, it has a lot of other garbage in for my particular solution, but it gives you a taste of how to do this:
public string CreatePDF(int variant, string subFolder, string reportName, byte[] result)
{
//We want 16 variants, but we pass in a number from 1 to 48, so use modulo division to convert this back to a 1 to 16 range
variant = (variant - 1) % 16 + 1;
Console.WriteLine("Saving " + reportName + "_Variant_" + variant.ToString("00") + ".pdf");
try
{
//Determine the target folder/ filename for the PDF
//Snail Mail has its own folder, all PDFs go into that folder and then are manually processed
string folder = #"S:\Change Management Documents\SMETS1\Inheritance Comms\" + subFolder + #"\";
string filename = reportName + "_Variant_" + variant.ToString("00") + ".pdf";
//Remove any existing content
string[] filePaths = Directory.GetFiles(folder, filename);
foreach (string filePath in filePaths)
File.Delete(filePath);
//Now save the PDF
string path = folder + #"\" + filename;
FileStream stream = File.Create(path, result.Length);
stream.Write(result, 0, result.Length);
stream.Close();
return filename;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return "";
}
}
I would like to somehow cycle through my Reporting Server and display available reports to the user. Is this possible?
My Code is as follows (still in development):
ServerReport sr = new ServerReport();
sr.ReportPath = reportViewer1.ServerReport.ReportPath;
sr.ReportServerUrl = new Uri(Path);
ReportParameterInfoCollection rpc = sr.GetParameters();
if (rpc.Count > 0)
Console.WriteLine("New");
string outputPath = #"C:\Temp\PdfReport.pdf";
string mimeType;
string encoding;
string extension;
string[] streams;
Warning[] warnings;
byte[] pdfBytes= sr.Render("PDF", string.Empty, out mimeType,
out encoding, out extension, out streams, out warnings);
// save the file
using (FileStream fs = new FileStream(outputPath, FileMode.Create))
{
fs.Write(pdfBytes, 0, pdfBytes.Length);
fs.Close();
}
I use the ReportingService2010 web service to retrieve all deployed items (data sources, shared data sets and reports) and also to deploy directly to Reporting Services.
Here is just one example of the many methods available:
http://msdn.microsoft.com/en-us/library/reportservice2010.reportingservice2010.listchildren.aspx
The ListChildren method will return all items (as a CatalogItem object) under a folder. If you give it the root folder, it will return everything. You should then be able to determine what item each CatalogItem represents.
Hope that helps,
Ash
For anyone else having this problem and would like more information about Ash Shah's answer, see this SO post:
How do I get a list of the reports available on a reporting services instance
Currently I have this code right now,
In my html page, on the form I have this:
<input type="file" id="txtUploadFile" accept="image/*" onchange="changetext();"/>
I upload the picture using javascript on my doUpload() function
function doUpload() {
var srwebserviceURL = "/Webservices/Facilities/ServiceRequest.asmx";
var sMsgBody = "<filePath>" + txtUploadFile.value + "</filePath>";
var a = sendSoapMsg(srwebserviceURL, "SaveSRLogoPhotoSite", sMsgBody, "SaveSRLogoPhotoSiteResult");
}
So as you can see from the code above, I am passing the file path of the photo to my webservice.
On my webservice, the SaveSRLogoPhotoSite, I have the ff. code:
public SRLogoPhoto SaveSRLogoPhotoSite(string filePath)
{
DataSet ds = null;
Hashtable param = new Hashtable();
SRLogoPhoto srlp = new SRLogoPhoto();
try
{
System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
Byte[] b = new Byte[fs.Length];
fs.Read(b, 0, b.Length);
fs.Close();
SqlParameter P = new SqlParameter("#Picture", SqlDbType.VarBinary, b.Length, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Current, b);
string sqlStr = "UPDATE SRSiteLogo SET srImage = #Picture ";
param.Add("Picture", P);
ds = dbHelper.GetDataSet(sqlStr, param);
}
catch (Exception ex)
{
srlp.Error = "SaveSRLogoPhotoSite() web method failed on call to dbHelper.GetDataSet - " + ex.Message;
}
return srlp;
}
This is working on my local pc. But it does not seem to work when I deploy it to an environment other than my pc. When I try to debug in soapUI, it says that it cannot find the file path.
It seems that the filepath I should pass on my webservice should be on the server first instead of the filepath of the current filesystem of the pc it is in.
How do I do that?
--edit-- I was informed that this is possible using ajax..I'm new to ajax and don't know how to do it..
Thank you in advance
When you run web on local, file that you need upload and server lie on a machine, so you can determine file path and execute upload task. Howerver, when you deploy your web to another server, you can't determine path file. You have to convert file to stream and send to server, read stream, convert to expect format and go ahead.
Thanks.
I have read a few questions around and i tried those examples and they worked for me, here are links:
- Link 1
- Link 2
- Link 3
However,
What i'm tryin to accomplish its a little bit different, im trying to modify/upload a .DAT file that contains plain text inside. Im able to read file contents with no problems but i always get 400 Bad Request(Protocol Error). Heres my code.
DocumentsService service = new DocumentsService("Man");
service.setUserCredentials(UserName, Passwod);
DocumentsListQuery fileQuery = new DocumentsListQuery();
fileQuery.Query = User.FileName;
fileQuery.TitleExact = true;
DocumentsFeed feed = service.Query(fileQuery);
//Here I get my file to update
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Set the media source
//Here I have tried application/octet-stream also
entry.MediaSource = new MediaFileSource(DataStream, User.FileName, text/plain");
// Instantiate the ResumableUploader component.
ResumableUploader uploader = new ResumableUploader();
// Set the handlers for the completion and progress events
uploader.AsyncOperationCompleted += new AsyncOperationCompletedEventHandler(OnDone);
uploader.AsyncOperationProgress += new syncOperationProgressEventHandler(OnProgress);
ClientLoginAuthenticator authenticator = new ClientLoginAuthenticator("Man", ServiceNames.Documents,Credentials);
Uri updateUploadUrl = new Uri(UploadUrl);
AtomLink aLink = new AtomLink(updateUploadUrl.AbsoluteUri);
aLink.Rel = ResumableUploader.CreateMediaRelation;
entry.Links.Add(aLink);
// Start the update process.
uploader.UpdateAsync(authenticator,entry,new object());
Thanks.
EDIT:
This is how i solved it. Thanks to Claudio for guide me on the proper direction
Download Example Application from : Download Sample (.zip)
Implement to your project from SampleHelper Project these: AuthorizationMgr, INativeAuthorizationFlow, LoopbackServerAuthorizationFlow, WindowTitleNativeAuthorizationFlow
Use it with this code:
//Call Authorization method... (omitted)
File body = new File();
body.Title = title;
body.Description = description;
body.MimeType = mimeType;
byte[] byteArray = System.IO.File.ReadAllBytes(filename);
MemoryStream stream = new MemoryStream(byteArray);
try {
FilesResource.InsertMediaUpload request = service.Files.Insert(body, stream, mimeType);
request.Upload();
File file = request.ResponseBody;
// Uncomment the following line to print the File ID.
// Console.WriteLine("File ID: " + file.Id);
return file;
} catch (Exception e) {
Console.WriteLine("An error occurred: " + e.Message);
return null;
}
Whenever the server returns a 400 Bad Request, it also includes a descriptive error message telling what is invalid in your request. If you can't get to it from the debugger, you should install Fiddler and capture the HTTP request and response.
Another advice I have for you is to start using the newer Drive API instead of the Documents List API. Here is a 5-minute C# quickstart sample showing how to upload a file to Google Drive:
https://developers.google.com/drive/quickstart