0

In my application, there is a form for updating user profiles. Part of the user profile is uploading photo. It was working, but for some reason the pictures uploaded by the user has null value in the controller. In other words, I cannot retrieve the uploaded pictures in the controller.

This is the AJAX call to serialize the form and post it to the controller. This code is in _Layout.cshtml:

 $("#btn_SaveProfile").click(function (e) {
    e.preventDefault();
    var form = $("#form_UpdateProfile");
    var serialized = form.serialize();
    $.ajax({
       url: '@Url.Action("UpdateProfile", "Account")',
       data: serialized,
       contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
       type: 'POST',
       success: function (data) {//This is successfully
    }}).error(function (xhr, status) {
           $("body").append(xhr.responseText);
    })
 })

This is the _Partial View:

@model UpdateProfileViewModel
<form name="form_Update" id="form_UpdateProfile" enctype="multipart/form-data">  @* method="post" action="/Account/UpdateProfile"*@ 
    @Html.HiddenFor(m => m.Id)
    <div class="modal fade" id="modalUpdateProfile" tabindex="-1" role="dialog" aria-labelledby="modalUpdateProfileLabel" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                    <h4 class="modal-title">Update Profile</h4>
                </div>
                <div class="modal-body">
                    <ul class="nav nav-tabs" style="margin-top: 15px;" id="myTab">
                        <li class="active"><a href="#mainProfile" data-toggle="tab" id="update_profile">Update Profile</a></li>
                        <li><a href="#anonymousProf" data-toggle="tab" id="anonymous_profile">Anonymous Profile</a></li>
                        <li><a href="#cropPhoto" data-toggle="tab" id="crop_photo">Crop Profile Photo</a></li>
                        <li><a href="#updatePassword" data-toggle="tab" id="change_password">Change Password</a></li>
                    </ul>
                    <div class="tab-content" style="margin-top: 15px;">
                        <div id="mainProfile" class="tab-pane fade in active">
                            <div class="form-group">
                                @Html.LabelFor(m => m.FirstName, new { htmlAttributes = new { @class = "control-label" } })
                                @Html.EditorFor(m => m.FirstName, new { htmlAttributes = new { @class = "form-control" } })
                            </div>
                            <div class="form-group table-condensed">
                                @Html.LabelFor(m => m.LastName, new { @class = "control-label" })
                                @Html.EditorFor(m => m.LastName, new { htmlAttributes = new { @class = "form-control" } })
                            </div>
                            <div class="form-group table-condensed">
                                @Html.LabelFor(m => m.IsProfilePublic, new { @class = "control-label" })
                                @Html.CheckBoxFor(m => m.IsProfilePublic, new { @checked = Model.IsProfilePublic })
                                <span class="small text-muted">(When your profile is public, others can access your achievements such as points, badges, etc.)</span>
                            </div>
                            <div class="form-group table-condensed">
                                @Html.LabelFor(m => m.Email, new { @class = "control-label" })
                                @Html.EditorFor(m => m.Email, new { htmlAttributes = new { @class = "form-control" } })
                                <span class="small text-muted">(Make sure your email address is valid. This is important for receiving email notifications.)</span>
                            </div>
                            <div class="form-group table-condensed">
                                @Html.LabelFor(m => m.ImageUploadPublic, new { @class = "control-label" })
                                &nbsp;<span class="text-muted small">(If you want to add a new photo or replace the existing photo, click "Choose File" below. Otherwise, leave this field blank.)</span>
                                @Html.TextBoxFor(m => m.ImageUploadPublic, new { type = "file", htmlAttributes = new { @class = "form-control" } })
                            </div>
                        </div>
                        <div id="anonymousProf" class="tab-pane fade">
                            <div class="form-group table-condensed">
                                @Html.LabelFor(m => m.AnonymousName, new { @class = "control-label" })
                                @Html.EditorFor(m => m.AnonymousName, new { htmlAttributes = new { @class = "form-control" } })
                                &nbsp;<span class="text-muted small">(used when you choose to post an entry anonymously)</span>
                            </div>
                            <div class="form-group table-condensed">
                                @Html.LabelFor(m => m.ImageUploadAnonymous, new { @class = "control-label" })
                                &nbsp;<span class="text-muted small">(If you want to add a new photo or replace the existing photo, click "Choose File" below. Otherwise, leave this field blank.)</span>
                                @Html.TextBoxFor(m => m.ImageUploadAnonymous, new { type = "file", htmlAttributes = new { @class = "form-control" } })
                            </div>
                        </div>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default pull-right" data-dismiss="modal" >Close</button>
                    <button type="button" class="btn btn-default btn-primary pull-right" id="btn_SaveProfile">Update</button>
                </div>
            </div>
        </div>
    </div>
</form>

This is the Model:

public class UpdateProfileViewModel
{
    public string Id { get; set; }

    [Required]
    [Display(Name = "First Name")]
    public string FirstName { get; set; }

    [Required]
    [Display(Name = "Last Name")]
    public string LastName { get; set; }

    [Required]
    [Display(Name = "Email")]
    [EmailAddress]
    public string Email { get; set; }

    [Display(Name = "Public Profile Photo")]
    public string ProfilePhoto { get; set; }

    [Required]
    [DataType(DataType.Upload)]
    [Display(Name = "Public Profile Photo")]
    public HttpPostedFileBase ImageUploadPublic { get; set; }

    [Required]
    [Display(Name = "Anonymous Name")]
    public string AnonymousName { get; set; }

    [Display(Name = "Anonymous Profile Photo")]
    public string AnonymousPhoto { get; set; }

    [Required]
    [DataType(DataType.Upload)]
    [Display(Name = "Anonymous Profile Photo")]
    public HttpPostedFileBase ImageUploadAnonymous { get; set; }

    [Display(Name = "Make My Profile Public")]
    public bool IsProfilePublic { get; set; }
}

And, here is the Action:

public ActionResult UpdateProfile(UpdateProfileViewModel model)
{
    //Here model.ImageUploadPublic and model.ImageUploadAnonymous are empty.
}

I have spend a day to resolve this issue, but cannot figure out the mistake. Any ideas?

renakre
  • 8,001
  • 5
  • 46
  • 99
  • 1
    You need to use `FormData` to upload files using ajax - refer [this answer](http://stackoverflow.com/questions/29293637/how-to-append-whole-set-of-model-to-formdata-and-obtain-it-in-mvc/29293681#29293681) –  May 19 '16 at 22:26
  • @StephenMuecke I see, thank you very much! I wonder if you have any idea why this code stopped working suddenly? I am sure I had this code running perfect 2-days ago. – renakre May 19 '16 at 22:34
  • Other that not being able to upload the file (you could never have made that work with the ajax code you have), what is not working? –  May 19 '16 at 22:36
  • @StephenMuecke it was posting the uploaded files to the controller action successfully. I do not know what has changed and I begin to get null files in the controller. Maybe I updated the jquery version? Anyway, so weird! Thanks for your help! – renakre May 19 '16 at 22:39
  • That would not had made any difference. Best guess is that if you were previously uploading a file, you did not have the `e.preventDefault();` line of code and you were doing both a normal submit and an ajax submit. –  May 19 '16 at 22:41

0 Answers0