So, Sitecore 9 has the replaced xDB in MongoDB with XConnect. Fine. Our contacts will be stored there (ultimately, in SQL server). Fine too.
One question though – how do we get the Sitecore.XConnect.Contact object for the current (possibly unidentified) contact?
It used to be that you could get the Contact record from Tracker.Current.Session.Contact, but that doesn’t work any more – that gets the Sitecore.Analytics.Tracking.Contact, which isn’t the same type at the Sitecore.XConnect.Contact which is replacing it. Confused yet?
Well, to make matters worse, the Sitecore.Analytics.Tracking.Contact.ContactId may or may not match the Sitecore.XConnect.Contact.ContactId. I think.
I couldn’t find any information about how to resolve the Tracker ID to the XConnect contact. What’s a boy to do?
EDIT: Sadly, there is a better way than below. Unfortunately, it’s in a different bit of the documentation. See https://doc.sitecore.net/developers/xp/tracking-and-session/tracker/tracking-contacts/contact-facets/update-facets.html
So something like this:
public Sitecore.XConnect.Contact LoadContactFromTracker() { if (Tracker.Current == null || Tracker.Current.Contact == null) return null; if (Sitecore.Analytics.Tracker.Current.Contact.IsNew) { if (_manager != null) { // Save contact to xConnect; at this point, a contact has an anonymous // TRACKER IDENTIFIER, which follows a specific format. Do not use the contactId overload // and make sure you set the ContactSaveMode as demonstrated Sitecore.Analytics.Tracker.Current.Contact.ContactSaveMode = ContactSaveMode.AlwaysSave; _manager.SaveContactToCollectionDb(Sitecore.Analytics.Tracker.Current.Contact); } } // Now that the contact is saved, you can retrieve it using the tracker identifier // NOTE: Sitecore.Analytics.XConnect.DataAccess.Constants.IdentifierSource is marked internal in 9.0 Initial and cannot be used. If you are using 9.0 Initial, pass "xDB.Tracker" in as a string. string tId = Sitecore.Analytics.Tracker.Current.Contact.ContactId.ToString("N"); var trackerIdentifier = new IdentifiedContactReference(Sitecore.Analytics.XConnect.DataAccess.Constants.IdentifierSource, tId); // Get contact from xConnect, update and save the facet using (XConnectClient client = Sitecore.XConnect.Client.Configuration.SitecoreXConnectClientConfiguration.GetClient()) { try { return client.Get<Sitecore.XConnect.Contact>(trackerIdentifier, _defaultExpandOptions); } catch (XdbExecutionException ex) { Log.Error($"Could not load contact by identifier {tId}", ex, this); return null; } } }
Below is what I’d originally come up with – but it’s probably worth ignoring….
Hanging around in the guts of XConnect, I found a method Sitecore.Analytics.XConnect.DataAccess.XConnectDataAdapterProvider.GetContactByTrackerContactId() It takes a tracker contact ID, and resolves to to an XConnect Contact:
Huzzah! That constant string – “xDB.Tracker” – seems interesting (and we’ll come back to it). So, what does the contactId.ToXConnectIdentifier() method do? Some complicated calculation, surely?
Na. Guid.ToString(“N”) . Fine.
Okay, so what is this ContactIdentifier stuff? Why xDB.Tracker? Well, a contact in XConnect can have multiple identifiers. These can be seen in the database:
The pixelated source is the name of the website I’m working on; this Identifier was added using the method Tracker.Current.Session.IdentifyAs(sitename, emailAddress) . Bonus points to those of you who spotted that its value is the hex representation of “andy@example.com”.
However, the other 2 are standard, and are talked about here: xConnect Contact identifiers
The Alias is simply an invariant internal identifier for a contact. xDB.Tracker is, well, the tracking identifier! The value of this is the hex representation of a Guid [2333363fdafb48ba984d6278dd33867d], which also happens to be my Global Analytics cookie value:
Great. We can join Tracker ID to XConnect Contact. How about a method to do this?
private Sitecore.XConnect.Contact GetContactByTrackerId(Guid trackerId) { if (trackerId == Guid.Empty) throw new ArgumentException("trackerId cannot be empty"); using (Sitecore.XConnect.Client.XConnectClient client = Sitecore.XConnect.Client.Configuration.SitecoreXConnectClientConfiguration.GetClient()) { // Guid N format seems to be used in Sitecore.Analytics.XConnect.DataAccess.IdConversionExtensions // See also Sitecore.Analytics.XConnect.DataAccess.XConnectDataAdapterProvider IdentifiedContactReference reference = new IdentifiedContactReference("xDB.Tracker", trackerId.ToString("N")); Sitecore.XConnect.Contact contact = client.Get(reference, _defaultExpandOptions); return contact; } }
If the “IdentifiedContactReference” is causing confusion – why would we be using this with an automatically assigned Tracker ID for a visitor who is anonymous – this of it like this. Your visitor has been given an identity (“43”) – but they’re still anonymous. It’s just like those numbered tickets you’d get at the supermarket – you’re identified as customer 81, but nobody knows who you are.
That’s all we need, right? Well, no. There may not be a contact for a new visitor yet. The XConnect Contact only gets created on the Session End event. In that case, if we’re storing data about the (currently unidentified) contact, we might want to create the contact before the session end:
private Sitecore.XConnect.Contact CreateContactFromTrackerId(Guid trackerId) { if (trackerId == Guid.Empty) throw new ArgumentException("trackerId cannot be null"); using (Sitecore.XConnect.Client.XConnectClient client = Sitecore.XConnect.Client.Configuration.SitecoreXConnectClientConfiguration.GetClient()) { // See - Sitecore.Analytics.XConnect.DataAccess.XConnectDataAdapterProvider.GetOrAddContactByTrackerId var contact = new Sitecore.XConnect.Contact(new Sitecore.XConnect.ContactIdentifier("xDB.Tracker", trackerId.ToString("N"), ContactIdentifierType.Anonymous)); client.AddContact(contact); // Extension found in Sitecore.XConnect.Operations client.Submit(); return GetContactById(contact.Id ?? Guid.Empty); } }
Tada! Hope that helps.