1

Please help me with my problem.

I am creating a website which the user can upload a word document to be converted to pdf. and the user should be able to download the processed file.

As of now i have this Html code

<input type="file" (change)="upload($event.target.files)" />
    Upload Percent: {{percentDone}}% <br />

    <ng-container *ngIf="uploadSuccess">
      <button type="button">Download</button>
    </ng-container> 

And this is the Angular Code

upload(files: File[]){

    this.uploadAndProgress(files);
  }

uploadAndProgress(files: File[]){
    console.log(files)
    var formData = new FormData();
    Array.from(files).forEach(f => formData.append('file',f))

    this.http.post('http://localhost:5000/api/DocumentToPdf/Document', formData, {reportProgress: true, observe: 'events'})
      .subscribe(event => {
        if (event.type === HttpEventType.UploadProgress) {
          this.percentDone = Math.round(100 * event.loaded / event.total);
        } else if (event instanceof HttpResponse) {
          this.uploadSuccess = true;
        }
    });
  }

And this is the Asp.net Core code

[Route("api/[controller]")]
[ApiController]
public class DocumentToPdfController : ControllerBase
{
    private readonly IDocumentToPdf _documentToPdf;

    public DocumentToPdfController(IDocumentToPdf documentToPdf)
    {
        _documentToPdf = documentToPdf;
    }    

    [HttpPost("Document")]
    public async Task<Stream> Document()
    {
        try
        {
            var file = Request.Form.Files;

            return  _documentToPdf.DocumentToPdf(file[0].OpenReadStream());
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            Console.WriteLine(ex.StackTrace);
            throw;
        }
    }
}

I was able to process the uploaded file.

But the problem is i don't have a functionality to download the output file.

As of now the return of the Asp.net core is Stream.

How can i make adjust it to be able to download the file process?

If i'm going to write the file processed in the server side. How can i create a download link which will be able to download the output file?

Update: As per sdev95 Comment. i changed my code into

Controller:

public HttpResponseMessage Document()
        {
            try
            {
                var file = Request.Form.Files;

                var fileData = _documentToPdf.DocumentToPdf(file[0].OpenReadStream());
                HttpResponseMessage response = null;


                response = new HttpResponseMessage
                {
                    StatusCode = HttpStatusCode.OK,
                    Content = new ByteArrayContent(fileData.ToArray())
                };
                response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
                response.Content.Headers.ContentDisposition.FileName = "pdf.pdf";
                response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                response.Content.Headers.ContentLength = fileData.Length;

                Console.WriteLine(fileData.Length);


                return response;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                throw;
            }
        }

And the angular code

upload(files: File[]){

    this.uploadAndProgress(files);
  }

  uploadAndProgress(files: File[]){
    console.log(files)
    var formData = new FormData();
    Array.from(files).forEach(f => formData.append('file',f))

    this.http.post('http://localhost:5000/api/DocumentToPdf/Document', formData, {reportProgress: true, responseType: 'blob',  observe: 'events'})
      .subscribe(event => {
        if (event.type === HttpEventType.UploadProgress) {
          this.percentDone = Math.round(100 * event.loaded / event.total);
        } else if (event instanceof HttpResponse) {
          this.uploadSuccess = true;
          console.log('Success');
          console.log('event: ' + event);
          this.downloadFile(event, 'download.pdf');
        }
    });
  }

  downloadFile(data: any, filename: string) {
    const blob = new Blob([data], { type: 'application/octet-stream' });
    saveAs(blob, filename);
  }

But my problem now is. It download a file but the file downloaded is only 1kb.

I debug the asp.net core and the code fileData.Length is returning something like 49648 but why does it only return a 1kb file. What's wrong with my code?

Thank you

classname13
  • 123
  • 3
  • 13

2 Answers2

0

Assuming you get the correct data back from your backend. You have a few options.

Several library options to download files on clientside:

If you dont want to use 3rd party libraries you could try to do it manually and return a bytearray from the backend, then the code below works :).

Result in the example is the response from the backend.

let file = new Blob([result.blob()], {type: 'application/pdf'});
let fileUrl = URL.createObjectURL(file);
var link = document.createElement('a');
link.href = fileUrl;
link.download = "filename___x.pdf";
document.body.appendChild(link);
link.click();
sdev95
  • 132
  • 1
  • 11
  • So i can use Stream or do i need a file that came from the backend. Thank you – classname13 Aug 09 '19 at 14:42
  • One possibility would be to read the file as bytearray in the backend and let the backend return it to something like: ``` HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.Accepted); result.Content = new ByteArrayContent(BYTEARRAYFROMFILE); result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); return result; ``` – sdev95 Aug 09 '19 at 15:00
  • Good day. I was able to change the code based on your comment. But why does it only download a 1kb file? I updated the question. Kindly help me. thank you – classname13 Aug 10 '19 at 13:15
  • Hello @classname13, Im not sure, what I have in my working code is new MediaTypeHeaderValue("application/pdf") instead of octet-stream and same in Angular code. What does the filesaver file show? And is fileData.ToArray() returning a byteArray? You could also see more info in the network tab in your browser and kinda debug from there :). – sdev95 Aug 12 '19 at 08:00
0

Since you file is coming from the cloud (server) I would try to recommend you to use server tech stuff

You could try to do it without filesaver or streamsaver too. If you submit a form that includes the document you want to convert and just hit submit then you could use the server to save a file by appending content-disposition header to the response and then it would save the file. (the content-disposition header means nothing when it is requested by a ajax method)

If the file is not selected via a file input then you could create a form, append a file input, attach the file as a FileList

StreamSaver tries to emulate what a server dose, So if you can do it with a server directly then there is no need to include filesaver, streamsaver or any ajax stuff

Endless
  • 34,080
  • 13
  • 108
  • 131