Upload File using Ajax in MVC

1. It's very simple and easy to upload a file without Ajax

It's easy to upload a file in a synchronous form, where you just post the file and read a HttpPostedFile variable in the server side: In plain html form, take note of the form ectype property:

In view write this code:

@using (Html.BeginForm("Upload", "Fileupload", FormMethod.Post, new { enctype = "multipart/form-data" }))

{

    <input type="file" name="file">

    <input type="submit" value="OK">

} 

And after this write this code in the controller

public class FileuploadController : Controller

{

        //it should show index.cshtml view

        public ActionResult Index()

        {

            return View();

        }

        [HttpPost]

        public ActionResult Upload(HttpPostedFile file)

        {

            if (file != null && file.ContentLength > 0)

            { //now you have a non-empty file

                //to save in a local directory

                var fileName = Path.GetFileName(file.FileName);

                var path = Path.Combine(Server.MapPath("~/Uploads"), fileName);

                file.SaveAs(path);

        }

        return new EmptyResult();

    }

}

2. But when you use the ajax form, it sends a null value in http posted file

To resolve this issue I use one js file that converts this in the I frame and easily uploads the file

That should work, no problem, but what if you have an ajax form, asynchronously, you will not be able to upload a file together with the other form fields. So, I've used a 3rd party javascript library to create a hidden iframe that will contain a file field.

Js file code is below:

jQuery.extend({

createUploadIframe: function (id, uri) {

//create frame

var frameId = 'jUploadFrame' + id;

 

if (window.ActiveXObject) {

var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');

if (typeof uri == 'boolean') {

io.src = 'javascript:false';

}

else if (typeof uri == 'string') {

io.src = uri;

}

}

else {

var io = document.createElement('iframe');

io.id = frameId;

io.name = frameId;

}

io.style.position = 'absolute';

io.style.top = '-1000px';

io.style.left = '-1000px';

document.body.appendChild(io);

return io

},

createUploadForm: function (id, fileElementId) {

alert("ajaxfile" + id)

alert("ajaxfile" + fileElementId)

//create form

var formId = 'jUploadForm' + id;

var fileId = 'jUploadFile' + id;

var form = $('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');

var oldElement = $('#' + fileElementId);

var newElement = $(oldElement).clone();

$(oldElement).attr('id', fileId);

$(oldElement).before(newElement);

$(oldElement).appendTo(form);

//set attributes

$(form).css('position', 'absolute');

$(form).css('top', '-1200px');

$(form).css('left', '-1200px');

$(form).appendTo('body');

return form;

},

ajaxFileUpload: function (s) {

alert("file");

// TODO introduce global settings, allowing the client to modify them for all requests, not only timeout

s = jQuery.extend({}, jQuery.ajaxSettings, s);

var id = new Date().getTime()

var form = jQuery.createUploadForm(id, s.fileElementId);

var io = jQuery.createUploadIframe(id, s.secureuri);

var frameId = 'jUploadFrame' + id;

var formId = 'jUploadForm' + id;

// Watch for a new set of requests

if (s.global && !jQuery.active++) {

jQuery.event.trigger("ajaxStart");

}

var requestDone = false;

// Create the request object

var xml = {}

if (s.global)

jQuery.event.trigger("ajaxSend", [xml, s]);

// Wait for a response to come back

var uploadCallback = function (isTimeout) {

var io = document.getElementById(frameId);

try {

if (io.contentWindow) {

xml.responseText = io.contentWindow.document.body ? io.contentWindow.document.body.innerHTML : null;

xml.responseXML = io.contentWindow.document.XMLDocument ? io.contentWindow.document.XMLDocument : io.contentWindow.document;

 

} else if (io.contentDocument) {

xml.responseText = io.contentDocument.document.body ? io.contentDocument.document.body.innerHTML : null;

xml.responseXML = io.contentDocument.document.XMLDocument ? io.contentDocument.document.XMLDocument : io.contentDocument.document;

}

} catch (e) {

jQuery.handleError(s, xml, null, e);

}

if (xml || isTimeout == "timeout") {

requestDone = true;

var status;

try {

status = isTimeout != "timeout" ? "success" : "error";

// Make sure that the request was successful or notmodified

if (status != "error") {

// process the data (runs the xml through httpData regardless of callback)

var data = jQuery.uploadHttpData(xml, s.dataType);

// If a local callback was specified, fire it and pass it the data

if (s.success)

s.success(data, status);

 

// Fire the global callback

if (s.global)

jQuery.event.trigger("ajaxSuccess", [xml, s]);

} else

jQuery.handleError(s, xml, status);

} catch (e) {

status = "error";

jQuery.handleError(s, xml, status, e);

}

// The request was completed

if (s.global)

jQuery.event.trigger("ajaxComplete", [xml, s]);

// Handle the global AJAX counter

if (s.global && ! --jQuery.active)

jQuery.event.trigger("ajaxStop");

// Process result

if (s.complete)

s.complete(xml, status);

jQuery(io).unbind()

setTimeout(function () {

try {

$(io).remove();

$(form).remove();

} catch (e) {

jQuery.handleError(s, xml, null, e);

}

}, 100)

xml = null

}

}

// Timeout checker

if (s.timeout > 0) {

setTimeout(function () {

// Check to see if the request is still happening

if (!requestDone) uploadCallback("timeout");

}, s.timeout);

}

try {

// var io = $('#' + frameId);

var form = $('#' + formId);

$(form).attr('action', s.url);

$(form).attr('method', 'POST');

$(form).attr('target', frameId);

if (form.encoding) {

form.encoding = 'multipart/form-data';

}

else {

form.enctype = 'multipart/form-data';

}

$(form).submit();

} catch (e) {

jQuery.handleError(s, xml, null, e);

}

if (window.attachEvent) {

document.getElementById(frameId).attachEvent('onload', uploadCallback);

}

else {

document.getElementById(frameId).addEventListener('load', uploadCallback, false);

}

return { abort: function () { } };

},

uploadHttpData: function (r, type) {

var data = !type;

data = type == "xml" || data ? r.responseXML : r.responseText;

// If the type is "script", eval it in global context

if (type == "script")

jQuery.globalEval(data);

// Get the JavaScript object, if JSON is used.

if (type == "json")

eval("data = " + data);

// evaluate scripts within html

if (type == "html")

jQuery("<div>").html(data).evalScripts();

//alert($('param', data).each(function(){alert($(this).attr('value'));}));

return data;

}

})

//index.cshtml view

<script src="@Url.Content("~/Scripts/ajaxfileupload.js")"

type="text/javascript"></script>

<script type="text/javascript">

function ajaxFileUpload() {

$.ajaxFileUpload

(

{

url: "@Url.Action("UploadAttachment", "File")",

secureuri: false,

fileElementId: 'FileUpload',

dataType: 'json',

data: {

Name: $('#Name').val(), //you can declare the other form elements here

},

success: function (data, status) {

if (typeof (data.error) != 'undefined') {

if (data.error != '') {

//alert(data.error);

} else {

//alert(data.msg);

}

}

},

error: function (data, status, e) {

//alert(e);

}

}

)

return false;

}

@using (Ajax.BeginForm("Upload", "File", new { }, new AjaxOptions { }, new { enctype = "multipart/form-data" }))

{

</script>

<table>

    <tr>

        <td class="label">

            @Html.LabelFor(m => m.Name)

        </td>

        <td>

            <div class="field_container">

                @Html.TextBoxFor(m => m.Name)

            </div>

        </td>

    </tr>

    <tr>

        <td class="label">

            @Html.LabelFor(m => m.PathToAttachment)

        </td>

        <td>

            <div class="field_container">

                @Html.TextBoxFor(m => m.FileUpload, new { type = "file" })

            </div>

        </td>

    </tr>

</table>

<input type="submit" value="OK">

}

public class FileController : Controller

{   
      //it should show index.cshtml view

        public ActionResult Index() { return View(); }

        //do nothing on form submit

        [HttpPost]

        public ActionResult AddAttachment(AttachmentModel model)

        {

            return Json(new { success = true });

        }

        //this is where the file gets save in the server

        public ActionResult UploadAttachment(String Name, HttpPostedFile FileUpload)

        {

            if (FileUpload.ContentLength > 0)

            {

                var r = new Random();

                var uploadPath = Server.MapPath("~/Uploads");

                var filename = FileName.Replace("_", "");

                var savedFileName = Path.Combine(uploadPath, Path.GetFileName(filename));

                //now you have your file

            }

            return new EmptyResult();

        }
 }