Asp.net Core, How to post file and model to controller in JQuery/Ajax?

13,094

You have few issues in your client side code.

You are using incorrect case for contenttype,contenttype and formdata. Remember javascript is case sensitive.

Your current code is only adding the image to the FormData object. you can loop through your input elements and add that as well.

This should work.

$(function () {

    $("#upload").click(function (evt) {
        evt.preventDefault();

        var fileupload = $("#files").get(0);
        var files = fileupload.files;
        var data = new FormData();
        for (var i = 0; i < files.length; i++) {
            data.append(files[i].name, files[i]);
        }

        // You can update the jquery selector to use a css class if you want
        $("input[type='text'").each(function (x, y) {
            data.append($(y).attr("name"), $(y).val());
        });

        $.ajax({
            type: "post",
            url: "/home/uploadfilesajax",
            contentType: false,
            processData: false,
            data: data,
            success: function (message) {
                alert(message);
            },
            error: function () {
                alert("there was error uploading files!");
            }
        });
    });  
});

You can still use the model validation framework to check for the property level validation of your view model. Since you are making an ajax call, you need to send the validation errors in a JSON response back to the client where it can display it to the user.

[HttpPost]
public async Task<IActionResult> UploadFilesAjax(Info model, IEnumerable<IFormFile> files)
{
    if (ModelState.IsValid)
    {
        var uploads = Path.Combine(hostingEnvironment.WebRootPath, "images");
        foreach (var file in files)
        {
            if (file != null && file.Length > 0)
            {
                var fileName = Guid.NewGuid().ToString().Replace("-", "") +
                                Path.GetExtension(file.FileName);
                using (var s = new FileStream(Path.Combine(uploads, fileName),
                                                            FileMode.Create))
                {
                    await file.CopyToAsync(s);
                    model.imgName = fileName;
                }
            }
        }
        return Json(new { status = "success", message = "success" });
    }
    else
    {
        var list = new List<string>();
        foreach (var modelStateVal in ViewData.ModelState.Values)
        {
            list.AddRange(modelStateVal.Errors.Select(error => error.ErrorMessage));
        }
        return Json(new { status = "error", errors = list });
    }
}

Now in the client side code, read the status property of the response and if it is error, loop through the errors property and display it to the user. In the below sample, i am simply alerting the errors to the user, but you can change it to display it in some part of your page.

$(function () {

    $("#upload").click(function (evt) {
        evt.preventDefault();
        var fileupload = $("#files").get(0);
        var files = fileupload.files;
        var data = new FormData();
        for (var i = 0; i < files.length; i++) {
            data.append('files', files[i]);
        }

        // You can update the jquery selector to use a css class if you want
        $("input[type='text'").each(function (x, y) {
            data.append($(y).attr("name"), $(y).val());
        });

        $.ajax({
            type: "post",
            url: "/home/uploadfilesajax",
            contentType: false,
            processData: false,
            data: data
        }).done(function(res) {
            if (res.status === "success") {
                alert(res.message);
            } else {
                $.each(res.errors,function(a, b) {
                        alert(b);
                    });
            }
        }).fail(function(xhr, b, error) {
            alert(error);
        });
    });  
});
Share:
13,094
topcool
Author by

topcool

Updated on June 16, 2022

Comments

  • topcool
    topcool almost 2 years

    This question is not a repetition with this because all details are fully described in this question and will be very suitable for beginners

    I have a view that inherits from a model. my field are in a form and I want to post form (or Model) to controller with JQuery/Ajax and insert it in database. I read this article and can upload image with ajax but i can not post whole form or model with data to controller.

    my view :

    @model ajax1.Models.Info
    
    <form method="post" enctype="multipart/form-data">
    
    <div class="form-group">
        <label asp-for="FirstName" class="col-lg-2 col-sm-2 control-label "></label>
        <div class="col-lg-6">
            <input asp-for="FirstName" class="form-control" />
            <span asp-validation-for="FirstName"></span>
        </div>
    </div>
    
    <div class="form-group">
        <label asp-for="LastName" class="col-lg-2 col-sm-2 control-label"></label>
        <div class="col-lg-6">
            <input asp-for="LastName" class="form-control" />
            <span asp-validation-for="LastName"></span>
        </div>
    </div>
    
    <input type="file" id="files" name="files" multiple />
    <input type="button" id="upload"  value="Upload Selected Files" />
    </form>
    

    JQuery Code at the bottom of view:

    @section Scripts{
    <script>
            $("#upload").click(function (evt) {
                var fileupload = $("#files").get(0);
                var files = fileupload.files;
                var data = new formdata();
                for (var i = 0; i < files.length; i++) {
                    data.append(files[i].name, files[i]);
                }
                $.ajax({
                    type: "post",
                    url: "/home/uploadfilesajax",
                    contenttype: false,
                    processdata: false,
                    data: data,
                    success: function (message) {
                        alert(message);
                    },
                    error: function () {
                        alert("there was error uploading files!");
                    }
                });
            });
    
    </script>
    

    }

    Controller :

        [HttpPost]
        public async Task<IActionResult> UploadFilesAjax(Info model)
        {
            var files = HttpContext.Request.Form.Files;
            foreach (var Image in files)
            {
                if (Image != null && Image.Length > 0)
                {
                    var file = Image;
                    var uploads = Path.Combine(_appEnvironment.WebRootPath, "img\\");
                    if (file.Length > 0)
                    {
                        var fileName = Guid.NewGuid().ToString().Replace("-", "") + Path.GetExtension(file.FileName);
                        using (var fileStream = new FileStream(Path.Combine(uploads, fileName), FileMode.Create))
                        {
                            await file.CopyToAsync(fileStream);
                            model.imgName = fileName;
                        }
                    }
                }
            }
    
            using (var db = _iServiceProvider.GetRequiredService<ApplicationDbContext>())
            {
    
                db.Info.Add(model);
                db.SaveChanges();
            }
            string message = "success";
            return Json(message);
        }
    

    Model :

    public class Info
    {
        [DisplayName("First Name")]
        [Required(ErrorMessage = "Enter First Name")]
        public string FirstName { get; set; }
    
        [DisplayName("Last Name")]
        [Required(ErrorMessage = "Enter Last Name")]
        public string LastName { get; set; }
    
        [DisplayName("select image")]
        public string imgName { get; set; }
    }
    

    When i put a breakpoint on the action and click on the submit button the application dose not go to action. How can i post all form or model to controller? I want if 'ModelStates.IsValid == false' the validation error shows.

    • Admin
      Admin over 6 years
      You should also make your button a submit button and handle the forms .submit() event, and check if(!$(this).valid()) { return; } to exit the function if the data is invalid
  • topcool
    topcool over 6 years
    You really recognize the problem well and accurately. how can i show asp-validation-for if ModelState.IsValid == false in view not alert?
  • Dushan Perera
    Dushan Perera over 6 years
    @saeed I made an update to handle that. Hope that helps
  • topcool
    topcool over 6 years
    Thnks, Your answer was very complete and understandable
  • djack109
    djack109 over 4 years
    The code makes complete sense, but doesn't work. I.e. does nothing. Not errors, nothing :(
  • ar.gorgin
    ar.gorgin about 4 years
    Thnkas, I use this code but send null for IFormFile