2

So either I'm going nuts, or I'm overlooking something obvious, or I'm just encountering some very weird behaviour.

The Setup

I have a page which calls an Init action in the controller from the page tag

<apex:page controller="myController" action="{!Init}">

The Init() method returns a PageReference.

I'm using some of Michaelforce's code to detect whether or not I'm in a sandbox environment, and if so I return a page reference to redirect the user. If not, I just return null so that the page loads as normal.

public PageReference Init()
{
    if(WhereAmI.IsSandbox())
    {
        PageReference pr = Page.PackPrefix__OtherPage;
        return pr.setRedirect(true);
    }

    return null;
}

The Problem

This code works in my development environment, i.e. it doesn't redirect. If i change my if statement for testing to if(!WhereAmI.IsSandbox()) then it correctly redirects also.

Once I package the code up and install the package (managed) in a sandbox, it does not redirect. I made the WhereAmI class and its methods global so that I could test them in Execute it's functioning perfectly, returning true and yet I don't get redirected.

The page does have a different content type to normal but I don't think that's the issue given that it works in production. So the quesiton: have I missed something that's right under my nose, or does this smell like a bug?

  • 1
    Not sure if it's because of the namespace prefix. SF sometimes adds and sometimes it doesn't add prefixes for the variables/pages etc. Try using the namespace prefix and also try without, see if that changes anything.... – Boris Bachovski Mar 7 '13 at 23:19
  • Have tried both on the page. Stuff that's in the package shouldn't need the namespace, but I threw it in just to check and same thing. – Matt Lacey Mar 7 '13 at 23:21
  • Have you tried with new pageReference('/apex/THEPAGE'); instead of Page.THEPAGE? – Boris Bachovski Mar 7 '13 at 23:25
  • Just tried that and still no luck. – Matt Lacey Mar 7 '13 at 23:51
7

URL.getSalesforceBaseUrl is execution context sensitive. The code you've linked to uses URL.getSalesforceBaseUrl(). This actually returns a different Salesforce base URL dependent on the context you run it from.

Possible Issue. While you've tested the function itself from a Sandbox environment and it returns true. I am wondering if that is from Developer Console / Execute Anonymous? Call this method from these contexts will typically return what you expect. As in what you typically see in your browser URL when your looking at a native page, e.g.

https://na7.salesforce.com

However when called from a VF controller execution context the URL returned is the VF URL including your namespace. I don't have a sandbox with a managed package containing this code to hand to test this theory, but I think the problem lies in how its parsing the host name part of the URL.

String server = host.substring(0,host.indexOf('.'));

So a base URL like this would return your namesapce prefix as the server.

https://namespace.na7.visual.force.com/apex/myVFPage

Summary: So I think the issue is that the isSandbox method is not considering the type of host name returned in a VF context. Note that in an unmanaged environment the host name part of the URL will be c.na7.visual.force.com. So you really just need to check for 'visual.force' in the URL, then skip the second part of the server name. If your not in a VF context, the existing code will work.

Working Code:

String server = host.contains('visual.force.com') ? host.split('\\.')[1] : host.split('\\.')[0];
|improve this answer|||||
  • Exactly the same thing I saw. The code has a server variable that evaluates to c and the code after it relies on it being cs. – Peter Knolle Mar 7 '13 at 23:55
  • Agreed, this is what I was getting at in a very round about sort of way. The base URL is returning a value that the IsSandbox() doesn't process correctly. – Daniel Ballinger Mar 8 '13 at 0:01
  • Think you're on the money with this guys. I just deployed the code with a forced redirect and it was good so now I'll try and cater for this other URL format and then report back... turn around is a bit slow as I have to package each time I change something! – Matt Lacey Mar 8 '13 at 0:03
2

As you mention, the redirect works if you reverse the logic on if(WhereAmI.IsSandbox()).

This makes me think that your IsSandbox() method isn't working as expected in this particular case.

What does URL.getSalesforceBaseUrl() return for the page in the sandbox. It might have some odd domain that is causing the method to return false.

It might be that you can't rely on the URL in your case or need to extend the logic to handle the particular URL in this context.


As a related aside, I did propose an alternative solution in Can we determine if the Salesforce instance is production org or a Sandbox org?. It uses the Pod Id from the Org ID. Perhaps not as robust as the URL, but I'm determined to find a problem that knowing the Pod Id solves.

|improve this answer|||||
  • It's not better, in both cases you need to keep track of the instances (SBox Org Id's or URL's)... – Boris Bachovski Mar 7 '13 at 23:38
  • @e-bacho2.0. Agreed, using the Pod Id isn't a better solution due to the dependence on knowing which Ids are sandboxes. It is however an alternative and will work with a large number of sandboxes, so it is a bit better than coding individual Org Ids. – Daniel Ballinger Mar 7 '13 at 23:45
  • Sorry - think it was a little unclear of me. It works if I reverse the logic in prod because it then acts as a sandbox. The method is correctly returning true in the sandbox. – Matt Lacey Mar 7 '13 at 23:46
  • @LaceySnr 's method is better as it is based on the server subdomain which doesn't change that often as the Org ID does :). Compare new org registrations (thousands per day) and servers (~17 so far, trust.salesforce.com/trust/status and it doesn't look that the CS will change)... – Boris Bachovski Mar 7 '13 at 23:48
0

The only thing I can think of here is that you can't do a redirect from your controller.

It's hard to say if this is the problem without seeing your controller, but your page should look like:

<apex:page action="{!Init)">

Whereas your comment that

I have a page which calls an Init action in the controller.

Suggests that your controller looks like:

public myController () {
    Init();
}

...which won't work

|improve this answer|||||
  • Sorry, my bad for not being explicit. I am in fact calling the action from the page tag. Don't remove this answer though as it'll definitely be useful for others finding this page! – Matt Lacey Mar 7 '13 at 23:19
  • 1
    Will do. I didn't think you'd make that error - but I know I've glossed over that and been completely stuck after staring at a screen for marathon stretches! – James Hill Mar 7 '13 at 23:22
  • Ha ha, all good. I asked the question precisely because I do those things all the time :) – Matt Lacey Mar 7 '13 at 23:23

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.