Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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!

like image 604
tarkil Avatar asked Jun 07 '16 06:06

tarkil


2 Answers

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.

like image 73
tarkil Avatar answered Oct 24 '22 06:10

tarkil


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...
}
like image 42
NightOwl888 Avatar answered Oct 24 '22 06:10

NightOwl888