Illegal Invocation Ajax File Upload With Working Example.

Have you ever tried to upload a file, whether it be an image or PDF file to only receive the following error: illegal invocation error, if yes, then this blog will help you solve it with a working example that you can download from GitHub.

This example uses jQuery 3.5.1

To start, let's add the form the which contains two text boxes, one for the users first name and one to upload the file. 

@model Web.Model.JQueryAjaxUploadModel.UploadFormModel
<div class="container">
    <div class="row">
        <div clas="col-12">
            <h2>jQuery Ajax Form With Image</h2>
            @using (Html.BeginForm("Upload", "JQueryForm", FormMethod.Post, new { enctype = "multipart/form-data", id = "frmAjaxForm", name = "frmAjaxForm" }))
            {
                <div>
                    @Html.LabelFor(x => x.Firstname)
                    @Html.TextBoxFor(x => x.Firstname)
                    @Html.ValidationMessageFor(x => x.Firstname)
                </div>
                <div>
                    @Html.LabelFor(x => x.UploadImage)
                    @Html.TextBoxFor(x => x.UploadImage, new { type = "file" })
                    @Html.ValidationMessageFor(x => x.UploadImage)
                </div>
                <div>
                    <button type="submit" value="Submit">Submit</button>
                </div>
                <div id="ajaxRegister"></div>
            }
        </div>
    </div>
</div>

@section scripts
{

    <script src="~/Scripts/custom/jqueryUploadImage.js"></script>
}

Now add the view model.

using System.ComponentModel.DataAnnotations;
using System.Web;

namespace Web.Model.JQueryAjaxUploadModel
{
    public class UploadFormModel
    {
        [Display(Name="First Name")]
        [Required(ErrorMessage = "First Name Required")]
        public string Firstname             { get; set; }

        [Display(Name = "Select Image")]
        [Required(ErrorMessage = "Image Required")]
        public HttpPostedFileBase UploadImage { get; set; }
    }
}

And finally the controller.

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using Web.Model.JQueryAjaxUploadModel;
using System.Drawing;
using System.Drawing.Imaging;

namespace Web.Controller.Controllers
{
    public class JQueryFormController  : System.Web.Mvc.Controller
    {
        [HttpGet]
        public ActionResult Home()
        {
            ViewBag.Message = "JQuery Ajax Form.";

            return View();
        }

        [HttpPost]
        public ActionResult Upload(UploadFormModel model)
        {
            if (!ModelState.IsValid)
            {
                //You would actually return the errors allowing the user to correct them
                return Json(new { Confirm = false, isJsonErrorList = true, message = $"{model.Firstname} Form Fields Not Valid" }, JsonRequestBehavior.AllowGet);
            }
            var files = Request.Files;
            HttpPostedFileBase image = files[0];

            if (image != null &&&& image.ContentLength > 0)
            {
                //Here you would do whatever validation you require

                bool isImageValid = IsFileTypeValid(image);

                if (isImageValid)
                {
                    //Either send as attachemnt or save to disk
                    //Then return message to user
                    return Json(new { Confirm = true, isJsonErrorList = false, message = $"{model.Firstname} Image Uploaded" }, JsonRequestBehavior.AllowGet);
                }
                return Json(new { Confirm = true, isJsonErrorList = false, message = $"{model.Firstname} Image Upload failed" }, JsonRequestBehavior.AllowGet);
            }

            return Json(new { Confirm = false, isJsonErrorList = true, message = $"{model.Firstname} Image Upload failed" }, JsonRequestBehavior.AllowGet);
        }

        private bool IsFileTypeValid(HttpPostedFileBase file)
        {
            bool isValid = false;
            try
            {
                using (var img = Image.FromStream(file.InputStream))
                {
                    if (IsImageValid(img.RawFormat))
                    {
                        isValid = true;
                    }
                }
            }
            catch (Exception e)
            {
                //Not Valid
            }

            return isValid;
        }

        private bool IsImageValid(ImageFormat rawFormat)
        {
            List formats = ValidFormats();

            foreach (ImageFormat format in formats)
            {
                if (rawFormat.Equals(format))
                {
                    return true;
                }
            }

            return false;
        }

        private List ValidFormats()
        {
            List formats = new List
            {
                ImageFormat.Jpeg,
                ImageFormat.Png
            };

            return formats;
        }
    }
}

With all the above in place, we need to add the jQuery that will submit the form as an ajax request.

$(function() {
    $("#ajaxRegister").hide();
    $(function() {
        var form = $("#frmAjaxForm");
        $(form).submit(function(event) {
            event.preventDefault();
            var isValid = $("#frmAjaxForm").valid();
            if (isValid) {
                $("#ajaxRegister").hide();
                $("#ajaxRegister").html("");

                var formData = new FormData($(this)[0]);

                jQuery.ajax({
                    type: "Post",
                    enctype:"multipart/form-data",
                    url: $(form).attr("action"),
                    data: formData,
                    processData: false,
                    contentType: false,
                    cache: false,
                    dataType: "json",
                    success: function(data) {
                        if (data.Confirm === true) {
                            $("#ajaxRegister").append(`<p class=\"text-success\">${data.message}</p>`).show();
                        } else {
                            $("#ajaxRegister").append(`<p class=\"text-danger\">${data.message}</p>`).show();
                        }
                    }
                });
            }
        });
    });
});

Unlike how we would normally submit a form using ajax with data: $(form).serialize(), this does not work when submitting a form with an upload, we have to use formdata in the following way var formData = new FormData($(this)[0]); what this does it basically gets all the form fields for us and then send them to the server.

Notice also how we have:

processData: false,
contentType: false,

The image below shows how the form looks in the browser:

type error illegal invocation

Clicking submit, will post the name and image to the server via ajax as can be seen below.

Illegal Invocation Ajax File Upload

Then once you have done whatever needs to be done with the file we return JSON back to the page with a message for the user and the final image shows.

Upload Image Success

The above was a quick example of how to fix the uncaught typeerror illegal invocation ajax file upload, thanks for reading.