Search code examples
c#angularjsrepositoryng-file-upload

How to send files along with the viewModel using Web API or how to save using temporary data


I've read many stackoverflow posts with the similar problems as well as several blogs but I am still uncertain as how to solve my problem :(

I have angularJS directive that allows to upload files to the server. The code is like this:

[HttpPost]       
    [Route("UploadFile")]
    public async Task<HttpResponseMessage> UploadFile()
    {          
        // Check if the request contains multipart/form-data.
        if (Request.Content.IsMimeMultipartContent("form-data"))
        {               
            try
            {
                var resultOut = new List<FileUploadResult>();

                var streamProvider = new MultipartMemoryStreamProvider();
                streamProvider = await Request.Content.ReadAsMultipartAsync(streamProvider);

                foreach (
                    var item in
                    streamProvider.Contents.Where(c => !string.IsNullOrEmpty(c.Headers.ContentDisposition.FileName))
                )
                {
                    FileUploadResult file = new FileUploadResult()
                    {
                        FileName = item.Headers.ContentDisposition.FileName,
                        //   Content = fileBytes, // No need to pass the info back as we're not going to read it save it yet
                        Key = Guid.NewGuid().ToString(),
                        Type = item.Headers.ContentDisposition.DispositionType
                    };
                    resultOut.Add(file);
                    //using (Stream stFileSource = new MemoryStream(await item.ReadAsByteArrayAsync()))                     {
                    //    byte[] fileBytes;

                    //    fileBytes = new Byte[stFileSource.Length];
                    //    stFileSource.Read(fileBytes, 0, Convert.ToInt32(stFileSource.Length));
                    //    FileUploadResult file = new FileUploadResult()
                    //    {
                    //        FileName = item.Headers.ContentDisposition.FileName,
                    //     //   Content = fileBytes, // No need to pass the info back as we're not going to read it save it yet
                    //        Key = Guid.NewGuid().ToString(),
                    //        Type = item.Headers.ContentDisposition.DispositionType
                    //    };
                    //    resultOut.Add(file);                            
                    //}
                }
                return Request.CreateResponse(HttpStatusCode.OK, resultOut.ToArray());
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.ToString());
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }
        else
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest);
        }
    }

Also directive saves the Files array into a property. My user form allows to remove some files / add more files and then I want to save the information from the form (somewhat complex view model) along with the files. I was unable to figure that problem so far. One possibility I see here is to save the files in the UploadFile method using Repository into a database. However, I would prefer to save that into some temporary table instead (e.g. #FileInfo table) and not the actual table. Or perhaps there is a way to save files (with its binary content) into some memory object so I will be able to get that content back when I am ready to save my model's data? Can you either show implementation of the temporary repository storage or give some other ideas for my dilemma?


Solution

  • Firstly, Your directive need to create a post request with 'multipart/form-data'.

    Check this link for reference.

    However, we use angular file upload to do this.

    angular
    .module('app', ['angularFileUpload'])
    .controller('AppController', function($scope, FileUploader) {
        $scope.uploader = new FileUploader(
        {
            url: 'Your/upload/url',
            headers: {
                'autorization': 'Bearer token if you need it'
            },
            onProgressItem: function () {
                 ...
            },
            onSuccessItem: function (opt, data) {
                ...
            },
            onErrorItem: function (opt) {
                ...
            }
        });
    
        //you may want to wrap the following in an event
        var uploadItem = $scope.uploader.queue[uploader.queue.length - 1];
        uploadItem.formData.push({
                    someData: "someData",
                    moreData: "moreData"
                });
    
        uploadItem.upload();
        uploadItem.formData = [];
    
    });
    

    Then in your controller, you can do the following to retrieve what you need:

    //your request
    var request = HttpContext.Current.Request;
    
    //your fields
    var someData = request.Form["someData"];
    var moreData = request.Form["moreData"];
    
    //your file
    var file = request.Files["file"];