Image Preview in ASP.NET MVC

  Introduction :


        Previewing an image is a great way to improve the UI of your site. Also it is always best to check the file type, size and see a preview before submitting the whole form. There are some ways to do this using simple JavaScript but not work in all browsers (like FF3).In this Article I will show you how do this using ASP.NET MVC application. You also see how this will work in case of nested form.

  Description :

 



        Update:  You can now use HTML 5 File API which is natively supported by most of the browsers today without sending a single byte to server. You can use HTML 5 Polyfill for browsers which don't support the File API natively.


         Create a new ASP.NET MVC project and then add a file upload and image control into your View.

<form id="form1" method="post" action="NerdDinner/ImagePreview/AjaxSubmit">
            <table>
                <tr>
                    <td>
                        <input type="file" name="imageLoad1" id="imageLoad1"  onchange="ChangeImage(this,'#imgThumbnail')" />
                    </td>
                </tr>
                <tr>
                    <td align="center">
                        <img src="images/TempImage.gif" mce_src="images/TempImage.gif" id="imgThumbnail" height="200px" width="200px">
                    </td>
                </tr>
            </table>
        </form>
 

         Note that here NerdDinner is refers to the virtual directory name, ImagePreview is the Controller and ImageLoad is the action name which you will see shortly

         I will use the most popular jQuery form plug-in, that turns a form into an AJAX form with very little code. Therefore you must get these from Jquery site and then add these files into your page.
 

        <script src="NerdDinner/Scripts/jquery-1.3.2.js" mce_src="NerdDinner/Scripts/jquery-1.3.2.js" type="text/javascript"></script>
        <script src="NerdDinner/Scripts/jquery.form.js" mce_src="NerdDinner/Scripts/jquery.form.js" type="text/javascript"></script>
 

          Then add the javascript function.

<script type="text/javascript">
function ChangeImage(fileId,imageId){
$("#form1").ajaxSubmit({success: function(responseText){
var d=new Date();
$(imageId)[0].src="NerdDinner/ImagePreview/ImageLoad?a=" mce_src="NerdDinner/ImagePreview/ImageLoad?a="+d.getTime();
}
});
}
</script>

          This function simply submit the form named form1 asynchronously to ImagePreviewController's method AjaxSubmit and after successfully receiving the response, it will set the image src property to the action method ImageLoad. Here I am also adding querystring, preventing the browser to serve the cached image.

          Now I will create a new Controller named ImagePreviewController.

 public class ImagePreviewController : Controller
{
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AjaxSubmit(int? id)
{
Session["ContentLength"] = Request.Files[0].ContentLength;
Session["ContentType"] = Request.Files[0].ContentType;
byte[] b = new byte[Request.Files[0].ContentLength];
Request.Files[0].InputStream.Read(b, 0, Request.Files[0].ContentLength);
Session["ContentStream"] = b;
return Content( Request.Files[0].ContentType+";"+ Request.Files[0].ContentLength );
}
public ActionResult ImageLoad(int? id)
{
byte[] b = (byte[])Session["ContentStream"];
int length = (int)Session["ContentLength"];
string type = (string)Session["ContentType"];
Response.Buffer = true;
Response.Charset = "";
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.ContentType = type;
Response.BinaryWrite(b);
Response.Flush();
Session["ContentLength"] = null;
Session["ContentType"] = null;
Session["ContentStream"] = null;
Response.End();
return Content("");
}
}

          The AjaxSubmit action method will save the image in Session and return content type and content length in response. ImageLoad action method will return the contents of image in response.Then clear these Sessions.

          Just run your application and see the effect.

Checking Size and Content Type of File:

         You may notice that AjaxSubmit action method is returning both content type and content length. You can check both properties before submitting your complete form.

  $(myform).ajaxSubmit({success: function(responseText)
            {               
                var contentType=responseText.substring(0,responseText.indexOf(';'));
                var contentLength=responseText.substring(responseText.indexOf(';')+1);
                // Here you can do your validation
                var d=new Date();
                $(imageId)[0].src=" /NerdDinner/ImagePreview/ImageLoad?a="+d.getTime();
            }
        });

Handling Nested Form Case:

         The above code will work if you have only one form. But this is not the case always.You may have a form control which wraps all the controls and you do not want to submit the whole form, just for getting a preview effect.

          In this case you need to create a dynamic form control using JavaScript, and then add file upload control to this form and submit the form asynchronously

function ChangeImage(fileId,imageId) {
    var myform=document.createElement("form");
    myform.style.display="none";
    myform.action="/ImagePreview/AjaxSubmit";
    myform.enctype="multipart/form-data";
    myform.method="post";
    var imageLoad;
    var imageLoadParent;
    var is_chrome = /chrome/.test( navigator.userAgent.toLowerCase() );
    if(is_chrome && document.getElementById(fileId).value=='')
        return;//Chrome bug onchange cancel
    if(document.all || is_chrome){//IE
        imageLoad=document.getElementById(fileId);
        imageLoadParent=document.getElementById(fileId).parentNode;
        myform.appendChild(imageLoad);
        document.body.appendChild(myform);
    }
    else{//FF
        imageLoad=document.getElementById(fileId).cloneNode(true);        
        myform.appendChild(imageLoad);
        document.body.appendChild(myform);
    }    
    $(myform).ajaxSubmit({success: 
        function(responseText){            
                var d=new Date();
                $(imageId)[0].src="http://weblogs.asp.net/ImagePreview/ImageLoad?a=" mce_src="http://weblogs.asp.net/ImagePreview/ImageLoad?a="+d.getMilliseconds();                
            if(document.all || is_chrome)//IE
                imageLoadParent.appendChild(myform.firstChild);
            else//FF                     
                document.body.removeChild(myform);
        }
    });
}

         You also need append the child in order to send request and remove them after receiving response.

Published Saturday, April 3, 2010 5:00 AM by imran_ku07
Filed under: , , , ,

Comments

# re: Image Preview in ASP.NET MVC

Wednesday, May 5, 2010 11:40 AM by lp

Do you have a copy of code that you can share? I tried the mentioned solution and it does not work. Thanks very much.

# re: Image Preview in ASP.NET MVC

Friday, May 7, 2010 9:07 AM by imran_ku07

>>@lp

The file is attached.

# re: Image Preview in ASP.NET MVC

Friday, June 4, 2010 2:09 AM by ignatandrei

Nice solution.

However, can you prevent submitting some large files (100MB by example)?

# re: Image Preview in ASP.NET MVC

Friday, June 4, 2010 3:47 AM by imran_ku07

>>@ignatandrei

In fact I am also checking the file size and file type in client code,

function(responseText){            

           var contentType = responseText.substring(0,responseText.indexOf(';'));

           var contentLength = responseText.substring(responseText.indexOf(';')+1);

if( contentLength >'Enter Here your Limit')

//Show Error

I think this is easy just check,

# re: Image Preview in ASP.NET MVC

Friday, June 4, 2010 4:50 AM by ignatandrei

You are checking AFTER submitting the file.

I mean checking before AjaxSubmit ...

# re: Image Preview in ASP.NET MVC

Friday, June 4, 2010 5:30 AM by imran_ku07

>>@ignatandrei

>>I mean checking before AjaxSubmit

Yes it may be checked at client side,

I had done this in this post,

forums.asp.net/.../3747487.aspx

I had tried only in IE,FF but may this not work in all browser

# re: Image Preview in ASP.NET MVC

Tuesday, August 10, 2010 8:11 AM by frazms

really nice article it really helps me in my scenario.

# re: Image Preview in ASP.NET MVC

Monday, September 27, 2010 11:25 AM by maz3tt

it doesn't work in ie

# re: Image Preview in ASP.NET MVC

Saturday, October 9, 2010 2:18 AM by imran_ku07

@maz3tt,

New Code is updated, It will now work in all browsers like FF,IE,Chrome

# re: Image Preview in ASP.NET MVC

Sunday, October 10, 2010 7:21 AM by Wahid

Thank you very much ;)

but how if i want show progress bar while uploading.

# re: Image Preview in ASP.NET MVC

Sunday, October 10, 2010 8:32 AM by imran_ku07

@Wahid,

This is very simple. just add an animated gif image. Initially set display none.

Then before this line

$(myform).ajaxSubmit(

set display to empty and after this line set display none.

# re: Image Preview in ASP.NET MVC

Monday, October 11, 2010 10:25 AM by Wahid

thank u very much.

i did that actually.

just one more thing :

I put validation in my "AjaxSubmit" method to check size and type.

But i wanna ask u if this validation occurs before file being uploaded !?.

I mean when file do upload to server and how to make validation before that ?

Thank u again.

# re: Image Preview in ASP.NET MVC

Monday, October 11, 2010 10:51 AM by imran_ku07

@Wahid, See

forums.asp.net/.../3747487.aspx

# re: Image Preview in ASP.NET MVC

Saturday, September 10, 2011 6:40 AM by Yousuf

Excellent... much appreciated

# re: Image Preview in ASP.NET MVC

Wednesday, September 21, 2011 1:47 AM by micheal

thanks for this ..it was really helpfull...but could you be specific where to write theses code ..that is oin which which pages..as i am very new to mvc...

# re: Image Preview in ASP.NET MVC

Wednesday, September 21, 2011 4:17 AM by imran_ku07

@micheal

Download the sample project.

# re: Image Preview in ASP.NET MVC

Tuesday, October 4, 2011 10:28 PM by DocMoD

how can I pass a Antiforgery token along with the ajaxsubmit? Great code by the way.

# re: Image Preview in ASP.NET MVC

Tuesday, October 4, 2011 11:04 PM by imran_ku07

@DocMoD see this,

stackoverflow.com/.../jquery-ajax-calls-and-the-html-antiforgerytoken

# re: Image Preview in ASP.NET MVC

Wednesday, October 5, 2011 12:57 AM by DocMoD

Thanks, I was close, was missing "data:" before the token

# re: Image Preview in ASP.NET MVC

Monday, November 7, 2011 4:10 PM by Kamil

I have used your solution and noticed that if I load one image after another, the second image might be resized based on the size of the first loaded image. Is there a way to have it work in such a way that image is displayed in its original size?

# re: Image Preview in ASP.NET MVC

Monday, November 7, 2011 10:03 PM by imran_ku07

@Kamil, Make sure you don't set the height and width of the image.

# re: Image Preview in ASP.NET MVC

Tuesday, November 8, 2011 4:07 PM by Kamil

Thanks for quick answer. The issue I had was not your code but jcrop.

# re: Image Preview in ASP.NET MVC

Friday, November 11, 2011 1:12 AM by rafi

Seems not working in safari, how can i get it work in safari --thanks

# re: Image Preview in ASP.NET MVC

Friday, November 11, 2011 1:17 AM by rafi

Tried with safari version 5.1.1 on windows 7

# re: Image Preview in ASP.NET MVC

Wednesday, November 16, 2011 1:33 PM by imran_ku07

@rafi,

Add this lines

var is_safari = navigator.userAgent.indexOf("Safari") > -1;

and update this line at two place,

if (is_safari || document.all || is_chrome)//IE

# re: Image Preview in ASP.NET MVC

Monday, November 28, 2011 9:19 AM by richof

Hello, I can not find the attached file of the sample project, could somebody give me the link to download it?

Thanks a lot

# re: Image Preview in ASP.NET MVC

Thursday, December 1, 2011 10:37 AM by imran_ku07

@richof, here is the link

weblogs.asp.net/.../7428769.ashx

# re: Image Preview in ASP.NET MVC

Wednesday, December 7, 2011 11:02 PM by Ais

hi, I downloaded and run your file but I got this error. Please help how to fix this, thank you.

Error 1 Could not load file or assembly 'System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified. C:\Users\Aissy\Documents\ais\Work Related\MvcApplication1\MvcApplication1\Views\Web.config 18

# re: Image Preview in ASP.NET MVC

Sunday, February 26, 2012 1:19 PM by garfbradaz

I have included some of your code in a Open Source Project i have done for Images and MVC. Thanks for the inspiration! :)

garfbradazweb.wordpress.com/.../mvc-3-mvcimage-project-its-alive

# re: Image Preview in ASP.NET MVC

Tuesday, May 15, 2012 4:48 PM by M,DelloStritto

First ... nice!!

I implemented the code from here and cross checked it with a download from the project you posted. Selecting a second image does not call the controller ImageLoad. Thus, the second image selected does not preview.

Any thoughts? Otherwise, I'll post when I figure it out.

# re: Image Preview in ASP.NET MVC

Saturday, May 19, 2012 3:57 AM by imran_ku07

@M,DelloStritto, It is the change event of input. So, you need to select a different image.