使用AngularJS从ASP.NET Web API方法下载文件

whe*_*ell 132 html javascript c# asp.net-web-api angularjs

在我的Angular JS项目中,我有一个<a>锚标记,当单击它时会GET向返回文件的WebAPI方法发出HTTP 请求.

现在,我希望在请求成功后将文件下载到用户.我怎么做?

锚标记:

<a href="#" ng-click="getthefile()">Download img</a>
Run Code Online (Sandbox Code Playgroud)

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) {
        // ...
    });
}
Run Code Online (Sandbox Code Playgroud)

我的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;
}
Run Code Online (Sandbox Code Playgroud)

Sco*_*ott 239

使用ajax支持下载二进制文件并不是很好,它仍然在开发中作为工作草案.

简单下载方法:

您只需使用下面的代码就可以让浏览器下载所请求的文件,并且所有浏览器都支持此操作,并且显然会触发WebApi请求.

$scope.downloadFile = function(downloadPath) { 
    window.open(downloadPath, '_blank', '');  
}
Run Code Online (Sandbox Code Playgroud)

Ajax二进制下载方法:

使用ajax下载二进制文件可以在某些浏览器中完成,下面是一个可以在最新版Chrome,Internet Explorer,FireFox和Safari中使用的实现.

它使用一种arraybuffer响应类型,然后将其转换为JavaScript blob,然后使用该saveBlob方法将其显示为保存- 尽管这仅存在于Internet Explorer中 - 或者转换为由浏览器打开的blob数据URL,从而触发如果支持在浏览器中查看mime类型,则下载对话框.

Internet Explorer 11支持(固定)

注意:Internet Explorer 11不喜欢使用该msSaveBlob功能,如果它已被别名 - 可能是一个安全功能,但更可能是一个缺陷,因此使用var saveBlob = navigator.msSaveBlob || navigator.webkitSaveBlob ... etc.确定可用saveBlob支持导致异常; 因此,为什么下面的代码现在navigator.msSaveBlob单独测试.谢谢?微软

// 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;
    });
};
Run Code Online (Sandbox Code Playgroud)

用法:

var downloadPath = "/files/instructions.pdf";
$scope.downloadFile(downloadPath);
Run Code Online (Sandbox Code Playgroud)

笔记:

您应该修改WebApi方法以返回以下标头:

  • 我使用x-filename标头发送文件名.为方便起见,这是一个自定义标头,但您可以content-disposition使用正则表达式从标头中提取文件名.

  • 您也应该content-type为响应设置mime标头,以便浏览器知道数据格式.

我希望这有帮助.


tfa*_*tfa 9

C#WebApi PDF下载全部使用Angular JS身份验证

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;
    }
Run Code Online (Sandbox Code Playgroud)

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;
        }
Run Code Online (Sandbox Code Playgroud)

任何一个人都会这样做

Angular JS Controller调用服务

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();
        });
    };
Run Code Online (Sandbox Code Playgroud)

并持续HTML页面

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

这将被重构只是共享代码现在希望它帮助某人,因为它花了我一段时间才能使这个工作.


Ank*_*itG 6

对我来说,Web API是Rails,客户端Angular与RestangularFileSaver.js一起使用

Web API

module Api
  module V1
    class DownloadsController < BaseController

      def show
        @download = Download.find(params[:id])
        send_data @download.blob_data
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

HTML

 <a ng-click="download('foo')">download presentation</a>
Run Code Online (Sandbox Code Playgroud)

角度控制器

 $scope.download = function(type) {
    return Download.get(type);
  };
Run Code Online (Sandbox Code Playgroud)

角度服务

'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');
    })
  }
});
Run Code Online (Sandbox Code Playgroud)