Today I decided to post about a feature I developed this week. I’m currently working on a Social Project hosted on SharePoint 2010 and we are developing a WebPart to Post your status and share an optional image.
The WebPart must display an input file field to choose the picture to share and a preview must be displayed to the user before he decides to post his status. We are trying to avoid as much as possible PostBacks to offer an improved user experience.
The problem : How to post an input file dynamically without refreshing the entire page ?
My first idea was : with an Ajax call of course ! Unfortunately to do this you have to use the File API added to the DOM in HTML5, but guess what? Internet Explorer does not support this.
The workaround : posting the ASP .Net form into a hidden frame. The frame returns the image, then a script extracts it from the frame’s DOM and insert it into a container in the main page. Thanks to this only the frame is reloaded, this is transparent to the user.
The image is not saved in the server, all the operations occurs in memory, the goal is only to display a preview of the image. Of course you can modify my sample to save the image server side.
Downloading the solution
You can download the entire solution here : download solution.
You should be able to compile it without doing anything else but if you want to deploy it on your SharePoint environment you will have to sign-it with your key.
Step 1 – The project
Creates a new Empty SharePoint Project with Visual Studio, I choosed “Wawawum.DynamicUpload”. If you don’t already have JQuery deployed in your environment you can reuse my project “Wawawum.JQuery” and include it into your solution.
Then add a Visual WebPart “ImagePreviewWebPart” and add it to the Default Feature if it is not already included.
Map the “Layouts” folder to your project and add a new Application Page “PreviewImage.aspx” into it.
Your project tree should be like the screenshot above. Now we just have to fill the blanks
Step 2 – The UserControl
Let’s create our controls that will post the image and display the preview. Add the following lines to your “ImagePreviewWebPartUserControl.ascx”:
This code is pretty straight forward but here is the goal of the controls:
- ImageInput : the form field which will contains the path to the file to upload
- ImagePreviewSubmit : the form button which submits the ASP .Net form into the iframe
- ImagePreviewLoadingContainer : the div which displays a “Loading” message and image
- ImagePreviewContainer : this div contains the preview of the image
- ImagePreviewUploadFrame : the frame in which the form is posted. Using this iframe avoids the entire page to be reloaded when uploading the file.
Here are the main points of this script:
- imagePreview_onPreviewLinkClick (line 22) : called when the preview button is clicked. This function posts the ASP .Net form in the iframe. We have to modify the target and action attributes of the form to do that. The original values of these attributes are saved before posting and restored after.
- imagePreview_onFrameLoaded (line 48) : called when the iframe is loaded. This function retrieves the img element generated by the browser (I tested it in Internet Explorer and Chrome and the code generated is compatible). Then this element is extracted from the frame DOM and added to the div “ImagePreviewContainer”.
- ImagePreviewEventsArgs (line 63) : object used to pass the controls to the event handlers. The action field contains the server-relative URL of the Application Page which returns the Image.
Step 4 – Code behind
Almost all the code of the User Control is in the ASCX file but we need to set one attribute in the code-behind. So edit the code-behind of the ImagePreviewWebPartUserControl and add the following lines:
This code set a unique name to the iframe to avoid conflicts when multiple instances of the WebPart are added to the page.
Step 5 – The Application Page
The goal of this page is to receive the image posted by the UserControl, resize it and return it to display the preview image into the iframe. It is important to notice that it does not return some HTML but an Image, thus the content type of the response header will be “image/jpeg”.
Open the code behind of the “PreviewImage.aspx” page and here is what it should look like :
This code is very simple. The posted file is retrieved thanks to the Request.Files collection of HttpPostedFile. The file’s content type and size are checked, then in the Render method override the image is resized and written to the response.
Step 6 – Disable Message Authentication Check on the Application Page
The last thing we have to modify is the ASPX page. We need to set the “EnableViewStateMac” attribute of the Page directive to “false” to avoid the “This Page has been modified since you opened it. You must open the page again” error message.
In fact the PreviewImage page receives its form data from another page. In this data is included the ViewState of the WebPart page which causes this error. That’s the reason why we have to disable the message authentication check.
Step 7 – Build and Deploy
Finished. We just have to build the solution and deploy it. Then add the WebPart to a WebPart page and you should obtain this result :
Yes I know there is no design here. But that’s not the point of this article right? If you browse for a picture and click on preview you should see the loading message then the preview :
And the most important part is the preview displayed without refreshing the entire page.
We can’t really say that there is no postback here because the ASP .Net form is actually posted in the iframe but this is transparent to the user. A lot of JQuery plugins that use the File API of HTML5 fall-back to this method when Internet Explorer is the client.
So I thought interesting to demonstrate how to implement it in a SharePoint environment in spite of the fact that there is not really any SharePoint code here. You can reuse this code as-is but I strongly recommend you to add some validation logic, security and error handling.
I hope it helps you and feel free to comment.