Uploading files asynchronously in asp.net mvc site
Hi,
I've been looking for quite some time for a complete solution to uploading files in ajax for my site.
For those of you who don't know, browsers won't let you upload files without making a full page reload.
I haven't been able to find a good, working and cross browser solution for this problem.
So after much research and development I have finally managed to solve this problem.
Lets take a look at the following controller.
1. Home
2. UploadImage
The Home action returns a simple view, that you'll see down below, and the UploadImage action is responsible for handling the file uploaded.
This is Index.cshtml:
For comfortable view I've written the css & js inside, but of course it's recommended to split them into different files.
The layout file contains only a reference to jQuery.
I've been looking for quite some time for a complete solution to uploading files in ajax for my site.
For those of you who don't know, browsers won't let you upload files without making a full page reload.
I haven't been able to find a good, working and cross browser solution for this problem.
So after much research and development I have finally managed to solve this problem.
Lets take a look at the following controller.
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult UploadImage(HttpPostedFileBase image)
{
try
{
if (Request.ContentLength > 1024 * 1024 * 2)
{
return UploadCompanyLogoResult(new { success = false, error = "File size too big. Maximum file size is 2MB." });
}
if (Request.Files.Count == 0)
{
return UploadCompanyLogoResult(new { success = false, error = "Failed uploading file" });
}
image = Request.Files[0];
var webImage = new WebImage(image.InputStream) { FileName = image.FileName };
var imageUrl = SaveImageToFile(webImage);
return UploadCompanyLogoResult(new { success = true, url = imageUrl });
}
catch (Exception e)
{
Logger.Instance.Error("Failed to upload image", LOG_CATEGORY, e.ToString());
return UploadCompanyLogoResult(new { success = false, error = "Unknown error uploading file" });
}
}
private string SaveImageToFile(WebImage webImage)
{
var filePath = Server.MapPath("~/Content/" + webImage.FileName);
System.IO.File.WriteAllBytes(filePath, webImage.GetBytes());
return Url.Content("Content/" + webImage.FileName);
}
private ActionResult UploadCompanyLogoResult(object json)
{
if (Request.UserAgent.ToLower().Contains("ie"))
{
var javascriptSerializer = new JavaScriptSerializer();
return Content(string.Format("<pre>{0}</pre>", javascriptSerializer.Serialize(json)));
}
return Json(json);
}
}
The controller has 2 actions:
1. Home
2. UploadImage
The Home action returns a simple view, that you'll see down below, and the UploadImage action is responsible for handling the file uploaded.
This is Index.cshtml:
For comfortable view I've written the css & js inside, but of course it's recommended to split them into different files.
The layout file contains only a reference to jQuery.
<style type="text/css">
#container { position: relative; display: inline-block; }
#container > .loading-circle-container { position: absolute; width: 100%; height: 100%; top: 0; left: 0; text-align: center; background: white; opacity: 0.9; display: none; }
#container > .loading-circle-container > .loading_circle { display: inline-block; position: static; background: url('https://pictures.reuters.com/ClientFiles/RTR/Images/ajax-loader.gif') no-repeat; width: 37px; height: 37px; }
#container > form { display: inline-block; text-align: center; }
#container > form > label { display: block; cursor: pointer; }
#container > form > label > #image { cursor: pointer; max-height: 150px; vertical-align: middle; }
#container > form > #imageUpload { position: absolute; left: -9999em; }
</style>
<div id="container">
@using (Html.BeginForm("UploadImage", "Home", FormMethod.Post, new { enctype = "multipart/form-data", target = "upload_file_target" }))
{
var defaultImage = "https://www.compuchecks.com/BJA/images/logo-placeholder.gif";
<label for="imageUpload" id="button">
<img id="image" src="@defaultImage">
</label>
<input type="file" name="imageUpload" id="imageUpload" />
}
<div class="loading-circle-container">
<div class="loading_circle">
</div>
</div>
</div>
<script type="text/javascript">
var uploadFileAjax = function (inputTag, successCallback) {
var iframe = $('#upload_file_target');
if (iframe.length == 0) {
iframe = $('<iframe>').attr({
id: 'upload_file_target',
name: 'upload_file_target'
}).css({
width: 0,
height: 0,
border: 0
}).appendTo($('body'));
}
iframe.load(function () {
var iframeContents = iframe[0].contentWindow.document.body.innerHTML;
successCallback($(iframeContents).html());
});
inputTag.parent().submit();
}
var container = $('#container');
var loader = $('.loading-circle-container', container);
var image = $('#image', container).load(function () {
loader.fadeOut();
});
var imageUpload = $('#imageUpload', container).on('change', function () {
uploadFileAjax(imageUpload, function (responseText) {
var responseJson = JSON.parse(responseText);
if (responseJson.success) {
image.attr('src', responseJson.url);
}
});
});
$('form', container).on('submit', function () {
loader.fadeIn();
});
if ($.browser.mozilla) {
$('#button', container).click(function () {
imageUpload.click();
});
}
</script>
You can test the code and see that it actually works (the page doesn't refresh - and the image uploads successfully).
Comments
Post a Comment