I have an app that uploads and reads excel files.
the controller returns JSON
public ActionResult OnPost(IFormFile file)
{
List<FlightModel> flights = new List<FlightModel>();
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
using (var stream = new MemoryStream())
{
file.CopyTo(stream);
stream.Position = 0;
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
while (reader.Read()) //Each row of the file
{
flights.Add(new FlightModel
{ Side = reader.GetValue(0).ToString(), REG = reader.GetValue(1).ToString()
,
Actual_Date = reader.GetValue(2).ToString(),
Actual_Time = reader.GetValue(3).ToString()
});
}
}
}
return new JsonResult(flights);
}
And it will be displayed in the view as JSON objects. I want to do some operation on the data using JS, so how to return it as a js object. I already tried $get but because I have to upload the file first the method won't work unless I have the data on a dataset?
Related
The scenario:
filter a jquery datatable according to our need.
use download button present besides page length dropdown(its a simple button not a submit button). to download the images for the filtered data.
get the record ids from the table, make its array and send it to the controller.
In controller, fetch the file paths from the database associated with the record ids sent from the
ajax req.
get the files, make a zip and send it back (in response) to the view (download).
as I mentioned the scenario I want the zip to get downloaded on the machine.
But the file is not getting downloaded.
--------------------------Edit [solution]:---------------------------
After Trying Many Solutions I finally got the solution.
So first, I used Controller Code as :
[HttpPost]
public ActionResult Ajax_DownloadImages(int[] records)
{
#region Variable Declaration
List<tbl_image_Details> obj_records = new List<tbl_image_Details>();
tbl_image_Details singleRecord = new tbl_image_Details();
var memorystream = new MemoryStream();
int temp = 0;
#endregion
using (Symphony_webServer_DBEntities db = new Symphony_webServer_DBEntities())
{
#region Get File paths from the database.
for (int i = 0; i < records.Count(); i++)
{
temp = records[i];
singleRecord = db.tbl_image_Details.Where(x => x.record_id == temp).FirstOrDefault<tbl_image_Details>();
obj_records.Add(singleRecord);
}
#endregion
#region Zipping and sending the data to download.
using (ZipFile obj_Zip = new ZipFile())
{
obj_Zip.AlternateEncodingUsage = ZipOption.AsNecessary;
obj_Zip.AddDirectoryByName("Images");
foreach (var file in obj_records)
{
obj_Zip.AddFile(file.image_path, "Images");
}
Response.ClearContent();
Response.ClearHeaders();
Response.AppendHeader("content-disposition", "attachment; filename=Myzip.zip");
obj_Zip.Save(memorystream);
}
memorystream.Position = 0;
return new FileStreamResult(memorystream, "application/octet-stream");
#endregion
}
}
The View:
Create a simple button and call the download function on its click event as follows.
Function That requests the zipped data from server is-
Note : I used XMLHttpRequest object to make a request call because,
jquery ajax call is not efficient to handle the blob response content.
funtion DownloadImages(){
// selecting the table
var Displayedtable = $("#recordTable").DataTable();
// fetching the rows of the table
var datatable_rows = Displayedtable.rows().data().toArray();
// creating an array to hold data.
var table_data = new Array();
// fetching data from each cell and putting it into the array.
$.each(datatable_rows, function (index, value) {
table_data.push(value['record_id']);
});
var records = JSON.stringify(table_data);
var ajax = new XMLHttpRequest();
ajax.open("Post", "/ReportsPage/Ajax_DownloadImages", true);
ajax.setRequestHeader("Content-Type", "application/json");
ajax.responseType = "blob";
ajax.onreadystatechange = function () {
if (this.readyState == 4) {
var blob = new Blob([this.response], { type: "application/octet-stream" });
console.log(this.response);
alert(this.response);
var fileName = "Myzip.zip";
saveAs(blob, fileName);
}
};
ajax.send(records);
}
This will definitely download the intended zip file.
I'm trying to zip varying amounts of files so that one zip folder can be served to the user instead of them having to click multiple anchor tags. I am using the System.IO.Compression namespace in asp.net core 3.1 to create the zip folder.
Here is the code I'm using to create the Zip folder.
public IActionResult DownloadPartFiles(string[] fileLocations, string[] fileNames)
{
List<InMemoryFile> files = new List<InMemoryFile>();
for (int i = 0; i < fileNames.Length; i++)
{
InMemoryFile inMemoryFile = GetInMemoryFile(fileLocations[i], fileNames[i]).Result;
files.Add(inMemoryFile);
}
byte[] archiveFile;
using (MemoryStream archiveStream = new MemoryStream())
{
using (ZipArchive archive = new ZipArchive(archiveStream, ZipArchiveMode.Create, true))
{
foreach (InMemoryFile file in files)
{
ZipArchiveEntry zipArchiveEntry = archive.CreateEntry(file.FileName, CompressionLevel.Fastest);
using (Stream zipStream = zipArchiveEntry.Open())
{
zipStream.Write(file.Content, 0, file.Content.Length);
zipStream.Close();
}
}
archiveStream.Position = 0;
}
archiveFile = archiveStream.ToArray();
}
return File(archiveFile, "application/octet-stream");
}
The files I am trying to zip are stored remotely so I grab them with this block of code. The InMemoryFile is a class to group the file name and file bytes together.
private async Task<InMemoryFile> GetInMemoryFile(string fileLocation, string fileName)
{
InMemoryFile file;
using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(fileLocation))
{
byte[] fileContent = await response.Content.ReadAsByteArrayAsync();
file = new InMemoryFile(fileName, fileContent);
}
return file;
}
The DownloadPartFiles method is called using Ajax. I grab the remote paths to the files and their respective names using javascript and pass them into the Ajax call.
function downloadAllFiles() {
let partTable = document.getElementById("partTable");
let linkElements = partTable.getElementsByTagName('a');
let urls = [];
for (let i = 0; i < linkElements.length; i++) {
urls.push(linkElements[i].href);
}
if (urls.length != 0) {
var fileNames = [];
for (let i = 0; i < linkElements.length; i++) {
fileNames.push(linkElements[i].innerText);
}
$.ajax({
type: "POST",
url: "/WebOrder/DownloadPartFiles/",
data: { 'fileLocations': urls, 'fileNames': fileNames },
success: function (response) {
var blob = new Blob([response], { type: "application/zip" });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "PartFiles.zip";
link.click();
window.URL.revokeObjectURL(blob);
},
failure: function (response) {
alert(response.responseText);
},
error: function (response) {
alert(response.responseText);
}
});
}
}
Now the issue I keep running into is that I can't open the zip folder within Windows 10. Every time I try to open the zip folder using Windows or 7-zip I get an error message that the folder can't be opened or the folder is invalid. I've tried looking at various similar issues on stackoverflow, ie Invalid zip file after creating it with System.IO.Compression, but still can't figure out why this is.
Could it be the encoding? I found that Ajax expects its responses to be encoded UTF-8 and when I view the zip file using notepad++ with UTF-8 I see that there are � characters indicating corruption.
Any thoughts on this would be helpful. Let me know if more information is needed.
If one of the corrupt zip files is needed I can provide that as well.
Edit:
I have since changed my method of receiving the byte array in javascript. I am using a XMLHttpRequest to receive the byte array.
var parameters = {};
parameters.FileLocations = urls;
parameters.FileNames = fileNames;
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "/WebOrder/DownloadPartFiles/", true);
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.responseType = "arraybuffer";
xmlhttp.onload = function (oEvent) {
var arrayBuffer = xmlhttp.response;
if (arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
var blob = new Blob([byteArray], { type: "application/zip" });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "PartFiles.zip";
link.click();
window.URL.revokeObjectURL(blob);
}
}
xmlhttp.send(JSON.stringify(parameters));
From what I read, Ajax is not the best for receiving byte arrays and binary data. With this method I was able to open one of the zip file with 7-zip, but not Windows, however, one of the files within the archive was showing as a size of 0KB and couldn't be opened. The other three files in the archive were fine. Other zip folders with different files could not be opened at all though.
After some time I found a post that was able to fix my issue, Create zip file from byte[]
From that post this is the revised method I'm using to create a zip folder with files in it.
public IActionResult DownloadPartFiles([FromBody] FileRequestParameters parameters)
{
List<InMemoryFile> files = new List<InMemoryFile>();
for (int i = 0; i < parameters.FileNames.Length; i++)
{
InMemoryFile inMemoryFile = GetInMemoryFile(parameters.FileLocations[i], parameters.FileNames[i]).Result;
files.Add(inMemoryFile);
}
byte[] archiveFile = null;
using (MemoryStream archiveStream = new MemoryStream())
{
using (ZipArchive archive = new ZipArchive(archiveStream, ZipArchiveMode.Create, true))
{
foreach (InMemoryFile file in files)
{
ZipArchiveEntry zipArchiveEntry = archive.CreateEntry(file.FileName, CompressionLevel.Optimal);
using (MemoryStream originalFileStream = new MemoryStream(file.Content))
using (Stream zipStream = zipArchiveEntry.Open())
{
originalFileStream.CopyTo(zipStream);
}
}
}
archiveFile = archiveStream.ToArray();
}
return File(archiveFile, "application/octet-stream");
}
I still don't know why the previous method was having issues so if anyone knows the answer to that in the future I'd love to know.
I was trying to download the file from azure data lake storage. it's working on c# side using Rest API. but it's not working in a java script.
My Sample c# code is
//Get Access Token
public DataLakeAccessToken ServiceAuth(string tenatId, string clientid, string clientsecret)
{
var authtokenurl = string.Format("https://login.microsoftonline.com/{0}/oauth2/token", tenatId);
using (var client = new HttpClient())
{
var model = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("grant_type","client_credentials"),
new KeyValuePair<string, string>("resource","https://management.core.windows.net/"),//Bearer
new KeyValuePair<string, string>("client_id",clientid),
new KeyValuePair<string, string>("client_secret",clientsecret),
};
var content = new FormUrlEncodedContent(model);
HttpResponseMessage response = client.PostAsync(authtokenurl, content).Result;
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var accessToken = JsonConvert.DeserializeObject<DataLakeAccessToken>(response.Content.ReadAsStringAsync().Result);
return accessToken;
}
else
{
return null;
}
}
}
File Download Code is
public void DownloadFile(string srcFilePath, ref string destFilePath)
{
int i = 0;
var folderpath = Path.GetDirectoryName(destFilePath);
var filename = Path.GetFileNameWithoutExtension(destFilePath);
var extenstion = Path.GetExtension(destFilePath);
Increment:
var isfileExist = File.Exists(destFilePath);
if (isfileExist)
{
i++;
destFilePath = folderpath+filename + "_" + i + "_" + extenstion;
goto Increment;
}
string DownloadUrl = "https://{0}.azuredatalakestore.net/webhdfs/v1/{1}?op=OPEN&read=true";
var fullurl = string.Format(DownloadUrl, _datalakeAccountName, srcFilePath);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _accesstoken.access_token);
using (var formData = new MultipartFormDataContent())
{
var response = client.GetAsync(fullurl).Result;
using (var fs = new FileStream(destFilePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
response.Content.CopyToAsync(fs).Wait();
}
}
}
}
first i was Generate the token using client credentials and the token based download file using path example https://mydatalaksestore.azuredatalaksestore.net/myfolder/myfile i pass myfolder/myfile in source path and destFilePath file name based download the file
in javascript i was get the accesstoken from my api server and send the request for mydatalakestore it's throw error for cross orgin for localhost:8085 like this
Any one know how to download the datalake store file using Javascript from Client Side using Access Token without cross orgin error
Thanks in Advance
I'm using the code below for downloading with the web API in ASP.NET.
When I'm trying to click the download button, it calls the API.
After executing the "DownloadFile"-function, the download dialog box isn't coming .
[HttpGet]
public HttpResponseMessage DownloadFile(string DownloadFilePath)
{
HttpResponseMessage result = null;
var localFilePath = HttpContext.Current.Server.MapPath(DownloadFilePath);
// check if parameter is valid
if (String.IsNullOrEmpty(DownloadFilePath))
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
// check if file exists on the server
else if (!File.Exists(localFilePath))
{
result = Request.CreateResponse(HttpStatusCode.Gone);
}
else
{// serve the file to the client
result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = DownloadFilePath;
}
return result;
}
I didn't get any exception from the code above, but the dialog box for downloading the file isn't coming.
Here is the code, I am using and it works great. I hope it will give you an idea
....
var fileBytes = Helper.GetFileBytes(filePath);//convert file to bytes
var stream = new MemoryStream(fileBytes);
resp.Content = new StreamContent(stream);
resp.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
resp.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = filerequest.FileName };
resp.Content.Headers.Add("Content-Encoding", "UTF-8");
return resp;
And, here is the code for GetFileBytes method,
public static byte[] GetFileBytes(string filePath)
{
var fileInfo = new FileInfo(filePath);
if (fileInfo.Exists)
{
return File.ReadAllBytes(fileInfo.FullName);
}
return null;
}
For introduction, I have problem with communication between servicestack and application written in ember.js via REST, I am using ember-uploader component to upload a file to service stack.
View hbs:
<table class="table table-bordered table-hover">
{{file-upload}}
</table>
component in coffee script
ABC.FileUploadComponent = Ember.FileField.extend(
url: "/api/upload"
filesDidChange: (->
uploadUrl = #get("url")
console.log uploadUrl
files = #get("files")
test = { fileName: "test" }
uploader = Ember.Uploader.create(
url: uploadUrl
)
uploader.upload(files[0],test) unless Ember.isEmpty(files)
console.log files
return
).observes("files")
)
component in javascript
ABC.FileUploadComponent = Ember.FileField.extend({
url: "/api/upload",
filesDidChange: (function() {
var files, test, uploadUrl, uploader;
uploadUrl = this.get("url");
console.log(uploadUrl);
files = this.get("files");
test = {
fileName: "test"
};
uploader = Ember.Uploader.create({
url: uploadUrl,
data: test
});
if (!Ember.isEmpty(files)) {
uploader.upload(files[0], test);
}
console.log(files);
}).observes("files")
});
My service model:
namespace ABC.Service.ServiceModel
{
public class Upload
{
[Route("/upload")]
public class UploadRequest : IRequiresRequestStream
{
public System.IO.Stream RequestStream { set; get; }
public object FileName { set; get; }
}
public class UploadResponse
{
public int Successed { set; get; }
}
}
}
My Service Method
namespace ABC.Service.Service
{
public class UploadService : ServiceBase // Service base inherites from ServiceStack.Service
{
public Upload.UploadResponse Post(Upload.UploadRequest request)
{
var req = base.Request;
var reqThatIwant = request.FileName;
return new Upload.UploadResponse() { Successed = 1 };
}
}
}
and here is screen from watch :
So my question is, how I have to change the code to get data marked as "2" into Request object marked as "1" (marked on the screen)?
Handling Raw Request Stream
When you use IRequiresRequestStream you're saying you want to take over deserializing the Request and access the raw input HTTP Request Body as a Stream. As a result ServiceStack wont attempt to read from the Request body and instead inject the HTTP Request stream - in this case the only Request DTO parameters it will be able to populate are those on the /pathinfo or ?QueryString, e.g:
[Route("/upload/{FileName}")]
public class Upload : IRequiresRequestStream
{
public Stream RequestStream { set; get; }
public string FileName { set; get; }
}
Accessing FormData HTTP POSTs
But if the JavaScript component is sending you HTTP POST FormData (i.e. application/x-www-form-urlencoded or multipart/form-data) than it's very unlikely you want to treat it like a raw Request Stream but instead access the Request.FormData or Request.Files that were posted.
Handling File Upload examples
Based on your screenshot, the HTTP Request Content-Type is multipart/form-data which case you will most likely be able to access any uploaded files using Request.Files.
Some examples of accessing HTTP Uploaded Files are available in the Live Demos:
Imgur - Save uploaded files to a MemoryStream
public object Post(Upload request)
{
foreach (var uploadedFile in Request.Files
.Where(uploadedFile => uploadedFile.ContentLength > 0))
{
using (var ms = new MemoryStream())
{
uploadedFile.WriteTo(ms);
WriteImage(ms);
}
}
return HttpResult.Redirect("/");
}
Rest Files - Save to FileSystem
public void Post(Files request)
{
var targetDir = GetPath(request);
var isExistingFile = targetDir.Exists
&& (targetDir.Attributes & FileAttributes.Directory) != FileAttributes.Directory;
if (isExistingFile)
throw new NotSupportedException(
"POST only supports uploading new files. Use PUT to replace contents of an existing file");
if (!Directory.Exists(targetDir.FullName))
Directory.CreateDirectory(targetDir.FullName);
foreach (var uploadedFile in base.Request.Files)
{
var newFilePath = Path.Combine(targetDir.FullName, uploadedFile.FileName);
uploadedFile.SaveTo(newFilePath);
}
}
HTTP Benchmarks - Handle multiple and .zip uploaded files
public object Post(UploadTestResults request)
{
//...
foreach (var httpFile in base.Request.Files)
{
if (httpFile.FileName.ToLower().EndsWith(".zip"))
{
using (var zip = ZipFile.Read(httpFile.InputStream))
{
var zipResults = new List<TestResult>();
foreach (var zipEntry in zip)
{
using (var ms = new MemoryStream())
{
zipEntry.Extract(ms);
var bytes = ms.ToArray();
var result = new MemoryStream(bytes).ToTestResult();
zipResults.Add(result);
}
}
newResults.AddRange(zipResults);
}
}
else
{
var result = httpFile.InputStream.ToTestResult();
newResults.Add(result);
}
}
}