17

For a developer who wants to use a PageReference to redirect to a Visualforce Page, are there any notable differences between constructing it by name versus using the Page.PageName factory method?

By Name

PageReference p1 = new PageReference('/apex/MyPage');

Factory

PageReference p2 = Page.MyPage

2 Answers 2

21

Today I Learned. From the Spring '17 Release Notes on Allow CSRF Protection on GET Requests to Visualforce Pages (Critical Update):

CRSF [sic] checks on GET requests also affect how Visualforce pages are referenced from Apex controllers. Methods that return the URL of CRSF-protected [sic] pages for navigation don’t work:

public String getPage() {
    return '/apex/PageName'; 
}

Instead, use methods that return a reference to the Visualforce page instead of the URL directly.

public class customController {
    public PageReference getPage() {
        return new PageReference('/apex/PageName'); 
    }
    public PageReference getPage1() {
        return Page.PageName; 
    }
}
6
  • 1
    +1 ... I need to learn to read release notes. Also, I have about 50 pages to fix in our org...
    – sfdcfox
    Jan 20, 2017 at 18:45
  • 1
    Ouch. I know the pain of pervious developers leaving a mess behind them. Hopefully others don't say that about my code...
    – Adrian Larson
    Jan 20, 2017 at 18:47
  • It also says for the pages with CSRF protection enabled, we cannot simply access the page by typing url in the browser. Out of curiosity, I tried this in my Spring'17 and get this error when accessing the page **The link you followed isn’t valid. This page requires a CSRF confirmation token. Report this error to your Salesforce administrator. **
    – javanoob
    Jan 20, 2017 at 20:32
  • Yeah I found that interesting as well. Seems a bit odd.
    – Adrian Larson
    Jan 20, 2017 at 20:34
  • 1
    I was about to edit the "CRSF" acronym, but that is how they spell it in the documentation.
    – martin
    Jan 21, 2017 at 1:00
12

One important aspect, besides the CRSF limitation, is that when you use the string constructor, you're explicitly avoiding creating a metadata link between your page and the class.

What this means for you is that if someone decides that your page is no longer used, and they delete the page, it can break your code, as you'll now be redirecting to a non-existent page. If you use the factory variable instead, you get automatic metadata protection. Similarly, if you make a typo in a string, you won't be notified, while if you're using the Page factory, you'll avoid simple typos or missing files during deployment.

When you attempt to delete the page, you'll be notified that the page is used in that class. Also, you can see a page's usage by clicking on the "Where is this used" button in the UI. This only detects "strong" links to the page, not weak links, such as using plain URLs. Change sets and packages also provide dependency management, but they can't protect you from simple string references.

Similarly, when possible, you should prefer to use the $Page global variable to link pages together, and use the Visualforce URL type for custom buttons and links that reference the page. Creating strong links in your metadata will help prevent accidental deletions.

4
  • +1 Yeah I thought about posting this as a separate answer. It's not really a pro or con, per se. True, I tend to prefer strong metadata links, but sometimes you don't want to tightly couple components. At least, in some circumstances you might create a circular reference using the factory pattern.
    – Adrian Larson
    Jan 20, 2017 at 18:31
  • @AdrianLarson From personal experience, I can say it's a pro. I've never had a situation arise where using the string somehow saved me effort, but I can tell you that I can't count the number of times I've deleted a page because "Where is this used?" showed no results...
    – sfdcfox
    Jan 20, 2017 at 18:35
  • If you had a multi-step wizard with back and forward buttons, for instance, wouldn't it be a royal PITA to delete them? For the record, I always use the factory pattern and consider it best practice. I'm not trying to advocate for string constructors.
    – Adrian Larson
    Jan 20, 2017 at 18:38
  • @AdrianLarson Nope. If you delete a page with its class at the same time, you won't trigger the protection mechanism. So, I'd build a simple destructiveChanges.xml with all of the wizard classes and pages, and workbench deploy. Problem solved. On the other hand, our org has 161 pages, which we're cleaning up for Lightning. Unfortunately, prior developers have not used Page references, so I can no longer easily identify which pages I can delete without manually searching all of our metadata...
    – sfdcfox
    Jan 20, 2017 at 18:41

You must log in to answer this question.

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