4

In our Sitecore 8.1-3 solution I have created a custom xDB facet with a few different elements. When users log in to our site we call Tracker.Current.Session.Identify(emailAddress); to properly identify them. I believe that what happens when we identify a user is that Sitecore gets a copy of their current Contact data and puts it in session. (I may be wrong about this)

Then later on our site if a user does certain things we have some custom code that updates some data in their xDB Contact record. The code that we use to update their xDB Contact record looks like this:

var manager = Sitecore.Configuration.Factory.CreateObject("tracking/contactManager", true) as ContactManager;

var lockResult = manager.TryLoadContact(_contact.ContactId);

switch (lockResult.Status)
{
    case LockAttemptStatus.Success:
        var lockedContact = lockResult.Object;
        lockedContact.ContactSaveMode = ContactSaveMode.AlwaysSave;

        //Update the contact

        //Marketing Info
        var marketingInfo = lockedContact.GetFacet<IMarketingData>("Marketing Data");

        marketingInfo.Organization = txtOrganization.Text;
        marketingInfo.Industries = txtIndustries.Text;
        marketingInfo.ProductTypes = txtProductTypes.Text;

        manager.SaveAndReleaseContactToXdb(lockedContact);

        break;
    case LockAttemptStatus.NotFound:
        Log.Info("LockAttempStatus.NotFound", this);
        break;
    default:
        Log.Info("Contact could not be locked", this);
        break;
}

So when that code runs it immediately updates the contact record in xDB. I have used RoboMongo to verify this. However what I have noticed is that if I let the user's session expire that the contact record in xDB seems to revert back to the data that was there before. I am guessing that Sitecore keeps a copy of the contact record in session and when the session expires it writes it back to xDB and overwrites the changes that my code made.

Is there a way to prevent this? I am thinking that maybe there is some way after the manager.SaveAndReleaseContactToXdb line of code that I could update the contact data stored in session so that it now has the updated data.

8

The solution

If you are sure that the contact currently has a session on the site, then you should NOT release it to the Collection Database.

Instead, you should use this method:

manager.SaveAndReleaseContact(lockedContact);

This will save the contact data back to the Shared Session. All data will be saved to the Collection Database at the end of the session.

Background

ContactManager class uses two storage types underneath:

  • ContactRepository which works directly with the Collection database;
  • SharedSessionStateManager which works with the Shared Session.

When you call .TryLoadContact(contactId) and the contact does not have a live session, then the contact will be locked in the Collection DB and loaded into the Shared Session. It is then also locked in the Shared Session so that your current thread can work with the contact exclusively.

If you call .TryLoadContact(contactId) and the contact does have a live session in the same cluster, that means that the contact is already present in the Shared Session (and is locked in the Collection Database). The contact will be locked and loaded from the Shared Session without querying the Collection DB.

At this point, regardless of where the contact was loaded from, it is now in the Shared Session and locked to your thread. You can now update contact data before releasing it.

When you call .SaveAndReleaseContact(contact), the contact is released in the Shared Session, so other threads and members of the web cluster can use it. It is not released in the Collection DB yet - it remains in the Shared Session until it expires.

When you call .SaveAndReleaseContactToXdb(contact), it will be saved and unlocked in the Collection Database. This is not what you want in your scenario, because the web instance should be able to continue working with the contact. This method does NOT remove the contact from the Shared Session, so xDB will assume it still has a lock on the contact. This is why it simply overwrites the data at the end of the session.

Note that there is another override of the last method: .SaveAndReleaseContactToXdb(contactId), which takes a contact ID instead of a contact object. The important difference is that this method WILL remove the contact from the Shared Session before saving it to xDB.

Choosing between the available ways of accessing the contact

  1. If you are in a page request, you should access the current contact via Tracker.Current.Contact.

  2. If your code is not in a page request, but the user may have a live session, use the ContactManager with the methods described above.

  3. If the contact is not in a live session right now, you should use ContactRepository. See an example on how to use it here.

  • My ultimate goal is to be able to write a wrapper class that represents a user on our site. Sometimes the user will be registered on our site and have a Membership account with a few custom fields in the Sitecore custom profile as well as custom facets in xDB. I was hoping to write basic methods to retrieve user data and save user data. But it seems to be a bit more complex than that. :) – Corey Burnett Dec 13 '16 at 13:59
  • @CoreyBurnett Yeah, xDB has a distributed architecture, and so the API is not quite straightforward (yet). Hopefully, this will improve a lot with Sitecore 8.3 and XConnect. – Dmytro Shevchenko Dec 13 '16 at 14:01
  • is there any way to retrieve a contact using Contact Manager when you only know the email address (identifier)? – Corey Burnett Dec 14 '16 at 19:11
  • @CoreyBurnett Yes, use .LoadContactReadOnly(identifier). This will not lock the contact anywhere and will not load it into the Shared Session. Note that ContactRepository has the same method. – Dmytro Shevchenko Dec 14 '16 at 19:16
  • Ok. And I assume that LoadContactReadOnly figures out whether to load the contact from xDB or from SharedSession - right? – Corey Burnett Dec 14 '16 at 19:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.