Monday, December 4, 2017

Exploring Sitecore xConnect: Working with Contacts and the xConnect Client API

Standard

Background

As I started exploring xConnect in XP 9, one of the questions I asked myself was how the change in the xDB contact and interaction model architecture would effect my existing Sitecore xDB implementations if we decided to upgrade. 

With this in mind, the focus of this post is on the changes to contact identification and updating contacts within Sitecore context, and what you need to know when you start working with the xConnect Client API in and outside of Sitecore context.

The xConnect documentation site was my initial point of reference, along with some guidance from Jason Wilkerson's series of posts

Working with Contacts

Identifying Contacts 

In XP 7.5 - 8.x, each xDB contact could be identified using a single, unique value. 

Your code looked like this:

 Tracker.Current.Session.Identify("menglish");  
 Tracker.Current.Contact.Identifiers.IdentificationLevel = ContactIdentificationLevel.Known;  

This changed in XP 9, as you now need to specify the source along with a unique value when identifying the contact.

 Tracker.Current.Session.IdentifyAs("corporateweb", "menglish");  
 //corporateweb is the source and menglish is the identifier.   

In XP 9, each contact can have multiple identifiers and sources within the new model. The magic lies in the ability to identify and merge contacts from all different sources together into a single contact.

Omnichannel contact identification and merging is a powerful thing!



Updating Contacts

In XP 7.5 - 8.x, updating contact information in xDB was achieved by using the Tracker Contact (Tracker.Current.Contact), and calling GetFacet using the Interface of the type and passing in the name of the Facet. 

Your code looked like this:

 var existingContact = Tracker.Current.Contact;  
                            
 var personalFacet = existingContact.GetFacet<IContactPersonalInfo>("Personal");  
   
 personalFacet.FirstName = "Martin";  
 personalFacet.Surname = "English";  

This code will still run in XP 9, but it will no longer save the information to xDB. The update will only persist within session.

In XP 9, you need to use the xConnect Client API in order to update contact information.

 using (Sitecore.XConnect.Client.XConnectClient client = Sitecore.XConnect.Client.Configuration.SitecoreXConnectClientConfiguration.GetClient())  
 {  
      try  
      {  
           var webContactIdentifier = Tracker.Current.Contact.Identifiers.FirstOrDefault(t => t.Source == "corporateweb")?.Identifier;  
           var existingContact = client.Get<Sitecore.XConnect.Contact>(new IdentifiedContactReference("corporateweb", webContactIdentifier), new Sitecore.XConnect.ContactExpandOptions(PersonalInformation.DefaultFacetKey));  
   
           if (existingContact != null)  
           {  
                var personalFacet = existingContact.GetFacet<PersonalInformation>() ?? new PersonalInformation();  
   
                personalFacet.FirstName = "Martin";  
                personalFacet.LastName = "English";  
   
                client.SetFacet(existingContact, PersonalInformation.DefaultFacetKey, personalFacet);  
   
                client.Submit();  
           }  
      }  
      catch (XdbExecutionException ex)  
      {  
           //Oops, something went wrong  
      }  
 }  

Some important things that you need to be aware of:

  • The xConnect Contact and Tracker Contact models are different. 
  • The legacy facet classes are available in XP 9, so your existing code won't break. 
  • When you update your Tracker facet's in session, the update will persist throughout session, but won't save to xDB.
  • On session end, the Tracker contact data is run through a series of conversion pipelines where it ends up in xConnect. 
  • When the web contact returns to the site, the Tracker contact is hydrated through another set of conversion pipelines using the contact's data stored in xConnect.
  • If you have been updating xDB contact data using the Tracker Contact and calling GetFacet, you will need to update your code to use the xConnect Client API in order to update contact information. 

Working with the xConnect Client API

xConnect Client API within Sitecore Context

If you are working within a Sitecore Context, using the xConnect client is really straightforward. You don't have to worry about endpoints or certificates, as all that is abstracted. An example of this is shown above.

xConnect Client API outside Sitecore Context

Unsecured Client Connection

The example code that Jason has on GitHub requires an untrusted client connection in order to work.

Example:

 private static XConnectClient GetClient()  
 {  
   var config = new XConnectClientConfiguration(new XdbRuntimeModel(CollectionModel.Model), new Uri("https://sc90.xconnect"), new Uri("https://sc90.xconnect"));  
     
   try  
   {  
     config.Initialize();  
   }  
   catch (XdbModelConflictException ex)  
   {  
     Console.WriteLine(ex.Message);  
     throw;  
   }  
   
    return new XConnectClient(config);  
 }  

In order to run this, you need to disable these two xml files: sc.XConnect.Security.EnforceSSLWithCertificateValidation.xml and sc.XConnect.Security.EnforceSSL.xml located at:  [location of your xConnect instance]\App_data\config\sitecore\CoreServices

If you don't, you will receive the following Sitecore.XConnect.XdbCollectionUnavailableException "The HTTP response was not successful: Unauthorized".

Making this type of adjustment is fine if you are writing some POC code, but it is obviously not recommended as you start writing code for your customers.

Secured Client Connection

In order to establish a trusted client connection, you need to add the security certificate info to the request.

The most important thing you will need is the xConnect client certificate thumbprint that is found in the validateCertificateThumbprint setting in the your xConnect AppSettings.config, located at [location of your xConnect instance]\App_Config\ or in the ConnectionStrings.config of your Sitecore instance. The "FindValue" part of each xConnect Connection String contains this value.

For example:

  <add name="xconnect.collection.certificate" connectionString="StoreName=My;StoreLocation=LocalMachine;FindType=FindByThumbprint;FindValue=ADC6D07F383B2E116CC7510F4681EA34EE822F22" />  
    

To see this value within the certificate itself, you can navigate to it within your Personal Certificates store, shown below:

Using this thumbprint, we can make a secure xConnect client connection using the following code sample:

 var certThumbprint = "adc6d07f383b2e116cc7510f4681ea34ee822f22";  
 var xConnectUrl = "https://sc90.xconnect";  
   
 var options = CertificateWebRequestHandlerModifierOptions.Parse($"StoreName=My;StoreLocation=LocalMachine;FindType=FindByThumbprint;FindValue={certThumbprint}");  
 var certificateModifier = new CertificateWebRequestHandlerModifier(options);  
   
 var clientModifiers = new List<IHttpClientModifier>();  
 var timeoutClientModifier = new TimeoutHttpClientModifier(new TimeSpan(0, 0, 20));  
   
 clientModifiers.Add(timeoutClientModifier);  
   
 var collectionClient = new CollectionWebApiClient(new Uri($"{xConnectUrl}/odata"), clientModifiers, new[] { certificateModifier });  
 var searchClient = new SearchWebApiClient(new Uri($"{xConnectUrl}/odata"), clientModifiers, new[] { certificateModifier });  
 var configurationClient = new ConfigurationWebApiClient(new Uri($"{ xConnectUrl }/configuration"), clientModifiers, new[] { certificateModifier });  
 var config = new XConnectClientConfiguration(new XdbRuntimeModel(CollectionModel.Model), collectionClient, searchClient, configurationClient);  
   
 try  
 {  
      config.Initialize();  
 }  
 catch (Exception e)  
 {  
      Console.WriteLine(e);  
      throw;  
 }  
   
 return new XConnectClient(config);  

Wrap Up

I hope that this post has helped you understand some of the contact changes that xConnect presents us with, and also provides enough crumbs to get you started using the xConnect Client API.

Happy Exploring!


1 comment: