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:
has someone managed to do this? thanks!
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.
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 love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With