If you are looking to send Form Data from Sitecore to Dynamics, one option you might consider is to first of all save the data to xDB. By taking this approach, you can then use the Sitecore to Dynamics Connector (which sits on top of Data Exchange Framework [DEF]) to pull data out of xDB and push it to Microsoft Dynamics.
This requires you to:
- Create a custom facet
- Create a custom model
- Deploy the custom model
- Create a custom save action
- Send data to XConnect
Create a custom facet
In Sitecore, facets are part of the xConnect/Experience Database (xDB) model. They’re essentially typed “buckets” of information attached to contacts or interactions (e.g., personal info, addresses, devices, campaigns).
Out of the box, Sitecore provides a set of predefined facets so you don’t have to build them all from scratch. Here are the main ones:
Contact Facets (attached to contacts in xDB)
-
Personal Information
(First name, last name, middle name, gender, job title, birthdate, etc.) -
Email Address List
(Primary and additional emails) -
Phone Number List
(Primary and additional phone numbers) -
Address List
(Billing, shipping, business, etc.) -
Consent Information
(Marketing consent and communication preferences — GDPR relevant) -
Identifiers
(IDs for mapping contacts across systems, e.g., CRM ID, loyalty number)
Custom Facet
The information we need to send to Dynamics will inevitabely contain a variety of new fields that are not covered by the OTB facets. Therefore, we need to create a new customised facet to hold our data. This sitecore article goes through the steps to create a custom facet and model in detail. Essentially we just need to create a new class that extends Sitecore.XConnect.Facet and add our custom properties. In our example, we decided to store any properties that will eventually be mapped to a Contact entity (in Dynamics) directly against our Marketing facet. Then to collect all form submissions into a collection of Lead objects, stored on the Marketing facet, with the view that each lead would then be mapped to an Inbound Interest entity (in Dynamics). We also add functionality to create or update the facet, by passing in a list of KeyValuePair<string, string>.
You can find the Marketing facet here.
Create a custom model
After creating the facet, you then need to define a new custom model to house it. This is covered in detail in the previously linked article. But essentially all you need to do is create a new class that provides an instance of the XdbModelBuilder. Then define the new facet as part of the build process
public static XdbModel Model { get; } = BuildModel(); private static XdbModel BuildModel() { XdbModelBuilder modelBuilder = new XdbModelBuilder("MarketingCollectionModel", new XdbModelVersion(1, 0)); // Reference the default collection model modelBuilder.ReferenceModel(CollectionModel.Model); // Register contact facets modelBuilder.DefineFacet<Contact, MarketingFacet>(MarketingFacet.DefaultFacetKey); return modelBuilder.BuildModel(); }
See example here.
Deploy the custom model
In order to start interacting with your new model, you need to first of all define what the model looks like in xConnect. To do this, you need to first of all 'serialise' the model to JSON, then deploy that representaion to the various different XConnect roles that need to be aware of it (i.e. Collection, Collection Search and Reference Data).
This process is covered in alot more detail in the sitecore article 'Deploy a custom model'.
In order to serialise the model, you need to create a console application as below:
class Program { static void Main(string[] args) { var x = new SerializeModel(); x.SerializeXConnectModel(); } } public class SerializeModel { private XdbModel _xDbModel = null; public void SerializeXConnectModel() { _xDbModel = MarketingCollectionModel.Model; var json = XdbModelWriter.Serialize(_xDbModel); var filename = _xDbModel + ".json"; File.WriteAllText(filename, json); } }
Create a custom save action
Now that XConnect knows about our custom model, we can start trying to save data to it. To do this, we create a custom save action, that can be added to any form in the GUI.
To do this, we extend the SubmitActionBase<string> sitecore class and override the Execute() action. In this action, we check for any errors and then pass the fields on to be submitted to our XConnect Service. Before doing so however, we need to pull out the field names and values and add them to a list of KeyValuePair<string, string>. This simplifies the data and removes the dependency on the ExperienceForms IViewModel, in preparation to pass it to our custom facet.
We use the following function to pull out the values, depending on their types:
private static string GetValue(object field) { if (field is CustomStringInputViewModel) { CustomStringInputViewModel customStringInputViewModel = field as CustomStringInputViewModel; return customStringInputViewModel.Value; } else if (field is DateViewModel) { DateViewModel dateField = field as DateViewModel; return dateField.Value?.ToString("dd/M/yyyy", CultureInfo.InvariantCulture); } else if (field is DropDownListViewModel) { DropDownListViewModel dropdownField = field as DropDownListViewModel; return dropdownField.Value.FirstOrDefault(); } else if (field is CheckBoxViewModel) { CheckBoxViewModel dropdownField = field as CheckBoxViewModel; if(dropdownField.Value) return "Y"; return "N"; } return field?.GetType().GetProperty("Value")?.GetValue(field, null)?.ToString() ?? string.Empty; }
The full code for the save action can be found here. For more info, on how to create a save action, see the sitecore walkthrough: Create a save action
Send data to XConnect
The final step in the process is to send the data to XConnect, which is done using our XConnectService.
To begin with, the service gets a contact from XConnect using the GetContactFromXConnect() method. This checks to see if the contact in session is new (using Tracker.Current.Contact.IsNew), if so it saves that contact to XConnect. We then retieve the new (or existing) contact back from XConnect, making sure to grab any facets that belong to it (i.e. PersonalInformation, EmailAddressList, PhoneNumberList, AddressList or MarketingFacet).
private Sitecore.XConnect.Contact GetContactFromXConnect(Sitecore.Analytics.Tracking.ContactManager manager, XConnectClient client, Sitecore.XConnect.Contact contact) { if (Tracker.Current.Contact.IsNew) { Log.Info("Creating NEW contact", this); Tracker.Current.Contact.ContactSaveMode = ContactSaveMode.AlwaysSave; manager.SaveContactToCollectionDb(Tracker.Current.Contact); try { var trackerIdentifier = new IdentifiedContactReference(Sitecore.Analytics.XConnect.DataAccess.Constants.IdentifierSource, Tracker.Current.Contact.ContactId.ToString("N")); var contactExpandOptions = new ContactExpandOptions(PersonalInformation.DefaultFacetKey, EmailAddressList.DefaultFacetKey, MarketingFacet.DefaultFacetKey, PhoneNumberList.DefaultFacetKey, AddressList.DefaultFacetKey); contact = client.Get<Sitecore.XConnect.Contact>(trackerIdentifier, new ContactExecutionOptions(contactExpandOptions)); } catch (XdbExecutionException ex) { Log.Error($"Failed to get NEW contact from xDB) \n\r Exception: {ex}", this); } } else { Log.Info("Updating EXISTING contact", this); var anyIdentifier = Tracker.Current.Contact.Identifiers.FirstOrDefault(); if (anyIdentifier != null) { try { var trackerIdentifier = new IdentifiedContactReference(anyIdentifier.Source, anyIdentifier.Identifier); var contactExpandOptions = new ContactExpandOptions(PersonalInformation.DefaultFacetKey, EmailAddressList.DefaultFacetKey, MarketingFacet.DefaultFacetKey, PhoneNumberList.DefaultFacetKey, AddressList.DefaultFacetKey); contact = client.Get<Sitecore.XConnect.Contact>(trackerIdentifier, new ContactExecutionOptions(contactExpandOptions)); if (contact == null) Log.Warn($"Failed to get EXISTING contact from xDB \n\r anyIdentifier: {anyIdentifier.Source}|{anyIdentifier.Identifier}", this); } catch (XdbExecutionException ex) { Log.Error($"Failed to get EXISTING contact from xDB \n\r Exception: {ex}", this); } } } return contact; }
If the contact is new, we also attempt to Identify (a special sitecore process that gives a contact a unique identifier) the contact, using their email address.
Then we take the XConnect contact and either add (if it doesnt exist) or update each of the different facets. We do this by cycling through each of the different fields (passed to us from the save action), and checking to see if their exists a property on the facet that matches the name of the field in our list of KeyValuePair<string, string>. If found, then the value is assigned. In the exact same manner, our custom MarketingFacet is updated, with contact information added directly to the facet and lead information added as a new lead in the collection.
Finally, we submit the updated contact back to XConnect. Then unload and reload the contact back into session, so as to bring the updated facets into the object in session.
You can find a copy of the XConnectService in full here on the SitecoreToDynamics Repository.