Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Neil Hodges 338 posts 987 karma points
    Sep 12, 2017 @ 07:50
    Neil Hodges
    0

    Uploading File/Image from Custom Dashboard form via AngularJs and UmbracoAuthorizedApiController

    Hi

    I'm using Umbraco 7.4.3

    I have a custom dashboard with several new sections and tabs. I have some forms that ive set up and are hitting my API methods.

    I have one form in particular where I need to upload the form with an image. A profile picture for instance. So the form consists of:

    Profile Pic :

    <input type="file" id="driver.Pic" name="file" onchange="angular.element(this).scope().LoadFileData(this.files)"  accept="image/*" required/>
    

    First Name :

    <input type="text" name="driver.FirstName" ng-model="driver.FirstName" id="DriverFirstName" class="umb-editor umb-textstring textstring ng-pristine ng-valid ng-valid-required" ng-required="true" ng-trim="false" required>
    

    There are more form elements but i've left them out for brevity.

    I can pass all the textual form elements to my API method not a problem, but I need to pass the uploaded file. Preferably via HttpPostedFileBase.

    Does anyone have any examples of passing an uploaded file to their controller.js and onto a UmbracoAuthorizedApiController HttpResponseMessage??

  • Rune Grønkjær 1372 posts 3103 karma points
    Apr 13, 2018 @ 07:11
    Rune Grønkjær
    0

    Did you solve this?

  • Neil Hodges 338 posts 987 karma points
    Apr 21, 2018 @ 07:50
    Neil Hodges
    0

    Hi Rune

    Yeh I did in the end, not sure if is was the most elegant solution. Do you want me to post what I did?

  • Neil Hodges 338 posts 987 karma points
    Apr 21, 2018 @ 08:07
    Neil Hodges
    0

    I did this in case anyone else needs it in the HTML:

    <label for="driverAdd.DriverImage" style="display: inherit">Driver's Picture</label>
                                                <input type="file" id="driverAdd.DriverImage" name="file" onchange="angular.element(this).scope().LoadFileData(this.files)" accept="image/*" />
    <button class="btn publish" ng-click="addDriver(driverAdd)">Create</button>
    

    In my JS controller:

    $scope.post = "/umbraco/Surface/DriverSurface/CreateDriver";
    $scope.files = [];
    $scope.LoadFileData = function (files) {
        $scope.files = files;
    };
    $scope.addDriver = function (driver) {
    
        $http({
            url: $scope.post,
            method: "POST",
            headers: { "Content-Type": undefined },
            transformRequest: function (data) {
                var formData = new FormData();
                formData.append("driverDetail", angular.toJson(driver));
                for (var i = 0; i < data.files.length; i++) {
                    formData.append("files[" + i + "]", data.files[i]);
                }
                return formData;
            },
            data: { driverDetail: driver, files: $scope.files}
        })
        .success(function (response) {
            };
            $scope.statusMsg = "Driver Added";
        });
    };
    

    Then in my SurfaceController to get the HttpPostedFileBase I did this:

         [System.Web.Http.HttpPost]
        public ActionResult CreateDriver(string driverDetail, HttpPostedFileBase[] files)
        {}
    

    Like i say not sure if there is a more elegant way of doing this but it sure works Ok for me :)

  • Rune Grønkjær 1372 posts 3103 karma points
    Apr 23, 2018 @ 07:33
    Rune Grønkjær
    0

    Thanks Neil. I found another solution that was much more complicated, but still works pretty good. It ended up being very specific for my solution, so I cannot really post code unless i clean it up good and I haven't got the time right now. Your's looks nice and simple to work with.

    /Rune

  • Adriano Fabri 469 posts 1633 karma points
    Oct 05, 2018 @ 14:26
    Adriano Fabri
    0

    Hi Neil, I'm trying to replicate your code in my custom package, but it doesn't work.

    I have a custom section with a custom tree. The first voice of the tree allows users to upload an image in my custom directory in "~/Media" directory on file system

    Below you can find view, controller, resource and c# code.

    Can you help me to understand where is the problem and how to solve it?

    Thank you

    Adriano


    The View:

    (No problem on rendering file upload fields)

        <div class="file-uploader">
            <label for="vm.bkgImage">Select an image</label>
            <input type="file" id="vm.bkgImage" name="file" ng-model="vm.bkgImage" onchange="angular.element(this).scope().LoadFileData(this.files)" accept="image/jpg, image/png" />
             <button class="btn publish" ng-click="vm.addBkgImage(vm.bkgImage)">Upload</button>
        </div>
    

    The Controller:

    (No problems on file selection)

        vm.bkgImage = [];
        var allFiles = [];
        var file = [];
    
        $scope.LoadFileData = function (files) {
            file = files[0];
            allFiles = files;
        };
    
        vm.addBkgImage = function (bkgImage) {
            afclpResource.postUploadImage(file, allFiles).then(function (response) {
                if (response.data !== "null") {
                    notificationsService.add(vm.uploadSuccessNotification);
                }
                else {
                    notificationsService.add(vm.uploadErrorNotification);
                    vm.showDeletePanel = false;
                }
            });
        };
    

    The Resource

    (Here I receive a "500 - Internal Server Error" after click the "upload" button. The action stops and don't reach c# code)

        postUploadImage: function (file, allFiles) {
            return $http({
                method: "POST",
                url: 'AFCLP/AFCLPResourceApi/PostAFCLPUploadImage',
                headers: { "Content-Type": "undefined" },
                transformRequest: function (data) {
                    var formData = new FormData();
                    formData.append("file", angular.toJson(file.name));
                    for (var i = 0; i < allFiles.length; i++) {
                        formData.append("files[" + i + "]", allFiles[i]);
                    }
                    console.log(formData);
                    console.log(data);
                    return formData;
                },
                data: { file, allFiles }
            });
        }
    

    The C# method

        /// <summary>
        /// Post - Upload Image
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public bool PostAFCLPUploadImage(HttpPostedFileBase file, HttpPostedFileBase[] files)
        {
            string afclpMediaPath = HttpContext.Current.Server.MapPath(SystemDirectories.Media + "/AFCLP/backgrounds");
    
            try
            {
                // HERE WILL BE THE UPLOAD CODE
    
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.Error<Exception>(ex.Message, ex);
    
                return false;
            }
        }
    
  • Neil Hodges 338 posts 987 karma points
    Oct 05, 2018 @ 14:46
    Neil Hodges
    0

    Hi

    Were you able to put a breakpoint onto your method PostAFCLPUploadImage?

    Does the code execute that far?

    If not it could be a path problem where the Ajax is not hitting your method? Although I would of thought that should return a 404 error if it can't find it.

  • Adriano Fabri 469 posts 1633 karma points
    Oct 05, 2018 @ 15:15
    Adriano Fabri
    0

    Thank you for your quick answer.

    Yeah, I put a breakpoint at the first line of the c# method but the code don't execute.

    Yeah, there is a problem in Ajax but I don't understand where. The info about the error, are very poor.

    I tried to put a breakpoint in the resource code, It seems all ok but when the c# method must be called, the console (Client) display the "500 - Internal Server Error".

    I tried also to call the method without send the file upload data and the c# method is executed correctly.

  • Neil Hodges 338 posts 987 karma points
    Oct 05, 2018 @ 15:28
    Neil Hodges
    0

    I can only think it's maybe down to the routing in Umbraco? In my version i'm using a SurfaceController and an ActionResult type of Method.

    Maybe try creating one in a SurfaceController of type ActionResult and see if it hits that with the HttpPostedFileBase

  • Adriano Fabri 469 posts 1633 karma points
    Oct 05, 2018 @ 15:36
    Adriano Fabri
    0

    I already used a custom upload in frontend with a SurfaceController and ActionResult and it function properly, but now I need to do the same in my backoffice extension.

    But unfortunately it doesn't work. :-(

  • Neil Hodges 338 posts 987 karma points
    Oct 05, 2018 @ 15:44
    Neil Hodges
    0

    That's really Odd.

    I've created a custom dashboard and within one of the views im using this method and it hits my code Ok.

    Could you maybe try just passing one parameter - allFiles and see if it hits it Ok then?

  • Adriano Fabri 469 posts 1633 karma points
    Oct 05, 2018 @ 16:08
    Adriano Fabri
    0

    Now the error is :

    POST http://localhost:55701/umbraco/AFCLP/AFCLPResourceApi/PostAFCLPUploadImage 415 (Unsupported Media Type)
    

    This is the content of "allFiles"

    allFiles: FileList
        0: File(433305) {name: "Honda NC750X (2017).jpg", lastModified: 1538639411579, lastModifiedDate: Thu Oct 04 2018 09:50:11 GMT+0200 (Ora legale dell’Europa centrale), webkitRelativePath: "", size: 433305, …}
        length: 1
        __proto__: FileList
        __proto__: Object
    
  • Adriano Fabri 469 posts 1633 karma points
    Oct 08, 2018 @ 07:54
    Adriano Fabri
    0

    Hi Neil, watching the header, when start upload, I found this exception message:

    No MediaTypeFormatter is available to read an object of type 'HttpPostedFile' with media type "multipart/form-data"

    Any Idea? :-o

  • Adriano Fabri 469 posts 1633 karma points
    Oct 08, 2018 @ 15:36
    Adriano Fabri
    0

    I tried to modify the code as below and finally I arrive on my POST method. The problem now is that for some reason the request.FileData is empty (no file)


    The View:

    <div class="file-uploader">
        <form id="afclpUploadForm" name="afclpUploadForm" role="form" class="form-inline">
            <label for="file">Select an image</label>
            <input type="file" ng-model="picFile" name="file" ngf-change="fileSelected(this)" ngf-accept="'image/jpg, image/png'" />
            <button ng-click="saveBkgImage(picFile)" class="btn publish">Upload</button>
        </form>
    </div>
    

    The Controller:

    $scope.picFile = [];
    $scope.files = [];
    
    $scope.fileSelected = function (element) {
        //add the file object to the scope's files collection
        $scope.files.push(element.picFile);
    };
    
    //the save method
    $scope.saveBkgImage = function (picFile) {
        afclpResource.postUploadImage($scope, picFile).then(function (response) {
            if (response.data !== "null") {
                notificationsService.add($scope.uploadSuccessNotification);
            }
            else {
                notificationsService.add($scope.uploadErrorNotification);
                $scope.showDeletePanel = false;
            }
        });
    };
    

    The Resource

    postUploadImage: function (file, allFiles) {
        return $http({
            method: "POST",
            url: 'AFCLP/AFCLPResourceApi/PostAFCLPUploadImage',
            headers: { 'Content-Type': undefined },
            transformRequest: function (data) {
                var formData = new FormData();
                formData.append("model", angular.toJson(data.model));
                for (var i = 0; i < data.files.lenght; i++) {
                    formData.append("file" + i, data.files[i]);
                }
    
                return formData;
            },
            data: { model: model, files: file }
        });
    }
    

    The C# method

    /// <summary>
    /// Post - Upload Image
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    public async Task<HttpResponseMessage> PostAFCLPUploadImage()
    {
        try
        {
            // Save File
            if (!Request.Content.IsMimeMultipartContent())
            {
                LogHelper.Error<HttpResponseException>(HttpStatusCode.UnsupportedMediaType.ToString(), new HttpResponseException(HttpStatusCode.UnsupportedMediaType));
                return Request.CreateResponse(HttpStatusCode.UnsupportedMediaType, new HttpResponseException(HttpStatusCode.UnsupportedMediaType));
            }
    
            //Directory.CreateDirectory(afclpMediaPath);
            var provider = new MultipartFormDataStreamProvider(afclpMediaPath);
            var result = await Request.Content.ReadAsMultipartAsync(provider);
    
            if (result.FormData["model"] == null)
            {
                LogHelper.Error<HttpResponseException>(HttpStatusCode.BadRequest.ToString(), new HttpResponseException(HttpStatusCode.BadRequest));
                return Request.CreateResponse(HttpStatusCode.BadRequest, new HttpResponseException(HttpStatusCode.BadRequest));
            }
    
            var model = result.FormData["model"];
    
            if (result.FileData.Count() > 0)
            {
                //Get the files
                foreach (var file in result.FileData)
                {
                    //Save each uploaded file
    
                }
            }
    
            return Request.CreateResponse(HttpStatusCode.OK, "Success!");
    
            //LogHelper.Error<HttpResponseException>("Error! (" + HttpStatusCode.InternalServerError + ") FileData Empty", new HttpResponseException(HttpStatusCode.InternalServerError));
            //throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.InternalServerError, "Error! FileData Empty"));
        }
        catch (HttpResponseException ex)
        {
            LogHelper.Error<HttpResponseException>("Error! (" + HttpStatusCode.InternalServerError + ") " + ex.Message, ex);
            return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
        }
    }
    
  • Anton Oosthuizen 206 posts 486 karma points
    Jun 16, 2020 @ 18:06
    Anton Oosthuizen
    0

    Hi Adriano

    Did you resolve this problem? I also get FileData is empty

  • Adriano Fabri 469 posts 1633 karma points
    Jun 18, 2020 @ 13:59
    Adriano Fabri
    0

    Hi Anton, wow...It's been a long time since the last post.

    OK, I remember...I couldn't solve it so i decided to use a javascript uploader (kartikBootstrapUploader)

    This solved my problem.

    if you want I can give you the code.

    Adriano

  • Anton Oosthuizen 206 posts 486 karma points
    Jun 18, 2020 @ 14:20
    Anton Oosthuizen
    1

    Thanks for getting back to me.

    All good.

    Seemed like a nice solution to upload multiple files

  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies