javascript – How to upload and download in the same request using AngularJS and web api?

Question:

I'm developing a feature that will receive a spreadsheet in .xlsx format, process it and return this spreadsheet with the added columns, in this case I should upload a file and on success I would download it. In my attempts, either I can send the file or just receive I still couldn't both without corrupting the return file, in the code below I can receive the file, perform the processing and download but the file is corrupted, I don't believe that be a problem in my api because if I make a get call or even post I can download the file.

Angular

 // chamada do upload.
$scope.uploadFiles = function () {

    //FILL FormData WITH FILE DETAILS.
    var data = new FormData();

    for (var i in $scope.files) {
        data.append("uploadedFile", $scope.files[i]);
    }

    // ADD LISTENERS.
    var objXhr = new XMLHttpRequest();
    objXhr.responseType = "arraybuffer";
    //objXhr.setRequestHeader("Accept", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    objXhr.onload = onsuccess;
    objXhr.onerror = onerror;

    // SEND FILE DETAILS TO THE API.
    objXhr.open("POST", "/api/v1/public/PostContent");
    objXhr.send(data);

    function onsuccess(result) {
        if (result == null) {
            toastr["error"]("RETORNO NULO", "Título da mensagem");
        }
        var blob = new Blob([result], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
        var objectUrl = URL.createObjectURL(blob);
        window.open(objectUrl);
    };

    function onerror(result) {

        if (result.status == 415) {
            toastr["error"]("Arquivo não suportado", "Título da mensagem");
        } else {
            toastr["error"]("Erro ao tentar ler o arquivo", "Título da mensagem");
        }
    };
}

Controller Web Api

[HttpPost]
    [Route("PostContent")]
    public async Task<HttpResponseMessage> PostContent()
    {
        if (!Request.Content.IsMimeMultipartContent())
            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);

        CustomMultipartFormDataStreamProvider provider = new CustomMultipartFormDataStreamProvider(HttpContext.Current.Server.MapPath("~/App_Data"));

        await Request.Content.ReadAsMultipartAsync(provider);
        MultipartFileData file = provider.FileData.FirstOrDefault();

        FileInfo info = new FileInfo(file.LocalFileName);
        var package = new ExcelPackage(info)
        //PROCESSAMENTO DA PLANILHA

            MemoryStream ms = new MemoryStream();

            package.SaveAs(ms);

            var result = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new ByteArrayContent(ms.GetBuffer())
            };
            result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
            {
                FileName = $"Vai{ DateTime.Now }.xlsx"
            };
            return result;
}

In View Loading the file

        <input type="file" id="file" name="file" multiple
               onchange="angular.element(this).scope().getFileDetails(this)" />

        <button type="button" ng-click="uploadFiles()">Carregar</button>

Does anyone know how to do this?

Answer:

I managed to solve it, here's how the code was, I'm using Angular Material for this the 'apsUploadFile' directive to leave the input file button in the material design style.

Angular

    app.controller('processoCtrl', function ($scope, $http, $location) {

        function send(data, uploadUrl, success, error) {
                var fd = new FormData();
                for (var key in data) {
                    fd.append(key, data[key]);
                }
                return $http.post(uploadUrl, fd, {
                    headers: { 'Content-Type': undefined },
                    responseType: 'arraybuffer'
                });
            };

        $scope.uploadArquivo = function (data) {
                var upload = { data: data };
                var uploadUrl = 'api/enviaraquivo';
                var nomearquivo = $('input').val().split('\\')[2].split('.')[0];
                send(upload, uploadUrl).
                    then(function (result, status, xhr) {
                        $scope.actived = !$scope.actived;
                        $scope.publicacaonaoencontrada = false;
                        $("#upload").prop('disabled', false);
                        var filename = nomearquivo + '_Analisada_.xlsx';
                        var blob = new Blob([result.data], { type:     "application/octet-stream" });
                        if (typeof window.navigator.msSaveBlob !== 'undefined') {
                            // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
                            window.navigator.msSaveBlob(blob, filename);
                        } else {
                            var URL = window.URL || window.webkitURL;
                            var downloadUrl = URL.createObjectURL(blob);

                            if (filename) {
                                // use HTML5 a[download] attribute to specify filename
                                var a = document.createElement("a");
                                // safari doesn't support this yet
                                if (typeof a.download === 'undefined') {
                                    window.location = downloadUrl;
                                } else {
                                    a.href = downloadUrl;
                                    a.download = filename;
                                    document.body.appendChild(a);
                                    a.click();
                                }
                            } else {
                                window.location = downloadUrl;
                            }

                            setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100);
                        }
                       alert('arquivo processado com sucesso');
                    }, function (result) {
                        $("#upload").prop('disabled', false);

                        if (result.status == 401) {
                            alert('acesso não autorizado, realize o login');
                        } else {
                            alert('Arquivo fora dos padrões');
                        }

                    });
            }
    }).directive('apsUploadFile', apsUploadFile);
//Código para colocar um design material no input file

function apsUploadFile() {
    var directive = {
        restrict: 'E',
        template: '<input id="upload"  accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" type="file" class="ng-hide" file-model="upload">' +
            ' <md-button id="uploadButton" class="md-raised md-primary" aria-label="attach_file"> Carregar planilha </md-button>' +
            '<md-input-container class="input-file-text" md-no-float><input id="textInput" ng-model="fileName" type="text" placeholder="Nenhum arquivo selecionado" ng-readonly="true"></md-input-container>' +
            '<md-button class="md-raised md-primary" ng-disabled="upload == null" ng-click="uploadArquivo(upload)">Upload</md-button>',
        link: apsUploadFileLink
    };
    return directive;
}

function apsUploadFileLink(scope, element, attrs) {
    var input = $(element[0].querySelector('#upload'));
    var button = $(element[0].querySelector('#uploadButton'));
    var textInput = $(element[0].querySelector('#textInput'));

    if (input.length && button.length && textInput.length) {
        button.click(function (e) {
            input.click();
        });
        textInput.click(function (e) {
            input.click();
        });
    }

    input.on('change', function (e) {
        var files = e.target.files;
        if (files[0]) {
            scope.fileName = files[0].name;
        } else {
            scope.fileName = null;
        }
        scope.$apply();
    });
}

View

<div ng-controller="processoCtrl as processo">
    <div class="upload-page">
        <div class="form">
            <form method="post" target="hidden-form">
                <h2>Carregue o arquivo</h2>
                <div class="form">
                    <div class="input-group">
                        <md-content layout-padding layout="row" layout-align="start end">
                            <aps-upload-file style="text-align: center;"></aps-upload-file>
                        </md-content>
                    </div>
                </div>
            </form>
        </div>
    </div>
</div>

Fire Web Controller

 [HttpPost]
    [Route("enviararquivo")]
    public async Task<HttpResponseMessage> PostArquivo()
    {

        if (!Request.Content.IsMimeMultipartContent())
            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);

        try
        {
            CustomMultipartFormDataStreamProvider provider = new CustomMultipartFormDataStreamProvider(HttpContext.Current.Server.MapPath("~/App_Data"));
            await Request.Content.ReadAsMultipartAsync(provider);

            MultipartFileData file = provider.FileData.FirstOrDefault();

            FileInfo info = new FileInfo(file.LocalFileName);
            var planilhaDaRequisicao = new ExcelPackage(info);
            MemoryStream streamPlanilhaRequisicao = new MemoryStream();
            planilhaDaRequisicao.SaveAs(streamPlanilhaRequisicao);

            var streamPlanilhaAnalizada = servicePublicacao.VerificaPublicacao(streamPlanilhaRequisicao);
            var result = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new ByteArrayContent(streamPlanilhaAnalizada.GetBuffer())
            };
            result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
            {
                FileName = $"download{ DateTime.Now }.xlsx"
            };

            return result;
        }
        catch (Exception ex)
        {
            return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Arquivo fora dos padrões para consulta");
        }
    }

For spreadsheet processing I'm using the EPPlus library.

Scroll to Top
AllEscort