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 を参照できます。
さんのコメント: さんのコメント: