xConnect tutorial #5: Create custom facets and events

You need to complete xConnect tutorial #1, xConnect tutorial #2, xConnect tutorial #3, and xConnect tutorial #4 before starting this tutorial.

In the following tutorial, you will be extending the collection model. You are Sitecore Cinema, and you want to collect the following information from your visitors:

Class

Purpose

Notes

CinemaInfo

Interaction facet

Information about the cinema visited during the interaction.

CinemaVisitorInfo

Contact facet

Information about the visitor - such as loyalty ID.

WatchMovie

Custom outcome

Triggered from the PoS system when the contact buys a movie ticket.

BuyConcessions

Custom outcome

Triggered from the PoS system when the contact buys concessions.

UseSelfService

Custom event

Triggered from the self service ticket machine when the contact uses them.

This information relies on visitors using their loyalty card each time they interaction with one of your cinemas. You offer free popcorn after 10 usages of the loyalty card as incentive.

  1. Create a new solution and Class Library project named SitecoreCinema.

  2. Create a class for your collection model:

    namespace SitecoreCinema.Model.Collection
    {
        public class SitecoreCinemaModel
        {
            // Your model here later
        }
    }
    
  3. Create a class named CinemaInfo:

    using Sitecore.XConnect;
    
    namespace SitecoreCinema.Model.Collection
    {
        [FacetKey(DefaultFacetKey)]
        public class CinemaInfo : Facet
        {
            public const string DefaultFacetKey = "CinemaInfo";
            public int CinemaId { get; set; } // e.g. SC123567 - all cinemas have a unique identifier
        }
    }
    
  4. Create a class named CinemaVisitorInfo :

    using Sitecore.XConnect;
    
    namespace SitecoreCinema.Model.Collection
    {
        [FacetKey(DefaultFacetKey)]
        public class CinemaVisitorInfo : Facet
        {
            public const string DefaultFacetKey = "CinemaVisitorInfo";
    
            public string FavoriteMovie { get; set; } // Plain text; e.g. "Apocalypse Now" or "Legally Blonde"
        }
    }
    
  5. Create a class named WatchMovie . This step assumes that you have created a matching outcome in Sitecore and copied the GUID into this class.

    using Sitecore.XConnect;
    using System;
    
    namespace SitecoreCinema.Model.Collection
    {
        public class WatchMovie : Outcome
        {
            public static Guid EventDefinitionId { get; } = new Guid("0b7e9e7e-f7ac-4ac2-8f8e-26a9c8644b23");
    
            public WatchMovie(DateTime timestamp, string currencyCode, decimal monetaryValue) : base(EventDefinitionId, timestamp, currencyCode, monetaryValue) { }
            public string EIDR { get; set; } // Entertainment Identifier Registry number - e.g. 10.5240/24D3-956D-0575-0244-CB28-I
        }
    }
    
  6. Create a class named BuyConcessions . This step assumes that you have created a matching outcome in Sitecore and copied the GUID into this class.

    using Sitecore.XConnect;
    using System;
    
    namespace SitecoreCinema.Model.Collection
    {
        public class BuyConcessions : Outcome
        {
            public static Guid EventDefinitionId { get; } = new Guid("2a7e9e7e-a7ac-2ac2-8a8e-26a9c8644b23");
    
            public BuyConcessions(DateTime timestamp, string currencyCode, decimal monetaryValue) : base(EventDefinitionId, timestamp, currencyCode, monetaryValue) { }
    
            public bool BoughtAlcoholicDrink { get; set; }
        }
    }
    
  7. Create a class named UseSelfService . This step assumes that you have created a matching event in Sitecore and copied the GUID into this class.

    using Sitecore.XConnect;
    using System;
    
    namespace SitecoreCinema.Model.Collection
    {
        public class UseSelfService : Event
        {
            public static Guid EventDefinitionId { get; } = new Guid("9a7e9e7e-27ac-2ac2-8a8e-26a9c8644b23");
            public UseSelfService(DateTime timestamp) : base(EventDefinitionId, timestamp) { }
        }
    }
    
  8. Go back to the model you created in step #1 and register your facets and events as shown. Notice that we are referencing Sitecore’s core collection model:

    using Sitecore.XConnect;
    using Sitecore.XConnect.Schema;
    
    namespace SitecoreCinema.Model.Collection
    {
        public class SitecoreCinemaModel
        {
            public static XdbModel Model { get; } = BuildModel();
    
            private static XdbModel BuildModel()
            {
                XdbModelBuilder modelBuilder = new XdbModelBuilder("SitecoreCinemaModel", new XdbModelVersion(1, 0));
    
                modelBuilder.DefineFacet<Contact, CinemaVisitorInfo>(FacetKeys.CinemaVisitorInfo);
                modelBuilder.DefineFacet<Interaction, CinemaInfo>(FacetKeys.CinemaInfo);
                modelBuilder.DefineEventType<WatchMovie>(false);
                modelBuilder.DefineEventType<BuyConcessions>(false);
                modelBuilder.DefineEventType<UseSelfService>(false);
    
                modelBuilder.ReferenceModel(Sitecore.XConnect.Collection.Model.CollectionModel.Model);
    
                return modelBuilder.BuildModel();
            }
        }
    
        public class FacetKeys
        {
            public const string CinemaInfo = "CinemaInfo";
            public const string CinemaVisitorInfo = "CinemaVisitorInfo";
        }
    }
    
  9. Create a new console application project in your solution. This app will generate the JSON version of the model, which must be manually copied into your xConnect instance. Reference the following DLLs:

    • Sitecore.XConnect.dll

    • Sitecore.XConnect.Client.dll

    • Sitecore.XConnect.Collection.Model.dll

  10. Copy the following code into Program.cs:

    using System.IO;
    
    namespace SitecoreCinema.Console.Deploy
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                System.Console.WriteLine("Generating your model...");
    
                var model = SitecoreCinema.Model.Collection.SitecoreCinemaModel.Model;
    
                var serializedModel = Sitecore.XConnect.Serialization.XdbModelWriter.Serialize(model);
    
                File.WriteAllText("c:\\temp\\" + model.FullName + ".json", serializedModel);
    
                System.Console.WriteLine("Press any key to continue! Your model is here: " + "c:\\temp\\" + model.FullName + ".json");
                System.Console.ReadKey();
            }
        }
    }
    
  11. Modify the file path as required, then run the application by choosing the correct startup project and pressing the green Start button:

    deploy-button1.png
    console-works-91.png
  12. Copy the JSON file into the xConnect model folder - for example: C:\inetpub\wwwrootR217_xconnect\Website\App_data\Models. You do not need to copy the model DLL.

    xconnect-model1.png
  13. Create a second console application that will simulate your contact’s journey through the cinema. This journey will include:

    • Using self service to buy a ticket

    • Buying some popcorn and a drink

    • Scanning a ticket to get into the movie

  14. Copy the following code into Program.cs. This program simulates 4 interactions of someone visiting the cinema:

    using Sitecore.XConnect;
    using Sitecore.XConnect.Client;
    using Sitecore.XConnect.Client.WebApi;
    using Sitecore.XConnect.Collection.Model;
    using Sitecore.XConnect.Schema;
    using Sitecore.Xdb.Common.Web;
    using SitecoreCinema.Model.Collection;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Sitecore.Xdb.Common.Web;
    
    namespace SitecoreCinema.Console.Journey
    {
        public class Program
        {
            public static string Identifier { get; set; }
    
            private static void Main(string[] args)
            {
    
                // Welcome to...
                //   _____ _ __                            _______
                //  / ___/(_) /____  _________  ________  / ____(_)___  ___  ____ ___  ____ _
                //  \__ \/ / __/ _ \/ ___/ __ \/ ___/ _ \/ /   / / __ \/ _ \/ __ `__ \/ __ `/
                // ___/ / / /_/  __/ /__/ /_/ / /  /  __/ /___/ / / / /  __/ / / / / / /_/ /
                // ____/_/\__/\___/\___/\____/_/   \___/\____/_/_/ /_/\___/_/ /_/ /_/\__,_/
    
                //   ____            _     _
                //  |  _ \ ___  __ _(_)___| |_ ___ _ __
                //  | |_) / _ \/ _` | / __| __/ _ \ '__|
                //  |  _ <  __/ (_| | \__ \ ||  __/ |
                //  |_| \_\___|\__, |_|___/\__\___|_|
                //             |___/
    
                // You decide to register for the loyalty card scheme on the website - apparently you
                // get a free popcorn for every 10 times you swipe your card.
    
                Task.Run(async () => { await Register(); }).Wait();
    
                //   ___       _                      _   _               _  _   _
                //  |_ _|_ __ | |_ ___ _ __ __ _  ___| |_(_) ___  _ __  _| || |_/ |
                //   | || '_ \| __/ _ \ '__/ _  |/ __| __| |/ _ \| '_ \|_  ..  _| |
                //   | || | | | ||  __/ | | (_| | (__| |_| | (_) | | | |_      _| |
                //  |___|_| |_|\__\___|_|  \__,_|\___|\__|_|\___/|_| |_| |_||_| |_|
    
                // You cycle to the nearest Sitecore Cinema (which has great bicycle storage facilities, by the way)
                // and use a self service machine to buy a ticket. You swipes your loyalty card - the machine
                // immediately sends this interaction to xConnect. Because you're a loyalty card member
                // you don't even pay at this point!
    
                Task.Run(async () => { await SelfServiceMachine(); }).Wait();
    
                //   ___       _                      _   _               _  _  ____
                //  |_ _|_ __ | |_ ___ _ __ __ _  ___| |_(_) ___  _ __  _| || ||___ \
                //   | || '_ \| __/ _ \ '__/ _  |/ __| __| |/ _ \| '_ \|_  ..  _|__) |
                //   | || | | | ||  __/ | | (_| | (__| |_| | (_) | | | |_      _/ __/
                //  |___|_| |_|\__\___|_|  \__,_|\___|\__|_|\___/|_| |_| |_||_||_____|
    
                // You decides to buy some candy and a bottle of water (gotta stay balanced)
                // You use your loyalty card - that's 2 swipes already! The machine sends this interaction to xConnect.
    
                Task.Run(async () => { await BuyCandy(); }).Wait();
    
                //   ___       _                      _   _               _  _  _____
                //  |_ _|_ __ | |_ ___ _ __ __ _  ___| |_(_) ___  _ __  _| || ||___ /
                //   | || '_ \| __/ _ \ '__/ _  |/ __| __| |/ _ \| '_ \|_  ..  _||_ \
                //   | || | | | ||  __/ | | (_| | (__| |_| | (_) | | | |_      _|__) |
                //  |___|_| |_|\__\___|_|  \__,_|\___|\__|_|\___/|_| |_| |_||_||____/
    
                // Finally, you scan your ticket and head in - your loyalty card details
                // are embedded in the barcode of your ticket. At this point, the system takes payment.
    
                Task.Run(async () => { await WatchAMovie(); }).Wait();
    
                System.Console.ForegroundColor = ConsoleColor.DarkGreen;
                System.Console.WriteLine("");
                System.Console.WriteLine("END OF PROGRAM.");
                System.Console.ReadKey();
            }
    
            private static async Task Register()
            {
                CertificateHttpClientHandlerModifierOptions options =
                CertificateHttpClientHandlerModifierOptions.Parse("StoreName=My;StoreLocation=LocalMachine;FindType=FindByThumbprint;FindValue=15E6693B0AECB63DE57D991EC363CA462DC52432");
    
                var certificateModifier = new CertificateHttpClientHandlerModifier(options);
    
                List<IHttpClientModifier> clientModifiers = new List<IHttpClientModifier>();
                var timeoutClientModifier = new TimeoutHttpClientModifier(new TimeSpan(0, 0, 20));
                clientModifiers.Add(timeoutClientModifier);
    
                var collectionClient = new CollectionWebApiClient(new Uri("https://xconnect/odata"), clientModifiers, new[] { certificateModifier });
                var searchClient = new SearchWebApiClient(new Uri("https://xconnect/odata"), clientModifiers, new[] { certificateModifier });
                var configurationClient = new ConfigurationWebApiClient(new Uri("https://xconnect/configuration"), clientModifiers, new[] { certificateModifier });
    
                var cfg = new XConnectClientConfiguration(
                    new XdbRuntimeModel(SitecoreCinemaModel.Model), collectionClient, searchClient, configurationClient);
    
                try
                {
                    await cfg.InitializeAsync(); // cfg.InitializeAsync();
    
                    // Print xConnect if configuration is valid
                    var arr = new[]
                    {
                            @"  ____            _     _               ",
                            @"  |  _ \ ___  __ _(_)___| |_ ___ _ __   ",
                            @"  | |_) / _ \/ _` | / __| __/ _ \ '__|  ",
                            @"  |  _ <  __/ (_| | \__ \ ||  __/ |     ",
                            @"  |_| \_\___|\__, |_|___/\__\___|_|     ",
                            @"             |___/                      ",
                            };
                    System.Console.WindowWidth = 160;
                    foreach (string line in arr)
                        System.Console.WriteLine(line);
                    System.Console.WriteLine(); // Extra space
                }
                catch (XdbModelConflictException ce)
                {
                    System.Console.WriteLine("ERROR:" + ce.Message);
                    return;
                }
    
                // Initialize a client using the validated configuration
                using (var client = new XConnectClient(cfg))
                {
                    try
                    {
                        ContactIdentifier identifier = new ContactIdentifier("SitecoreCinema", "L94564543543543534" + Guid.NewGuid(), ContactIdentifierType.Known);
    
                        System.Console.WriteLine("We will generate an ID for you and print it onto a cool card!");
                        System.Console.WriteLine("Alright, your ID is - drumroll please... - " + identifier.Identifier + "! Congratulations. Ctrl+C, Ctrl+V that number into your brain.");
    
                        // Let's just save this for later
                        Identifier = identifier.Identifier;
    
                        Contact contact = new Contact(new ContactIdentifier[] { identifier });
    
                        System.Console.WriteLine("What is your first name?");
    
                        var firstname = System.Console.ReadLine();
    
                        System.Console.WriteLine("What is your last name?");
    
                        var lastname = System.Console.ReadLine();
    
                        PersonalInformation personalInfo = new PersonalInformation()
                        {
                            FirstName = firstname,
                            LastName = lastname, // It's an ancient family name
                        };
    
                        System.Console.WriteLine("Favourite movie?");
    
                        var favouriteMovie = System.Console.ReadLine();
    
                        CinemaVisitorInfo visitorInfo = new CinemaVisitorInfo()
                        {
                            FavoriteMovie = favouriteMovie
                        };
    
                        client.AddContact(contact);
                        client.SetFacet<CinemaVisitorInfo>(contact, CinemaVisitorInfo.DefaultFacetKey, visitorInfo);
                        client.SetFacet<PersonalInformation>(contact, PersonalInformation.DefaultFacetKey, personalInfo);
    
                        var offlineChannel = Guid.NewGuid(); //
                        var registrationGoalId = Guid.NewGuid();
    
                        Interaction interaction = new Interaction(contact, InteractionInitiator.Brand, offlineChannel, String.Empty);
    
                        interaction.Events.Add(new Goal(registrationGoalId, DateTime.UtcNow));
    
                        client.AddInteraction(interaction);
    
                        await client.SubmitAsync();
    
                        // var waitForSearch = await client.Contacts.Any();
    
                        System.Console.WriteLine("Great! See you at the cinema. :) Press any key to continue.");
                        System.Console.ReadKey();
                    }
                    catch (XdbExecutionException ex)
                    {
                        // Deal with exception
                    }
                }
            }
    
            private static async Task SelfServiceMachine()
            {
                CertificateHttpClientHandlerModifierOptions options =
                CertificateHttpClientHandlerModifierOptions.Parse("StoreName=My;StoreLocation=LocalMachine;FindType=FindByThumbprint;FindValue=15E6693B0AECB63DE57D991EC363CA462DC52432");
    
                var certificateModifier = new CertificateHttpClientHandlerModifier(options);
    
                List<IHttpClientModifier> clientModifiers = new List<IHttpClientModifier>();
                var timeoutClientModifier = new TimeoutHttpClientModifier(new TimeSpan(0, 0, 20));
                clientModifiers.Add(timeoutClientModifier);
    
                var collectionClient = new CollectionWebApiClient(new Uri("https://xconnect/odata"), clientModifiers, new[] { certificateModifier });
                var searchClient = new SearchWebApiClient(new Uri("https://xconnect/odata"), clientModifiers, new[] { certificateModifier });
                var configurationClient = new ConfigurationWebApiClient(new Uri("https://xconnect/configuration"), clientModifiers, new[] { certificateModifier });
    
                var cfg = new XConnectClientConfiguration(
                    new XdbRuntimeModel(SitecoreCinemaModel.Model), collectionClient, searchClient, configurationClient);
    
                try
                {
                    await cfg.InitializeAsync();
    
                    // Print xConnect if configuration is valid
                    var arr = new[]
                    {
                            @" _____ _      _        _   ",
                            @"|_   _(_) ___| | _____| |_ ",
                            @"  | | | |/ __| |/ / _ \ __|",
                            @"  | | | | (__|   <  __/ |_ ",
                            @"  |_| |_|\___|_|\_\___|\__|",
                            };
                    System.Console.WindowWidth = 160;
                    foreach (string line in arr)
                        System.Console.WriteLine(line);
                    System.Console.WriteLine(); // Extra space
                }
                catch (XdbModelConflictException ce)
                {
                    System.Console.WriteLine("ERROR:" + ce.Message);
                    return;
                }
    
                // Initialize a client using the validated configuration
                using (var client = new XConnectClient(cfg))
                {
                    try
                    {
                        System.Console.ForegroundColor = ConsoleColor.Cyan;
                        System.Console.WriteLine("You swipe your loyalty card.");
    
                        System.Console.ForegroundColor = ConsoleColor.White;
    
                        var identifier = new IdentifiedContactReference("SitecoreCinema", Identifier);
    
                        var contact = await client.GetAsync<Contact>(identifier, new ContactExpandOptions(PersonalInformation.DefaultFacetKey, CinemaVisitorInfo.DefaultFacetKey));
    
    
                        if (contact != null)
                        {
                            var presonalInfo = contact.GetFacet<PersonalInformation>();
                            var cinemaInfo = contact.GetFacet<CinemaVisitorInfo>();
    
                            System.Console.WriteLine("Why hello there " + presonalInfo.FirstName + " " + presonalInfo.LastName + ", whose favorite film is... " + cinemaInfo.FavoriteMovie + ". Wow, really? OK, to each their own I guess.");
    
                            var interaction = new Interaction(contact, InteractionInitiator.Contact, Guid.NewGuid(), ""); // GUID should be from a channel item in Sitecore
    
                            client.SetFacet<CinemaInfo>(interaction, CinemaInfo.DefaultFacetKey, new CinemaInfo() { CinemaId = 22 });
                            interaction.Events.Add(new UseSelfService(DateTime.UtcNow));
    
                            client.AddInteraction(interaction);
    
                            await client.SubmitAsync();
    
                            System.Console.WriteLine("Here's your ticket - we'll charge you when you use it, in case you have some sort of emergency between here and movie.");
                            System.Console.WriteLine("It's just one of those courtesies we offer loyalty card members! Press any key to go buy some candy.");
                            System.Console.ReadKey();
                        }
                    }
                    catch (XdbExecutionException ex)
                    {
                        // Deal with exception
                    }
                }
    
            }
            private static async Task BuyCandy()
            {
                CertificateHttpClientHandlerModifierOptions options =
                CertificateHttpClientHandlerModifierOptions.Parse("StoreName=My;StoreLocation=LocalMachine;FindType=FindByThumbprint;FindValue=15E6693B0AECB63DE57D991EC363CA462DC52432");
    
                var certificateModifier = new CertificateHttpClientHandlerModifier(options);
    
                List<IHttpClientModifier> clientModifiers = new List<IHttpClientModifier>();
                var timeoutClientModifier = new TimeoutHttpClientModifier(new TimeSpan(0, 0, 20));
                clientModifiers.Add(timeoutClientModifier);
    
                var collectionClient = new CollectionWebApiClient(new Uri("https://xconnect/odata"), clientModifiers, new[] { certificateModifier });
                var searchClient = new SearchWebApiClient(new Uri("https://xconnect/odata"), clientModifiers, new[] { certificateModifier });
                var configurationClient = new ConfigurationWebApiClient(new Uri("https://xconnect/configuration"), clientModifiers, new[] { certificateModifier });
    
                var cfg = new XConnectClientConfiguration(
                    new XdbRuntimeModel(SitecoreCinemaModel.Model), collectionClient, searchClient, configurationClient);
    
                try
                {
                    await cfg.InitializeAsync(); // cfg.InitializeAsync();
    
                    // Print xConnect if configuration is valid
                    var arr = new[]
                    {
                            @"  ____                _       ",
                            @" / ___|__ _ _ __   __| |_   _ ",
                            @"| |   / _` | '_ \ / _` | | | |",
                            @"| |__| (_| | | | | (_| | |_| |",
                            @" \____\__,_|_| |_|\__,_|\__, |",
                            @"                        |___/ ",
                            };
                    System.Console.WindowWidth = 160;
                    foreach (string line in arr)
                        System.Console.WriteLine(line);
                    System.Console.WriteLine(); // Extra space
                }
                catch (XdbModelConflictException ce)
                {
                    System.Console.WriteLine("ERROR:" + ce.Message);
                    return;
                }
    
                // Initialize a client using the validated configuration
                using (var client = new XConnectClient(cfg))
                {
                    try
                    {
                        System.Console.ForegroundColor = ConsoleColor.Cyan;
                        System.Console.WriteLine("You swipe your loyalty card.");
    
                        System.Console.ForegroundColor = ConsoleColor.White;
    
                        var identifier = new IdentifiedContactReference("SitecoreCinema", Identifier);
    
                        var contact = await client.GetAsync<Contact>(identifier, new ContactExpandOptions(PersonalInformation.DefaultFacetKey, CinemaVisitorInfo.DefaultFacetKey));
    
                        if (contact != null)
                        {
                            var presonalInfo = contact.GetFacet<PersonalInformation>();
                            var cinemaInfo = contact.GetFacet<CinemaVisitorInfo>();
    
                            System.Console.WriteLine("Why hello again " + presonalInfo.FirstName + "!");
                            System.Console.WriteLine("Candy? You got it.");
    
    
                            var interaction = new Interaction(contact, InteractionInitiator.Contact, Guid.NewGuid(), ""); // GUID should be from a channel item in Sitecore
                            client.SetFacet<CinemaInfo>(interaction, CinemaInfo.DefaultFacetKey, new CinemaInfo() { CinemaId = 22 });
    
                            interaction.Events.Add(new BuyConcessions(DateTime.UtcNow, "DKK", 150m));
    
                            client.AddInteraction(interaction);
    
                            await client.SubmitAsync();
    
                            System.Console.WriteLine("Enjoy the movie! Press any key to continue.");
                            System.Console.ReadKey();
                        }
                    }
                    catch (XdbExecutionException ex)
                    {
                        // Deal with exception
                    }
                }
            }
    
            private static async Task WatchAMovie()
            {
                CertificateHttpClientHandlerModifierOptions options =
                CertificateHttpClientHandlerModifierOptions.Parse("StoreName=My;StoreLocation=LocalMachine;FindType=FindByThumbprint;FindValue=15E6693B0AECB63DE57D991EC363CA462DC52432");
    
                var certificateModifier = new CertificateHttpClientHandlerModifier(options);
    
                List<IHttpClientModifier> clientModifiers = new List<IHttpClientModifier>();
                var timeoutClientModifier = new TimeoutHttpClientModifier(new TimeSpan(0, 0, 20));
                clientModifiers.Add(timeoutClientModifier);
    
                var collectionClient = new CollectionWebApiClient(new Uri("https://xconnect/odata"), clientModifiers, new[] { certificateModifier });
                var searchClient = new SearchWebApiClient(new Uri("https://xconnect/odata"), clientModifiers, new[] { certificateModifier });
                var configurationClient = new ConfigurationWebApiClient(new Uri("https://xconnect/configuration"), clientModifiers, new[] { certificateModifier });
    
                var cfg = new XConnectClientConfiguration(
                    new XdbRuntimeModel(SitecoreCinemaModel.Model), collectionClient, searchClient, configurationClient);
    
                try
                {
                    await cfg.InitializeAsync(); // cfg.InitializeAsync();
    
                    // Print xConnect if configuration is valid
                    var arr = new[]
                    {
                            @" __  __            _      ",
                            @"|  \/  | _____   _(_) ___ ",
                            @"| |\/| |/ _ \ \ / / |/ _ \",
                            @"| |  | | (_) \ V /| |  __/",
                            @"|_|  |_|\___/ \_/ |_|\___|",
    
                            };
                    System.Console.WindowWidth = 160;
                    foreach (string line in arr)
                        System.Console.WriteLine(line);
                    System.Console.WriteLine(); // Extra space
                }
                catch (XdbModelConflictException ce)
                {
                    System.Console.WriteLine("ERROR:" + ce.Message);
                    return;
                }
    
                // Initialize a client using the validated configuration
                using (var client = new XConnectClient(cfg))
                {
                    try
                    {
                        System.Console.ForegroundColor = ConsoleColor.Cyan;
                        System.Console.WriteLine("You scan your ticket - the bar code has your loyalty card information embedded in it.");
    
                        System.Console.ForegroundColor = ConsoleColor.White;
    
                        var identifier = new IdentifiedContactReference("SitecoreCinema", Identifier);
    
                        var contact = await client.GetAsync<Contact>(identifier, new ContactExpandOptions(PersonalInformation.DefaultFacetKey, CinemaVisitorInfo.DefaultFacetKey));
    
                        if (contact != null)
                        {
                            var presonalInfo = contact.GetFacet<PersonalInformation>();
                            var cinemaInfo = contact.GetFacet<CinemaVisitorInfo>();
    
                            System.Console.WriteLine("Enjoy your movie, " + presonalInfo.FirstName + "!");
                            System.Console.WriteLine("Since you're a loyalty card holder, we'll take payment for your ticket now.");
    
                            var interaction = new Interaction(contact, InteractionInitiator.Contact, Guid.NewGuid(), ""); // GUID should be from a channel item in Sitecore
    
                            interaction.Events.Add(new WatchMovie(DateTime.UtcNow, "DKK", 100m) { EIDR = "10.5240/08B0-F8C2-5525-BF22-BA07-4" });
                            client.SetFacet<CinemaInfo>(interaction, CinemaInfo.DefaultFacetKey, new CinemaInfo() { CinemaId = 22 });
                            client.AddInteraction(interaction);
    
                            await client.SubmitAsync();
    
                            System.Console.WriteLine("Before you go - do you want to see the data we collected about you today? :)");
    
                            var contactAgain = await client.GetAsync<Contact>(identifier, new ContactExpandOptions(PersonalInformation.DefaultFacetKey, CinemaVisitorInfo.DefaultFacetKey)
                            {
                                Interactions = new RelatedInteractionsExpandOptions(new string[] { CinemaInfo.DefaultFacetKey })
                                {
                                    StartDateTime = DateTime.Today
                                }
                            });
    
                            if (contactAgain != null)
                            {
                                var details = contactAgain.GetFacet<PersonalInformation>();
                                var movie = contactAgain.GetFacet<CinemaVisitorInfo>();
    
                                System.Console.WriteLine(String.Format("Your name is {0} {1} and your favorite movie is {2}", details.FirstName, details.LastName, movie.FavoriteMovie));
    
                                System.Console.WriteLine("Today you have had " + contactAgain.Interactions.Count + " interactions with us.");
    
                                var i = 0;
    
                                foreach (var interactionsToday in contactAgain.Interactions)
                                {
                                    i++;
    
                                    var cinemaId = interactionsToday.GetFacet<CinemaInfo>(CinemaInfo.DefaultFacetKey);
    
                                    System.Console.WriteLine("");
    
                                    System.Console.WriteLine("Interaction #" + i + (cinemaId != null ? " at Cinema #" + cinemaId.CinemaId : String.Empty));
                                    System.Console.Write("Events: ");
    
                                    foreach (var evv in interactionsToday.Events) { System.Console.Write(evv.GetType().ToString() + ""); };
    
                                    System.Console.WriteLine("");
                                }
                            }
    
    
                            System.Console.ReadKey();
                        }
                    }
                    catch (XdbExecutionException ex)
                    {
                        // Deal with exception
                    }
                }
            }
        }
    }
    
  15. Run the application and fill in your details:

    program1.png