[Sitecore 9]コンタクトのプロフィール情報をxDBに登録する

samatsu 3/25/2019 2748 N/A Sitecore Programming

Sitecore 9の環境で、ウェブサイト上で収集した個人のプロフィールをxDBに登録する方法のメモを記載します。登録した内容は Experience Profile アプリケーションで確認できるようになります。

今回のサンプルは、Set contact facets のドキュメントを参考に実装しています。

動作確認環境は Sitecore 9.1 Initial Release のスタンドアロン環境です。この記事は、Sitecoreの開発の知識(SXSDトレーニングを修了した程度の知識) を有していることを前提としています。そのため、Sitecoreの開発に関する基本的な手順は省いています。 

1. フォームの準備

何はともあれ、ユーザーの名前を登録するフォームを作成します。今回はモデルクラスとしてユーザーの名前を格納するシンプルなクラスを定義しました。

public class UserProfile
{
    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
}

次に、コントローラーレンダリング(XProfileController)とアクションメソッド(UpdateFacets)を次のように定義しました。ファセットは、XConnectFacets に記録されていますので、 GetFacets メソッドを使用してファセットの参照を取得しています。氏名などの情報は PersonalInfomation ファセットに格納されているので、 PersonalInformation.DefaultFacetKey プロパティを使って、既定のファセット名を指定して参照を取得します。このとき、ファセットキーに対応するファセットが未登録の場合はエラーが発生するので、ファセットの登録有無を確認しています。あとは、ファセットのプロパティをモデルに設定してビューに渡しているだけです。

public class XProfileController : Controller
{

    public ActionResult UpdateFacets()
    {
        var userprofile = new UserProfile();
        var xConnectFacets = Tracker.Current.Contact.GetFacet<IXConnectFacets>("XConnectFacets");
        if (xConnectFacets.Facets != null && xConnectFacets.Facets.ContainsKey(PersonalInformation.DefaultFacetKey))
        {
            var personel = xConnectFacets.Facets[PersonalInformation.DefaultFacetKey] as PersonalInformation;
            userprofile.FirstName = personel.FirstName;
            userprofile.LastName = personel.LastName;
        }

        return View(userprofile);
    }
}

あとは、UpdateFacets.cshtml 部分ビューを次のように作成しました。

@model SCSample.Models.UserProfile


<h2>プロフィール編集</h2>
@if (Sitecore.Analytics.Tracker.Current.Contact.IsNew)
{
    <h3>New Contact</h3>
}
else
{
    <h3>Existing Contact</h3>
}
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.LabelFor(m => m.FirstName)
    @Html.TextBoxFor(m => m.FirstName)
    <br/>
    @Html.LabelFor(m => m.LastName)
    @Html.TextBoxFor(m => m.LastName)
    <br/>
    <input type="submit" value="登録" />
}

コントローラレンダリングをSitecoreに登録して、任意のページで表示すると次のようなマークアップがレンダリングされます。

2. 更新処理の実装

XProfileController に、Postメッセージ処理用のアクションメソッドと、プロフィールを更新するためのメソッドを次のように実装しました。

xDBでのコンタクトレコードの登録の有無をTracker.Current.Contact.IsNew プロパティでチェックし、メソッドを分けています。未登録の場合は、xDB上にまずコンタクトレコードを作成するという処理を行ってから、プロフィール情報を更新するコードを実装しています。プロフィールを実装するファセットは、ContactManagerを使用して更新します。Sitecore 8と異なり、コンタクトのロックを取得しないアーキテクチャーになっているので、xDB上のプロフィールを変更したら、オンラインのコンタクトデータをリロードしてあげる必要があります。コード例では、リロードするコードも実装されています。

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult UpdateFacets(UserProfile model)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }
        if (Tracker.Current.Contact.IsNew)
        {
            // 初めてサイトを訪問したコンタクト
            UpdateNewContactProfile(model);
        }
        else
        {
            // 再訪した訪問者
            UpdateExistingContactProfile(model);
        }
        return View(model);
    }
    /// <summary>
    /// 既存(2回目以降の訪問者のプロフィールを更新
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    private bool UpdateExistingContactProfile(UserProfile model)
    {
        var manager = Sitecore.Configuration.Factory.CreateObject("tracking/contactManager", true) 
            as Sitecore.Analytics.Tracking.ContactManager;
        if (manager != null)
        {
            Sitecore.Analytics.Model.Entities.ContactIdentifier anyIdentifier = Tracker.Current.Contact.Identifiers.FirstOrDefault();
            using (XConnectClient client = SitecoreXConnectClientConfiguration.GetClient())
            {
                try
                {
                    Sitecore.XConnect.Contact contact = client.Get<Contact>(
                        new IdentifiedContactReference(anyIdentifier.Source, anyIdentifier.Identifier)
                        , new ExpandOptions(PersonalInformation.DefaultFacetKey));
                    if (contact != null)
                    {
                        PersonalInformation personal = contact.Personal() ?? new PersonalInformation();
                        personal.FirstName = model.FirstName;
                        personal.LastName = model.LastName;
                        personal.Birthdate = DateTime.Today.AddYears(-20);
                        client.SetFacet<PersonalInformation>(contact, PersonalInformation.DefaultFacetKey, personal);
                        client.Submit();
                         // 共有セッションからコンタクトデータを削除し、以降のページリクエスト時にリロードさせる
                        manager.RemoveFromSession(Tracker.Current.Contact.ContactId);
                        Tracker.Current.Session.Contact = manager.LoadContact(Tracker.Current.Contact.ContactId);
                    }
                }
                catch (XdbExecutionException ex)
                {
                    Sitecore.Diagnostics.Log.Error("error", ex, this);
                    return false;
                }
            }
        }
        return true;
    }
    private bool UpdateNewContactProfile(UserProfile model)
    {
        var manager = Sitecore.Configuration.Factory.CreateObject("tracking/contactManager", true)
               as Sitecore.Analytics.Tracking.ContactManager;
        if (manager != null)
        {
            // xDB状にコンタクトレコードがないので、作成する
            Sitecore.Analytics.Tracker.Current.Contact.ContactSaveMode = ContactSaveMode.AlwaysSave;
            manager.SaveContactToCollectionDb(Tracker.Current.Contact);
            // コンタクトが保存されたので、ロード (9.0の場合は、"xDB.Tracker" を IdentifierSource の代わりに指定
            var trackerIdentifier = new IdentifiedContactReference(Sitecore.Analytics.XConnect.DataAccess.Constants.IdentifierSource,
                Tracker.Current.Contact.ContactId.ToString("N"));
            using (XConnectClient client = SitecoreXConnectClientConfiguration.GetClient())
            {
                try
                {
                    var contact = client.Get<Contact>(trackerIdentifier, new Sitecore.XConnect.ContactExpandOptions());
                    if (contact != null)
                    {
                        PersonalInformation personal = contact.Personal() ?? new PersonalInformation();
                        personal.FirstName = model.FirstName;
                        personal.LastName = model.LastName;
                        personal.Birthdate = DateTime.Today.AddYears(-34);
                         client.SetFacet<PersonalInformation>(contact, PersonalInformation.DefaultFacetKey, personal);
                        client.Submit();
                        // 共有セッションからコンタクトデータを削除し、以降のページリクエスト時にリロードさせる
                        manager.RemoveFromSession(Tracker.Current.Contact.ContactId);
                        Tracker.Current.Session.Contact = manager.LoadContact(Tracker.Current.Contact.ContactId);
                     }
                }
                catch (XdbExecutionException ex)
                {
                    Sitecore.Diagnostics.Log.Error("error", ex, this);
                    return false;
                }
           }
        }
        return true;
    }

これで準備は完了です。ちなみにコンタクトデータをリロードしても2回訪問したことにならないので安心してください。

3. 動作確認

フォームに名前を入力して、登録しています。

登録が成功するとコレクションデータベースのContactFacetsテーブルにファセットデータがPersonal というキーを使用して登録されていることを確認できるはずです。

FacetDataカラムはJSON形式になっているので、例えば次のようにデータが格納されます。

個人が特定されているコンタクト(Identified contact) の場合は、xProfile からコンタクトを検索して、登録されたプロフィールを確認できます。

簡単ですが、説明は以上です。

xDB上にコンタクトのデータを登録する場合は基本的にドキュメントサイトのコード例を参考にすれば簡単に実装することができます。

組み込みのファセットの一覧は、Use core collection model facets にあります。カスタムファセットの作り方は、Create a custom facet を参照できます。