简体   繁体   English

我如何通过AngularJS视图/控制器将文件上传到C#代码背后?

[英]How can I upload a file to C# code-behind via an AngularJS view/controller?

I have an Angular view and controller which collect user data from several forms. 我有一个Angular视图和控制器,它从几种形式收集用户数据。 The data from the Angular code is then passed to several C# classes. 然后,来自Angular代码的数据将传递到几个C#类。 The user data currently comes into C# as an IEnumerable<> object; 用户数据当前作为IEnumerable <>对象进入C#。 this collection has a type of FormData, which is a custom class of 6 properties (no methods). 此集合具有FormData类型,该类型是6个属性的自定义类(无方法)。 All user data is stored in the 'Data' property of the FormData class via the IEnumerable<> object, and the 'Data' property is a string. 所有用户数据都通过IEnumerable <>对象存储在FormData类的'Data'属性中,并且'Data'属性是一个字符串。 Because 'Data' is a string, any file uploads that enter the C# come in as a string, not an actual file. 因为“数据”是字符串,所以任何输入C#的文件上传都是字符串,而不是实际文件。 Here's the View: 这是视图:

<div data-ng-controller="customFormController as formController" data-ng-init="formController.init(@Model.Form, '@Model.EmailResults', '@Model.EmailTo')">
    <div data-ng-if="!formController.loading && !formController.submitted" mc-form data-on-submit="formController.submit(model, formData)" data-on-file-select="formController.fileSelect(e)">
    <!--form fields are added dynamically via a separate set of Angular/C# controllers-->
</div>
</div>

Here's part of the controller: 这是控制器的一部分:

self.submit = function (model, formData) {

                var deferred = $q.defer();

                var formPostData = {
                    formId: self.formId,
                    data: formData,
                    emailData: self.emailData,
                    emailTo: self.emailTo,
                    saveData: true
                };

                customFormService.postData(formPostData).then(function (result) {

                    self.submitted = true;
                    deferred.resolve(result);

                    window.location.href = '#form-' + self.formId;

                    // push any files
                    if (typeof window.FormData !== 'undefined' && result) {
                        var formData = new FormData();

                        if (fileList && fileList.length) {
                            for (var f in fileList) {
                                if (fileList.hasOwnProperty(f)) {
                                    formData.append('file', fileList[f]);
                                    console.log('Files added to formData property');
}
                            }
                            customFormService.postFiles(result.data, formData);
                            console.log('files posted to customFormService');
                        }
                    }
                }, function (err) {
                    deferred.reject(err);
                });
                return deferred.promise;
            }
//Here's the file-select method:
            self.fileSelect = function (e) {
                for (var x = 0; x < e.length; x++) {
                    fileList.push(e[x]);
                }
            }

Sorry, that was long-winded. 抱歉,这很long。 Is there a way to grab the actual file object (not just a JSON string) using the Angular controller and access that object in C#? 有没有一种方法可以使用Angular控制器获取实际的文件对象(而不仅仅是JSON字符串),并使用C#访问该对象? Thanks! 谢谢!

You'd basically need to submit a form containing the file inputs, then process it as multipart form data on the server. 基本上,您需要提交一个包含文件输入的表单,然后在服务器上将其作为多部分表单数据进行处理。 The files would come across as Streams. 这些文件将作为流出现。

Here's an example with code to get you started: 这是一个示例代码,可以帮助您入门:

http://www.strathweb.com/2012/08/a-guide-to-asynchronous-file-uploads-in-asp-net-web-api-rtm/ http://www.strathweb.com/2012/08/a-guide-to-asynchronous-file-uploads-in-asp-net-web-api-rtm/

The full solution for this problem is laid out below: 下面列出了该问题的完整解决方案:

//get files from custom form controls
self.fileSelect = function (files) {
    var reader = new FileReader();
    reader.onload = function (e) {
        console.log("about to encode");
        $scope.encoded_file = btoa(e.target.result.toString());
    };
    reader.readAsBinaryString(files[0]);
    self.file = files[0];
    filesFromFileSelect.push(files[0]);
}

//need to post files one at a time. a loop iterates through the files array.
customFormService.postFiles(filesFromFileSelect[i], formDataForFile, self.formId, strResult, formFieldId)
    .success(function (data) {
        self.submitted = true;
        console.log('file posted', data);
    })
    .error(function (data) {
        self.submitted = false;
        console.log('error posting file. Message: ', data);
    });

//inside the service posting the files...
function postFiles(postfile, formData, formId, strResult, formFieldId) {
    var fd = new FormData();
    fd.append("data", JSON.stringify(formData));
    fd.append('file', postfile);

    return $http.post('/api/customformfile/post?id=' + formId + '&submissionGuid=' + strResult + '&formFieldId=' + formFieldId, fd, {
                withCredentials: false,
                headers: {
                    'Content-Type': undefined
                },
                transformRequest: angular.identity
            });
    }

//essential parts of the server-side controller handling the files...
var httpPostedFile = HttpContext.Current.Request.Files["file"];
if (httpPostedFile != null) {
    var savePath = "\\someFile\someOtherFile";
}

try {
    var uploadsDirectory = savePath;
    string pathToCheck = savePath + fileName;
    char[] charsToTrim = { '"', '\\', '/' };
    string trimmedFileName = fileName.Trim(charsToTrim).Replace(' ', '_');
    string tempFileName = trimmedFileName;

    if (File.Exists(pathToCheck))
    {
        int copyCount = 2;
        while (File.Exists(pathToCheck))
        {
            //insert copy number of file before file extension
            if (tempFileName.IndexOf('.') != -1)
            {
                tempFileName = trimmedFileName.Insert(trimmedFileName.IndexOf('.'), "_(" + copyCount + ")");
            }

            pathToCheck = savePath + tempFileName;
            copyCount++;
        }
        httpPostedFile.SaveAs(Path.Combine(uploadsDirectory, tempFileName));
    }
    else
    {
    httpPostedFile.SaveAs(Path.Combine(uploadsDirectory, trimmedFileName));
    }
}
catch(Exception fileEx) {
    //log the error
    return Request.CreateResponse(HttpStatusCode.InternalServerError, exc.Message);
}

Processing the files one at a time is an ugly way to do it, but it works for now. 一次处理一个文件是一种丑陋的方式,但是现在可以使用。 Will investigate other ways to process a whole file array vs. one file at a time in the future. 将来将研究其他方式来处理整个文件阵列而不是一次处理一个文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM