visual tutorial studio framework example ejemplo crear c# javascript html angularjs asp.net-web-api

studio - web api rest c# tutorial



Descargar archivo de un método API Web ASP.NET utilizando AngularJS (6)

El soporte para descargar archivos binarios al usar ajax no es muy bueno, todavía está en desarrollo como borradores de trabajo .

Método simple de descarga:

Puede hacer que el navegador descargue el archivo solicitado simplemente usando el siguiente código, y esto es compatible con todos los navegadores, y obviamente activará la solicitud de WebApi de la misma manera.

$scope.downloadFile = function(downloadPath) { window.open(downloadPath, ''_blank'', ''''); }

Método de descarga binario Ajax:

El uso de ajax para descargar el archivo binario se puede hacer en algunos navegadores y debajo hay una implementación que funcionará con los últimos sabores de Chrome, Internet Explorer, Firefox y Safari.

Utiliza un tipo de respuesta de arraybuffer , que luego se convierte en un blob JavaScript, que luego se presenta para guardar utilizando el método saveBlob , aunque esto solo está presente actualmente en Internet Explorer, o se convierte en un URL de datos de blob que se abre navegador, activando el diálogo de descarga si el tipo mime es compatible para ver en el navegador.

Compatibilidad con Internet Explorer 11 (Fixed)

Nota: a Internet Explorer 11 no le gustó usar la función msSaveBlob si hubiera sido un alias, tal vez una característica de seguridad, pero más probablemente un defecto, entonces usando var saveBlob = navigator.msSaveBlob || navigator.webkitSaveBlob ... etc. var saveBlob = navigator.msSaveBlob || navigator.webkitSaveBlob ... etc. para determinar si el soporte de saveBlob disponible causó una excepción; de ahí por qué el código siguiente ahora prueba para navigator.msSaveBlob por separado. ¿Gracias? Microsoft

// Based on an implementation here: web.student.tuwien.ac.at/~e0427417/jsdownload.html $scope.downloadFile = function(httpPath) { // Use an arraybuffer $http.get(httpPath, { responseType: ''arraybuffer'' }) .success( function(data, status, headers) { var octetStreamMime = ''application/octet-stream''; var success = false; // Get the headers headers = headers(); // Get the filename from the x-filename header or default to "download.bin" var filename = headers[''x-filename''] || ''download.bin''; // Determine the content type from the header or default to "application/octet-stream" var contentType = headers[''content-type''] || octetStreamMime; try { // Try using msSaveBlob if supported console.log("Trying saveBlob method ..."); var blob = new Blob([data], { type: contentType }); if(navigator.msSaveBlob) navigator.msSaveBlob(blob, filename); else { // Try using other saveBlob implementations, if available var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob; if(saveBlob === undefined) throw "Not supported"; saveBlob(blob, filename); } console.log("saveBlob succeeded"); success = true; } catch(ex) { console.log("saveBlob method failed with the following exception:"); console.log(ex); } if(!success) { // Get the blob url creator var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL; if(urlCreator) { // Try to use a download link var link = document.createElement(''a''); if(''download'' in link) { // Try to simulate a click try { // Prepare a blob URL console.log("Trying download link method with simulated click ..."); var blob = new Blob([data], { type: contentType }); var url = urlCreator.createObjectURL(blob); link.setAttribute(''href'', url); // Set the download attribute (Supported in Chrome 14+ / Firefox 20+) link.setAttribute("download", filename); // Simulate clicking the download link var event = document.createEvent(''MouseEvents''); event.initMouseEvent(''click'', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null); link.dispatchEvent(event); console.log("Download link method with simulated click succeeded"); success = true; } catch(ex) { console.log("Download link method with simulated click failed with the following exception:"); console.log(ex); } } if(!success) { // Fallback to window.location method try { // Prepare a blob URL // Use application/octet-stream when using window.location to force download console.log("Trying download link method with window.location ..."); var blob = new Blob([data], { type: octetStreamMime }); var url = urlCreator.createObjectURL(blob); window.location = url; console.log("Download link method with window.location succeeded"); success = true; } catch(ex) { console.log("Download link method with window.location failed with the following exception:"); console.log(ex); } } } } if(!success) { // Fallback to window.open method console.log("No methods worked for saving the arraybuffer, using last resort window.open"); window.open(httpPath, ''_blank'', ''''); } }) .error(function(data, status) { console.log("Request failed with status: " + status); // Optionally write the error out to scope $scope.errorDetails = "Request failed with status: " + status; }); };

Uso:

var downloadPath = "/files/instructions.pdf"; $scope.downloadFile(downloadPath);

Notas:

Debe modificar su método WebApi para devolver los siguientes encabezados:

  • He usado el encabezado x-filename para enviar el nombre de archivo. Este es un encabezado personalizado para su comodidad; sin embargo, puede extraer el nombre de archivo del encabezado de content-disposition usando expresiones regulares.

  • También debe configurar el encabezado mime de content-type para su respuesta, de modo que el navegador conozca el formato de datos.

Espero que esto ayude.

En mi proyecto Angular JS, tengo una etiqueta de anclaje <a> , que al hacer clic hace una solicitud HTTP GET a un método WebAPI que devuelve un archivo.

Ahora, quiero que el archivo se descargue al usuario una vez que la solicitud sea exitosa. ¿Cómo puedo hacer eso?

La etiqueta de anclaje:

<a href="#" ng-click="getthefile()">Download img</a>

AngularJS:

$scope.getthefile = function () { $http({ method: ''GET'', cache: false, url: $scope.appPath + ''CourseRegConfirm/getfile'', headers: { ''Content-Type'': ''application/json; charset=utf-8'' } }).success(function (data, status) { console.log(data); // Displays text data if the file is a text file, binary if it''s an image // What should I write here to download the file I receive from the WebAPI method? }).error(function (data, status) { // ... }); }

Mi método WebAPI:

[Authorize] [Route("getfile")] public HttpResponseMessage GetTestFile() { HttpResponseMessage result = null; var localFilePath = HttpContext.Current.Server.MapPath("~/timetable.jpg"); 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 = "SampleImg"; } return result; }


Envíe su archivo como una cadena base64.

var element = angular.element(''<a/>''); element.attr({ href: ''data:attachment/csv;charset=utf-8,'' + encodeURI(atob(response.payload)), target: ''_blank'', download: fname })[0].click();

Si el método attr no funciona en Firefox, también puedes usar el método javaScript setAttribute


La descarga de C # WebApi PDF funciona con Angular JS Authentication

Controlador web Api

[HttpGet] [Authorize] [Route("OpenFile/{QRFileId}")] public HttpResponseMessage OpenFile(int QRFileId) { QRFileRepository _repo = new QRFileRepository(); var QRFile = _repo.GetQRFileById(QRFileId); if (QRFile == null) return new HttpResponseMessage(HttpStatusCode.BadRequest); string path = ConfigurationManager.AppSettings["QRFolder"] + + QRFile.QRId + @"/" + QRFile.FileName; if (!File.Exists(path)) return new HttpResponseMessage(HttpStatusCode.BadRequest); HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); //response.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read)); Byte[] bytes = File.ReadAllBytes(path); //String file = Convert.ToBase64String(bytes); response.Content = new ByteArrayContent(bytes); response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); response.Content.Headers.ContentDisposition.FileName = QRFile.FileName; return response; }

Servicio Angular JS

this.getPDF = function (apiUrl) { var headers = {}; headers.Authorization = ''Bearer '' + sessionStorage.tokenKey; var deferred = $q.defer(); $http.get( hostApiUrl + apiUrl, { responseType: ''arraybuffer'', headers: headers }) .success(function (result, status, headers) { deferred.resolve(result);; }) .error(function (data, status) { console.log("Request failed with status: " + status); }); return deferred.promise; } this.getPDF2 = function (apiUrl) { var promise = $http({ method: ''GET'', url: hostApiUrl + apiUrl, headers: { ''Authorization'': ''Bearer '' + sessionStorage.tokenKey }, responseType: ''arraybuffer'' }); promise.success(function (data) { return data; }).error(function (data, status) { console.log("Request failed with status: " + status); }); return promise; }

Cualquiera de los dos hará

Controlador Angular JS llamando al servicio

vm.open3 = function () { var downloadedData = crudService.getPDF(''ClientQRDetails/openfile/29''); downloadedData.then(function (result) { var file = new Blob([result], { type: ''application/pdf;base64'' }); var fileURL = window.URL.createObjectURL(file); var seconds = new Date().getTime() / 1000; var fileName = "cert" + parseInt(seconds) + ".pdf"; var a = document.createElement("a"); document.body.appendChild(a); a.style = "display: none"; a.href = fileURL; a.download = fileName; a.click(); }); };

Y por último la página HTML

<a class="btn btn-primary" ng-click="vm.open3()">FILE Http with crud service (3 getPDF)</a>

Esto se refactorizará, solo compartir el código ahora espero que ayude a alguien, ya que me tomó un tiempo hacerlo funcionar.


Para mí, la API web era Rails y Angular del lado del cliente utilizada con Restangular y FileSaver.js

API web

module Api module V1 class DownloadsController < BaseController def show @download = Download.find(params[:id]) send_data @download.blob_data end end end end

HTML

<a ng-click="download(''foo'')">download presentation</a>

Controlador angular

$scope.download = function(type) { return Download.get(type); };

Servicio angular

''use strict''; app.service(''Download'', function Download(Restangular) { this.get = function(id) { return Restangular.one(''api/v1/downloads'', id).withHttpConfig({responseType: ''arraybuffer''}).get().then(function(data){ console.log(data) var blob = new Blob([data], { type: "application/pdf" }); //saveAs provided by FileSaver.js saveAs(blob, id + ''.pdf''); }) } });


Puede implementar una función showfile que toma los parámetros de los datos devueltos por WEBApi y un nombre de archivo para el archivo que está tratando de descargar. Lo que hice fue crear un servicio de navegador por separado que identifica el navegador del usuario y luego maneja la representación del archivo basado en el navegador. Por ejemplo, si el navegador de destino es Chrome en un ipad, debe usar el objeto javascripts FileReader.

FileService.showFile = function (data, fileName) { var blob = new Blob([data], { type: ''application/pdf'' }); if (BrowserService.isIE()) { window.navigator.msSaveOrOpenBlob(blob, fileName); } else if (BrowserService.isChromeIos()) { loadFileBlobFileReader(window, blob, fileName); } else if (BrowserService.isIOS() || BrowserService.isAndroid()) { var url = URL.createObjectURL(blob); window.location.href = url; window.document.title = fileName; } else { var url = URL.createObjectURL(blob); loadReportBrowser(url, window,fileName); } } function loadFileBrowser(url, window, fileName) { var iframe = window.document.createElement(''iframe''); iframe.src = url iframe.width = ''100%''; iframe.height = ''100%''; iframe.style.border = ''none''; window.document.title = fileName; window.document.body.appendChild(iframe) window.document.body.style.margin = 0; } function loadFileBlobFileReader(window, blob,fileName) { var reader = new FileReader(); reader.onload = function (e) { var bdata = btoa(reader.result); var datauri = ''data:application/pdf;base64,'' + bdata; window.location.href = datauri; window.document.title = fileName; } reader.readAsBinaryString(blob); }


También tuvimos que desarrollar una solución que incluso funcionaría con las API que requieren autenticación (ver este artículo )

Usando AngularJS en pocas palabras aquí es cómo lo hicimos:

Paso 1: crea una directiva dedicada

// jQuery needed, uses Bootstrap classes, adjust the path of templateUrl app.directive(''pdfDownload'', function() { return { restrict: ''E'', templateUrl: ''/path/to/pdfDownload.tpl.html'', scope: true, link: function(scope, element, attr) { var anchor = element.children()[0]; // When the download starts, disable the link scope.$on(''download-start'', function() { $(anchor).attr(''disabled'', ''disabled''); }); // When the download finishes, attach the data to the link. Enable the link and change its appearance. scope.$on(''downloaded'', function(event, data) { $(anchor).attr({ href: ''data:application/pdf;base64,'' + data, download: attr.filename }) .removeAttr(''disabled'') .text(''Save'') .removeClass(''btn-primary'') .addClass(''btn-success''); // Also overwrite the download pdf function to do nothing. scope.downloadPdf = function() { }; }); }, controller: [''$scope'', ''$attrs'', ''$http'', function($scope, $attrs, $http) { $scope.downloadPdf = function() { $scope.$emit(''download-start''); $http.get($attrs.url).then(function(response) { $scope.$emit(''downloaded'', response.data); }); }; }] });

Paso 2: crea una plantilla

<a href="" class="btn btn-primary" ng-click="downloadPdf()">Download</a>

Paso 3: usarlo

<pdf-download url="/some/path/to/a.pdf" filename="my-awesome-pdf"></pdf-download>

Esto generará un botón azul. Al hacer clic, se descargará un PDF (¡Atención: el servidor debe entregar el PDF en la codificación Base64!) Y colocarlo en el href. El botón se pone verde y cambia el texto a Guardar . El usuario puede hacer clic de nuevo y se le presentará un diálogo de archivo de descarga estándar para el archivo my-awesome.pdf .