Загрузка файлов в Angular 6 с помощью ASP.NET Web API - PullRequest
0 голосов
/ 11 декабря 2018

У нас есть угловой клиент (Angular 6) с серверной частью веб-API ASP.NET.

Требование: Для загрузки файлов в пользовательском интерфейсе, обслуживаемом серверной частью.Файлы могут быть любого типа - PDF-файлы, изображения, документы, файлы Excel, блокноты.

Реализация выглядит следующим образом:

Web API

        [Route("api/Clients/{id:int}/Documents/{documentId}")]
        public HttpResponseMessage GetDocument(int id, string documentId)
        {
            string methodName = "GetDocument";
            logger.Info(methodName + ": begins. Id: " + id + ". Document Id: " + documentId);
            HttpResponseMessage response = null;

            try
            {
                var ticket = Request.Properties["Ticket"];
                var userName = ((Microsoft.Owin.Security.AuthenticationTicket)ticket).Identity.Name;
                ClientHelper clientHelper = new ClientHelper(userName);

                MemoryStream fileContent = new MemoryStream();

                //this._googleDriveManager.Get(documentId).CopyTo(fileContent);
                var fileData = this._googleDriveManager.Get(documentId);

                //Get file extension
                var document = clientHelper.GetDocumentbyDriveId(documentId);


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

            }
            catch (Exception exception)
            {
                //Log exception.
                logger.Error(methodName, exception);
                var errorModel = new { error = "There was an error." };
                response = new HttpResponseMessage();
                response.StatusCode = HttpStatusCode.InternalServerError;
            }

            logger.Info(methodName + " ends");
            return response;
        }

Угловой код указан ниже:

Обслуживание

import { Injectable } from '@angular/core';
import { AppSettings } from '../helpers/AppConstants';
import { HttpClient, HttpRequest, HttpEventType, HttpResponse, HttpHeaders } from '@angular/common/http';
import { Observable, Subject } from 'rxjs';
import { map, filter, catchError, mergeMap } from 'rxjs/operators';

@Injectable()
export class SharedService {

  constructor(private http: HttpClient) { }

  //This method gets the details of one client.
  public getDocument(id: number, fileId: string) {
    return this.http.get(AppSettings.DOCUMENTDOWNLOAD_ENDPOINT(id, fileId),
         {responseType: 'blob' as 'json'});

  }
}

Компонент

import { Component, OnInit, ViewChild, ElementRef, Input, Output, EventEmitter } from '@angular/core';
import { Document } from '../../../../models/document';
import { DocumentType } from '../../../../models/document-type';
import { SharedService } from '../../../../services/shared.service';
import { MatDialog, MatDialogConfig, MatTableDataSource, MatPaginator } from '@angular/material';

@Component({
  selector: 'app-documents',
  templateUrl: './documents.component.html',
  styleUrls: ['./documents.component.scss']
})
export class DocumentsComponent implements OnInit {

  constructor(private _sharedService: SharedService, public dialog: MatDialog) { }

  ngOnInit() {

  }

  fileDownload(document: any) {
    this._sharedService.getDocument(document.clientId, document.driveId)
      .subscribe(fileData => {
        console.log(fileData);
        let b: any = new Blob([fileData], { type: 'application/pdf' });
        var url = window.URL.createObjectURL(b);
        window.open(url);
      }
      );
  }
}

На клиенте мы изменили между application / pdf и application / octet-stream, и нет никакой разницы.По сути, заголовки контента, установленные в API, вообще не имеют значения, и это просто блоб с размером, который принимается в ответных данных.

Снимок экрана: enter image description here

При доступе к той же конечной точке API через Postman и отправке запроса на отправку и загрузку появляется диалоговое окно загрузки файла, как и ожидалось -с именем файла и расширением.Но в API он просто показывает BLOB-объект без имени файла или расширения.

Чего нам здесь не хватает?

1 Ответ

0 голосов
/ 12 декабря 2018

Использование библиотеки файловой заставки решило проблему.

https://www.npmjs.com/package/file-saver

https://shekhargulati.com/2017/07/16/implementing-file-save-functionality-with-angular-4/

Код в службе теперь выглядит следующим образом

import { Injectable } from '@angular/core';
import { AppSettings } from '../helpers/AppConstants';
import { HttpClient, HttpRequest, HttpEventType, HttpResponse, HttpHeaders } from '@angular/common/http';
import { Observable, Subject } from 'rxjs';
import {saveFile, saveAs} from 'file-saver';
import { map, filter, catchError, mergeMap } from 'rxjs/operators';

@Injectable()
export class SharedService {
  constructor(private http: HttpClient) {}

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

  //This method gets the details of one client.
  public getDocument(id: number, fileId: string, fileName: string) {

    this.http.get(AppSettings.DOCUMENTDOWNLOAD_ENDPOINT(id, fileId), {responseType: 'blob'})
      .subscribe((data) => this.downloadFile(data, fileName), error => console.log('Error downloading the file.'),
        () => console.info('OK'));
  }
}

import { Component, OnInit, ViewChild, ElementRef, Input, Output, EventEmitter } from '@angular/core';
import { Document } from '../../../../models/document';
import { DocumentType } from '../../../../models/document-type';
import { SharedService } from '../../../../services/shared.service';
import { MatDialog, MatDialogConfig, MatTableDataSource, MatPaginator } from '@angular/material';
import { DialogComponent } from '../upload/dialog/dialog.component';
//import 'rxjs/Rx' ;

@Component({
  selector: 'app-documents',
  templateUrl: './documents.component.html',
  styleUrls: ['./documents.component.scss']
})
export class DocumentsComponent implements OnInit {


  @Input() documentTypes: DocumentType[] = [];
  @ViewChild(MatPaginator) paginator: MatPaginator;

  @Input()
  set documents (value: Document[]) {
    if (!value) {
      value = [];
    }

  constructor(private _sharedService: SharedService, public dialog: MatDialog) { }


  fileDownload(document: any) {
    this._sharedService.getDocument(document.clientId, document.driveId, document.fileName);
  }
}
...