7

I am trying to save the data to the Experience Profile when the user submits the form, but the data is not getting displayed in the dashboard.

Below is my code for storing data:

public void IdentityUser(string FirstName, string LastName, string Email, string PhoneNumber)
    {
      // identify the user
      Tracker.Current.Session.IdentifyAs("contactform",Email);
      // get the contact
      var contact = Tracker.Current.Contact;
      // get the personal facet
      var contactPersonalInfo = contact.GetFacet<IContactPersonalInfo>("Personal");
      // set the contact's name
      contactPersonalInfo.FirstName = FirstName;
      contactPersonalInfo.Surname = LastName;
      // get the email facet
      var contactEmail = contact.GetFacet<IContactEmailAddresses>("Emails");
      // Create an email if not already present.
      // This can be named anything, but must be the same as "Preferred" if you want
      // this email to show in the Experience Profiles backend. 
      if (!contactEmail.Entries.Contains("Personal"))
      {
        contactEmail.Entries.Create("Personal");
      }
      // set the email
      var email = contactEmail.Entries["Personal"];
      email.SmtpAddress = Email;
      contactEmail.Preferred = "Personal";
      IContactPhoneNumbers phoneNumberInfo = contact.GetFacet<IContactPhoneNumbers>("Phone Numbers");
      if (!phoneNumberInfo.Entries.Contains("Mobile"))
      {
        phoneNumberInfo.Entries.Create("Mobile");
      }
      var mobile = phoneNumberInfo.Entries["Mobile"];
      mobile.Number = PhoneNumber;

//abandoning session so the data get persisted straight into xDb. I have tried removing them as well no effect
          Sitecore.Context.HttpContext.Session.Abandon();
          HttpContext.Current.Session.Abandon();
        }

The Experience Profile looks like this: enter image description here

I have updated my code as below after comments:

public void TrackAnonymousUser(string FirstName, string LastName, string Email, string PhoneNumber)
    {
      if (Sitecore.Analytics.Tracker.Current.Contact.IsNew)
      {
        var manager = Sitecore.Configuration.Factory.CreateObject("tracking/contactManager", true) as Sitecore.Analytics.Tracking.ContactManager;

        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 - use "xDB.Tracker"
          var trackerIdentifier = new IdentifiedContactReference("ContactForm", Sitecore.Analytics.Tracker.Current.Contact.ContactId.ToString("N"));

          // Get contact from xConnect, update and save the facet
          using (XConnectClient client = Sitecore.XConnect.Client.Configuration.SitecoreXConnectClientConfiguration.GetClient())
          {
            try
            {
             //contact is null
              var contact = client.Get<Sitecore.XConnect.Contact>(trackerIdentifier, new Sitecore.XConnect.ContactExpandOptions());

              if (contact != null)
              {
                if (contact.Personal() != null)
                {
                  contact.Personal().FirstName = FirstName;
                  contact.Personal().LastName = LastName;
                }
                else
                {
                  client.SetFacet<PersonalInformation>(contact, "MyFacetKey", new PersonalInformation()
                  {
                    FirstName = FirstName,
                    LastName = LastName,
                  });
                }
                if (contact.PhoneNumbers() != null)
                {
                  contact.PhoneNumbers().PreferredPhoneNumber = new Sitecore.XConnect.Collection.Model.PhoneNumber(string.Empty, PhoneNumber);
                }
                else
                {
                  client.SetFacet<PhoneNumberList>(contact, "MyFacetKey", new PhoneNumberList(new PhoneNumber(string.Empty, PhoneNumber), "mobile"));
                }
                if (contact.Emails() != null)
                {
                  contact.Emails().PreferredEmail = new EmailAddress(Email, true);
                }
                else
                {
                  client.SetFacet<EmailAddressList>(contact, "MyFacetKey", new EmailAddressList(new EmailAddress(Email, true), "email"));
                }
                client.Submit();

                // Remove contact data from shared session state - contact will be re-loaded
                // during subsequent request with updated facets
                //manager.RemoveFromSession(Sitecore.Analytics.Tracker.Current.Contact.ContactId);
              }
            }
            catch (XdbExecutionException ex)
            {
              // Manage conflicts / exceptions
            }
          }
        }
      }
    }

The problem is that my contact object is null even after pushing it to the xConnect repository. I can see in the comments as below:

// 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 - use "xDB.Tracker"
          var trackerIdentifier = new IdentifiedContactReference("ContactForm", Sitecore.Analytics.Tracker.Current.Contact.ContactId.ToString("N"));

I am not too sure where to find xDB.Tracker I can't seem to have reference to it. Is that the reason for the contact is null?

Furthermore, I see the following in the xConnect logs:

2018-02-14 09:37:26.897 +10:00 [Error] Sitecore.XConnect.Operations.AddContactOperation: Sitecore.XConnect.Operations.EntityOperationException: Operation #0, AlreadyExists, Contact
2018-02-14 09:37:26.897 +10:00 [Error] Sitecore.XConnect.Operations.SetFacetOperation`1[Sitecore.XConnect.Facet]: Sitecore.XConnect.Operations.FacetOperationException: Operation #1, ReferenceNotFound, Contact, Classification
2018-02-14 09:37:26.897 +10:00 [Error] ["XdbContextLoggingPlugin"] XdbContext Batch Execution Exception
Sitecore.XConnect.Operations.EntityOperationException: Operation #0, AlreadyExists, Contact
5
  • Have a look at the documents for working with xConnect, doc.sitecore.net/developers/xp/tracking-and-session/tracker/…. You need to write the data with the xConnect client as well as the cached facet values. Commented Feb 13, 2018 at 9:25
  • Which version of Sitecore are you using?
    – Gatogordo
    Commented Feb 13, 2018 at 11:03
  • @Gatogordo Sitecore version 9 initial release
    – Arun Kumar
    Commented Feb 13, 2018 at 12:45
  • In the initial release, you should use "xDB.Tracker" instead of Sitecore.Analytics.XConnect.DataAccess.Constants.IdentifierSource (as const string)
    – Gatogordo
    Commented Feb 14, 2018 at 8:19
  • And btw.. the code is not ok - check the examples again. You are mixing known and anonymous contacts.. (as I metnioned in my answer)
    – Gatogordo
    Commented Feb 14, 2018 at 8:22

3 Answers 3

6

Facets that are loaded into session can be edited but are not saved to xConnect on session end. You must use the xConnect Client API to update facets.

Check the documentation here.

You need to use XConnectClient and set your values there. Values set on the contact in session are not saved. This is a big difference between v8 and v9.

You must update a contact’s facets directly in xConnect using the xConnect Client API and manually update the copy of that facet that exists in session. The tracker does not lock contact data, which means that a contact with an ongoing session can still be updated by other systems. Holding a facet in session and submitting that facet to xConnect on session end could result in a conflict if a more recent version of that facet is available.

Make sure to note the difference between anonymous and known contacts. The code is a bit different. The documentation mentioned earlier has good code examples that will get you going.

1
  • I have updated my code in the question itself. I am getting issue with contact being returned as null. It would be greatly appreciated if you can help me.
    – Arun Kumar
    Commented Feb 14, 2018 at 2:46
2

The following code worked for me in Sitecore 9 initial release:

public void TrackAnonymousUser(string FirstName, string LastName, string Email, string PhoneNumber)
    {
        var manager = Sitecore.Configuration.Factory.CreateObject("tracking/contactManager", true) as Sitecore.Analytics.Tracking.ContactManager;

      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 - use "xDB.Tracker"
        var trackerIdentifier = new IdentifiedContactReference("xDB.Tracker", Sitecore.Analytics.Tracker.Current.Contact.ContactId.ToString("N"));

        // Get contact from xConnect, update and save the facet
        using (XConnectClient client = Sitecore.XConnect.Client.Configuration.SitecoreXConnectClientConfiguration.GetClient())
        {
          try
          {
            var contact = client.Get<Sitecore.XConnect.Contact>(trackerIdentifier, new Sitecore.XConnect.ContactExpandOptions());

            if (contact != null)
            {
              if (contact.Personal() != null)
              {
                contact.Personal().FirstName = FirstName;
                contact.Personal().LastName = LastName;
              }
              else
              {
                client.SetFacet<PersonalInformation>(contact, PersonalInformation.DefaultFacetKey, new PersonalInformation()
                {
                  FirstName = FirstName,
                  LastName = LastName,
                });
              }
              if (contact.PhoneNumbers() != null)
              {
                contact.PhoneNumbers().PreferredPhoneNumber = new Sitecore.XConnect.Collection.Model.PhoneNumber(string.Empty, PhoneNumber);
              }
              else
              {
                client.SetFacet<PhoneNumberList>(contact, PhoneNumberList.DefaultFacetKey, new PhoneNumberList(new PhoneNumber(string.Empty, PhoneNumber), "mobile"));
              }
              if (contact.Emails() != null)
              {
                contact.Emails().PreferredEmail = new EmailAddress(Email, true);
              }
              else
              {
                client.SetFacet<EmailAddressList>(contact, EmailAddressList.DefaultFacetKey, new EmailAddressList(new EmailAddress(Email, true), "email"));
              }
              client.Submit();

              // Remove contact data from shared session state - contact will be re-loaded
              // during subsequent request with updated facets
              //manager.RemoveFromSession(Sitecore.Analytics.Tracker.Current.Contact.ContactId);
            }
          }
          catch (Exception ex)
          {
            Log.Error("Error saving data to profile", ex, this);
            IdentityUserInSitecoreProfile(FirstName, LastName, Email, PhoneNumber);
            // Manage conflicts / exceptions
          }
        }
      }
    }
0

In your new code, you use the same facet key MyFacetKey over and over again. Best to set a DefaultFacetKey on your custom facet classes and use those. On the standard classes, they're already implemented. So, for example, do this:

client.SetFacet<PersonalInformation>(contact, PersonalInformation.DefaultFacetKey, new PersonalInformation()
              {
                FirstName = FirstName,
                LastName = LastName,
              });

So for all the other facets, also use Facet.DefaultFacetKey for these.

Also, when getting the contact, you won't get any facets unless you include them in the expand options; so change

 var contact = client.Get<Sitecore.XConnect.Contact>(trackerIdentifier, new Sitecore.XConnect.ContactExpandOptions());

to

 var facets = new string[] { PersonalInformation.DefaultFacetKey }; 
 var contact = client.Get<Sitecore.XConnect.Contact>(trackerIdentifier, new Sitecore.XConnect.ContactExpandOptions(facets));

Now you can get the facet of the contact object and manipulate it.

Example:

// Within the client using

var facets = new string[] { PersonalInformation.DefaultFacetKey }; 
var contact = client.Get<Sitecore.XConnect.Contact>(trackerIdentifier, new Sitecore.XConnect.ContactExpandOptions(facets));

// Assuming contact != null
var personalInformationFacet = contact.GetFacet<PeronalInformation>(PersonalInformation.DefaultFacetKey);

// Assuming personalInformationFacet != null
personalInformationFacet.FirstName = FirstName;
personalInformationFacet.LastName = LastName;

client.SetFacet<PersonalInformation>(contact,  PersonalInformation.DefaultFacetKey, personalInformationFacet);
await client.SubmitAsync();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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