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:
all stack overflow answers
online answers
removing the content of the "Upload" function, and changing to MVC's Controller base class -> still same result.
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:
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:
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:
- 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... }
0 comments:
Post a Comment