3

I can't seem to get this working with ng-file upload. I need to pass in fine in my controller with bridge Id

The error I'm getting is:

"{"Message":"No HTTP resource was found that matches the request URI 
'http://localhost/api/BridgeController/'.","MessageDetail":"No type was 
found that matches the controller named 'BridgeController'."}"

Can't figure out why it can't find my method. Any ideas?

Here is my controller code that will get moved into a service

$scope.uploadFile = function (file) {
    console.log("hitting file upload", $scope.selectedBridge);
    if (file) {
        debugger;

        var request = {
            method: 'POST',
            url: '/api/Bridge/UploadBridgeImage',
            data: angular.toJson($scope.selectedBridge.BridgeID),
            file: file,
            headers: { 'Content-Type': undefined }
        };

        Upload.upload(request).then(function (response) {

        });
    }
}

and back end C#

[HttpPost]
[Route("api/Bridge/UploadBridgeImage")]
public IHttpActionResult UploadBridgeImage()
{
    try
    {
        var uploadedFiles = HttpContext.Current.Request.Files;

        for (int i = 0; i < uploadedFiles.Count; i++)
        {
            var fileToSave = uploadedFiles[i];

            var fileBytes = _iStremHelper.GetBytes(fileToSave.InputStream, fileToSave.ContentLength);
            var file = BridgeFileEntity(fileBytes, fileToSave, 1);

            using (_iFileRepository)
            {
                _iFileRepository.Save(file);
            }
        }
        return Ok();
    }
    catch (Exception ex)
    {
        return InternalServerError();
    }
}

Edited Code Here. I was able to hit my break point in that post method in my C# controller. File have all the data I need. Now I need to get "data" some how. Any idea where is it located in context?

kkdeveloper7
  • 497
  • 2
  • 11
  • 25
  • Is attribute routing enabled in web api? – Aleksey L. Jun 20 '16 at 05:06
  • Try and rename the route to "api/Bridge/UploadBridgeImage" in both client and route-attribute. The default way is not to name the controller by sufix controller. – Marcus Höglund Jun 20 '16 at 05:41
  • @AlekseyL. yes they are enable config.MapHttpAttributeRoutes(); – kkdeveloper7 Jun 21 '16 at 03:09
  • @MarcusH tried your suggestion getting same error message. – kkdeveloper7 Jun 21 '16 at 03:13
  • @kkdeveloper7 another routes are working? Are you sure your dev port is 80? (maybe http://localhost:portNumber) – Aleksey L. Jun 21 '16 at 04:25
  • @AlekseyL. yes another routes are working and they are on same port. – kkdeveloper7 Jun 23 '16 at 02:38
  • here is some additional information getting 415 status now Failed to load resource: the server responded with a status of 415 (Unsupported Media Type). I narrowed down my search, seems like the issue is that im not accepting muplipart form properly. started to read about this but cant really understand what is going on yet. any suggestions ? – kkdeveloper7 Jun 23 '16 at 02:45
  • @kkdeveloper7 [here's](http://aspnet.codeplex.com/sourcecontrol/latest#Samples/WebApi/FileUploadSample/Controllers/FileUploadController.cs) a demo how to save file on server side. And [one more](http://stackoverflow.com/questions/10320232/how-to-accept-a-file-post-asp-net-mvc-4-webapi) – Aleksey L. Jun 23 '16 at 04:33
  • @AlekseyL.Thank you for the link. I am saving file a little bit differently. I want it to have in binary version in my sql column. the issue im having is that i cant pass parameters in my post method. i was able to make a post with new FormData() but i am unable to get that form data on my controller side now. – kkdeveloper7 Jun 24 '16 at 02:03
  • Please see Edited Code – kkdeveloper7 Jun 24 '16 at 02:32
  • @kkdeveloper7 you can pass additional parameters through url (`Route("api/Bridge/UploadBridgeImage/{bridgeId}"`); another option is to [send form data multipart request] (https://github.com/danialfarid/ng-file-upload#upload-service) like `data: {file: file, bridgeId: $scope.selectedBridge.BridgeID}` – Aleksey L. Jun 26 '16 at 17:44
  • @AlekseyL. i was trying and working on second approach, passing it into a multi part form. on my C# side in controller i cant find that Id in context. – kkdeveloper7 Jul 01 '16 at 15:13
  • @kkdeveloper7 post code of controller - maybe I'll be able to help you – Aleksey L. Jul 01 '16 at 15:22
  • @AlekseyL. this is what I have in my controller and js file at the moment. I edited the post. I am currently passing just file, to get it working and upload images. When i post object into file property i still hit my controller but i can not find my actual image file in Context. – kkdeveloper7 Jul 02 '16 at 04:11

1 Answers1

1

In order to get both file stream (in memory) and additional json data in web api controller you can define custom MultipartStreamProvider:

class MultipartFormDataInMemoryStreamProvider : MultipartFormDataRemoteStreamProvider
{
    public override RemoteStreamInfo GetRemoteStream(HttpContent parent, HttpContentHeaders headers)
    {
        return new RemoteStreamInfo(new MemoryStream(), string.Empty, string.Empty);
    }
}

Then use it in controller:

public async Task<IHttpActionResult> UploadBridgeImage()
{
    var provider = await Request.Content.ReadAsMultipartAsync(new MultipartFormDataInMemoryStreamProvider());
    foreach (var httpContent in provider.Contents)
    {
        if (!string.IsNullOrEmpty(httpContent.Headers.ContentDisposition?.FileName))
        {
            var byteArray = await httpContent.ReadAsByteArrayAsync();
            //do whatever you need with byteArray
        }
    }

    var bridgeId = provider.FormData["bridgeId"];

    return Ok();
}

And on client side:

var request = {
    url: '/api/Bridge/UploadBridgeImage',
    data: {
        file:file,
        bridgeId:$scope.selectedBridge.BridgeID
    }
};

Upload.upload(request).then(function (response) {

});
Aleksey L.
  • 35,047
  • 10
  • 74
  • 84
  • thank you i will try that. the only thing i dont understand is where do i use this 'MultipartStreamProvider' – kkdeveloper7 Jul 02 '16 at 16:53
  • in web api controller - see example – Aleksey L. Jul 02 '16 at 16:55
  • ohh, sorry i missed that new line – kkdeveloper7 Jul 05 '16 at 02:42
  • This worked for me Thank you so much!!! Couple questions though, 1. provider.Content gives me the count of 2 because i have file and bridge Id coming in. Is there a way for me to separate this only for file and not have Id in that Content? and if no why is it like this? – kkdeveloper7 Jul 05 '16 at 03:02
  • 1
    It is because multipart content contains two parts: file + bridgeId. You can identify file content by checking if file name exists in content disposition header. see updated answer – Aleksey L. Jul 05 '16 at 04:52