Skip Ribbon Commands
Skip to main content

Calling a Custom Web Service from MS CRM 4.0 Using Javascript

Date: 4/22/2011 | Contributor: Patty Banks | Keywords: MS CRM, Javascript, CRM Webservices, Code Snippet, MS CRM Devlopment; Calling WebS Service in MS CRM 4

In CRM 4.0, you can take advantage of the built-in RemoteCommand javascript function found in \_static\_controls\RemoteCommands\RemoteCommands.js. The RemoteCommand function executes a SOAP request to a webservice and parses the result into an easily managable object. You can easily pass parameters, and evaluate the response from the webserver method.

Building a Basic Webservice

Here are the steps to build and test a basic webservice in CRM 4.

  1. Build a webservice
  2. Deploy the webservice to CRM
  3. Modify a copy of CRM’s RemoteCommand.js file
  4. Add javascript to a form’s event to call the webservice and process the response
  5. Test and debug the webservice

The following sections cover these three steps in detail

Build a Webservice

  1. In VS2008, choose File>New>Project and choose ASP.NET Web Service Application
  2. Target the appropriate .NET Framework for the deployment. See the dropdown in the upper-right of the New Project window
  3. Name the webservice appropriately and Click OK
  4. Delete Service1 from the project
  5. Right-click the Project and choose Add>New Item. Choose Web Service, name it appropriately and click Add. The name can be the same as your project name
  6. You must modify the Namespace:=”http://tempuri.org/” tag to Namespace:=” http://schemas.microsoft.com/crm/2006/WebServices” or your webservice call will fail. This is the namespace that RemoteCommand uses.
  7. You’ll see that a HelloWorld WebMethod is created in your class. You can test the CRM javascript webservice call with this webmethod

Deploy the Webservice to CRM

  1. Build the webservice project in debug mode
  2. Create the following folder structure: <CRM Web Root>\ISV\Allin\WebServices.
  3. Copy the .asmx file from your project to the folder you just created.
  4. Copy the .dll in the bin folder of your project to the <CRM Web Root>\bin folder.

Modify a Copy of CRM’s RemoteCommand.js file

You can call a custom webservice in a CRM page’s javascript using CRM’s RemoteCommand.js. This file contains a function called RemoteCommand that will construct a SOAP request with parameters you specify and calls any webservice you specify. The catch is that it is an unsupported feature in CRM. If Microsoft decides to make changes to, or replace RemoteCommand.js in future releases of CRM, then your use of RemoteCommand.js may not be supported. To circumvent possible incompatibility problems with future releases, we can copy and modify CRM’s RemoteCommand.js file and use our copy of AllinRemoteCommand.js. Here’s what to do

  1. Copy the <CRM Root> \_static\_controls\RemoteCommands\RemoteCommand.js to <CRM Web Root>\ISV\Allin\Javascript\AllinRemoteCommand.js
  2. Open the AllinRemoteCommand.js file with a text editor and make the following text replacements throught the file:
    1. RemoteCommand  →  AllinRemoteCommand
    2. RemoteCommandDefaultErrorHandler  →  AllinRemoteCommandDefaultErrorHandler
    3. AsyncResultHandler  →  AllinAsyncResultHandler
    4. RemoteCommandResult  →  AllinRemoteCommandResult
    5. CommandParameter  →  AllinCommandParameter

Add Javascript

  1. Pick a form and add the following code to the OnLoad event. This code dynamically includes the AllinRemoteCommand.js file in the page:
    var util = document.createElement('script'); 
    
    util.type = 'text/javascript';util.src = '/ISV/Allin/Javascript/AllinRemoteCommand.js'; 
    
    document.getElementsByTagName('head')[0].appendChild(util);
    
  2. Add the following code to an attribute’s OnChange event. This will cause the webservice to be called when a user changes the value of that attribute. A picklist of lookup is the best type of attribute to use:
    var cmd = new AllinRemoteCommand("<YourWebServiceName>", "HelloWorld","/<CRMSERVER>/ISV/Allin/WebServices/"); 
    
    var result = cmd.Execute(); 
    
    alert(result.ReturnValue);
  3. Save and Publish the change.

Test and Debug

In CRM open the Form that you modified. Make a change to the value of the attribute that you modified and see if the MessageBox appears with the message “Hello World”. If so, your page successfully called your webservice from javascript! If not, debug by viewing request and response with Fiddler (download from fiddlertool.com).

Modify Webservice to Pass Parameters

  1. Modify your project’s HelloWorld function like so:
    Public Function HelloWorld(ByVal name as String, ByVal age as Integer) As String
    
        Return name & “ is “ & age.ToString
    
    End Function
    
  2. Build and copy files following the steps in Deploy the Webservice to CRM.
  3. Modify the CRM form’s OnLoad event with cmd.SetParameter like so:
    var cmd = new AllinRemoteCommand("/ISV/Allin/WebServices/");
    
    cmd.SetParameter("name", "Craig");
    
    cmd.SetParameter("age", 42);
    
    var result = cmd.Execute();
    
    alert(result.ReturnValue);
    
  4. Save and Publish the change. Test by going to the form in CRM and seeing the MessageBox display “Craig is 42”.

Incorporate CRM SDK in Webservice

  1. Add references to the project for microsoft.crm.sdk.dll  and  microsoft.crm.sdktypeproxy.dll.
  2. Add Imports statements to the .asmx page for Microsoft.Crm.Sdk  and  Microsoft.Crm.SdkTypeProxy.
  3. Use CrmService and associated classes to query the CRM database.

GetOppLeadSource Webservice

The following code is a complete webservice with a WebMethod that takes  an id as a string and returns a object that contains Status, OppleadSource, OppLeadSourceOther and ErrorMessage. Note: where no value is returned, the property is set to Nothing. This has the effect of leaving out the node for that property in the XML response. Your javascript needs to handle the condition when no property is returned. The next section shows the javascript that calls this webmethod and handles the response.

AllinWebService.asmx.vb:

Imports System.Web.Services

Imports System.Web.Services.Protocols

Imports System.ComponentModel

Imports Microsoft.Crm.Sdk

Imports Microsoft.Crm.SdkTypeProxy

<System.Web.Services.WebService(Namespace:="http://schemas.microsoft.com/crm/2006/WebServices")> _

<System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _

<ToolboxItem(False)> _

Public Class AllinWebService

Inherits System.Web.Services.WebService

<WebMethod()> _

Public Function HelloWorld(ByVal name As String, ByVal age As Integer) As String

    Return name & " is " & age.ToString

End Function

Public Class ReturnValue

    Public Status As String

    Public OppLeadSource As String

    Public OppLeadSourceOther As String

    Public SourceCampaignId As String

    Public SourceCampaignName As String

    Public ErrorMessage As String

End Class

<WebMethod()> _

Public Function GetOppLeadSource(ByVal id As String) As ReturnValue

    Dim result As New ReturnValue

    Try

        Dim colSet As New Query.ColumnSet(New String() {"ht_oppleadsource", "ht_oppleadsourceother"})

        Dim targetRetrieve As New TargetRetrieveDynamic()

        targetRetrieve.EntityName = EntityName.opportunity.ToString()

        targetRetrieve.EntityId = New Guid(id)

        Dim retrieve As New RetrieveRequest()

        retrieve.Target = targetRetrieve

        retrieve.ColumnSet = colSet

        retrieve.ReturnDynamicEntities = True

        Dim service As CrmService = GetMyService()

        Dim retrieved As RetrieveResponse = CType(service.Execute(retrieve), RetrieveResponse)

        Dim dynEntity As DynamicEntity = CType(retrieved.BusinessEntity, DynamicEntity)

        result.Status = "success"

        result.OppLeadSource = GetTextValue(dynEntity, "ht_oppleadsource")

        result.OppLeadSourceOther = GetTextValue(dynEntity, "ht_oppleadsourceother")

        result.SourceCampaignId = GetTextValue(dynEntity, "ht_campaignid")

        If result.SourceCampaignId IsNot Nothing Then

            Dim campaignRetrieve As New TargetRetrieveDynamic

            campaignRetrieve.EntityName = EntityName.campaign.ToString()

            campaignRetrieve.EntityId = New Guid(result.SourceCampaignId)

            retrieve = New RetrieveRequest()

            retrieve.Target = campaignRetrieve

            retrieve.ColumnSet = New Query.ColumnSet(New String() {"name"}) 'New Query.AllColumns '

            retrieve.ReturnDynamicEntities = True

            retrieved = CType(service.Execute(retrieve), RetrieveResponse)

            dynEntity = CType(retrieved.BusinessEntity, DynamicEntity)

            result.SourceCampaignName = GetTextValue(dynEntity, "name")

        End If

    Catch ex As Exception

        result.Status = "failure"

        result.OppLeadSource = Nothing

        result.OppLeadSourceOther = Nothing

        result.ErrorMessage = String.Format("guid = {0}, error = {1}", id, ex.Message)

    End Try

    Return result

End Function

Private Function GetTextValue(ByRef dynEntity As DynamicEntity, ByRef attribute As String) As String

    If dynEntity.Properties.Contains(attribute) Then

        If (dynEntity(attribute).GetType Is GetType(Picklist)) Then

            Return CType(dynEntity(attribute), Picklist).Value.ToString

        Else

            Return dynEntity(attribute).ToString

        End If

    Else

        Return Nothing

    End If

End Function

Private Function GetMyService() As CrmService

    Dim service As New CrmService()

    service.Credentials = System.Net.CredentialCache.DefaultCredentials

    service.Url = "http://gfscrmserver/MSCrmServices/2007/CrmService.asmx"

    Dim token As CrmAuthenticationToken = New CrmAuthenticationToken()

    token.OrganizationName = "GFSCRM"

    token.AuthenticationType = 0

    service.CrmAuthenticationTokenValue = token

    Return service

    End Function

End Class

Javascript for Calling and Handling Response from GetOppLeadSource

Place this code in the Account form’s Opportunity field’s OnChange Event:

    var lookupData = new Array;

    lookupData = crmForm.all.gfs_opportunityid.DataValue;

    if ((lookupData != null) && (lookupData[0] != null))

    {

        var cmd = new AllinRemoteCommand

        cmd.SetParameter("orgName", ORG_UNIQUE_NAME);

        cmd.SetParameter("serverUrl", SERVER_URL);

        cmd.SetParameter("id", lookupData[0].id);

        var result = cmd.Execute();

        if (!IsNull(result.ReturnValue.Status) && result.ReturnValue.Status == "success")

        {

            if (!IsNull(result.ReturnValue.OppLeadSource))

            {

                crmForm.all.htc_leadsource.DataValue = result.ReturnValue.OppLeadSource

            }

            else

            {

                crmForm.all.htc_leadsource.DataValue = null;

            }

            if (!IsNull(result.ReturnValue.OppLeadSourceOther))

            {

                crmForm.all.htc_leadsourceother.DataValue = result.ReturnValue.OppLeadSourceOther

            }

            else

            {

                crmForm.all.htc_leadsourceother.DataValue = null;

            }

            var lookupItem = new Object();

            if (!IsNull(result.ReturnValue.SourceCampaignId) &&!IsNull(result.ReturnValue.SourceCampaignName))

            {

                lookupItem.typename = "campaign";

                lookupItem.id = result.ReturnValue.SourceCampaignId;

                lookupItem.name = result.ReturnValue.SourceCampaignName;

                lookupData = new Array();

                lookupData[0] = lookupItem;

                crmForm.all.htc_campaignid.DataValue = lookupData;

            }

            else

            {

                crmForm.all.htc_campaignid.DataValue = null;

            }

        }

        else

        {

            if (!IsNull(result.ReturnValue.ErrorMessage))

            {

                alert("A webservice error has occurred: " + result.ReturnValue.ErrorMessage)

            }

            else

            {

                alert("A webservice error has occurred")

            }

        }

    }

    else

    {

        crmForm.all.htc_leadsource.DataValue = null;

        crmForm.all.htc_leadsourceother.DataValue = null;

        crmForm.all.htc_campaignid.DataValue = null;

    }

}

Code Notes

Notice that the return value for the GetOppLeadSource is an instance of a class that contains many public properties, each of type string. The AllinRemoteCommand handles receiving this data quite easily. Notice in the javascript code the data is accessed through a variable named result. Result has a property named ReturnValue, and ReturnValue has properties by the same name as the properties in your webmethod’s return value class. If you do not want to pass a value back for a property, set that property to Nothing in the webmethod. In the javascript, test for !IsNull( result.ReturnValue.<property>).


About the authors: