Search code examples
c#asp.netangularjsweb-servicesng-file-upload

ng-file-upload with WebService


I'm trying to add the ability to upload zip files to a server. The client side is built with AngularJS, and the server side is C# ASP.NET, but I can't get it to work.

My server-side code looks like this:

[System.Web.Script.Services.ScriptService]
public class xyz : System.Web.Services.WebService
{
// Other WebMethods that work fine

    [WebMethod]
    public string UploadFile(byte[] file, string filename)
    {
        // do whatever
    }
}

And I'm using ng-file-upload to attempt to do the actual upload. The HTML looks like:

<form>
    <div class="form-group">
        <label class="control-label h3" for="zipFile">Zip File</label>
        <input class="form-control my-file" type="file" ngf-select ng-model="zipFile" id="zipFile" name="zipFile" accept=".zip" required />
    </div>
    <button class="btn btn-default" ng-click="submit()">Submit</button>
</form>

And the Javascript in my controller looks like this:

FileLoadController.$inject = ['$scope', 'Upload']; 
function FileLoadController($scope, Upload) {
    var vm = this;
    vm.scope = $scope;
    vm.scope.submit = function () {
        if (vm.scope.zipFile) {
            vm.scope.upload(vm.scope.zipFile);
        }
    }

    vm.scope.upload = function (file) {
        Upload.upload({
            url: 'xyz.asmx/UploadFile',
            data: { 'file': file, 'filename': file.name },
            },
        })
        .then(function (response) {
            alert(response);
        });
    }
}

Upload.upload gets called, but the UploadFile method on the server side is never executed.

It's probably something simple, but what am I doing wrong? Is there a better, or easier, way to do this?

Thank you.


Solution

  • I wound up not trying to use the existing WebHandler and added an IHttpHandler specifically for uploading. I didn't want to add a different handler, but whatever works.

    There is an example referenced by ng-upload-file (ng-file-upload .NET example), but let me summarize what I did.

    1. Added a 'Generic Handler' to my project, and called it UploadHandler.
    2. Tweak the ProcessRequest method to do what I want
    3. Updated the AngularJS controller to send to the new handler
    4. Updated the HTML to allow large files
    5. Tweak the web.config file to allow large files to be uploaded

    (Steps 1 & 2) adding the Generic Handler to the project creates a class derived from IHttpHandler, and it looks like this

    public class UploadHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
    
            if (context.Request.Files.Count > 0)
            {
                HttpFileCollection files = context.Request.Files;
                for (int i = 0; i < files.Count; i++)
                {
                    HttpPostedFile file = files[i];
                    string fname = context.Server.MapPath("uploads\\" + file.FileName);
                    file.SaveAs(fname);
    
                    // Do something with the file if you want
                }
                context.Response.Write("File/s uploaded successfully");
            }
            else
                context.Response.Write("No files uploaded");
        }
    
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
    

    (Step 3) Updating the AngularJS controller made it look like this

        vm.scope.submit = function () {
            if (vm.scope.zipFile) {
                vm.scope.upload(vm.scope.zipFile);
            }
        }
    
        vm.scope.upload = function (file) {
            Upload.upload({
                url: 'UploadHandler.ashx',
                data: { },
                file: file
            })
            .then(function (response) {
                alert(response.data);
            })
        }
    

    (Step 4) Added ngf-max-size so files up to 1GB can be uploaded

    <form>
        <div class="form-group">
            <label class="control-label h3" for="zipFile">Zip File</label>
            <input class="form-control my-file" type="file" ngf-select ng-model="zipFile" id="zipFile" name="zipFile" ngf-max-size="1GB" accept=".zip" required />
        </div>
        <button class="btn btn-default" ng-click="submit()">Submit</button>
    </form>
    

    (Step 5) Then I had to tweak the web.config file to allow those large files. It involved adding two things. The first was maxRequestLength added to the httpRuntime, like so:

    <configuration>
      <!--Lots of omitted stuff-->
      <system.web>
        <httpRuntime targetFramework="4.5.1" maxRequestLength="1073741824" />
      </system.web>
    </configuration>
    

    The second was to add a security section so large things wouldn't be filtered out:

    <configuration>
      <!--Lots more omitted stuff-->
      <system.webServer>
        <security>
          <requestFiltering>
            <requestLimits maxAllowedContentLength="1073741824"/>
          </requestFiltering>
        </security>
      </system.webServer>
    </configuration>