RSS

Category Archives: WebServices and SOAP

How to Associate Marketing List with Lead, Contact or Account Entity using SOAP Service

Introduction

As we know SDK.REST.js is a JavaScript library having functionality to do many ‘Client-Server‘ operations, so it provides a function to associate two records of different Entities.

Background

I have a requirement in my project to open a Marketing List Lookup on click of a custom button and able to add multiple Marketing List to Lead, Contact or Account records. I have tried this using REST service, but it threw an error message of “Associate not support for Marketing List“. Then I tried using SOAP service and got a fruitful solution.

Let’s do it…

Create a Web Resource for Custom Button and go through the following code.
Here “OpenLookUp function will be fired on button click.

var relationname;
var entityName;
function OpenLookUp(grid) {
    // prepare the CRM URL
    //var serverurl = Xrm.Page.getServerUrl();
    var customServerURL = document.location.protocol + "//" + document.location.host;

    var membertypecode;
    entityName = Xrm.Page.data.entity.getEntityName();
    if (entityName == "lead")
        membertypecode = "4";
    else if (entityName == "account")
        membertypecode = "1";
    else if (entityName == "contact")
        membertypecode = "2";
    
    var url = customServerURL + '/_controls/lookup/lookupinfo.aspx?AllowFilterOff=1&objecttypes=4300&DefaultType=4300&DefaultViewId=%7b7D7737D8-1A05-4ABB-BEBD-843404A83DAD%7d&DisableQuickFind=0&DisableViewPicker=1&LookupStyle=multi&ShowNewButton=1&ShowPropButton=1&browse=0&listType=static&membertypecode=' + membertypecode + '';
    var lookUp = window.showModalDialog(url, "entity", "dialogWidth:600px0px;dialogHeight:600px0px;,resizable=1,menubar=0,status=1,location=0,toolbar=0,scrollbars=1");
    
    if (lookUp != null) {
        if (typeof lookUp != 'object') {
            lookUp = $.parseJSON(lookUp);
            associateMarketingListToEntity(lookUp);
        }
    }
}

///<summary>
/// Associates records asynchronously and displays messages so you can verify the association
///</summary>
function associateMarketingListToEntity(lookup) {
    var id = Xrm.Page.data.entity.getId();
    
    relationname = "Referenced" + entityName + "_parent_list";
    entityName = (entityName.charAt(0)).toUpperCase() + entityName.substr(1, entityName.length - 1);

    var itemLists = lookup.items;
    for (var i = 0; i < itemLists.length; i++) {
        AddMemberListRequest(id.replace(/[{}]/g, ""), (itemLists[i].id).replace(/[{}]/g, ""));
    }
}

function AddMemberListRequest(id, Listid) {
    var requestMain = "";

    requestMain += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
    requestMain += "  <s:Body>";
    requestMain += "    <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
    requestMain += "      <request i:type=\"b:AddListMembersListRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
    requestMain += "        <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
    requestMain += "          <a:KeyValuePairOfstringanyType>";
    requestMain += "            <c:key>ListId</c:key>";
    requestMain += "            <c:value i:type=\"d:guid\" xmlns:d=\"http://schemas.microsoft.com/2003/10/Serialization/\">" + Listid + "</c:value>";
    requestMain += "          </a:KeyValuePairOfstringanyType>";
    requestMain += "          <a:KeyValuePairOfstringanyType>";
    requestMain += "            <c:key>MemberIds</c:key>";
    requestMain += "            <c:value i:type=\"d:ArrayOfguid\" xmlns:d=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">";
    requestMain += "              <d:guid>" + id + "</d:guid>";

    requestMain += "            </c:value>";
    requestMain += "          </a:KeyValuePairOfstringanyType>";
    requestMain += "        </a:Parameters>";
    requestMain += "        <a:RequestId i:nil=\"true\" />";
    requestMain += "        <a:RequestName>AddListMembersList</a:RequestName>";
    requestMain += "      </request>";
    requestMain += "    </Execute>";
    requestMain += "  </s:Body>";
    requestMain += "</s:Envelope>";

    var req = new XMLHttpRequest();
    req.open("POST", _getServerUrl(), true);

    // Responses will return XML. It isn't possible to return JSON.
    req.setRequestHeader("Accept", "application/xml, text/xml, */*");
    req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
    var successCallback = null;
    var errorCallback = null;
    req.onreadystatechange = AddListMembersListResponse(req, null, null);
    req.send(requestMain);
}

function ReLoadForm() {
    window.location.reload(true);
}

///<summary>
/// Receives the assign response
///</summary>
///<param name="req" Type="XMLHttpRequest">
/// The XMLHttpRequest response
///</param>
///<param name="successCallback" Type="Function">
/// The function to perform when an successful response is returned.
/// For this message no data is returned so a success callback is not really necessary.
///</param>
///<param name="errorCallback" Type="Function">
/// The function to perform when an error is returned.
/// This function accepts a JScript error returned by the _getError function
///</param>
function AddListMembersListResponse(req, successCallback, errorCallback) {
    if (req.readyState == 4) {
        if (req.status == 200) {
            if (successCallback != null)
            { successCallback(); }
        }
        else {
            _getError(req.responseXML);
        }
    }
}

///<summary>
/// Returns the URL for the SOAP endpoint using the context information available in the form
/// or HTML Web Resource.
///</summary>
function _getServerUrl() {   
    var OrgServicePath = "/XRMServices/2011/Organization.svc/web";
    var serverUrl = "";
    if (typeof GetGlobalContext == "function") {
        var context = GetGlobalContext();
        serverUrl = context.getServerUrl();
    }
    else {
        if (typeof Xrm.Page.context == "object") {
            serverUrl = Xrm.Page.context.getServerUrl();
        }
        else
        { throw new Error("Unable to access the server URL"); }
    }
    if (serverUrl.match(/\/$/)) {
        serverUrl = serverUrl.substring(0, serverUrl.length - 1);
    }
    return serverUrl + OrgServicePath;
}

///<summary>
/// Parses the WCF fault returned in the event of an error.
///</summary>
///<param name="faultXml" Type="XML">
/// The responseXML property of the XMLHttpRequest response.
///</param>
function _getError(faultXml) {    
    var errorMessage = "Unknown Error (Unable to parse the fault)";

    if (typeof faultXml == "object") {
        try {
            var bodyNode = faultXml.firstChild.firstChild;
            //Retrieve the fault node
            for (var i = 0; i < bodyNode.childNodes.length; i++) {
                var node = bodyNode.childNodes[i];
                //NOTE: This comparison does not handle the case where the XML namespace changes
                if ("s:Fault" == node.nodeName) {
                    for (var j = 0; j < node.childNodes.length; j++) {
                        var faultStringNode = node.childNodes[j];
                        if ("faultstring" == faultStringNode.nodeName) {
                            errorMessage = faultStringNode.text;
                            break;
                        }
                    }
                    break;
                }
            }
        }
        catch (e) { };
    }
    return new Error(errorMessage);
}

By Sukanta Mangal
Software Engineer @Team DynamicsCRM.
Mindfire Solutions

Advertisements
 

Tags: , , , , , , , , , , , , , , , , , ,

CRM 2011 Exception “The HTTP request is unauthorized with client authentication scheme ‘Anonymous’. The authentication header received from the server was ‘NTLM'”

Introduction

This is in reference to my previous post Calling external Web Service from a CRM 2011 Plug-in. This blog post is just a modification of the last post.

Background

In one of the project while calling an external Web Service hosted in some other server(other than CRM server), I found an issue like the one below.

” The HTTP request is unauthorized with client authentication scheme ‘Anonymous’. The authentication header received from the server was ‘NTLM’ “

Problem

Clearly its an Authentication Issue. Then I found out that in Authentication Section of IIS, the Authentication Scheme for the service was Ntlm, whereas I was using Default Authentication Scheme in my HTTP Binding inside Configuration Information.

Solution

Instead of using the Default Authentication, I changed my Binding to use Ntlm Authentication.

So, instead of the following code,

BasicHttpBinding myBinding = new BasicHttpBinding();

myBinding.Name = "BasicHttpBinding_Service";
myBinding.Security.Mode = BasicHttpSecurityMode.None;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
myBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
myBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;

I changed my code like below…

BasicHttpBinding myBinding = new BasicHttpBinding();

myBinding.Name = "BasicHttpBinding_Service";
myBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
myBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
myBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;

And to my utter surprise, it started to work :). !!!

By Dibyasingh Tripathy
Senior Software Engineer @Team DynamicsCRM.
Mindfire Solutions

 

Tags: , , , , , , , , , , , , , , , ,

Calling external Web Service from a CRM 2011 Plug-in

Introduction

This blog explains how to call external Web Service from a CRM 2011 Plug-in.

Background

Sometimes we need to call a Web Service from a Plug-in. We had a similar requirement, but while trying to access the service, we got the following error.

“Could not find default endpoint element that references contract ‘ServiceReference.Service′ in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.”

Problem

The reason for this is because the configuration information for the Web Service from the client side is missing.

Using the Code

So, now in case of our plugin, we need to define the binding and endpoint information programmatically. Something like this…

using System;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using TestPluginConnectWebService.TestService;

namespace TestPluginConnectWebService
{
    public class TestConnectWebService : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            //Context = Info passed to the plugin at runtime
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

            //Service = access to data for modification
            IOrganizationService service = factory.CreateOrganizationService(context.UserId);

            // Adding Basic Http Binding and its properties.
            BasicHttpBinding myBinding = new BasicHttpBinding();
            myBinding.Name = "BasicHttpBinding_Service";
            myBinding.Security.Mode = BasicHttpSecurityMode.None;
            myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
            myBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
            myBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;

            // Endpoint Address defining the asmx Service to be called.
            EndpointAddress endPointAddress = new EndpointAddress(@"http:///ReturnRecords/GetRecords.asmx");

            // Call to the Web Service using the Binding and End Point Address.
            GetGrantRecordsSoapClient myClient = new GetGrantRecordsSoapClient(myBinding, endPointAddress);

            var ab = myClient.GetGrants();

            if (ab != null)
            {
                 throw new InvalidPluginExecutionException("Success");
            }
            else
            {
                 throw new InvalidPluginExecutionException("Failure");
            }
        }
    }
}

This way we would be able to access our Web Service inside Plug-in.

Note

The following are some of the points that needs special attention.

Sandboxed Plug-ins can access network through the HTTP and HTTPS protocols. This capability provides support for accessing popular Web resources like Social Sites, News Feeds, Web services, and more.
The following Web access restrictions apply to this Sandbox capability.

  • Only the HTTP and HTTPS protocols are allowed.
  • Access to localhost (loopback) is not permitted.
  • IP addresses cannot be used. You must use a named Web address that requires DNS name resolution.

Reference – [MSDN] Plug-in Isolation, Trusts, and Statistics

By Dibyasingh Tripathy
Senior Software Engineer @Team DynamicsCRM.
Mindfire Solutions

 

Tags: , , , , , , , , , , , , , , , , , , , , , ,

Closing Opportunity using SOAP Request with Close Date

Project scenario

Using SOAP request I need to close opportunity from a custom HTML page. While closing opportunity, I need to send date also as close date for ‘Close Opportunity’.

Explanation of Code

Here format of date is very much different which is used to send through SOAP. I faced problem and stuck for 3 to 4 hours for this.

Finally I did.

Suppose,

var dateToSend = new Date();

Take a Date object and format it as :

dateToSend.format("yyyy-MM-ddThh:mm:ss.sszzz");

Only this Date format is taken by SOAP request.

Total SOAP request is as follows :

function CreateSoapXml(Id, Description, ActualRevenue, CloseDate, CompetitorId, Subject, Status) {
    var callback;

    xml += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
    xml += " <s:Body>";
    xml += " <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
    xml += " <request i:type=\"b:LoseOpportunityRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
    xml += " <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
    xml += " <a:KeyValuePairOfstringanyType>";
    xml += " <c:key>OpportunityClose</c:key>";
    xml += " <c:value i:type=\"a:Entity\">";
    xml += " <a:Attributes>";
    xml += " <a:KeyValuePairOfstringanyType>";
    xml += " <c:key>opportunityid</c:key>";
    xml += " <c:value i:type=\"a:EntityReference\">";
    xml += " <a:Id>" + Id + "</a:Id>";
    xml += " <a:LogicalName>opportunity</a:LogicalName>";
    xml += " <a:Name i:nil=\"true\" />";
    xml += " </c:value>";
    xml += " </a:KeyValuePairOfstringanyType>";
    xml += " <a:KeyValuePairOfstringanyType>";
    xml += " <c:key>description</c:key>";
    xml += " <c:value i:type=\"d:string\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">" + Description + "</c:value>";
    xml += " </a:KeyValuePairOfstringanyType>";
    xml += " <a:KeyValuePairOfstringanyType>";
    xml += " <c:key>competitorid</c:key>";
    xml += " <c:value i:type=\"a:EntityReference\">";
    xml += " <a:Id>" + CompetitorId + "</a:Id>";
    xml += " <a:LogicalName>competitor</a:LogicalName>";
    xml += " <a:Name i:nil=\"true\" />";
    xml += " </c:value>";
    xml += " </a:KeyValuePairOfstringanyType>";
    xml += " <a:KeyValuePairOfstringanyType>";
    xml += " <c:key>actualrevenue</c:key>";
    xml += " <c:value i:type=\"a:Money\">";
    xml += " <a:Value>" + ActualRevenue + "</a:Value>";
    xml += " </c:value>";
    xml += " </a:KeyValuePairOfstringanyType>";
    xml += " <a:KeyValuePairOfstringanyType>";
    xml += " <c:key>subject</c:key>";
    xml += " <c:value i:type=\"d:string\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">" + Subject + "</c:value>";
    xml += " </a:KeyValuePairOfstringanyType>";
    xml += " <a:KeyValuePairOfstringanyType>";
    xml += " <c:key>actualend</c:key>";
    xml += " <c:value i:type=\"d:dateTime\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">" + CloseDate + "</c:value>";
    xml += " </a:KeyValuePairOfstringanyType>";
    xml += " </a:Attributes>";
    xml += " <a:EntityState i:nil=\"true\" />";
    xml += " <a:FormattedValues />";
    xml += " <a:Id>00000000-0000-0000-0000-000000000000</a:Id>";
    xml += " <a:LogicalName>opportunityclose</a:LogicalName>"
    xml += " <a:RelatedEntities />";
    xml += " </c:value>";
    xml += " </a:KeyValuePairOfstringanyType>";
    xml += " <a:KeyValuePairOfstringanyType>";
    xml += " <c:key>Status</c:key>";
    xml += " <c:value i:type=\"a:OptionSetValue\">";
    xml += " <a:Value>" + Status + "</a:Value>";
    xml += " </c:value>"
    xml += " </a:KeyValuePairOfstringanyType>";
    xml += " </a:Parameters>";
    xml += " <a:RequestId i:nil=\"true\" />";
    xml += " <a:RequestName>LoseOpportunity</a:RequestName>";
    xml += " </request>";
    xml += " </Execute>";
    xml += " </s:Body>";
    xml += "</s:Envelope>";
}

//Then send SOAP request as :

var req = new XMLHttpRequest();
req.open("POST", GetServerUrl(), (callback != null));
req.setRequestHeader("Accept", "application/xml, text/xml, */*");
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
req.send(xml);

if (req.readyState == 4) {
    if (req.status == 200) {
        alert("Opportunity Closed");
        Cancel();
        //window.opener.location.reload();
    }
    else {
        //errorCallback(_getError(req.responseXML));
        alert("There is an error occured");
    }
}

By Anish Thakur
Senior Software Engineer @Team DynamicsCRM.
Mindfire Solutions

 

Tags: , , , , , , , , , , , , , , , , ,

 
%d bloggers like this: