I have a Java API endpoint that returns an excel (I am using content-disposition=Content-Disposition","attachment; filename=Audit.Report.xlsx).
I have another Angular-Node JS application that needs to consume this API and when the user clicks on a link, it should pull the excel and display a pop-up asking them the location to save the document. I am at a loss as to how I can do this. I tried doing the following on the server side though,
Server Code:
getAuditReport = function ( req, resp ) {
var numberOfMonths = req.query.numberOfMonths;
console.log('In first method ' + numberOfMonths);
var auditReportPromise = this.getAuditReportXlPromise ( numberOfMonths );
auditReportPromise.then ( function ( data ) {
resp.headers('Content-Disposition: attachment; filename="audit.report_'+ new Date() + '".xls"');
resp.ContentType = "application/vnd.ms-excel";
resp.status ( 200 ).send ( data );
} ).catch ( function ( err ) {
resp.status ( 500 ).send ( err );
} );
}
The getAuditReportXlPromise method returns a promise to invoke the get method of the Java API. On invoking this API via a browser, I get the excel content on the browser rather than a prompt requesting me to save the document somewhere.
Can someone suggest what's wrong here, and what I need to do on the client side for the click functionality to work.
Update 1:
Following is the code from the HTML
<a id='10051' href="{{url}}" target=_blank class="ok-white-text">
Download Report
</a>
Based on the duration the user selects, I'm building the URL - this is getting built correctly.
If your API provides the file using GET then you should be able to download the file in a simple way by just setting a link to that API (i.e. an anchor containing the link like Download).
In this scenario the browser will take over the download process (i.e. locating the folder to download to, if configured to do so).
If you want to process the file on client side, then you need to transfer it in a binary mode as suggested by multiple answer for this question.
To answer how I did manage to get around this,
Client Side:
In the component, I did the following - wrote a method on clicking the button that contains a window.open to the url - something like,
window.open("<path to the java api>", '_blank');
The link like I mentioned above was a java api that was already generating the excel file.
Related
Hi and thank you in advance for any help,
I am trying to post a JSON-Object to an ASP.Net MVC-Server via JQuery/Ajax. The Controller method is supposed to take the JSON input and use it as a DataProvider for List&Label 22. The Report should then be generated and offered to the user as a PDF file for download.
Since I want the structure of the JSON Object to be generic, I don't want to create a specific model in ASP.Net for this request, but rather pass over the JSON object as a string (I know that I might run into some size restrictions, but I will worry about that later :) ).
Here is my POST request:
<script>
function getReport() {
//dummy data
data = { JsonVariable1: 1, JsonVariable2: "JsonVariable2" };
var dataSource = JSON.stringify(data);
$.ajax({
type: "POST",
dataType: "text",
url: "#Url.Action("/JsonTest")",
data: "aDataSource=" + dataSource,
async: false,
success: function (result) {
alert('Success!');
}
});
}
And this is the Controller method:
[HttpPost]
public ActionResult JsonTest(string aDataSource) {
combit.ListLabel22.ListLabel vLL = new combit.ListLabel22.ListLabel();
JsonDataProvider vJsonProvider = new JsonDataProvider(aDataSource);
vLL.FileRepository = GetCurrentRepository();
vLL.AutoProjectFile = mReportRepositoryId;
vLL.DataSource = vJsonProvider;
vLL.ExportOptions.Add(LlExportOption.ExportTarget, "PDF");
vLL.Print(); //This causes problem on published server
return Json("Success");
}
Locally, i.e. in my Visual Studio (2015) dev environment this works fine. However, when I publish the code to my IIS-Server, the POST-request doesn't terminate. I have found this line
vLL.Print();
to be the problem. If I comment out this line, the request terminates as expected. This line generates the report and exports it to a PDF which will in turn be offered to the user as a download.
I'm using IIS 8.5 and .NET-Framework 4.5 on a Machine running Windows Server 2012 R2. A Printer Driver is installed and the regular List&Label funcationality is working (e.g. starting the web designer, previewing reports via HTML, etc).
Does anyone have any idea what I am missing here? I am not a web developer, and I may also have forgotten to adjust some configurations on my IIS Server.
Thanks!
Just calling the Printmethod is not enough as you need to tell List & Label where to generate the report. I'd rather use the Export method (as it wires up a number of convenient things like muting the file dialogs) in this way:
string reportResult = "Report." + Guid.NewGuid() + ".pdf";
string outputFile = Server.MapPath("~/exports/") + reportResult;
ExportConfiguration exportConfiguration = new ExportConfiguration(LlExportTarget.Pdf, outputFile, mReportRepositoryId);
vLL.Export(exportConfiguration);
You should then find your PDF in the "exports" path of your web application on the server. To troubleshoot issues like this you can use the provided debugging tool Debwin4. It shows you all calls to the API and hints on missing options or input.
Let's say I configure redstone as follows
#app.Route("/raw/user/:id", methods: const [app.GET])
getRawUser(int id) => json_about_user_id;
When I run the server and go to /raw/user/10 I get raw json data in a form of a string.
Now I would like to be able to go to, say, /user/10 and get a nice representation of this json I get from /raw/user/10.
Solutions that come to my mind are as follows:
First
create web/user/user.html and web/user/user.dart, configure the latter to run when index.html is accessed
in user.dart monitor query parameters (user.dart?id=10), make appropriate requests and present everything in user.html, i.e.
var uri = Uri.parse( window.location.href );
String id = uri.queryParameters['id'];
new HttpRequest().getString(new Uri.http(SERVER,'/raw/user/${id}').toString() ).then( presentation )
A downside of this solution is that I do not achieve /user/10-like urls at all.
Another way is to additionally configure redstone as follows:
#app.Route("/user/:id", methods: const [app.GET])
getUser(int id) => app.redirect('/person/index.html?id=${id}');
in this case at least urls like "/user/10" are allowed, but this simply does not work.
How would I do that correctly? Example of a web app on redstone's git is, to my mind, cryptic and involved.
I am not sure whether this have to be explained with connection to redstone or dart only, but I cannot find anything related.
I guess you are trying to generate html files in the server with a template engine. Redstone was designed to mainly build services, so it doesn't have a built-in template engine, but you can use any engine available on pub, such as mustache. Although, if you use Polymer, AngularDart or other frameowrk which implements a client-side template system, you don't need to generate html files in the server.
Moreover, if you want to reuse other services, you can just call them directly, for example:
#app.Route("/raw/user/:id")
getRawUser(int id) => json_about_user_id;
#app.Route("/user/:id")
getUser(int id) {
var json = getRawUser();
...
}
Redstone v0.6 (still in alpha) also includes a new foward() function, which you can use to dispatch a request internally, although, the response is received as a shelf.Response object, so you have to read it:
#app.Route("/user/:id")
getUser(int id) async {
var resp = await chain.forward("/raw/user/$id");
var json = await resp.readAsString();
...
}
Edit:
To serve static files, like html files and dart scripts which are executed in the browser, you can use the shelf_static middleware. See here for a complete Redstone + Polymer example (shelf_static is configured in the bin/server.dart file).
I'm building up a test in Geb (WebDriver) and need to submit a form which will create a file in response.
I am able to download the file (the Browser save it automatically to the disk), but I wand to check it in GEB.
I've tried withNewWindow(), but it only works on URIs??
I've tried downloadXXX(), but no luck either...
How can I download a file into a variable?
class CSVTest extends GebReportingTest
#Test
void csvCreation() {
to CSVExport
// select entries / fill values
selectAllEntries.value(true)
//// this will do a post
//// the server will render a file and deliver it back as a result of the submit
// CORRECTLY downloads the file
submitButton.click()
// NOT WORKING
withNewWindow (submitButton.click()) {
...
}
// NOT WORKING
def csv = download(submitButton.click())
}
}
You won't be able to intercept the file downloaded by the browser after clicking a button that does a post in any way unfortunately.
You will have to synthesize a post request with the right content which is sent when using the form. While it is possible to do so using Geb's DownloadSupport class it will be complicated and clunky. You're better off using a library for which performing such requests is the main functionality, like for example REST-Assured.
I am currently doing a POST to a Web Api method and am posting an array of objects. When I get to the method, my parameters are resolved properly, and I make a call to the DB and return a list of records.
I then take those records and convert them to a MemoryStream to be downloaded by the browser as an Excel spreasheet. From there, I create an HttpResponseMessage object and set properties so that the browser will recognize this response as a spreadsheet.
public HttpResponseMessage ExportSpreadsheet([FromBody]CustomWrapperClass request){
var result = new HttpResponseMessage();
var recordsFromDB = _service.GetRecords(request);
MemoryStream export = recordsFromDB.ToExcel(); //custom ToExcel() extension method
result.Content = new StreamContent(export);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.Name = "formName";
result.Content.Headers.ContentDisposition.FileName = "test.xlsx";
return result;
}
Instead of seeing the spreadsheet being downloaded, nothing seems to happen. When I check the developer tools (for any browser), I see the Response Headers below while the Response tab just shows binary data. Does anyone know what I might be missing here?
How are you doing your POST? It sounds like you might be trying to this via a javascript AJAX call, which cannot be done (https://stackoverflow.com/a/9970672/405180).
I would instead make this a GET request for starters, and use something like window.location="download.action?para1=value1....". Generally web api Post requests are made to create a file/entry, not retrieve one.
Alternatively, you could use a HTML Form with hidden elements corresponding to your query parameters, and use javascript to submit the form.
I had this working on kohana 2, but in kohana 3 it doesn't.
To serve an image stored as BLOB in a database, I did the following:
1- A controller to which I request what image do I want. I connects to the database, using a model of course, and serve the image using a view.
$prod = ORM::factory('product',$idx);
$img = new View('image');
$img->pic = $prod->getImage();
2-The model has a little trick to get this working:
public function getImage()
{
return imagecreatefromstring($this->image);
}
image is the blob column where I store the picture I want to serve.
3- In the view:
I set the content-type header and then serve the image
header('content-type: image/png; charset=UTF-8');
imagepng($pic);
This worked in Kohana 2, but in KO3 it doesn't,
I'm trying to use $response->send_file(), but I'm getting lost
First, you should never send headers with header() unless you're hacking the fw. Ko3.1 nicely separates Request from Response and the latter is the one responsible for response headers / everything else (both of them are written pretty much following the RFC 2616).
Secondly, there is absolutelly no need for a view file in this case, Response::$_body is what the current response object returns.
Response::send_file() returns the response as download, I suppose that's not what you're trying to accomplish?
So, you need something like this (modify to your own needs):
public function action_image($id)
{
$image = ORM::factory('product', $id);
if ( ! $image->loaded()) // ... 404 ?
$this->response
->headers('Content-Type','image/png')
->body($image->image)
->check_cache(NULL, $this->request); // 304 ?
}