1

I am using the transient keyword to allow users to upload files greater than 135kb (viewstate limit) on a VF page however since the transient keyword doesn't transmit the attachment past the view state, when inserting the attachment, the filename and body is missing.

I set setRedirect to false in the Apex class when users navigate to the next page in the form.

Is there a way to upload files greater than the viewstate limit using transient?

Apex

public without sharing class AWF_FormClass {
    
    public Application__c app {
        get{
            if(app == null)
                app = new Application__c();
            return app;
        }
        set;
    }
    
    public Transient Attachment ID {
        get {
            if(ID == null)
                ID = new Attachment();
            return ID;
        }
        set;
    }
    
    public Transient Attachment Diploma{
        get{
            if(Diploma == null)
                Diploma = new Attachment();
            return Diploma;
        }
        set;
    }
    
    public AWF_FormClass(){
        
        //Empty constructor
    }
    
    
    
    public PageReference step4(){
            
        PageReference pageRef3;
        PageRef3 = Page.AWF_Employment;
        PageRef3.setRedirect(false);
        if(ID.Name == null){
        ApexPages.addMessage(
        new ApexPages.Message(
        ApexPages.Severity.ERROR,
        'You must upload a copy of your New York State ID to proceed.'
        )
     );
        return null;
        }
        return Page.AWF_Employment;
    }
    
    
    public pageReference saveApplication(){
        try {     
            
        upsert app;
        ID.ParentId = app.Id;
        Diploma.ParentId = app.Id;
        insert ID;
        insert Diploma;
        return Page.AWF_Success;  
            
        } catch(DMLException e){
            Apexpages.addMessage(new ApexPages.Message(ApexPages.SEVERITY.FATAL, 'No such combination exists'));    
        }
        return null;
    }
}

VF

<apex:page showHeader="false" controller="AWF_FormClass" standardStylesheets="false">
    
    <head>
    <link rel = "icon" href = "{!URLFOR($Resource.BCATLogo)}" type = "image/x-icon"/>
    <apex:slds ></apex:slds>
    <apex:stylesheet value="{!URLFOR($Resource.AWF_FormStyle)}"/>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    </head>
    
    <br/>
    <div class="center">
    <apex:image value="{!URLFOR($Resource.BCATLogo)}" width="200" height="50"></apex:image>
    <br/>   
    <br/>
    <p class="slds-text-heading_large">2021 Adult Enrollment Form</p>
        
    <!-- progressbar -->
    <ul id="progressbar">
        <li class="active">Personal<br/>Information</li>
        <li>Professional <br/>Background</li>
        <li>Application</li>
        <li>Submit</li>
    </ul>
    </div>
    
    <p class="heading">Identification Vertification</p>    
        <apex:form styleClass="fsWrapper">
        <apex:pageBlock >
        <apex:pageBlockSection columns="1">
        <div class="step1">
            <apex:outputLabel value="Please upload a copy of your New York State ID below:"></apex:outputLabel>
            <br/>  
        <div align="center" style="margin-left: 400px">  
         <apex:pageMessages ></apex:pageMessages>
        </div>
            <br/>
            <div align="center">
             <apex:inputfile value="{!ID.Body}" fileName="{!ID.Name}"></apex:inputfile>
            </div>
        </div> 
        </apex:pageBlockSection>
            <apex:pageBlockButtons location="bottom" >
                <div id="sldsbutton" align="center" draggable="false">
                    <apex:commandbutton action="{!step4}" value="Next" styleClass="slds-button slds-button_destructive"></apex:commandbutton>
                </div>  
            </apex:pageBlockButtons>
        </apex:pageBlock>
    </apex:form>
</apex:page>
2
  • Add your vf markup as well? Apr 18 at 1:19
  • Added VF above @MohithShrivastava
    – SpicyPat
    Apr 18 at 1:24
2

The Setters are not called when using the transient keyword and hence you may be seeing null in the body or title or any other fields.

You can revert back to the non-transient version

 public Attachment attachmentRec {
    get {
        if(attachmentRec == null)
            attachmentRec = new Attachment();
        return attachmentRec;
    }
    set;
}

Just make sure that you nullify the body after you insert the attachment to clear ViewState for the blob. The pseudo-code is below

public pageReference saveApplication(){
    try {     
        
    upsert app;
    attachmentRec.ParentId = app.Id;
    Diploma.ParentId = app.Id;
    insert attachmentRec;
    // Clear this value so view state is saved
    attachmentRec.body = null;
    insert Diploma;
    return Page.AWF_Success;  
        
    } catch(DMLException e){
        Apexpages.addMessage(new ApexPages.Message(ApexPages.SEVERITY.FATAL, 'No such combination exists'));   
       attachmentRec.body = null; 
    }
    return null;
}

Notice I changed the variable for Attachment record from ID to attachmentRec

Some thoughts on implementation

  1. Attachments are outdated and do not have advanced security compared to ContentVersion. Hence use ContentVersion to store files.
  2. You can get away with the view state problem by using pure JavaScript and not using Visualforce Markups like Inputfile.

Use a JavaScript library like jsforce to do this work for you. Here is an example

1
  • Thanks Mohith. However the error is thrown when the user advances to the next page since the view state limit is being reached in the step4() method. The saveApplication method is only called at the end of the form on a different VF page. So the trick is including the attachment to the new Application__c record without exceeding the view state
    – SpicyPat
    Apr 18 at 14:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.