|
Hi I have React application, which is calling api on download button click, on the button click the values are being posted properly and api is returning the zip file, but I want to let the zip file to be downloaded on the client side.
Here is my code for the API
[HttpPost]
public FileContentResult Post([FromForm] string communityName, [FromForm] string files)
{
var removedInvalidCharsFromFileName = removeInvalidCharsFromFileName(files);
var tFiles = removedInvalidCharsFromFileName.Split(',');
string rootPath = Configuration.GetValue<string>("ROOT_PATH");
string communityPath = rootPath + "\\" + communityName;
byte[] theZipFile = null;
using (MemoryStream zipStream = new MemoryStream())
{
using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
{
foreach (string attachment in tFiles)
{
var zipEntry = zip.CreateEntry(attachment);
using (FileStream fileStream = new FileStream(communityPath + "\\" + attachment, FileMode.Open))
using (Stream entryStream = zipEntry.Open())
{
fileStream.CopyTo(entryStream);
}
}
}
theZipFile = zipStream.ToArray();
}
return File(theZipFile, "application/zip", communityName + ".zip");
}
And my React components download method is as below:
handleDownload = (e) => {
e.preventDefault();
var formData = new FormData();
formData.append('communityname', this.state.selectedCommunity);
formData.append('files', JSON.stringify(this.state['checkedFiles']));
let url = clientConfiguration['filesApi.local'];
axios({
method: 'post',
url: url,
data: formData
});
window.open(url, '_blank');
}
This window.open(url, '_blank'); is not letting me download the zip files, aren't the path of the zip file and path of the api the same? What can I do to make sure the file downloads on the client side - any help - thanks in advance.
|
|
|
|
|
The problem is, you're making two separate requests - an AJAX POST request, which throws away the response; and a regular GET request with no parameters, which doesn't match your controller action.
Probably the simplest option would be to create a hidden <form> element, populate the values, and then submit that form.
handleDownload = (e) => {
e.preventDefault();
let form = document.createElement("form");
form.action = clientConfiguration['filesApi.local'];
form.method = "POST";
form.target = "_blank";
let input = document.createElement("input");
input.type = "hidden";
input.name = "communityname";
input.value = this.state.selectedCommunity;
form.appendChild(input);
this.state['checkedFiles'].forEach((f) =>
{
let input = document.createElement("input");
input.type = "hidden";
input.name = "files";
input.value = f;
});
document.body.appendChild(form);
form.submit();
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Hi Richard, after researching online a little bit I could able to do the following, now the zip file is being downloaded but the problem it seems its not downloading correctly
handleDownload = (e) => {
e.preventDefault();
var formData = new FormData();
formData.append('communityname', this.state.selectedCommunity);
formData.append('files', JSON.stringify(this.state['checkedFiles']));
let url = clientConfiguration['filesApi.local'];
axios({
method: 'post',
url: url,
data: formData
})
.then(res => {
console.log(res.data);
var binaryData = [];
binaryData.push(res.data);
const src = window.URL.createObjectURL(new Blob(binaryData, { type: "application/zip" }));
var fileName = `${this.state['selectedCommunity']}.zip`;
saveAs(src, fileName);
});
}
The error that I am getting when uzipping the file is as below:
Can not open the file as zip archive, is not archiving, Warning Headers error. Any help please?
modified 14-Oct-19 18:16pm.
|
|
|
|
|
What does your console.log output show?
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
It shows the byte Array, it is being returned but what is the problem in creating right zip file I am not able to understand I changed a little bit the API method to return the bytes instead of file, still not much help, its the same error message unable to open the file as zip I don't know is the encoding etc different or the bytes limit is the problem, I am not sure. But there is another app doing the same thing in jQuery but its able to download the file - thank you Richard.
|
|
|
|
|
Actually I downloaded the file from the Server code, so the bytes are correct, then I modified the api code to read that newly created zip file as byte array then return, the array, I thought maybe accuracy is lost because of that, then saving that file as zip, still getting unable to open the file, and it says I have to add files to the zip folder before extracting it. I am not understanding what could be the reason. It is working with jQuery though but that's direct submit - any help please?
|
|
|
|
|
You're going to need to compare the bytes of the file that works with the bytes of the file that doesn't to see if there's any clue what the problem is.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Hi Richard, when I checked the length of the array on the Server it is: 113175
and on at the client it is: 150900, why is client side the array length is more IDK - any idea please?
|
|
|
|
|
No idea. What does the axios method look like?
I've just done something similar today using jQuery, and I had to explicitly set xhrFields: { responseType: "blob" } to get the binary data to download properly. Maybe there's a similar issue with your method?
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I could able to resolve that issue by returning byte array but lead wants it only by using FileStreamResult - hah, any help, how to handle FileStreamResult, I am not sure if this Result post-fix good for Web Api because it looks View specific to me. If you have some idea please help me, an another day in this industry
|
|
|
|
|
I don't follow - a FileStreamResult just returns the bytes from the stream. What are you doing differently if you return it as a byte array?
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I am not sure but it is giving me error code 500 Richard, any help please - thank you
|
|
|
|
|
I completed the code I am pasting it here as answer to my own question
|
|
|
|
|
axios is same as fetch, we have fetch I think almost all js libraries including Typescript and Angular. I am not sure the difference but responseType: 'arraybuffer' worked for me, if the return type is FileStreamResult which is of 'octet-stream' on the api side. Yeah its little bit complicated as many return types and as we don't much of it - thanks for jumping in Richard.
|
|
|
|
|
Finally implemented by using the FileStreamResult as well maybe some people would be needed this, here is my API code and then I made call to the post method using axios, so here is my React code. In the axios call responseType becomes arraybuffer and the in the blob declaration it becomes the application/octet-stream type, Hence it completes everything, as I have imported the file-saver, I could able to use saveAs method of it. Finally after many efforts and hearing the screaming from PM, yes it is achieved - but that's the life of any Software Programmer.
Here is Web Api code C#:
[EnableCors("AnotherPolicy")]
[HttpPost]
public FileStreamResult Post([FromForm] string communityName, [FromForm] string files)
{
var removedInvalidCharsFromFileName = removeInvalidCharsFromFileName(files);
var tFiles = removedInvalidCharsFromFileName.Split(',');
string rootPath = Configuration.GetValue<string>("ROOT_PATH");
string communityPath = rootPath + "\\" + communityName;
MemoryStream zipStream = new MemoryStream();
using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
{
foreach (string attachment in tFiles)
{
var zipEntry = zip.CreateEntry(attachment);
using (FileStream fileStream = new FileStream(communityPath + "\\" + attachment, FileMode.Open))
{
using (Stream entryStream = zipEntry.Open())
{
fileStream.CopyTo(entryStream);
}
}
}
}
zipStream.Position = 0;
return File(zipStream, "application/octet-stream");
}
Then my client side React code is here:
handleDownload = (e) => {
e.preventDefault();
var formData = new FormData();
formData.append('communityname', this.state.selectedCommunity);
formData.append('files', JSON.stringify(this.state['checkedFiles']));
let url = clientConfiguration['filesApi.local'];
axios({
method: 'post',
responseType: 'arraybuffer',
url: url,
data: formData
})
.then(res => {
let extension = 'zip';
let tempFileName = `${this.state['selectedCommunity']}`
let fileName = `${tempFileName}.${extension}`;
const blob = new Blob([res.data], {
type: 'application/octet-stream'
})
saveAs(blob, fileName)
})
.catch(error => {
console.log(error.message);
});
};
this event is called when button is clicked or form submitted. Thanks for all the support the SO has given - thanks a lot.
|
|
|
|
|
Hi I have stored an Array of strings into a state object, when I am trying to retrieve it as appended string, it is giving me appended objects as below, my code is as below and I am getting the result as below:
handleDownload = (e) => {
e.preventDefault();
var formData = new FormData();
formData.append('communityname', this.state.selectedCommunity);
formData.append('files', this.state['files']);
alert(this.state['files'].join(','));
let url = clientConfiguration['filesApi.local'];
axios({
method: 'post',
url: url,
data: formData
});
}
My Results are coming as below:
[object Object],[object Object],[object Object],[object Object]
Any help would be very much appreciated - thanks in advance
|
|
|
|
|
Looks like the values stored in this.state['files'] aren't what you thought they are.
Try adding console.debug(this.state['files']); to the method, and look at the output in the browser's developer console.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks Richard, it has been resolved, I have to stringify it before posting it into the Api, here is the code that resolved it. Thanks for jumping into help.
handleDownload = (e) => {
e.preventDefault();
var formData = new FormData();
formData.append('communityname', this.state.selectedCommunity);
formData.append('files', JSON.stringify(this.state['checkedFiles']));
let url = clientConfiguration['filesApi.local'];
axios({
method: 'post',
url: url,
data: formData
});
}
in the above code instead of files I am just passing the selected files and posting them, but I have a question, can't json or react post handle if I want to post Array as it is? If it can - I want to understand that as well - but thanks a lot again Richard.
|
|
|
|
|
I have an event like below:
handleDownload(e) {
e.preventDefault();
alert('Hi');
let communityName = this.state['selectedCommunity'];
let files = this.state[files];
fetch(clientConfiguration['filesApi.local'], {
method: 'POST',
headers: new Headers(),
body: JSON.stringify({ communityName: communityName, body: files })
}).then((res) => res.json())
.then((data) => console.log(data))
.catch((err) => console.log(err))
};
I have a button as below:
renderDownloadButton() {
if (this.state.files && this.state.files.filter(i => i.checked).length) {
return (
<button id="download" styles="display: none;" onClick={this.handleDownload} >
Download
</button>
);
}
};
It fires but it is giving following error, any help please - thank you. At
let communityName = this.state['selectedCommunity'];
its giving me the error;
Can not read property state undefined
Any help please?
|
|
|
|
|
state is undefined, it has no value and is not null either.
state is not inside the function, so you have to initialize earlier in code.
Or maybe pass the state into the function, but I can't see how you can pickup the state in the HTML section and not have it valid in the function. Check your renderDownloadButton
Not sure how React works but I would imagine this is required.
onClick={this.handleDownload($event)}
If it ain't broke don't fix it
Discover my world at jkirkerx.com
|
|
|
|
|
Yes it was taking the function as the current object that's how all javascript libraries work, so changing the scope worked for me - thanks a lot.
|
|
|
|
|
Hi mates, I am conditionally setting up the state in my React component, I did it in the following way, it works but please let me know if there is any better approach to do it in React - thanks a lot.
handleDDLCommunityChange = event => {
this.setState(
{
selectedCommunity: event.target.value
});
if (event.target.value == "") {
this.setState(
{
files: null
});
}
else {
fetch(clientConfiguration['filesApi.local'] + '/' + event.target.value)
.then((response) => { return response.json(); })
.then(data => {
this.setState({
files: data.map(file => {
return {
fileName: file,
checked: false
}
})
})
})
.catch(error => {
console.log(error);
debugger;
});
}
};
modified 9-Oct-19 21:09pm.
|
|
|
|
|
Why not this instead? Maybe the target value is null or undefined and not a blank string.
This should check all 3 conditions in TypeScript at least.
if (!event.target.value)
If it was me, I would not inline this, but if it's proven to always work guess it's ok.
fetch(clientConfiguration['filesApi.local'] + '/' + event.target.value)
const fApi = clientConfiguration['filesApi.local'];
if (fApi) {
fetch(fApi + '/' + event.target.value)
Have you considered trying Jet Brains Refactor Ultimate to sharpen your skills?
ReSharper: The Visual Studio Extension for .NET Developers by JetBrains
If it ain't broke don't fix it
Discover my world at jkirkerx.com
|
|
|
|
|
Hello,
I plot a chart based on different datasets.
one datasets has different datapoints (xn,yn)
dataset 1 = (x1,y1) .... dataset 10 (x10,y10)
First question, how to plot those datasets in javascript?
Second question:
I want to add a dropdown menu to select dataset1, dataset2 , dataset3 in the graph.
would be nice if you have a code samples for me which solve my problem.
|
|
|
|
|
After huge research, i am thinking to build with JavaScript - Search engine with Angular/Vue.js/Meteor/React as front-end
Choice of javascript client side storage is below
1) IndexedDB
2) JScene
3) LargeLocalStorage
4) ydn db
5) PouchDB
Couple of Links
https:
https:
http:
https:
Please kindly suggest which one would be best suited...
Basically planning to built a cross platform system which accepts huge files from the user and finally does a full text search...
In this way, the user just needs the browser no installation is required......
In this way, the application will be purely portable irrespective of OS....
This would be absolutely cross platform
Featurs trying to build once the files got indexed by the front-end code/logic
1) Search Box with type-ahead search
2) Combo box to choose the language
3) Number of hits should be while typing. Please type some text in and
you will understand what is number of hits
4) Search keyword should be highlighted in the left with portion of text.
On clicking the text, the entire subject with highlighted search
should shown in the right
nearly 2,000 files are in text format of 600 kB each size.
the files can be anything - log file or any text file....If support other formats also it is well and good
Please kindly advice with suggestions or comments... As this will benefit for many...
I never come across several open source apps which does full text search or have the functionality which does everything in front-end or client-side
Thanks.
|
|
|
|
|