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 1371 posts 3102 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 1371 posts 3102 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 459 posts 1602 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 459 posts 1602 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 459 posts 1602 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 459 posts 1602 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 459 posts 1602 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 459 posts 1602 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 459 posts 1602 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

Please Sign in or register to post replies

Write your reply to:

Draft