Wednesday, February 15, 2012

CRM 2011: Get the Right Server URL in Your CRM Client Script

If you have worked with Microsoft Dynamics CRM 2011 long enough, you have most likely used getServerUrl function provided by the platform's API.

However, there is a problem with this function, it returns the base server URL which is the one registered in CRM deployment manager. When you work with a CRM form or web resource, you don't want to use the base server URL directly, instead you need the local server URL that hosts the current form or web resource. For instance, if the user is using a URL which is different from what's in deployment manager, say IP address or a domain alias, the URL will cause cross-domain calls, which will fail.

For this reason, I have baked a solution today which might be able to address this issue universally for all scenarios (hopefully).
var getServerUrl = function () {
    var context, crmServerUrl;
    if (typeof GetGlobalContext != "undefined") {
        context = GetGlobalContext();
    }
    else if (typeof Xrm != "undefined") {
        context = Xrm.Page.context;
    }
    else {
        throw new Error("CRM context is not available.");
    }

    if (context.isOutlookClient() && !context.isOutlookOnline()) {
        crmServerUrl = window.location.protocol + "//" + window.location.host;
    } else {
        crmServerUrl = context.getServerUrl();
        crmServerUrl = crmServerUrl.replace(/^(http|https):\/\/([_a-zA-Z0-9\-\.]+)(:([0-9]{1,5}))?/, window.location.protocol + "//" + window.location.host);
        crmServerUrl = crmServerUrl.replace(/\/$/, ""); // remove trailing slash if any
    }
    return crmServerUrl;
}; 
In the code snippet, I assumed that a server host name can only be made of English, numeric characters, _ (underscore), . (dot), - (dash).

If you are using Silverlight web resource, you need to translate the code to C#, which shouldn't be something difficult. [Update - Please refer to my another blog post for C# code that works for Silverlight]

Although I am bluntly positive that this could solve the problem universally, but there might be exceptional scenarios that I am not currently aware. If that's the case, please let me know by leaving a comment below, I will try to come up with something better. ;-)

Thanks for reading, hope this helps.

11 comments:

  1. Hello Daniel,
    Why not to use relative urls like
    var url = Xrm.Page.prependOrgName("Your Url");?

    ReplyDelete
    Replies
    1. Hi Andrii, if you construct url that way, you might have trouble with CRM offline client, although I haven't confirmed if that's the case. The goal of my post is to replace CRM getServerUrl function, since that's widely used in the CRM development practice, and it's causing a lot of trouble.

      Delete
    2. It should work without issue. I've noticed that getServerUrl can create a lot of issues that's why I use relative urls in JavaScript that I develop.

      Delete
  2. So you would do this way?

    var odataEndpointUrl = Xrm.Page.prependOrgName("/XRMServices/2011/OrganizationData.svc");

    ReplyDelete
  3. Yes, I use it in my code. Should work without issues.
    Offtopic - see you in 3 days ;)

    ReplyDelete
    Replies
    1. Hey, Andrii. You are right, perpendOrgName works for offline client, hopefully it works for CRM online and IFD deployment (I don't have an environment to verify either of them).

      Just one minor note, it's Xrm.Page.context.prependOrgName, I was trapped by Xrm.Page.prependOrgName. ;-)

      During my testing, I realized, CRM returns http://localhost:2525 instead of the base server URL when getServerUrl() function is called for offline client. So I have updated my post to reflect this.

      Thanks for your tips, see you at the summit.

      Delete
  4. prependOrgName will return empty string when using the context from ClientGlobalContext.js.aspx and not from CRM form.
    I believe because the IS_PATHBASEDURLS variable is not defined in the ClientGlobalContext.js.aspx, and this is needed in prependOrgName function.

    ReplyDelete
  5. Hi Daniel,

    In my case it doesn't work but I think there is a problem with the configuration.
    This is a CRM 2011 RU11 and I have configured to access by https.
    I have 3 different ways to access:
    1.-Within the LAN
    If I type https://servername there is no problem, but if I type the IP adrress instead the name of the server, the access denied error appears.
    2.-By internet
    https://crm.domain-name.com I obtain the access denied error too. I have not configured the enviroment as an IFD.

    In all the cases before entering to CRM system a certificate error appears.

    I hope you can help me.

    Regards

    ReplyDelete
    Replies
    1. That's strange, can you check what you get after calling the method? Do you see a different server name?

      Delete
  6. I have a Dynamics instance with a custom host header, and my REST calls were failing, so I replaced getServerUrl(); with "/" + Xrm.Page.context.getOrgUniqueName(); and it works great.

    The URL is relative then, which seems to work fine as Adrii points out.

    I do all my calls from the CRM page, not any custom pages that use the ClientGlobalContext.js.aspx which apparently doesn't work (see posting above..)

    ReplyDelete