2017-02-01 24 views
6

Mam doświadczenie w backend C# i ASP.Net MVC. Teraz robię swoją pierwszą próbę na Angular 2. Zajmuje to trochę czasu, ale lubię większość z nich. Teraz utknąłem na prostym pobieraniu plików.Pobierz plik z MVC 5 do Angular 2

Przeczytałem wszystkie przykłady, które znalazłem tutaj na Stackoverflow, ale nadal nie dostaję mojego przykładu do pracy.

Na stronie serwera Mam ten kod C#:

public ActionResult DownloadPicture(long id) 
    { 
     var bytes = System.IO.File.ReadAllBytes("images\dummy.jpg"); 
     return GetAttachement(bytes, "DummyFile.jpg"); 
    } 

    private ActionResult GetAttachement(byte[] bytes, string fileName) 
    { 
     var contentType = MimeMapping.GetMimeMapping(fileName); 
     var contentDisposition = new System.Net.Mime.ContentDisposition 
     { 
      FileName = fileName, 
      Inline = true 
     }; 
     Response.AppendHeader("Content-Disposition", contentDisposition.ToString()); 
     return File(bytes, contentType); 
    } 

po stronie klienta Mam ten kod maszynopis:

public pictureDownload(id: number): void { 
    let options = new RequestOptions({ search: new URLSearchParams("id=" + id) }); 
    this.http.get(this.urlPictureDownload, options).subscribe((data: any) => { 
       // var blob = new Blob([data._body], { type: "image/jpeg" }); 
       // var url = window.URL.createObjectURL(blob); 
       // window.open(url); 
     }); 
} 

żądanie pochodzi się, by po stronie serwera. Tablica zostanie pobrana. Myślę, że mój problem leży po stronie klienta. Czy ktoś może mi pomóc?

+1

Interesujące - Nie [próbuje tej] (https: //templth.wordpress.com/2014/11/21/handle-downloads-with-angle//) z [FileSaver.js] (https://github.com/eligrey/FileSaver.js). Zauważ "arraybuffer". Hth ... – EdSF

+0

Czy istnieje powód, dla którego nie można po prostu użyć zwykłego starego linku do pliku? To najprawdopodobniej najłatwiejsze. – Casey

+0

Wiem, naprawdę chciałbym, ale pliki nie znajdują się na dysku. Są one przechowywane w pamięci wewnętrznej, więc faktycznie mam je jako strumień. –

Odpowiedz

0

Dla wszystkich przyszłych czytelników podsumuję tutaj wszystko. Według sugestii z EsDF z sugestią od peinearydevelopment Mam teraz działające rozwiązanie. Określanie responseType jako ArrayBuffer w żądaniu było najważniejszą częścią, a trik pobierania był bardzo pomocny.

Alt 1: Myślę, że Casey ma rację. Gdy tylko jest to możliwe, najprostszym sposobem jest użycie prostego znacznika łącza, który wskazuje na zasób serwera. Kiedy, tak jak w moim przypadku, nie jest to możliwe, przydatna będzie każda z dwóch pozostałych opcji.

Alt 2: Metoda openPictureInNewWindow jest prostym i prostym podejściem. Minusem jest to, że wyświetli nieparzysty URL, który wygląda tak: blob: http://localhost/037713d1-a8b9-4fe3-8c43-ee5998ffdc5d.

Alt 3: Inna metoda downloadFile pójdzie o krok dalej i utworzy tymczasowy tag linku i użyje go do pobrania pliku. To dla większości użytkowników będzie wyglądało jak normalne podejście. Ale nie ma wrażenia "podejścia Angular 2" manipulującego DOM, ale jest to bardziej przyjazny dla użytkownika sposób, więc na razie to ten, który będę używał. Dzięki za wszystkie dobre dane wejściowe!

public pictureDownload(id: number) { 
    let options = new RequestOptions({ search: new URLSearchParams("id=" + id), responseType: ResponseContentType.ArrayBuffer }); 
    this.http.get(this.urlPictureDownload, options).subscribe((data: any) => { 
     //this.openPictureInNewWindow(data._body, "image/jpeg"); 
     this.downloadFile(data._body, "Screenshot_" + id + ".jpg", "image/jpeg"); 
    }); 
} 

private openPictureInNewWindow(data: ArrayBuffer, contentType: string) { 
    var blob = new Blob([data], { type: contentType }); 
    var url = window.URL.createObjectURL(blob); 
    window.open(url); 
} 

private downloadFile(data: ArrayBuffer, fileName: string, contentType: string) { 
    var blob = new Blob([data], { type: contentType }); 
    var url = window.URL.createObjectURL(blob); 

    var link = document.createElement("a"); 
    link.setAttribute("href", url); 
    link.setAttribute("download", fileName); 
    link.style.display = "none"; 
    document.body.appendChild(link); 
    link.click(); 
    document.body.removeChild(link); 
} 
+0

Też miałem trudności z tym w kątowym1. Zrobiłem moje obrazy jako bytearray z db, przeszedłem je przez webapi jako json i wstawiłem wynik w znaczniku img src. (pracował) Miał jednak problem, że json stał się dość duży i nie wystąpiło buforowanie klienta. (Użyłem tego podejścia, aby uzyskać małe obrazy, więc temat został pozostawiony do przyszłych ulepszeń). – Nils

2

Niezależnie od wartości, nie jest to tylko problem z Angular2. To wydaje się być "problemem" z przeglądarkami (lub prawdopodobnie specyfikacją). Jest kilka różnych opcji, z których jestem świadomy.

  1. Po ByteArray jest zwracany do przeglądarki, można zrobić coś takiego: var pom = document.createElement('a'); pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(data)); pom.setAttribute('download', 'PICTURENAME.jpeg'); pom.style.display = 'none'; document.body.appendChild(pom); pom.click(); document.body.removeChild(pom);

  2. Drugie podejście Jestem świadomy jest, aby utworzyć plik na serwerze, na ścieżce i temp następnie zwróć wynik przekierowania użytkownikowi z identyfikatorem identyfikującym ten plik (często z identyfikatorem GUID) i przekierowaną drogą, która zwróci wynik twojego pliku.

1

Jeśli widzisz obraz w przeglądarce dla twojego URL-a backendu aplikacji. Następnie możesz bezpośrednio przypisać go do src z IMG w znaczniku komponentu w ten sposób:

Załóżmy, że deklarujesz pole z imgurL w komponencie i zainicjujesz je za pomocą metody działania backendu. następnie w znaczniku można to zrobić:

<img src='{{imgURL}}' alt='any message'/> 
+0

Prawdopodobnie bym był bardziej szczegółowy na ten temat. Chciałbym użyć prostego adresu URL, ale pliki nie znajdują się na dysku. Są one przechowywane w pamięci wewnętrznej, więc faktycznie mam je jako strumień. –