Trying to download file from server using angularJS and c# webapi

19,492

Added arraybuffer as a responsetype of the GET request, now the browser interprets the files correctly.

    /******** FILE DOWNLOAD  **********/
$scope.downloadFiles = function (file) {
        $http({
            method: 'GET',
            cache: false,
            url: host + 'api/Files/GetFile',
            responseType:'arraybuffer',
            headers: {
                'Content-Type': 'application/json; charset=utf-8',
                'fileID': file.id
            }
Share:
19,492
SomeRandomName
Author by

SomeRandomName

SOreadytohelp

Updated on June 16, 2022

Comments

  • SomeRandomName
    SomeRandomName almost 2 years

    When uploading files to the server it goes great; no damaged files. However when i download files ( other than pure txt:s they woork) they grow in size and become corrupt. After alot of investigation I dont know what could be wrong. Im simply writing the file as a stream to the response and downloading the blob.
    Any ideas are welcome!

    Relied heavily on this Thread for the solution ; Download file from an ASP.NET Web API method using AngularJS

    Current Code below;

    WebApi:

        [Route("GetFile")]
    public HttpResponseMessage GetFile()
    {
        HttpResponseMessage result = null;
        //Get file object here
        try 
        {
            IEnumerable<string> headerValues = Request.Headers.GetValues("fileID");
            int key = Int32.Parse(headerValues.FirstOrDefault());
            var fetchFile = db.FileRecords.Single(a => a.id == key);
    
            var localFilePath = fetchFile.path + fetchFile.name;
    
            if (!System.IO.File.Exists(localFilePath))
            {
                result = Request.CreateResponse(HttpStatusCode.Gone);
            }
            else
            {// serve the file to the client
                //I have used the x-filename header to send the filename. This is a custom header for convenience.
                //You should set the content-type mime header for your response too, so the browser knows the data format.
                var info = System.IO.File.GetAttributes(localFilePath);
                result = Request.CreateResponse(HttpStatusCode.OK);
                result.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
                result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                result.Content.Headers.Add("x-filename", fetchFile.name);
                result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
                result.Content.Headers.ContentDisposition.FileName = fetchFile.name;
            }
            return result;
        }
        catch (Exception e)
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest);
        }
    }
    

    View:

    <button type="button" class="btn btn-default btn-sm" data-localize="DOWNLOAD" ng-click="downloadFiles(file)">
        Download file
    </button>
    

    Controller:

        /******** FILE DOWNLOAD  **********/
    $scope.downloadFiles = function (file) {
            $http({
                method: 'GET',
                cache: false,
                url: host + 'api/Files/GetFile',
                headers: {
                    'Content-Type': 'application/json; charset=utf-8',
                    'fileID': file.id
                }
            }).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 {
    
                    console.log(filename);
                    // 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;
            });
    }