AngularJS и MVC — загрузка файла из запроса JSON с дополнительными данными

#c# #angularjs #asp.net-mvc #jsonresult

Вопрос:

У меня есть приложение AngularJS, использующее ASP.NET MVC и я хочу вернуть запрос JSON от контроллера MVC с одним из свойств, содержащих файл, который пользователь может загрузить, если он прошел успешно. У меня есть базовый DTO, который я использую для всех запросов, чтобы я мог указывать успех / неудачу и возвращать любые сообщения, которые должен видеть пользователь.

Я смог добиться успешной загрузки файла при использовании метода window.open(someURL) в javascript и выполнении действия MVC, которое возвращает результат FileResult. Я вызываю тот же метод для генерации файла, поэтому я уверен, что файл генерируется правильно. Однако это не совсем тот пользовательский интерфейс, который я хочу, поскольку я хочу также возвращать дополнительные данные для отображения пользователю вместе с файлом. Возможно ли вернуть файл в JsonResult с дополнительными данными и разрешить пользователю загружать файл? Моя текущая реализация загружает файл, но когда я пытаюсь его открыть, я получаю сообщение об ошибке «Excel не может открыть файл xxxxxx.xlsx потому что формат файла или расширение файла недопустимы. Убедитесь, что файл не поврежден и что расширение файла соответствует формату файла «.

ПРИМЕЧАНИЕ: файл создается правильно на стороне сервера. Я смог записать его в каталог и успешно открыть. Я также смог использовать window.open для вызова действия, которое возвращает результат FileResult и которое также работает без каких-либо проблем.

Вот моя функция angularjs, которая пытается загрузить файл:

     $scope.createImportFile = function () {
        ctrl.TestImportCreation.Messages = resetMessageDisplay();
        ctrl.TestImportCreation.IsDownloading = true;
        
        let data = {
            id: ctrl.TestImportCreation.ID
        };
        let service = services.createImportFile(data);
        service.then(function (response) {
            ctrl.TestImportCreation.IsDownloading = false;
            if (response.data.IsSuccess) {
                $scope.downloadFile(response.data.Entity, "ImportTestFile.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            }

            ctrl.TestImportCreation.Messages = response.data.Messages;
        });
    };

    $scope.downloadFile = function (data, fileName, contentType) {
        var blob = new Blob([data], { type: contentType });
        var url = window.URL.createObjectURL(blob);

        var link = document.createElement("a");
        link.setAttribute("href", url);
        link.setAttribute("download", fileName);
        link.style.display = "none";
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    };
 

Вот вызов службы angularjs:

 this.createImportFile = function (data) {
    let request = $http({
        method: "POST",
        url: baseUrl   "/CreateTestImport",
        data: data
    });
    return request;
};
 

Вот действие MVC:

     [HttpPost]
    [Route("CreateTestImport")]
    public JsonResult CreateTestImport(int id)
    {
        SaveEntityDTO<byte[]> response = new SaveEntityDTO<byte[]>();
        try
        {
            response.Entity = CreateTestImportFile(id);
            response.IsSuccess = true;

            return Json(response, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            response.IsSuccess = false;
            response.AddException(ex);
            return Json(response);
        }
    }
 

ответ.Сущность — это байт[].

Если кто-либо из вас, javascript / AngularJS / .NET гуру, знает, как это сделать, я был бы очень признателен за помощь.

Комментарии:

1. Похоже, вы ищете библиотеку JS для отображения версии файла Excel, доступной только для чтения, и для того, чтобы у нее была кнопка загрузки, которая позволяет пользователю получить файл из данных, которые клиент уже загрузил. SheetJS должен сделать свое дело. Вероятно, вам вообще не нужно это для взаимодействия с AngularJS, поскольку вам это нужно только для рендеринга и загрузки, но на случай, если вы хотите пойти по этому пути, вот демонстрация с AngularJS .