On the angular side I have the below code. Once the method subscribes (InitializeDownload()) I can see the download on the developer tools under network once the transfer is done the code under subscribe method executes
when looking at the serve logs
WARN 2020-06-17 09:57:07,055 [23 ] nostics.DeveloperExceptionPageMiddleware - The response has already started, the error page middleware will not be executed. ERROR 2020-06-17 09:57:07,056 [23 ] Microsoft.AspNetCore.Server.Kestrel - Connection id "0HM0IRS3OGV70", Request id "0HM0IRS3OGV70:00000035": An unhandled exception was thrown by the application.
Second part of code is the asp.netcore
I can't figure out why it makes two request and why it takes really long for the download to start.
Angular: downlodFile(id): void {
let filedownloadInput = new FileDownloadInput();
filedownloadInput.id = id;
this._FileManagerService.downloadFile(filedownloadInput).subscribe(item => {
this.InitializeDownload(item.fileName, item.fileToken).subscribe((data: any) => {
this.blob = new Blob([data], { type: 'application/pdf' });
var downloadURL = window.URL.createObjectURL(data);
var link = document.createElement('a');
link.href = downloadURL;
link.download = item.fileName;
link.click();
});
});
}
InitializeDownload(fileName:string, fileToken:string) {
const url = AppConsts.remoteServiceBaseUrl + '/FileManager/GetFile';
this.token = this._tokenService.getToken();
let params = new HttpParams();
params = params.append('fileName', fileName);
params = params.append('fileToken', fileToken);
const httpOptions = {
responseType: 'blob' as 'json',
headers: new HttpHeaders({
"Authorization": "Bearer " + this.token
}),
params: params
};
return this._httpClient.get(url, httpOptions);
}
**
necore**
public async Task GetFile( string fileName, string fileToken)
{
Stream stream = null;
int bufferSize = 1048576;
byte[] buffer = new byte[bufferSize];
int length;
long lengthToRead;
try
{
string filePath = Path.Combine(_env.WebRootPath, $"Common{Path.DirectorySeparatorChar}", $"Files{Path.DirectorySeparatorChar}", fileToken);
stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
long dj = stream.Length / bufferSize;
if (stream.Length % bufferSize > 0)
{
dj += 1;
}
dj = dj * bufferSize;
lengthToRead = stream.Length;
Response.ContentType = "application/pdf";
Response.Headers.Add("Content-Disposition", "attachment; filename=" + fileName);
Response.Headers.Add("content-length", dj.ToString());
// Response.ContentLength = dj;
while( lengthToRead > 0)
{
length = stream.Read(buffer, 0, bufferSize);
await Response.BodyWriter.WriteAsync(buffer);
await Response.BodyWriter.FlushAsync();
lengthToRead = lengthToRead - length;
}
}
catch(Exception exp)
{
Response.ContentType = "text/html";
}
finally
{
if(stream != null)
{
stream.Close();
}
}
}
}
9 Answer(s)
-
0
hi
You should use mvc
FileStreamResult
instead of operating onResponse
object.https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.file?view=aspnetcore-3.1
eg:
public Task<FileStreamResult> GetFile(....) { var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); var fileStreamResult = new FileStreamResult(stream, ""application/pdf"); fileStreamResult.FileDownloadName = fileName; ///.... return fileStreamResult; }
-
0
I no longer get the kestreI error but still get the same result. I can see the content download on dev tools (zone.js as XHR) then once transfer is complete the download starts.
-
0
hi mmorales
Please share the code of downloadFile method.
this._FileManagerService.downloadFile()
-
0
public async Task<FileDownloadOutput> DownloadFile(FileDownloadInput input) { var fileInfo = await _filesObjectsRepository.FirstOrDefaultAsync(c => c.Id == input.Id); var output = new FileDownloadOutput() { FileName = fileInfo.FileName, FileToken = fileInfo.Identifier }; return output; }
-
0
hi mmorales
I mean Angular code. : )
this._FileManagerService.downloadFile(filedownloadInput) { }
-
0
this was generated with the refresh.bat command.
/** * @param body (optional) * @return Success */ downloadFile(body: FileDownloadInput | undefined): Observable<FileDownloadOutput> { let url_ = this.baseUrl + "/api/services/app/FileManager/DownloadFile"; url_ = url_.replace(/[?&]$/, ""); const content_ = JSON.stringify(body); let options_ : any = { body: content_, observe: "response", responseType: "blob", headers: new HttpHeaders({ "Content-Type": "application/json-patch+json", "Accept": "text/plain" }) }; return this.http.request("post", url_, options_).pipe(_observableMergeMap((response_ : any) => { return this.processDownloadFile(response_); })).pipe(_observableCatch((response_: any) => { if (response_ instanceof HttpResponseBase) { try { return this.processDownloadFile(<any>response_); } catch (e) { return <Observable<FileDownloadOutput>><any>_observableThrow(e); } } else return <Observable<FileDownloadOutput>><any>_observableThrow(response_); })); } protected processDownloadFile(response: HttpResponseBase): Observable<FileDownloadOutput> { const status = response.status; const responseBlob = response instanceof HttpResponse ? response.body : (<any>response).error instanceof Blob ? (<any>response).error : undefined; let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }}; if (status === 200) { return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { let result200: any = null; let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); result200 = FileDownloadOutput.fromJS(resultData200); return _observableOf(result200); })); } else if (status !== 200 && status !== 204) { return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { return throwException("An unexpected server error occurred.", status, _responseText, _headers); })); } return _observableOf<FileDownloadOutput>(<any>null); }
-
0
Hi @mmorales
Sorry but i dont understand the exact problem. Can you please explain it more detailed?
If what you ask is what is 204, it is prefligh request. The main goal is to determinate whether the actual request is safe to send. It comes from angular, requests are preflighted since they may have implications to user data etc.(https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request)
-
0
Hello @musa.demir
I have the below method. The problem is that when I execute the download method it takes a long time to actually see the file start downloading on my screen. After further looking at development tools when executing downloadFile method I see the content in the background transferring as seen below.
once the transfer is complete the code under subscribe executes and I can see the actual file downloading as below
Please advise. I haven't been able to figure how to skip the transfer content as it seems redudant to perform the content transfer and the download.
downlodFile(id): void {
let filedownloadInput = new FileDownloadInput(); filedownloadInput.id = id; this._FileManagerService.downloadFile(filedownloadInput).subscribe(item => { this.InitializeDownload(item.fileName, item.fileToken).subscribe((data: any) => { this.blob = new Blob([data], { type: 'application/pdf' }); var downloadURL = window.URL.createObjectURL(data); var link = document.createElement('a'); link.href = downloadURL; link.download = item.fileName; link.click(); }); });
} InitializeDownload(fileName:string, fileToken:string) { const url = AppConsts.remoteServiceBaseUrl + '/FileManager/GetFile'; this.token = this._tokenService.getToken(); let params = new HttpParams();
params = params.append('fileName', fileName); params = params.append('fileToken', fileToken); const httpOptions = { responseType: 'blob' as 'json', headers: new HttpHeaders({ "Authorization": "Bearer " + this.token }), params: params }; return this._httpClient.get(url, httpOptions);
}
-
0
What we do in chat module is download it from server via redirecting user to host project's GetUploadedObject.
https://github.com/aspnetzero/aspnet-zero-core/blob/7b48ab6dd9b7aad3bde44f4a331b56c85d222a77/aspnet-core/src/MyCompanyName.AbpZeroTemplate.Web.Host/Controllers/ChatController.cs#L19-L32