Question

I have 2 file upload for editing user profile in partial view that called from user profile page. The problem is HttpPostedFileBase parameter in action method always null.

When I'm calling this partial view out of profile page and without layout, file uploads was successfully done and sent files to action method.

This is my action method in controller:

[AcceptVerbs(HttpVerbs.Post)]
[Authorize(Roles = "User")]
public ActionResult EditProfile(ProfileGeneralDescription editedModel,
                                   HttpPostedFileBase imageFile,
                                   HttpPostedFileBase coverFile)
{
         //Some code here...   
}

And this is my partial view cshtml code:

@model Website.Models.ViewModel.Profile

@using (Ajax.BeginForm("EditProfile", "Profile", new { postOwnerUser = User.Identity.Name }, new AjaxOptions()
{
    HttpMethod = "POST",
    InsertionMode = InsertionMode.Replace,
    UpdateTargetId = "GeneralSection"
}, new { enctype = "multipart/form-data" }))
{

    <div>
        <button type="submit" name="Save" class="btn btn-default btn-xs">Save Changes</button>
        @Ajax.ActionLink("Cancel", "ProfileDescription", "Profile",
            new {username = Model.Username, type = "Show"},
            new AjaxOptions()
            {
                HttpMethod = "GET",
                InsertionMode = InsertionMode.Replace,
                UpdateTargetId = "GeneralSection"
            },
            new {@class = "btn btn-default btn-xs"})
    </div>

    <input type="hidden" name="username" id="username" value="@Model.Username"/>

    <fieldset>
        <legend>Edit Photos</legend>
        <div>
            Select profile picture:
            <input id="imageFile" type="file" name="imageFile" accept="image/png, image/jpeg" />
            @Html.CheckBoxFor(modelItem => modelItem.DefaultCover)<span>Remove profile photo</span>
        </div>
        <div>
            Select cover picture:
            <input id="coverFile" type="file" name="coverFile" accept="image/png, image/jpeg" />
            @Html.CheckBoxFor(modelItem => modelItem.DefaultCover)<span>RemoveCover</span>
        </div>
    </fieldset>
}

Where is my mistake?
Thanks in advance.

Was it helpful?

Solution

File uploads are normally initiated using a straightforward form post. If you want to initiate an upload using AJAX, you need to write some javascript to use the XmlHttpRequest (XHR) object, something like this (using jQuery):

<script>
    function submit (e){
        e.preventDefault = true;
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(e) {
            if ( 4 == this.readyState ) {
                console.log(['xhr upload complete', e]);
            }
        };
        xhr.open('post', 'Profile/EditProfile', true);
        xhr.setRequestHeader("Content-Type","multipart/form-data");
        var formData = new FormData();
        formData.append("imageFile", $("#imageFile").files[0]);
        formData.append("coverFile", $("#coverFile").files[0]);
        // etc
        xhr.send(formData);
    };
</script>

Note that you populate the javascript FormData object in code using the values from your form elements. Then wire this function to your submit button's click event:

    <button type="button" name="Save" onclick="submit()" class="btn btn-default btn-xs">Save Changes</button>

You can also remove the Ajax form in your view as it won't be needed when using this approach.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top