1

I'm using Angular js and API Controller c# to upload files, I have a fileupload control,

cshtml

<input id="file" name="file" type="file" 
      ng-file-model="files" ng-model="file" multiple />

I'm able to upload 1MB, 2 MB files by passing filebytestring from service.js to API Controller after making changes in web.config,

web.config

<httpRuntime targetFramework="4.6.1" maxRequestLength="1048576" executionTimeout="3600"/>


<security>
    <requestFiltering>
        <requestLimits maxAllowedContentLength="1073741824" />
    </requestFiltering>
</security>

But when I try to upload file more than 3MB it is not working.

Controller.js

//Directive
app.directive('ngFileModel', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var model = $parse(attrs.ngFileModel);
            var isMultiple = attrs.multiple;
            var modelSetter = model.assign;
            element.bind('change', function () {
                var values = [];
                angular.forEach(element[0].files, function (item) {
                    var reader = new FileReader();
                    reader.readAsArrayBuffer(item);
                    reader.onload = function () {
                        var arrayBuffer = reader.result
                        var bytes = new Uint8Array(arrayBuffer);
                        var fileByteString = JSON.stringify(bytes);
                        var value = {
                            // File Name 
                            name: item.name,
                            //File Size 
                            size: item.size,
                            //File URL to view 
                            url: URL.createObjectURL(item),
                            // File Input Value 
                            _file: item,
                            // File byte string
                            fileByteString: fileByteString
                        };

                        values.push(value);
                    }
                });
                scope.$apply(function () {
                    if (isMultiple) {
                        modelSetter(scope, values);
                    } else {
                        modelSetter(scope, values[0]);
                    }
                });
            });
        }
    };
}]);

service.js

FormService.uploadFile = function (FileModel) {

    var requestURL = "/api/FileModelAPI/UploadFile";
    var uploadFile = $http({
        url: requestURL,
        method: 'POST',
        data: FileModel,
        headers: { "accept": "application/json;odata=verbose" },

    });
    return (uploadFile.then(handleUploadFileSuccess, handleUploadFileError));
}

function handleUploadFileSuccess(response) {
    return response.data;
}

function handleUploadFileError(xhr) {
    console.log(xhr);
}

API Controller

    [HttpPost]
    public ERFileResponseModel UploadFile([FromBody] FileModel request)
    {
        ERFileResponseModel response = new ERFileResponseModel();
        try
        {
            FileManager fileMgr = new FileManager();
            response = fileMgr.AddFile(request);
        }
        catch (Exception ex)
        {
        }

        return response;

    }

Thanks in advance.

Maxim Shoustin
  • 77,483
  • 27
  • 203
  • 225
Vijay
  • 133
  • 1
  • 10
  • I suggest using the [ng-file-select directive](https://stackoverflow.com/a/43074638/5535245) and directly POST the file object. This is more efficient than loading the file into memory. It will handle larger files. – georgeawg Jun 22 '20 at 00:26
  • Thank you!. Will try this and let you know – Vijay Jun 23 '20 at 01:51
  • @georgeawg Is there any way to pass file byte string or file byes as chunks to API controller. Lets say If I upload 3MB file pass 1MB chunk each to API controller and merge those chunks in API controller an upload file ? – Vijay Jun 24 '20 at 01:46

2 Answers2

1

What is the error code on the client-side during the upload?
maxRequestLength property might influence limiting a large file upload.
https://learn.microsoft.com/en-us/dotnet/api/system.web.configuration.httpruntimesection.maxrequestlength?view=netframework-4.8
Try to set a large value.

<httpRuntime targetFramework="4.6.1" maxRequestLength="2147483647" />

    <system.webServer>
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength="2147483647" />
    </requestFiltering>
  </security>
  </system.webServer>

Also, I suggest you change your function signature referring to the below best practice so that upload a file.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-2
The signature of this function should not contain a parameter when fetching the data stream from the Html form.

   public Task<HttpResponseMessage> PostFormData()
{
    // Check if the request contains multipart/form-data.
    if (!Request.Content.IsMimeMultipartContent())
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }

    string root = HttpContext.Current.Server.MapPath("~/App_Data");
    var provider = new MultipartFormDataStreamProvider(root);

    // Read the form data and return an async task.
    var task = Request.Content.ReadAsMultipartAsync(provider).
        ContinueWith<HttpResponseMessage>(t =>
        {
            if (t.IsFaulted || t.IsCanceled)
            {
                Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
            }

            // This illustrates how to get the file names.
            foreach (MultipartFileData file in provider.FileData)
            {
                Trace.WriteLine(file.Headers.ContentDisposition.FileName);
                Trace.WriteLine("Server file path: " + file.LocalFileName);
            }
            return Request.CreateResponse(HttpStatusCode.OK);
        });

    return task;
}

Here is an example.
https://www.c-sharpcorner.com/article/upload-large-files-in-web-api-with-a-simple-method/
Feel free to let me know if there is anything I can help with.

Abraham Qian
  • 7,117
  • 1
  • 8
  • 22
  • Thanks for the response. There is no error on the client-side while upload. Whenever the file size is more than 3MB the object that we are passing from client-side to API controller is becoming null/empty. Is there any setting that would allow the large file to API controller like "maxRequestLength","maxAllowedContentLength". I have changed those values but still not able to upload file more than 3MB – Vijay Jun 23 '20 at 01:58
  • @Vijay , In order to verify these settings are valid, please check the setting in the Request Filtering module. https://i.stack.imgur.com/VtAFL.png I doubt if these settings have been taking effect. Check this link for detailed steps. https://www.inflectra.com/support/knowledgebase/kb306.aspx – Abraham Qian Jun 23 '20 at 02:22
  • Thanks @Abraham I have verified the settings and but still the same issue.Is there any way to pass filebytestring or file bytes in chunks (example 1MB each chunk) and pass that to API controller and merge those chunks and upload. ? Is there any way to pass huge file bytes to API controller ? – Vijay Jun 24 '20 at 01:45
  • Check this link, the guy has the same thought with you. https://stackoverflow.com/questions/43746815/ng-file-upload-file-size-above-4-5mb – Abraham Qian Jun 24 '20 at 09:45
  • Thanks @Abraham will check this link – Vijay Jun 24 '20 at 21:03
0

In my case these were the changes I needed to apply:

web.config:

 <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="4294967295" />
      </requestFiltering>
 </security>

Controller:

 [HttpPost]
 [RequestFormLimits(MultipartBodyLengthLimit = 4294967295)]
 public VmResult Create(VmPostFileAndJson multiData){
  .
  .
  .

maxAllowedContentLength: By default it is set to 30000000 around 30MB and being an uint, it should theoretically allow a max of 4,294,967,295