AngularJS का उपयोग करके ASP.NET वेब एपीआई विधि से फ़ाइल डाउनलोड करें


132

मेरे एंगुलर जेएस प्रोजेक्ट में, मैंने एक <a>एंकर टैग लगाया है, जिस पर क्लिक GETकरने पर एक वेबएपीआई विधि के लिए एक HTTP अनुरोध होता है जो एक फाइल लौटाता है।

अब, मैं चाहता हूं कि अनुरोध सफल होने के बाद फ़ाइल को उपयोगकर्ता को डाउनलोड किया जाए। मैं उसको कैसे करू?

एंकर टैग:

<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) {
        // ...
    });
}

मेरी वेबएपीआई विधि:

[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;
}

1
तंतु क्या होगा? केवल छवि?
राशमिन जाविया

@RashminJaviya .jpg, .doc, .xlsx, .docx .txt या .pdf हो सकता है।
जहाँ DragonsDwell

आप किस नेट। फ्रेमवर्क का उपयोग कर रहे हैं?
राशमिन जाविया

@RashminJaviya .net 4.5
जहां

1
@ कुरकुला आपको फाइल की प्रणाली का उपयोग करना चाहिए ।IO। नियंत्रक से नहीं
जाविस्क

जवाबों:


242

अजाक्स का उपयोग करने में बाइनरी फ़ाइलों को डाउनलोड करने के लिए समर्थन महान नहीं है, यह अभी भी विकास के तहत काम कर रहा है ड्राफ्ट के रूप में

सरल डाउनलोड विधि:

आप नीचे दिए गए कोड का उपयोग करके ब्राउज़र को अनुरोधित फ़ाइल डाउनलोड कर सकते हैं, और यह सभी ब्राउज़रों में समर्थित है, और जाहिर है कि वेबएपीआई अनुरोध को केवल एक ही ट्रिगर करेगा।

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

Ajax द्विआधारी डाउनलोड विधि:

बाइनरी फाइल को डाउनलोड करने के लिए अजाक्स का उपयोग कुछ ब्राउज़रों में किया जा सकता है और नीचे एक कार्यान्वयन है जो क्रोम, इंटरनेट एक्सप्लोरर, फायरफॉक्स और सफारी के नवीनतम स्वादों में काम करेगा।

यह एक arraybufferप्रतिक्रिया प्रकार का उपयोग करता है , जिसे तब जावास्क्रिप्ट में परिवर्तित किया जाता है, जिसे बाद में प्रतिक्रिया blobका उपयोग करके सहेजने के लिए प्रस्तुत किया जाता हैsaveBlob विधि - हालांकि यह केवल वर्तमान में इंटरनेट एक्सप्लोरर में मौजूद है - या एक ब्लॉब डेटा URL में बदल गया है जो ब्राउज़र द्वारा खोला जाता है, ट्रिगर होता है यदि ब्राउज़र में माइम प्रकार देखने के लिए समर्थित है तो डाउनलोड संवाद।

Internet Explorer 11 समर्थन (फिक्स्ड)

नोट: इंटरनेट एक्सप्लोरर 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;
    });
};

उपयोग:

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

टिप्पणियाँ:

आपको निम्नलिखित शीर्ष लेखों को वापस करने के लिए अपनी WebApi विधि को संशोधित करना चाहिए:

  • मैंने x-filenameफ़ाइल नाम भेजने के लिए हेडर का उपयोग किया है । यह सुविधा के लिए एक कस्टम हैडर है, लेकिन आप content-dispositionनियमित रूप से अभिव्यक्ति का उपयोग करके हेडर से फ़ाइलनाम निकाल सकते हैं ।

  • आपको content-typeअपनी प्रतिक्रिया के लिए माइम हेडर भी सेट करना चाहिए , ताकि ब्राउज़र डेटा प्रारूप को जानता हो।

आशा है कि ये आपकी मदद करेगा।


हाय @Scott मैंने आपके तरीके का उपयोग किया और यह काम करता है लेकिन ब्राउज़र फ़ाइल को html html पीडीएफ के रूप में सहेजता है। मैं एप्लिकेशन / पीडीएफ़ पर सामग्री-प्रकार सेट करता हूं और जब मैं डेवलपर टूल में क्रोम में जांचता हूं तो प्रतिक्रिया का प्रकार आवेदन / पीडीएफ पर सेट होता है, लेकिन जब मैं फ़ाइल को सहेजता हूं तो इसे html के रूप में दिखाया जाता है, यह काम करता है, जब मैं इसे खोलता हूं फ़ाइल पीडीएफ के रूप में खोला, लेकिन ब्राउज़र में और मेरे ब्राउज़र के लिए आइकन डिफ़ॉल्ट है। क्या आप जानते हैं कि मैं क्या गलत कर सकता था?
बार्टोज़ बियाल्की

1
:-( क्षमा करें। मैं यह देखने से चूक गया। BTW यह बहुत काम कर रहा है। यहां तक ​​कि filesaver.js की तुलना में भी बेहतर है
जीव जेएसबी

1
जब मैं इस विधि के माध्यम से Microsoft निष्पादन योग्य डाउनलोड करने का प्रयास करता हूं, तो मुझे एक वास्तविक आकार वापस मिलता है जो वास्तविक फ़ाइल आकार का लगभग 1.5 गुना है। डाउनलोड की जाने वाली फ़ाइल में ब्लॉब का गलत आकार है। ऐसा क्यों हो रहा है पर कोई विचार? फ़िडलर को देखने के आधार पर, प्रतिक्रिया का आकार सही है, लेकिन सामग्री को एक बूँद में परिवर्तित करना इसे किसी तरह बढ़ा रहा है।
user3517454

1
अंत में समस्या का पता लगा ... मैंने पाने के लिए एक पोस्ट से सर्वर कोड बदल दिया था, लेकिन मैंने $ http.get के मापदंडों को नहीं बदला था। इसलिए प्रतिक्रिया प्रकार को कभी भी सरणीबफ़र के रूप में सेट नहीं किया जा रहा था क्योंकि इसे तीसरे तर्क के रूप में पारित किया जा रहा था और दूसरा नहीं।
user3517454

1
@RobertGoldwein आप ऐसा कर सकते हैं, लेकिन धारणा यह है कि यदि आप एक एंगुलरज एप्लिकेशन का उपयोग कर रहे हैं, तो आप चाहते हैं कि उपयोगकर्ता एप्लिकेशन में बना रहे, जहां डाउनलोड शुरू होने के बाद कार्यक्षमता का उपयोग करने की स्थिति और क्षमता। यदि आप डाउनलोड करने के लिए सीधे नेविगेट करते हैं तो कोई गारंटी नहीं है कि एप्लिकेशन सक्रिय रहेगा, क्योंकि ब्राउज़र डाउनलोड को हमारे द्वारा अपेक्षित तरीके से संभाल नहीं सकता है। कल्पना करें कि सर्वर 500 या 404 अनुरोध करता है। उपयोगकर्ता अब एंगुलर ऐप से बाहर हो गया है। एक नई विंडो का उपयोग करके लिंक खोलने का सबसे सरल सुझाव window.openदिया गया है।
स्कॉट

10

C # WebApi PDF सभी कोणीय जेएस प्रमाणीकरण के साथ काम करते हुए डाउनलोड करता है

वेब एप नियंत्रक

[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;
    }

कोणीय जेएस सेवा

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;
        }

या तो एक करेंगे

सेवा को कॉल करने वाला कोणीय जेएस नियंत्रक

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();
        });
    };

और HTML पेज को लास्ट करे

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

यह केवल कोड साझा करने के बाद फिर से बनाया जाएगा, आशा है कि यह किसी को मदद करता है क्योंकि मुझे यह काम करने में थोड़ा समय लगा।


यदि आप ios चरण 1 चेक पर काम करने के लिए इस जरूरत से ऊपर कोड ios को छोड़कर सभी सिस्टम पर काम करता है ताकि इन चरणों का उपयोग करता है, तो ios stackoverflow.com/questions/9038625/detect-if-device-is-ios चरण 2 (यदि ios) इस का उपयोग stackoverflow.com/questions/24485077/…
18


6

मेरे लिए वेब एपीआई रेल और ग्राहक पक्ष कोणीय का उपयोग किया गया था Restangular और FileSaver.js

वेब एपीआई

module Api
  module V1
    class DownloadsController < BaseController

      def show
        @download = Download.find(params[:id])
        send_data @download.blob_data
      end
    end
  end
end

एचटीएमएल

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

कोणीय नियंत्रक

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

कोणीय सेवा

'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');
    })
  }
});

आपने इसके साथ Filesaver.js का उपयोग कैसे किया? आपने इसे कैसे लागू किया?
एलन डनिंग

2

हमें एक समाधान भी विकसित करना था, जो प्रमाणीकरण की आवश्यकता वाले एपीआई के साथ भी काम करेगा ( इस लेख को देखें )

संक्षेप में AngularJS का उपयोग करना है कि हमने यह कैसे किया:

चरण 1: एक समर्पित निर्देश बनाएँ

// 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);
            });
        };
    }] 
});

चरण 2: एक टेम्पलेट बनाएँ

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

चरण 3: इसका उपयोग करें

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

यह एक नीले बटन को प्रस्तुत करेगा। जब क्लिक किया जाता है, तो एक पीडीएफ डाउनलोड किया जाएगा (सावधानी: बैकएंड को बेस 64 एनकोडिंग में पीडीएफ डिलीवर करना होगा!) और href में डाल दिया जाएगा। बटन हरे रंग में बदल जाता है और टेक्स्ट को सेव पर स्विच करता है । उपयोगकर्ता फिर से क्लिक कर सकता है और फ़ाइल my-awesome.pdf के लिए एक मानक डाउनलोड फ़ाइल संवाद के साथ प्रस्तुत किया जाएगा ।


1

अपनी फाइल को बेस 64 स्ट्रिंग के रूप में भेजें।

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

अगर फ़ायरफ़ॉक्स में attr मेथड काम नहीं कर रहा है तो आप javaScript setAttribute मेथड का भी उपयोग कर सकते हैं


var blob = new Blob ([atob (response.payload)], {"data": "अनुलग्नक / csv; चारसेट = utf-8;"}); बचत (बूँद, 'फ़ाइल नाम');
पीपीबी

धन्यवाद पीपीबी, आपके समाधान ने मेरे लिए काम किया सिवाय एओबी के। यह मेरे लिए आवश्यक नहीं था।
लैरी फ्लेवेलिंग

0

आप एक शोफाइल फ़ंक्शन को लागू कर सकते हैं जो WEBApi से लौटाए गए डेटा के मापदंडों में लेता है, और उस फ़ाइल का फ़ाइल नाम जिसे आप डाउनलोड करने का प्रयास कर रहे हैं। मैंने जो किया था वह एक अलग ब्राउज़र सेवा थी जो उपयोगकर्ता के ब्राउज़र की पहचान करती है और फिर ब्राउज़र के आधार पर फ़ाइल के प्रतिपादन को संभालती है। उदाहरण के लिए यदि टारगेट ब्राउज़र किसी आईपैड पर क्रोम है, तो आपको 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);
}

1
उन वस्तुओं को पकड़ने के लिए स्कॉट का शुक्रिया। मैंने रिफलेक्ट किया है और एक स्पष्टीकरण जोड़ा है।
एरकिन जिंदजिवे

0

मैं समाधान के माध्यम से चला गया हूँ और यह वही है जो मैंने पाया है कि मेरे लिए महान काम किया है।

मेरे मामले में मुझे कुछ क्रेडेंशियल्स के साथ पोस्ट अनुरोध भेजने की आवश्यकता थी। छोटे ओवरहेड को स्क्रिप्ट के अंदर jquery जोड़ना था। लेकिन इसके लायक था।

var printPDF = function () {
        //prevent double sending
        var sendz = {};
        sendz.action = "Print";
        sendz.url = "api/Print";
        jQuery('<form action="' + sendz.url + '" method="POST">' +
            '<input type="hidden" name="action" value="Print" />'+
            '<input type="hidden" name="userID" value="'+$scope.user.userID+'" />'+
            '<input type="hidden" name="ApiKey" value="' + $scope.user.ApiKey+'" />'+
            '</form>').appendTo('body').submit().remove();

    }

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.