15

I have used simple code to upload File.

Now My page is giving me the following error:

Maximum view state size limit (135KB) exceeded. Actual view state size for this page was 838.719KB

  • I have tried making all variables Transient
  • Removed PageBlock

Instead of coming on this error page - I want to show an Error Message like "Too big File. Upload files having size less than 2 MB."

How can I achieve this. Any Help or Any other suggestions ?

Visualforce Code :

    <apex:page standardController="Contact" showHeader="true" extensions="PhotoUploadController">
  <apex:sectionHeader title="Upload photo of {!obj.name}"/>   
    <apex:form >
    <apex:pagemessages />
        <br/>
        <apex:outputText ><b>1. Select the photo</b></apex:outputText><br/><br/> &nbsp; &nbsp; &nbsp;
        <apex:outputText > Click the <b>"Choose File" </b>to find the photo.</apex:outputText><br/><br/>&nbsp; &nbsp; &nbsp;
        <apex:inputFile title="Upload Photo" contentType="{!objAttach.ContentType}" value="{!objAttach.body}" fileName="{!objAttach.name}" id="file"></apex:inputFile>
        <br/><br/><br/>
        <apex:outputText><b>2. Upload Photo</b></apex:outputText><br/><br/>&nbsp; &nbsp; &nbsp;
        <apex:outputText >Click the <b>"Upload Photo"</b> button.</apex:outputText><br/><br/>&nbsp; &nbsp; &nbsp;
        <apex:commandButton value="Upload Photo" action="{!savePhoto}"/><br/><br/>
    </apex:form>   
</apex:page>

Controller Code :

public with sharing class PhotoUploadController {
    public Attachment objAttach{  get {
                                        if(objAttach== null)
                                          objAttach= new Attachment();
                                        return objAttach;
                                     }
                                   set;
                                 }

    transient Public Contact obj{get;set;}

     public PhotoUploadController(ApexPages.StandardController controller){
        objAttach=new Attachment();
        obj= (Contact)controller.getRecord();
        if(obj.id!=null){
            obj= [select id,name from Contact where id=:obj.id];
        }
     }

     public pageReference savePhoto(){  
        try {
                transient String contentType=objAttach.ContentType;

                if(contentType == 'image/jpeg' || contentType== 'image/png' ){

                    if(objAttach.body!=null && objAttach.name!=null){
                        objAttach.parentId=obj.id;                       
                        try {
                             upsert objAttach;
                             obj.Image_URL__c=URL.getSalesforceBaseUrl().toExternalForm()+'/servlet/servlet.FileDownload?file='+objAttach.id;
                             objAttach =null;
                             upsert obj;
                             obj=null;
                        }catch (DMLException e) {
                            ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error uploading attachment'));
                            return null;
                        }finally {
                          objAttach.body = null;
                        }    
                  }
                  return new pagereference('/'+obj.id);                  
                }else{
                      ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'Please, Upload image file with extension .JPG or .PNG'));
                      return null;
               }
           }
           catch(Exception e){
                 ApexPages.addMessages(e);
                 return null;
           }               
     }
}
3
  • Per your comment on an answer below, the entity which needs to be marked as transient is the Attachment member, objAttach. This is where the large binary data is stored when the form is posted and then this data is serialized into the viewstate.
    – Mark Pond
    Apr 1, 2015 at 18:36
  • I tried doing transient for my Attachment, still I am facing the issue, when I am trying to upload Image more than 2MB size. Apr 2, 2015 at 6:59
  • Possible duplicate of Loading files greater than 5M using VF page
    – Adrian Larson
    Jan 29, 2016 at 20:08

6 Answers 6

12
+25

If you are comfortable with javascript, the best way to achieve this use case is to use AJAX API. After you have fixed view state error, it will hit apex heap limit of 6MB. But using AJAX API you can upload files of size up to 25MB, which is the maximum size limit of attachments in salesforce.

You just need to pass the parent Id and the image file. For sample code please check below post,

Loading files greater than 5M using VF page

Also you can get more creative by adding drag and drop feature for image upload. I have tried it in past. It will not take more than 50 lines of javascript to achieve it using HTML 5 file reader API.

3

You have this bit in your code:

} catch(Exception e) {
  return null;
} 

So ostensibly there is a try block around all of the rest of that code, although this is not shown.

The problem to me seems to be that if you do exceed the file size your catch block swallows any error that might be surfaced in Apex.

The other problem is that you don't give us any visibility to your client-side code, if there is any. So it entirely possible something on the client-side is not surfacing the code.

At the very least, to get an error surfaced into the message stack on the page you'd normally do something like this:

} catch(Exception e) {
  ApexPages.addMessages(e);
  return null;
} 

This will take the raw exception error text and push it into the page message stack to be surfaced into the apex:pageMessages component.

There are more sophisticated things you can do, such as adding your own error messages, but this is the minimum to get your error surfaced.

4
  • I have added all code now. Mar 27, 2015 at 12:34
  • I did the changes as you asked. And I am trying to upload Image file with 2.3 MB and 4MB and its still giving me the same error message. Mar 27, 2015 at 12:53
  • I thought the problem was that you weren't seeing an error message. I was going on your statement, "My page is not giving me the following error". So are you seeing an error, or are you not seeing an error? Is it a limit problem, or a UI problem.
    – pchittum
    Mar 27, 2015 at 12:58
  • I am seeing the Error : Maximum File Size limit exceeded (135MB). I click on button "Choose File" ---> Select File (4mb image) -----> Click on "Upload Photo" -------> Got above Error msg. Mar 27, 2015 at 12:59
3

I don't think you need anything transient in this case. Looking at your code, most of the confusion/problems is coming from try/catch blocks, the way exceptions are handled and the fact that your were nullifying some variables.

I've lightly simplified the page/code and it now loads pictures of up to 10MB without a problem.

VF:

<apex:page standardController="Contact" showHeader="true" extensions="PhotoUploadController">
  <apex:sectionHeader title="Upload photo of {!obj.name}"/>   
    <apex:form id="theForm" >
    <apex:pagemessages />
        <br/>
        <apex:outputText ><b>1. Select the photo</b></apex:outputText><br/><br/> &nbsp; &nbsp; &nbsp;
        <apex:outputText > Click the <b>"Choose File" </b>to find the photo.</apex:outputText><br/><br/>&nbsp; &nbsp; &nbsp;
        <apex:inputFile title="Upload Photo" contentType="{!objAttach.ContentType}" value="{!objAttach.body}" fileName="{!objAttach.name}" id="file"></apex:inputFile>
        <br/><br/><br/>
        <apex:outputText ><b>2. Upload Photo</b></apex:outputText><br/><br/>&nbsp; &nbsp; &nbsp;
        <apex:outputText >Click the <b>"Upload Photo"</b> button.</apex:outputText><br/><br/>&nbsp; &nbsp; &nbsp;
        <apex:commandButton value="Upload Photo" action="{!savePhoto}" status="statusDetail"/><br/><br/>
    </apex:form>   
</apex:page>

Apex:

public with sharing class PhotoUploadController{
    public Attachment objAttach{  get {
                                        if(objAttach== null)
                                          objAttach= new Attachment();
                                        return objAttach;
                                     }
                                   set;
                                 }

    Public Contact obj{get;set;}

     public PhotoUploadController(ApexPages.StandardController controller){
        objAttach=new Attachment();
        obj= (Contact)controller.getRecord();
        if(obj.id!=null){
            obj= [select id,name from Contact where id=:obj.id];
        }
     }

     public pageReference savePhoto(){  

        String contentType=objAttach.ContentType;

        if(contentType == 'image/jpeg' || contentType== 'image/png' ){

            if(objAttach.body!=null && objAttach.name!=null){
                objAttach.parentId=obj.id;                       
                try {
                     upsert objAttach;
                     obj.Image_URL__c=URL.getSalesforceBaseUrl().toExternalForm()+'/servlet/servlet.FileDownload?file='+objAttach.id;
                     upsert obj;
                }catch (DMLException e) {
                    ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error uploading attachment:'+e));
                    return null;
                }finally {
                  objAttach.body = null;
                }    
          }
          return new pagereference('/'+obj.id);                  
        }else{
              ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'Please, Upload image file with extension .JPG or .PNG'));
              return null;
       }
     }
}

I believe this will work up to 25MB attachments. The need for a filter on file size is thus heavily reduced. But if you insist on still having one, you could put a warning in the catch block's message.

3

I ran in the same problem and I solved it with this:

<input id="picture_info" type="file" accept="image/*" capture="camera" onchange="" />

    <apex:form enctype="multipart/form-data">
        <apex:actionRegion >
            <apex:actionfunction name="af_submitFile" action="{!post_image}" rerender="myHiddenField" oncomplete="stop_function();"/>
            <apex:inputHidden value="{!fileData}" id="myHiddenField"/>
            <apex:inputHidden value="{!comment}" id="comment_evidence"/>
        </apex:actionRegion>
    </apex:form>

This is the method (missing declare some variables, obviously are declared at the top of my class)

public void post_image(){
    String param = Apexpages.currentPage().getParameters().get('data64');
    System.debug('##Blob information: '+param);
    System.debug('##fierlddata: '+fileData);


    FeedItem post = new FeedItem();
    post.ParentId = UserInfo.getUserId();
    post.CreatedById=UserInfo.getUserId();
    post.Body = '#Evidence '+comment;
    post.ContentData = EncodingUtil.base64Decode(fileData);
    post.ContentFileName =' Evidence_'+Datetime.now().format('dd/MM/yyyy HH:mm:ss')+'.png';
    insert post;
}

This is the javascript function that is executed when you select the file.

$("#picture_info").change(handlePhoto);

    $('#sendpicture').prop('disabled', true);

    function handlePhoto(evt){

        console.log('## In handler');
        var file = evt.target.files[0];

        console.log('### File Size: '+file.size);

        var reader = new FileReader();

        reader.onload = (function(theFile) {
            return function(e) {
                // Extract raw base64 data from data URL
                imageData = e.target.result.split(',')[1];
                base64Information = imageData;

                $('[id$=myHiddenField]').val(imageData);
                $('#sendpicture').prop('disabled', false);

            };
        })(file);

        reader.readAsDataURL(file);


    }

This is the result uploaded from a salesforce 1 app so is the same if you want to upload images in a custom visualforce page.

enter image description here

I hope it helps.

Edgar,

1

Because You have mentioned that your page is simply coming back to its previous stage without parent record ID when trying to upload a file, there is a possibility that you check if you have hit the limit --Maximum View State Limit Exceeded.

Below are few docs which could help you. Let me know if it helps!

https://developer.salesforce.com/page/An_Introduction_to_Visualforce_View_State

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_keywords_transient.htm

http://www.salesforce.com/us/developer/docs/pages/Content/pages_js_remoting.htm

Maximum view state size limit (135KB) exceeded

Uploading file via visualforce page error "Maximum view state size limit (135KB) exceeded"

https://help.salesforce.com/apex/HTViewSolution?urlname=State-size-limit-1327107599450&language=en_US

1
  • Hi, I have gone through this stuff many times, Sometimes I did solved the problems. But sometimes I got simply confused. Like here - Now I dont know which variable should I declare as TRANSIENT. Mar 30, 2015 at 7:57
0

This can be resolved by adding body equal to null after insert statement

  try {
        upsert objAttach;
        obj.Image_URL__c=URL.getSalesforceBaseUrl().toExternalForm()+'/servlet/servlet.FileDownload?file='+objAttach.id;
        objAttach =null;
        upsert obj;
        obj.body=null;
        obj=null;
  }

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .