MIM 2016/FIM 2010 R2 ECMA2 SalesForce SOAP Webservice Connector

Overview SalesForce for Developers

The SalesForce SOAP API is quite a well-documented stack. There are various functions to help you do your task. For this blog post I will show how to retrieve users from SalesForce. There are many other things that you can do with the ECMA2 SalesForce connector. Such as

  • Create new user
  • Add user to Role
  • Create contact
  • Enable/Disable an account
  • And much more…..

Create Webservice Description WSDL for the Proxy client.

WSDL is a description of the services or functions that are advertised by the Webservice. There are two ways to supply the information of the of the Webservice to the Proxy client, you can do it via the url or you can put the SOAP data into a file and supply the data. I prefer the second option, there are some items to work out but I find it is a faster way to grab the data.

You can generate the SalesForce wsdl from here.

I will save it as “SFenterpriseVS.wsdl”

Generate the Proxy Client

You can add the Webservice to your ECMA2 solution or you can add it as a separate dll reference. I like to add it as a separate reference. If anything changes in the API, I don’t have to recompile my ECMA.

In VStudio open a new solution. Chose Class Library, name it “SalesForceConnector”

Right click on the Project and select “Add service reference”

Click Advanced

Click “Add web reference”

Enter the save file path

Enter ‘SalesForceWebReference’ in the ‘Web reference name’ text box and click on ‘Add Reference’ button. Which will generate the .NET proxy class of the client to consume.

There is proxy class generation does something that will throw a VS compile error.

Click on the “Show All Files” button on the right top.

Look for the Reference.cs file. Open the file.

Search for “[][]” and replace it with “[]”

In VStudio, compile the solution

Creating the ECMA2 Dll file

  1. In the Synchronization Manager, at the top, select Management Agents.
  2. At the top, select Actions, select Create Extension Projects, and choose Extensible Connectivity 2.0 Extension. This will open a Create Extension Project dialog box.
  3. In the Create Extension Project dialog box, next to Programming Language: select Visual C#
  4. In the Create Extension Project dialog box, next to Visual Studio Version: select Visual Studio 2010.
  5. In the Create Extension Project dialog box, next to Project Name: enter SalesForce_ECMA2.
  6. Click OK. This will launch Visual Studio 2010.
  7. On the right, at the top, under the Solutions Explorer, double-click SalesForce_ECMA2. This will open the file with code that has already been written.
  8. Note: if the firstname is blank, ECMA will through an error, so I have put a condition that if firstname is blank then use the lastname as firstname.
  9. Add the following references. Add a reference to the SalesForceConnector.dll


  1. Copy and paste this code (overwrite what is there)

<pre><code>

using System;

using System.Data;

using System.IO;

using System.Xml;

using System.Text;

using System.Collections.Specialized;

using Microsoft.MetadirectoryServices;

using System.Collections.ObjectModel;

using System.Collections.Generic;

using System.Web.Services.Protocols;

using SalesForceConnector.SalesForceWebReference;

using System.Net;

namespace FimSync_Ezma

{
public
class
EzmaExtension :

//IMAExtensible2CallExport,
IMAExtensible2CallImport,
//IMAExtensible2FileImport,
//IMAExtensible2FileExport,
//IMAExtensible2GetHierarchy,
IMAExtensible2GetSchema,
IMAExtensible2GetCapabilities,
IMAExtensible2GetParameters
//IMAExtensible2GetPartitions

{
private
int m_importDefaultPageSize = 1200;

private
int m_importMaxPageSize = 1500;

private
SforceService binding;

public
string Password;

public
string Username;

public
string SecurityToken;

public
string myFirst;

public
string myLast;

public
string myFull;

public
string myAccount;

//
// Constructor
//
public EzmaExtension()

{
//
// TODO: Add constructor logic here
//

}
public
MACapabilities Capabilities

{
get

{
MACapabilities myCapabilities = new
MACapabilities();

myCapabilities.ConcurrentOperation = true;

myCapabilities.ObjectRename = false;

myCapabilities.DeleteAddAsReplace = true;

myCapabilities.DeltaImport = true;

myCapabilities.DistinguishedNameStyle = MADistinguishedNameStyle.None;

myCapabilities.ExportType = MAExportType.AttributeUpdate;

myCapabilities.NoReferenceValuesInFirstExport = false;

myCapabilities.Normalizations = MANormalizations.None;
return myCapabilities;

}

}
public
int ImportDefaultPageSize

{
get

{
return m_importDefaultPageSize;

}

}
public
int ImportMaxPageSize

{
get

{
return m_importMaxPageSize;

}

}
public
CloseImportConnectionResults CloseImportConnection(CloseImportConnectionRunStep importRunStep)

{
//Close the Salesforce connection

binding.logout();
return
new
CloseImportConnectionResults();

}
public
IList<ConfigParameterDefinition> GetConfigParameters(KeyedCollection<string, ConfigParameter> configParameters, ConfigParameterPage page)

{
List<ConfigParameterDefinition> configParametersDefinitions = new
List<ConfigParameterDefinition>();

switch (page)

{
case
ConfigParameterPage.Connectivity:

configParametersDefinitions.Add(ConfigParameterDefinition.CreateStringParameter(“Username”, “”));

configParametersDefinitions.Add(ConfigParameterDefinition.CreateStringParameter(“Password”, “”));

configParametersDefinitions.Add(ConfigParameterDefinition.CreateStringParameter(“SecurityToken”, “”));


break;
//case ConfigParameterPage.Global:
// break;
//case ConfigParameterPage.Partition:
// break;
//case ConfigParameterPage.RunStep:
// break;

}
return configParametersDefinitions;

}


public
GetImportEntriesResults GetImportEntries(GetImportEntriesRunStep importRunStep)

{


List<CSEntryChange> csentries = new
List<CSEntryChange>();


GetImportEntriesResults importReturnInfo;


// Make a login call to Salesforce

LoginToSaleforceService(this.Username, this.Password, this.SecurityToken);


// Retrieve some data using a query


String soqlQuery = “select Id,FirstName, LastName,Name,Username from User”;


sObject[] records = null;


QueryResult qr = binding.query(soqlQuery);


if (qr.size > 0)

{

records = qr.records;


for (int i = 0; i < records.Length; i++)

{


User user = (User)records[i];


if (user.FirstName == null)

{

myFirst = user.LastName;

}


if (!(user.FirstName == null))

{

myFirst = user.FirstName;

}

myLast = user.LastName;

myFull = user.Name;

myAccount = user.Username;


CSEntryChange csentry1 = CSEntryChange.Create();

csentry1.ObjectModificationType = ObjectModificationType.Add;

csentry1.ObjectType = “Person”;

csentry1.AttributeChanges.Add(AttributeChange.CreateAttributeAdd(“Firstname”, myFirst));

csentry1.AttributeChanges.Add(AttributeChange.CreateAttributeAdd(“Lastname”, myLast));

csentry1.AttributeChanges.Add(AttributeChange.CreateAttributeAdd(“Fullname”, myFull));

csentry1.AttributeChanges.Add(AttributeChange.CreateAttributeAdd(“AccountName”, myAccount));

csentries.Add(csentry1);

}

}

importReturnInfo = new
GetImportEntriesResults();

importReturnInfo.MoreToImport = false;

importReturnInfo.CSEntries = csentries;


return importReturnInfo;

}


public
Schema GetSchema(KeyedCollection<string, ConfigParameter> configParameters)

{

Microsoft.MetadirectoryServices.SchemaType personType = Microsoft.MetadirectoryServices.SchemaType.Create(“Person”, false);


//myname = configParameters[“myname”].Value;


string myattribute = “Firstname”;


string myattribute2 = “Lastname”;


string myattribute3 = “AccountName”;


string myattribute5 = “Fullname”;


if (myattribute == “Firstname”)

{

personType.Attributes.Add(SchemaAttribute.CreateAnchorAttribute(myattribute, AttributeType.String));

}


if (myattribute2 == “Lastname”)

{

personType.Attributes.Add(SchemaAttribute.CreateAnchorAttribute(myattribute2, AttributeType.String));

}


if (myattribute3 == “AccountName”)

{

personType.Attributes.Add(SchemaAttribute.CreateAnchorAttribute(myattribute3, AttributeType.String));

}


if (myattribute5 == “Fullname”)

{

personType.Attributes.Add(SchemaAttribute.CreateAnchorAttribute(myattribute5, AttributeType.String));

}


Schema schema = Schema.Create();

schema.Types.Add(personType);


return schema;

}


public
OpenImportConnectionResults OpenImportConnection(KeyedCollection<string, ConfigParameter> configParameters, Schema types, OpenImportConnectionRunStep importRunStep)

{


this.Username = configParameters[“Username”].Value;


this.Password = configParameters[“Password”].Value;


this.SecurityToken = configParameters[“SecurityToken”].Value;


return
new
OpenImportConnectionResults();

}


public
ParameterValidationResult ValidateConfigParameters(KeyedCollection<string, ConfigParameter> configParameters, ConfigParameterPage page)

{


ParameterValidationResult myResults = new
ParameterValidationResult();


return myResults;

}


private
void LoginToSaleforceService(string UserName, string Password, string SecurityToken)

{


string username = UserName;


string password = Password + SecurityToken;


// Create a service object

binding = new
SforceService();


// Timeout after a minute

binding.Timeout = 60000;


// Try logging in


LoginResult lr;


Console.WriteLine(“\nLogging in…\n”);

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

lr = binding.login(username, password);


/** Once the client application has logged in successfully, it will use


* the results of the login call to reset the endpoint of the service


* to the virtual server instance that is servicing your organization


*/


// Save old authentication end point URL


String authEndPoint = binding.Url;


// Set returned service endpoint URL

binding.Url = lr.serverUrl;


/** The sample client application now has an instance of the SforceService


* that is pointing to the correct endpoint. Next, the sample client


* application sets a persistent SOAP header (to be included on all


* subsequent calls that are made with SforceService) that contains the


* valid sessionId for our login credentials. To do this, the sample


* client application creates a new SessionHeader object and persist it to


* the SforceService. Add the session ID returned from the login to the


* session header


*/

binding.SessionHeaderValue = new
SessionHeader();

binding.SessionHeaderValue.sessionId = lr.sessionId;

}

};

}

 </code></pre>

Create the ECMA2 Salesforce Connector

  1. In the Synchronization Manager, click Management Agents
  2. In the Synchronization Service, at the top, select Management Agents and over on the right, under Actions, select Create. This will open a Create Management Agent wizard.
  3. On the Create Management Agent screen, next to Management Agent for: select Extensible Connectivity 2
  4. On the Create Management Agent screen, next to Name: enter Salesforce_ECMA2

  1. Remove the check from Run this management agent in a separate process. This will allow for debugging should the need arise.
  2. Click Next.
  3. On the Select Extension DLL screen, click Browse and select SalesForce_ECMA2.dll. Click OK.
  4. On the Select Extension DLL screen, click Refresh interfaces. This will populate the box below. It should support Import

  1. Click Next.
  2. On the Connectivity screen, next to Security Token enter: the security Token for the userid. If you don’t have one, it can be generated for you by the Admin.
  3. On the Connectivity screen, next to username enter: the id of the MIM salesforce account
  4. On the Connectivity screen, next to password enter: password
  5. Enter the domain

  1. Click Next.


  1. On the Select Object Types screen, select Person.

  1. Click Next.
  2. On the Select Attributes screen, select all four.

  1. Click Next.
  2. On the Configure Anchors screen, click Specify Anchor. This will open a Set Anchor dialog box.
  3. On the Set Anchor dialog box, you may see several attributes there, click specify anchor and remove all attributes except Accountname and click Add>. Click OK.

  1. Click Next.
  2. On the Configure Connector Filter screen, click Next.

  1. Click Next.
  2. On the Configure Connector Join and Projection, click Next.

Click Next

Click Next

Click finish

  1. Configure Full Import run profile
  2. Run the Import, it should be successful and you can test sync via the preview screen to see that the person is provisioned to the MV.