Thursday, June 16, 2016

Ng-File-Upload with MVC & Web API - keep getting “404 Not Found”

Leave a Comment

I need to allow image upload in my AngularJS + WebAPI project. to achieve this I am using ng-file-upload according to this sample code: http://monox.mono-software.com/blog/post/Mono/233/Async-upload-using-angular-file-upload-directive-and-net-WebAPI-service/

with a few adjustments to the post code to look like this:

$scope.onFileSelect = function ($files) {     console.log("on file select is running!");     //$files: an array of files selected, each file has name, size, and type.     for (var i = 0; i < $files.length; i++) {         var $file = $files[i];         (function (index) {             Upload.upload({                 url: "/api/Uploads/Upload", // webapi url                 method: "POST",                                    file: $file             }).progress(function (evt) {                 // get upload percentage                 console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));             }).success(function (data, status, headers, config) {                 // file is uploaded successfully                 console.log(data);             }).error(function (data, status, headers, config) {                 // file failed to upload                 console.log(data);             });         })(i);     } } 

I have quite a few web API controllers already and I added a new one according to the code sample in the link above (that inherits from System.web.http.ApiController instead of the "regular" Microsoft.AspNet.Mvc.Controller class):

 [Route("api/[controller]")] public class UploadsController : ApiController {     [HttpPost] // This is from System.Web.Http, and not from System.Web.Mvc             public async Task<HttpResponseMessage> Upload()     {         if (!Request.Content.IsMimeMultipartContent())         {             this.Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);         }          var provider = GetMultipartProvider();         var result = await Request.Content.ReadAsMultipartAsync(provider);          // On upload, files are given a generic name like "BodyPart_26d6abe1-3ae1-416a-9429-b35f15e6e5d5"         // so this is how you can get the original file name         var originalFileName = GetDeserializedFileName(result.FileData.First());          // uploadedFileInfo object will give you some additional stuff like file length,         // creation time, directory name, a few filesystem methods etc..         var uploadedFileInfo = new FileInfo(result.FileData.First().LocalFileName);            // Through the request response you can return an object to the Angular controller         // You will be able to access this in the .success callback through its data attribute         // If you want to send something to the .error callback, use the HttpStatusCode.BadRequest instead         var returnData = "ReturnTest";         return this.Request.CreateResponse(HttpStatusCode.OK, new { returnData });     } 

The problem is, i keep getting "404 not found" when posting.

I tried:

  1. all stack overflow answers

  2. online answers

  3. removing the content of the "Upload" function, and changing to MVC's Controller base class -> still same result.

  4. changing the name of "Upload" method to "Post" and posting to "/api/uploads" -> same 404.

Please help! thanks!

EDIT

this is the browser "Network" tab: All previous posts succeeded, just the upload fails

  • I am using HTTPS

  • this was tested "live" (without localhost) = same result.

EDIT2

my routes:

  app.UseMvc(routes =>         {             routes.MapRoute(                 name: "default",                 template: "{controller=Home}/{action=Index}/{id?}");         }); 

these are the only routes that are declared.

EDIT3

I am 100% sure the problem is me using "ApiController" as base class instead of "Controller". i added a new controller and i can access it no problem. now just making it work as i don't have " Request.Content " in "Controller" - any ideas?

I see 2 possibilities to make it work:

  1. pass HttpRequestMessage as a parameter to the method:

    public async Task Post([FromBody]HttpRequestMessage request)

but i am getting HTTP 500 as i don't know how to pass from angular's POST.

or:

  1. get Request.Content to resolve under Controller (no idea how).

has someone managed to do this? thanks!

2 Answers

Answers 1

I was able to solve the problem i posted in EDIT3 by using:

 if (Request.Form.Files != null && Request.Form.Files.Count > 0)         {             var file = Request.Form.Files[0];             var contentType = file.ContentType;              using (var fileStream = file.OpenReadStream())             {                 using (var memoryStream = new MemoryStream())                 {                     await fileStream.CopyToAsync(memoryStream);                     FileStream newFS = new FileStream(Settings.UserImagesDir + "\\name.png", FileMode.Create);                     memoryStream.WriteTo(newFS);                     newFS.Close();                                      }             }         } 

and all this in a regular web api controller that inherits from Controller.

thanks everyone for your help, although no one solved it you all pushed me in the right direction.

Answers 2

The problem is that your routing is misconfigured for the URL /api/Uploads/Upload. In order to make it match, you have to specify a template for the method Upload, since it is not actually named after an HTTP method.

[HttpPost("upload")] public async Task<HttpResponseMessage> Upload() {     // code omitted... } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment