public static async Task <bool> MainAsync(bool test = false)
        {
            ISdsMetadataService metadataService = null;

            #region settings
            string typeValueTimeName = "Value_Time";
            string typePressureTemperatureTimeName = "Pressure_Temp_Time";

            string streamPressureName = "Pressure_Tank1";
            string streamTempName     = "Temperature_Tank1";
            string streamTank0        = "Vessel";
            string streamTank1        = "Tank1";
            string streamTank2        = "Tank2";
            #endregion

            try
            {
                #region configurationSettings

                _configuration = new ConfigurationBuilder()
                                 .SetBasePath(Directory.GetCurrentDirectory())
                                 .AddJsonFile("appsettings.json")
                                 .AddJsonFile("appsettings.test.json", optional: true)
                                 .Build();

                string tenantId     = _configuration["TenantId"];
                string namespaceId  = _configuration["NamespaceId"];
                string resource     = _configuration["Resource"];
                string clientId     = _configuration["ClientId"];
                string clientSecret = _configuration["ClientSecret"];
                #endregion

                (_configuration as ConfigurationRoot).Dispose();
                Uri uriResource = new (resource);

                // Step 1
                // Get Sds Services to communicate with server
                #region step1
                AuthenticationHandler authenticationHandler = new (uriResource, clientId, clientSecret);

                SdsService sdsService = new (new Uri(resource), authenticationHandler);
                metadataService = sdsService.GetMetadataService(tenantId, namespaceId);
                ISdsDataService  dataService  = sdsService.GetDataService(tenantId, namespaceId);
                ISdsTableService tableService = sdsService.GetTableService(tenantId, namespaceId);
                #endregion

                // Step 2
                #region step2b
                SdsType type = SdsTypeBuilder.CreateSdsType <TimeData>();
                type.Id = typeValueTimeName;
                type    = await metadataService.GetOrCreateTypeAsync(type).ConfigureAwait(false);

                #endregion

                // Step 3
                // create an SdsStream
                #region step3
                SdsStream pressureStream = new ()
                {
                    Id          = streamPressureName,
                    TypeId      = type.Id,
                    Description = "A stream for pressure data of tank1",
                };
                pressureStream = await metadataService.GetOrCreateStreamAsync(pressureStream).ConfigureAwait(false);

                SdsStream temperatureStream = new ()
                {
                    Id          = streamTempName,
                    TypeId      = type.Id,
                    Description = "A stream for temperature data of tank1",
                };
                temperatureStream = await metadataService.GetOrCreateStreamAsync(temperatureStream).ConfigureAwait(false);

                #endregion

                // Step 4
                // insert simple data
                #region step4c
                await dataService.InsertValuesAsync(pressureStream.Id, GetPressureData()).ConfigureAwait(false);

                await dataService.InsertValuesAsync(streamTempName, GetTemperatureData()).ConfigureAwait(false);

                #endregion

                // Step 5
                // create complex type
                #region step5b
                SdsType tankType = SdsTypeBuilder.CreateSdsType <PressureTemperatureData>();
                tankType.Id = typePressureTemperatureTimeName;
                tankType    = await metadataService.GetOrCreateTypeAsync(tankType).ConfigureAwait(false);

                #endregion

                // Step 6
                // create complex type stream
                #region step6
                SdsStream tankStream = new ()
                {
                    Id          = streamTank1,
                    TypeId      = tankType.Id,
                    Description = "A stream for data of tank1",
                };
                tankStream = await metadataService.GetOrCreateStreamAsync(tankStream).ConfigureAwait(false);

                #endregion

                // Step 7
                // insert complex data
                #region step7
                IList <PressureTemperatureData> data = GetData();
                await dataService.InsertValuesAsync(streamTank1, data).ConfigureAwait(false);

                #endregion

                // Step 8 and Step 9
                //  view data
                // note: step 9 is not done in this example as the JSON conversion by the library takes care of it automatically for you
                #region step8
                List <PressureTemperatureData> sortedData = data.OrderBy(entry => entry.Time).ToList();
                PressureTemperatureData        firstTime  = sortedData.First();
                PressureTemperatureData        lastTime   = sortedData.Last();

                List <TimeData> resultsPressure = (await dataService.GetWindowValuesAsync <TimeData>(
                                                       streamPressureName,
                                                       firstTime.Time.ToUniversalTime().ToString("o", CultureInfo.InvariantCulture),
                                                       lastTime.Time.ToUniversalTime().ToString("o", CultureInfo.InvariantCulture))
                                                   .ConfigureAwait(false))
                                                  .ToList();

                Console.WriteLine("Values from Pressure of Tank1:");
                foreach (TimeData evnt in resultsPressure)
                {
                    Console.WriteLine(JsonConvert.SerializeObject(evnt));
                }

                List <PressureTemperatureData> resultsTank = (await dataService.GetWindowValuesAsync <PressureTemperatureData>(
                                                                  streamTank1,
                                                                  firstTime.Time.ToUniversalTime().ToString("o", CultureInfo.InvariantCulture),
                                                                  lastTime.Time.ToUniversalTime().ToString("o", CultureInfo.InvariantCulture))
                                                              .ConfigureAwait(false))
                                                             .ToList();

                Console.WriteLine("Values from Tank1:");
                foreach (PressureTemperatureData evnt in resultsTank)
                {
                    Console.WriteLine(JsonConvert.SerializeObject(evnt));
                }
                #endregion

                if (test)
                {
                    // Testing to make sure we get back expected stuff
                    if (!string.Equals(JsonConvert.SerializeObject(resultsPressure.First()), "{\"Time\":\"2017-01-11T22:21:23.43Z\",\"Value\":346.0}", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new Exception("Value retrieved isn't expected value for pressure of Tank1");
                    }

                    if (!string.Equals(JsonConvert.SerializeObject(resultsTank.First()), "{\"Time\":\"2017-01-11T22:21:23.43Z\",\"Pressure\":346.0,\"Temperature\":91.0}", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new Exception("Value retrieved isn't expected value for Temperature from Tank1");
                    }
                }

                // Step 10
                //  view summary data
                #region step10
                List <SdsInterval <PressureTemperatureData> > resultsTankSummary = (await dataService.GetIntervalsAsync <PressureTemperatureData>(
                                                                                        streamTank1,
                                                                                        firstTime.Time.ToUniversalTime().ToString("o", CultureInfo.InvariantCulture),
                                                                                        lastTime.Time.ToUniversalTime().ToString("o", CultureInfo.InvariantCulture),
                                                                                        1)
                                                                                    .ConfigureAwait(false))
                                                                                   .ToList();

                Console.WriteLine("Summaries from Tank1:");
                foreach (SdsInterval <PressureTemperatureData> evnt in resultsTankSummary)
                {
                    Console.WriteLine(JsonConvert.SerializeObject(evnt.Summaries));
                }
                #endregion

                // Step 11
                //  Bulk calls
                #region step11a
                SdsStream tankStream0 = new ()
                {
                    Id     = streamTank0,
                    TypeId = tankType.Id,
                };
                tankStream = await metadataService.GetOrCreateStreamAsync(tankStream0).ConfigureAwait(false);

                SdsStream tankStream2 = new ()
                {
                    Id          = streamTank2,
                    TypeId      = tankType.Id,
                    Description = "A stream for data of tank2",
                };
                tankStream2 = await metadataService.GetOrCreateStreamAsync(tankStream2).ConfigureAwait(false);

                IList <PressureTemperatureData> data2       = GetData2();
                List <PressureTemperatureData>  sortedData2 = data2.OrderBy(entry => entry.Time).ToList();
                PressureTemperatureData         firstTime2  = sortedData2.First();
                PressureTemperatureData         lastTime2   = sortedData2.Last();

                await dataService.InsertValuesAsync(tankStream2.Id, data2).ConfigureAwait(false);

                await dataService.InsertValuesAsync(tankStream0.Id, GetData()).ConfigureAwait(false);

                #endregion

                Thread.Sleep(200); // slight rest here for consistency

                #region step11b
                IEnumerable <IList <PressureTemperatureData> > results2Tanks = await dataService.GetJoinValuesAsync <PressureTemperatureData>(
                    new string[] { tankStream0.Id, tankStream2.Id },
                    SdsJoinType.Outer,
                    firstTime2.Time.ToUniversalTime().ToString("o", CultureInfo.InvariantCulture),
                    lastTime2.Time.ToUniversalTime().ToString("o", CultureInfo.InvariantCulture))
                                                                               .ConfigureAwait(false);

                Console.WriteLine();
                Console.WriteLine();
                Console.WriteLine($"Bulk Values:   {tankStream0.Id}  then {tankStream2.Id}: ");
                Console.WriteLine();
                foreach (IList <PressureTemperatureData> tankResult in results2Tanks)
                {
                    foreach (PressureTemperatureData dataEntry in tankResult)
                    {
                        Console.WriteLine(JsonConvert.SerializeObject(dataEntry));
                    }

                    Console.WriteLine();
                }

                #endregion
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                _toThrow = ex;
                throw;
            }
            finally
            {
                if (metadataService != null)
                {
                    // Step 12
                    // delete everything
                    #region step12
                    await RunInTryCatch(metadataService.DeleteStreamAsync, streamPressureName).ConfigureAwait(false);
                    await RunInTryCatch(metadataService.DeleteStreamAsync, streamTempName).ConfigureAwait(false);
                    await RunInTryCatch(metadataService.DeleteStreamAsync, streamTank0).ConfigureAwait(false);
                    await RunInTryCatch(metadataService.DeleteStreamAsync, streamTank1).ConfigureAwait(false);
                    await RunInTryCatch(metadataService.DeleteStreamAsync, streamTank2).ConfigureAwait(false);

                    await RunInTryCatch(metadataService.DeleteTypeAsync, typeValueTimeName).ConfigureAwait(false);
                    await RunInTryCatch(metadataService.DeleteTypeAsync, typePressureTemperatureTimeName).ConfigureAwait(false);

                    #endregion

                    Thread.Sleep(10); // slight rest here for consistency

                    // Check deletes
                    await RunInTryCatchExpectException(metadataService.GetStreamAsync, streamPressureName).ConfigureAwait(false);
                    await RunInTryCatchExpectException(metadataService.GetStreamAsync, streamTempName).ConfigureAwait(false);
                    await RunInTryCatchExpectException(metadataService.GetStreamAsync, streamTank0).ConfigureAwait(false);
                    await RunInTryCatchExpectException(metadataService.GetStreamAsync, streamTank1).ConfigureAwait(false);
                    await RunInTryCatchExpectException(metadataService.GetStreamAsync, streamTank2).ConfigureAwait(false);

                    await RunInTryCatchExpectException(metadataService.GetTypeAsync, typeValueTimeName).ConfigureAwait(false);
                    await RunInTryCatchExpectException(metadataService.GetTypeAsync, typePressureTemperatureTimeName).ConfigureAwait(false);
                }
            }

            if (test && _toThrow != null)
            {
                throw _toThrow;
            }

            return(_toThrow == null);
        }
Пример #2
0
        public static async Task <bool> MainAsync(bool test = false)
        {
            IConfigurationBuilder builder = new ConfigurationBuilder()
                                            .SetBasePath(Directory.GetCurrentDirectory())
                                            .AddJsonFile("appsettings.json")
                                            .AddJsonFile("appsettings.test.json", optional: true);

            _configuration = builder.Build();

            // ==== Client constants ====
            string tenantId     = _configuration["TenantId"];
            string namespaceId  = _configuration["NamespaceId"];
            string resource     = _configuration["Resource"];
            string clientId     = _configuration["ClientId"];
            string clientSecret = _configuration["ClientSecret"];

            // ==== Metadata IDs ====
            string streamId          = "SampleStream_Dotnet";
            string streamIdSecondary = "SampleStream_Secondary_Dotnet";
            string streamIdCompound  = "SampleStream_Compound_Dotnet";

            string typeId             = "SampleType_Dotnet";
            string targetTypeId       = "SampleType_Target_Dotnet";
            string targetIntTypeId    = "SampleType_TargetInt_Dotnet";
            string autoStreamViewId   = "SampleAutoStreamView_Dotnet";
            string manualStreamViewId = "SampleManualStreamView_Dotnet";
            string compoundTypeId     = "SampleType_Compound_Dotnet";

            Uri uriResource = new (resource);

            // Step 1
            // Get Sds Services to communicate with server
            AuthenticationHandler authenticationHandler = new (uriResource, clientId, clientSecret);

            SdsService          sdsService      = new (new Uri(resource), null, HttpCompressionMethod.GZip, authenticationHandler);
            ISdsMetadataService metadataService = sdsService.GetMetadataService(tenantId, namespaceId);
            ISdsDataService     dataService     = sdsService.GetDataService(tenantId, namespaceId);
            ISdsTableService    tableService    = sdsService.GetTableService(tenantId, namespaceId);

            Console.WriteLine(@"-------------------------------------------------------------");
            Console.WriteLine(@"  _________    .___           _______  ______________________");
            Console.WriteLine(@" /   _____/  __| _/______     \      \ \_   _____/\__    ___/");
            Console.WriteLine(@" \_____  \  / __ |/  ___/     /   |   \ |    __)_   |    |   ");
            Console.WriteLine(@" /        \/ /_/ |\___ \     /    |    \|        \  |    |   ");
            Console.WriteLine(@"/_______  /\____ /____  > /\ \____|__  /_______  /  |____|   ");
            Console.WriteLine(@"        \/      \/    \/  \/         \/        \/            ");
            Console.WriteLine(@"-------------------------------------------------------------");
            Console.WriteLine();
            Console.WriteLine($"SDS endpoint at {resource}");
            Console.WriteLine();

            try
            {
                // Step 2
                // create an SdsType
                Console.WriteLine("Creating an SdsType");
                SdsType type = SdsTypeBuilder.CreateSdsType <WaveData>();
                type.Id = typeId;
                type    = await metadataService.GetOrCreateTypeAsync(type).ConfigureAwait(false);

                // Step 3
                // create an SdsStream
                Console.WriteLine("Creating an SdsStream");
                SdsStream stream = new ()
                {
                    Id          = streamId,
                    Name        = "Wave Data Sample",
                    TypeId      = type.Id,
                    Description = "This is a sample SdsStream for storing WaveData type measurements",
                };
                stream = await metadataService.GetOrCreateStreamAsync(stream).ConfigureAwait(false);

                // Step 4
                // insert data
                Console.WriteLine("Inserting data");

                // insert a single event
                WaveData wave = GetWave(0, 2);
                await dataService.InsertValueAsync(stream.Id, wave).ConfigureAwait(false);

                // insert a list of events
                List <WaveData> waves = new ();
                for (int i = 2; i <= 18; i += 2)
                {
                    waves.Add(GetWave(i, 2));
                }

                await dataService.InsertValuesAsync(stream.Id, waves).ConfigureAwait(false);

                // Step 5
                // get last event
                Console.WriteLine("Getting latest event");
                WaveData latest = await dataService.GetLastValueAsync <WaveData>(streamId).ConfigureAwait(false);

                Console.WriteLine(latest.ToString());
                Console.WriteLine();

                // get all events
                Console.WriteLine("Getting all events");
                List <WaveData> allEvents = (List <WaveData>) await dataService.GetWindowValuesAsync <WaveData>(streamId, "0", "180").ConfigureAwait(false);

                Console.WriteLine($"Total events found: {allEvents.Count}");
                foreach (WaveData evnt in allEvents)
                {
                    Console.WriteLine(evnt.ToString());
                }

                Console.WriteLine();

                // Step 6
                // getting all events in table format with headers
                SdsTable tableEvents = await tableService.GetWindowValuesAsync(stream.Id, "0", "180").ConfigureAwait(false);

                Console.WriteLine("Getting table events");
                foreach (IList <object> evnt in tableEvents.Rows)
                {
                    Console.WriteLine(string.Join(",", evnt.ToArray()));
                }

                Console.WriteLine();

                // Step 7
                // update events
                Console.WriteLine("Updating events");

                // update one event
                WaveData updatedWave = UpdateWave(allEvents.First(), 4);
                await dataService.UpdateValueAsync(stream.Id, updatedWave).ConfigureAwait(false);

                // update all events, adding ten more
                List <WaveData> updatedCollection = new ();
                for (int i = 2; i < 40; i += 2)
                {
                    updatedCollection.Add(GetWave(i, 4));
                }

                await dataService.UpdateValuesAsync(stream.Id, updatedCollection).ConfigureAwait(false);

                allEvents = (List <WaveData>) await dataService.GetWindowValuesAsync <WaveData>(stream.Id, "0", "180").ConfigureAwait(false);

                Console.WriteLine("Getting updated events");
                Console.WriteLine($"Total events found: {allEvents.Count}");

                foreach (WaveData evnt in allEvents)
                {
                    Console.WriteLine(evnt.ToString());
                }

                Console.WriteLine();

                // Step 8
                // replacing events
                Console.WriteLine("Replacing events");

                // replace one event
                WaveData replaceEvent = UpdateWave(allEvents.First(), multiplier: 5);

                await dataService.ReplaceValueAsync <WaveData>(streamId, replaceEvent).ConfigureAwait(false);

                // replace all events
                for (int i = 1; i < allEvents.Count; i++)
                {
                    allEvents[i] = UpdateWave(allEvents[i], multiplier: 5);
                }

                await dataService.ReplaceValuesAsync <WaveData>(streamId, allEvents).ConfigureAwait(false);

                Console.WriteLine("Getting replaced events");
                List <WaveData> replacedEvents = (List <WaveData>) await dataService.GetWindowValuesAsync <WaveData>(streamId, "0", "180").ConfigureAwait(false);

                Console.WriteLine($"Total events found: {replacedEvents.Count}");
                foreach (WaveData evnt in replacedEvents)
                {
                    Console.WriteLine(evnt.ToString());
                }

                Console.WriteLine();

                // Step 9
                // Property Overrides
                Console.WriteLine("SDS can interpolate or extrapolate data at an index location where data does not explicitly exist:");
                Console.WriteLine();

                // We will retrieve three events using the default behavior, Continuous
                IEnumerable <WaveData> retrieved = await dataService
                                                   .GetRangeValuesAsync <WaveData>(stream.Id, "1", 3, SdsBoundaryType.ExactOrCalculated).ConfigureAwait(false);

                Console.WriteLine("Default (Continuous) requesting data starting at index location '1', where we have not entered data, SDS will interpolate a value for this property and then return entered values:");
                foreach (WaveData value in retrieved)
                {
                    Console.WriteLine(value.ToString());
                }

                Console.WriteLine();

                IEnumerable <WaveData> retrievedInterpolated = await dataService
                                                               .GetValuesAsync <WaveData>(stream.Id, "5", "32", 4).ConfigureAwait(false);

                Console.WriteLine("SDS will interpolate a value for each index asked for (5,14,23,32):");
                foreach (WaveData value in retrievedInterpolated)
                {
                    Console.WriteLine(value.ToString());
                }

                Console.WriteLine();

                // Step 10
                // We will retrieve events filtered to only get the ones where the radians are less than 50.  Note, this can be done on index properties too.
                IEnumerable <WaveData> retrievedInterpolatedFiltered = await dataService.GetWindowFilteredValuesAsync <WaveData>(stream.Id, "0", "180", SdsBoundaryType.ExactOrCalculated, "Radians lt 50").ConfigureAwait(false);

                Console.WriteLine("SDS will only return the values where the radians are less than 50:");
                foreach (WaveData value in retrievedInterpolatedFiltered)
                {
                    Console.WriteLine(value.ToString());
                }

                Console.WriteLine();

                // Step 11
                // We will retrieve a sample of our data
                Console.WriteLine("SDS can return a sample of your data population to show trends.");
                Console.WriteLine("Getting Sampled Values:");
                IEnumerable <WaveData> sampledValues = await dataService.GetSampledValuesAsync <WaveData>(stream.Id, "0",
                                                                                                          "40", 4, new[] { nameof(WaveData.Sin) }).ConfigureAwait(false);

                foreach (WaveData sample in sampledValues)
                {
                    Console.WriteLine(sample);
                }

                Console.WriteLine();

                // Step 12
                // create a Discrete stream PropertyOverride indicating that we do not want Sds to calculate a value for Radians and update our stream
                SdsStreamPropertyOverride propertyOverride = new ()
                {
                    SdsTypePropertyId = "Radians",
                    InterpolationMode = SdsInterpolationMode.Discrete,
                };
                List <SdsStreamPropertyOverride> propertyOverrides = new () { propertyOverride };

                // update the stream
                stream.PropertyOverrides = propertyOverrides;
                await metadataService.CreateOrUpdateStreamAsync(stream).ConfigureAwait(false);

                retrieved = await dataService
                            .GetRangeValuesAsync <WaveData>(stream.Id, "1", 3, SdsBoundaryType.ExactOrCalculated).ConfigureAwait(false);

                Console.WriteLine("We can override this behavior on a property by property basis, here we override the Radians property instructing Sds not to interpolate.");
                Console.WriteLine("SDS will now return the default value for the data type:");

                foreach (WaveData value in retrieved)
                {
                    Console.WriteLine(value.ToString());
                }

                Console.WriteLine();

                // Step 13
                // StreamViews
                Console.WriteLine("SdsStreamViews");

                // create target types
                SdsType targetType = SdsTypeBuilder.CreateSdsType <WaveDataTarget>();
                targetType.Id = targetTypeId;

                SdsType targetIntType = SdsTypeBuilder.CreateSdsType <WaveDataInteger>();
                targetIntType.Id = targetIntTypeId;

                await metadataService.GetOrCreateTypeAsync(targetType).ConfigureAwait(false);

                await metadataService.GetOrCreateTypeAsync(targetIntType).ConfigureAwait(false);

                // create StreamViews
                SdsStreamView autoStreamView = new ()
                {
                    Id           = autoStreamViewId,
                    SourceTypeId = typeId,
                    TargetTypeId = targetTypeId,
                };

                // create explicit mappings
                SdsStreamViewProperty vp1 = new () { SourceId = "Order", TargetId = "OrderTarget" };
                SdsStreamViewProperty vp2 = new () { SourceId = "Sin", TargetId = "SinInt" };
                SdsStreamViewProperty vp3 = new () { SourceId = "Cos", TargetId = "CosInt" };
                SdsStreamViewProperty vp4 = new () { SourceId = "Tan", TargetId = "TanInt" };

                SdsStreamView manualStreamView = new ()
                {
                    Id           = manualStreamViewId,
                    SourceTypeId = typeId,
                    TargetTypeId = targetIntTypeId,
                    Properties   = new List <SdsStreamViewProperty>()
                    {
                        vp1, vp2, vp3, vp4
                    },
                };

                await metadataService.CreateOrUpdateStreamViewAsync(autoStreamView).ConfigureAwait(false);

                await metadataService.CreateOrUpdateStreamViewAsync(manualStreamView).ConfigureAwait(false);

                Console.WriteLine("Here is some of our data as it is stored on the server:");
                foreach (WaveData evnt in retrieved)
                {
                    Console.WriteLine($"Sin: {evnt.Sin}, Cos: {evnt.Cos}, Tan {evnt.Tan}");
                }

                Console.WriteLine();

                // get autoStreamView data
                IEnumerable <WaveDataTarget> autoStreamViewData = await dataService.GetRangeValuesAsync <WaveDataTarget>(stream.Id, "1", 3, SdsBoundaryType.ExactOrCalculated, autoStreamViewId).ConfigureAwait(false);

                Console.WriteLine("Specifying a StreamView with an SdsType of the same shape returns values that are automatically mapped to the target SdsType's properties:");

                foreach (WaveDataTarget value in autoStreamViewData)
                {
                    Console.WriteLine($"SinTarget: {value.SinTarget} CosTarget: {value.CosTarget} TanTarget: {value.TanTarget}");
                }

                Console.WriteLine();

                // get manualStreamView data
                Console.WriteLine("SdsStreamViews can also convert certain types of data, here we return integers where the original values were doubles:");
                IEnumerable <WaveDataInteger> manualStreamViewData = await dataService.GetRangeValuesAsync <WaveDataInteger>(stream.Id, "1", 3, SdsBoundaryType.ExactOrCalculated, manualStreamViewId).ConfigureAwait(false);

                foreach (WaveDataInteger value in manualStreamViewData)
                {
                    Console.WriteLine($"SinInt: {value.SinInt} CosInt: {value.CosInt} TanInt: {value.TanInt}");
                }

                Console.WriteLine();

                // get SdsStreamViewMap
                Console.WriteLine("We can query SDS to return the SdsStreamViewMap for our SdsStreamView, here is the one generated automatically:");
                SdsStreamViewMap autoStreamViewMap = await metadataService.GetStreamViewMapAsync(autoStreamViewId).ConfigureAwait(false);

                PrintStreamViewMapProperties(autoStreamViewMap);

                Console.WriteLine("Here is our explicit mapping, note SdsStreamViewMap will return all properties of the Source Type, even those without a corresponding Target property:");
                SdsStreamViewMap manualStreamViewMap = await metadataService.GetStreamViewMapAsync(manualStreamViewId).ConfigureAwait(false);

                PrintStreamViewMapProperties(manualStreamViewMap);

                // Step 14
                // Update Stream Type based on SdsStreamView
                Console.WriteLine("We will now update the stream type based on the stream view");

                WaveData firstVal = await dataService.GetFirstValueAsync <WaveData>(stream.Id).ConfigureAwait(false);

                await metadataService.UpdateStreamTypeAsync(stream.Id, autoStreamViewId).ConfigureAwait(false);

                SdsStream newStream = await metadataService.GetStreamAsync(stream.Id).ConfigureAwait(false);

                WaveDataTarget firstValUpdated = await dataService.GetFirstValueAsync <WaveDataTarget>(stream.Id).ConfigureAwait(false);

                Console.WriteLine($"The new type id {newStream.TypeId} compared to the original one {stream.TypeId}.");
                Console.WriteLine($"The new type value {firstValUpdated} compared to the original one {firstVal}.");
                Console.WriteLine();

                // Step 15
                // Show filtering on Type, works the same as filtering on Streams
                IEnumerable <SdsType> types = await metadataService.GetTypesAsync().ConfigureAwait(false);

                IEnumerable <SdsType> typesFiltered = await metadataService.GetTypesAsync("Id:*Target*").ConfigureAwait(false);

                Console.WriteLine($"The number of types returned without filtering: {types.Count()}.  With filtering {typesFiltered.Count()}.");
                Console.WriteLine();

                // Step 16
                // tags and metadata
                Console.WriteLine("Let's add some Tags and Metadata to our stream:");
                List <string> tags = new () { "waves", "periodic", "2018", "validated" };
                Dictionary <string, string> metadata = new () { { "Region", "North America" }, { "Country", "Canada" }, { "Province", "Quebec" } };

                await metadataService.UpdateStreamTagsAsync(streamId, tags).ConfigureAwait(false);

                await metadataService.UpdateStreamMetadataAsync(streamId, metadata).ConfigureAwait(false);

                tags = (List <string>) await metadataService.GetStreamTagsAsync(streamId).ConfigureAwait(false);

                Console.WriteLine();
                Console.WriteLine($"Tags now associated with {streamId}:");
                foreach (string tag in tags)
                {
                    Console.WriteLine(tag);
                }

                Console.WriteLine();
                Console.WriteLine($"Metadata now associated with {streamId}:");
                Console.WriteLine("Metadata key Region: " + await metadataService.GetStreamMetadataValueAsync(streamId, "Region").ConfigureAwait(false));
                Console.WriteLine("Metadata key Country: " + await metadataService.GetStreamMetadataValueAsync(streamId, "Country").ConfigureAwait(false));
                Console.WriteLine("Metadata key Province: " + await metadataService.GetStreamMetadataValueAsync(streamId, "Province").ConfigureAwait(false));
                Console.WriteLine();

                // Step 17
                // update metadata
                Console.WriteLine("Let's make some changes to the Metadata on our stream:");
                MetadataPatchDocument patch = new ();
                patch.Remove("Region");
                patch.Replace("Province", "Ontario");
                patch.Add("City", "Toronto");
                await metadataService.PatchStreamMetadataAsync(streamId, patch).ConfigureAwait(false);

                Console.WriteLine();
                Console.WriteLine($"Metadata now associated with {streamId}:");
                Console.WriteLine("Metadata key Country: " + await metadataService.GetStreamMetadataValueAsync(streamId, "Country").ConfigureAwait(false));
                Console.WriteLine("Metadata key Province: " + await metadataService.GetStreamMetadataValueAsync(streamId, "Province").ConfigureAwait(false));
                Console.WriteLine("Metadata key City: " + await metadataService.GetStreamMetadataValueAsync(streamId, "City").ConfigureAwait(false));
                Console.WriteLine();

                // Step 18
                // delete values
                Console.WriteLine("Deleting values from the SdsStream");

                // delete one event
                await dataService.RemoveValueAsync(stream.Id, 0).ConfigureAwait(false);

                // delete all events
                await dataService.RemoveWindowValuesAsync(stream.Id, 1, 200).ConfigureAwait(false);

                retrieved = await dataService.GetWindowValuesAsync <WaveData>(stream.Id, "0", "200").ConfigureAwait(false);

                if (retrieved.ToList().Count == 0)
                {
                    Console.WriteLine("All values deleted successfully!");
                }

                Console.WriteLine();

                // Step 19
                // Adding a new stream with a secondary index.
                Console.WriteLine("Adding a stream with a secondary index.");

                SdsStreamIndex measurementIndex = new ()
                {
                    SdsTypePropertyId = type.Properties.First(p => p.Id.Equals("Radians", StringComparison.OrdinalIgnoreCase)).Id,
                };

                SdsStream secondary = new ()
                {
                    Id      = streamIdSecondary,
                    TypeId  = type.Id,
                    Indexes = new List <SdsStreamIndex>()
                    {
                        measurementIndex,
                    },
                };

                secondary = await metadataService.GetOrCreateStreamAsync(secondary).ConfigureAwait(false);

                Console.WriteLine($"Secondary indexes on streams. {stream.Id}:{stream.Indexes?.Count}. {secondary.Id}:{secondary.Indexes.Count}. ");
                Console.WriteLine();

                // Modifying an existing stream with a secondary index.
                Console.WriteLine("Modifying a stream to have a secondary index.");

                stream = await metadataService.GetStreamAsync(stream.Id).ConfigureAwait(false);

                type = await metadataService.GetTypeAsync(stream.TypeId).ConfigureAwait(false);

                SdsStreamIndex measurementTargetIndex = new ()
                {
                    SdsTypePropertyId = type.Properties.First(p => p.Id.Equals("RadiansTarget", StringComparison.OrdinalIgnoreCase)).Id,
                };
                stream.Indexes = new List <SdsStreamIndex>()
                {
                    measurementTargetIndex
                };

                await metadataService.CreateOrUpdateStreamAsync(stream).ConfigureAwait(false);

                stream = await metadataService.GetStreamAsync(stream.Id).ConfigureAwait(false);

                // Modifying an existing stream to remove the secondary index
                Console.WriteLine("Removing a secondary index from a stream.");

                secondary.Indexes = null;
                await metadataService.CreateOrUpdateStreamAsync(secondary).ConfigureAwait(false);

                secondary = await metadataService.GetStreamAsync(secondary.Id).ConfigureAwait(false);

                Console.WriteLine($"Secondary indexes on streams. {stream.Id}:{stream.Indexes?.Count}. {secondary.Id}:{secondary.Indexes?.Count}. ");
                Console.WriteLine();

                // Step 20
                // Adding Compound Index Type
                Console.WriteLine("Creating an SdsType with a compound index");
                SdsType typeCompound = SdsTypeBuilder.CreateSdsType <WaveDataCompound>();
                typeCompound.Id = compoundTypeId;
                typeCompound    = await metadataService.GetOrCreateTypeAsync(typeCompound).ConfigureAwait(false);

                // create an SdsStream
                Console.WriteLine("Creating an SdsStream off of type with compound index");
                SdsStream streamCompound = new ()
                {
                    Id          = streamIdCompound,
                    Name        = "Wave Data Sample",
                    TypeId      = typeCompound.Id,
                    Description = "This is a sample SdsStream for storing WaveData type measurements",
                };
                streamCompound = await metadataService.GetOrCreateStreamAsync(streamCompound).ConfigureAwait(false);

                // Step 21
                // insert compound data
                Console.WriteLine("Inserting data");
                await dataService.InsertValueAsync(streamCompound.Id, GetWaveMultiplier(1, 10)).ConfigureAwait(false);

                await dataService.InsertValueAsync(streamCompound.Id, GetWaveMultiplier(2, 2)).ConfigureAwait(false);

                await dataService.InsertValueAsync(streamCompound.Id, GetWaveMultiplier(3, 1)).ConfigureAwait(false);

                await dataService.InsertValueAsync(streamCompound.Id, GetWaveMultiplier(10, 3)).ConfigureAwait(false);

                await dataService.InsertValueAsync(streamCompound.Id, GetWaveMultiplier(10, 8)).ConfigureAwait(false);

                await dataService.InsertValueAsync(streamCompound.Id, GetWaveMultiplier(10, 10)).ConfigureAwait(false);

                WaveDataCompound latestCompound = await dataService.GetLastValueAsync <WaveDataCompound>(streamCompound.Id).ConfigureAwait(false);

                WaveDataCompound firstCompound = await dataService.GetFirstValueAsync <WaveDataCompound>(streamCompound.Id).ConfigureAwait(false);

                IEnumerable <WaveDataCompound> data = await dataService.GetWindowValuesAsync <WaveDataCompound, int, int>(streamCompound.Id, Tuple.Create(2, 1), Tuple.Create(10, 8)).ConfigureAwait(false);

                Console.WriteLine($"First data: {firstCompound}.  Latest data: {latestCompound}.");

                Console.WriteLine();

                Console.WriteLine("Window Data:");

                foreach (WaveDataCompound evnt in data)
                {
                    Console.WriteLine(evnt.ToString());
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                _toThrow = ex;
            }
            finally
            {
                // Step 22
                Console.WriteLine();
                Console.WriteLine("Cleaning up");

                // Delete the stream, types and streamViews making sure
                Console.WriteLine("Deleting stream");
                await RunInTryCatch(metadataService.DeleteStreamAsync, streamId).ConfigureAwait(false);
                await RunInTryCatch(metadataService.DeleteStreamAsync, streamIdSecondary).ConfigureAwait(false);
                await RunInTryCatch(metadataService.DeleteStreamAsync, streamIdCompound).ConfigureAwait(false);

                Console.WriteLine("Deleting stream views");
                await RunInTryCatch(metadataService.DeleteStreamViewAsync, autoStreamViewId).ConfigureAwait(false);
                await RunInTryCatch(metadataService.DeleteStreamViewAsync, manualStreamViewId).ConfigureAwait(false);

                Console.WriteLine("Deleting types");
                await RunInTryCatch(metadataService.DeleteTypeAsync, typeId).ConfigureAwait(false);
                await RunInTryCatch(metadataService.DeleteTypeAsync, compoundTypeId).ConfigureAwait(false);
                await RunInTryCatch(metadataService.DeleteTypeAsync, targetTypeId).ConfigureAwait(false);
                await RunInTryCatch(metadataService.DeleteTypeAsync, targetIntTypeId).ConfigureAwait(false);

                Console.WriteLine("Complete!");
                if (!test)
                {
                    Console.ReadKey();
                }
            }

            if (test && _toThrow != null)
            {
                throw _toThrow;
            }
            return(_toThrow == null);
        }