public static void Main(string[] args) { string sampleNamespaceId = "WaveData_SampleNamespace"; string sampleTypeId = "WaveData_SampleType"; string sampleStreamId = "WaveData_SampleStream"; string sampleBehaviorId = "WaveData_SampleBehavior"; Console.WriteLine("Creating a .NET Qi Administration Service..."); IQiAdministrationService qiAdministrationService = GetQiAdministrationService(); Console.WriteLine("Creating a .NET Qi Metadata Service..."); IQiMetadataService qiMetadataService = GetQiMetadataService(sampleNamespaceId); Console.WriteLine("Creating a .NET Qi Data Service..."); IQiDataService qiDataService = GetQiDataService(sampleNamespaceId); try { // Create a QiNamespace to hold the streams, types, and behaviors Console.WriteLine("Creating a QiNamespace to hold the streams, types, and behaviors"); QiNamespace sampleNamespace = new QiNamespace(sampleNamespaceId); sampleNamespace = qiAdministrationService.GetOrCreateNamespaceAsync(sampleNamespace).GetAwaiter().GetResult(); DelayForQiConsistency(); // Create a Qi Type to reflect the event data being stored in Qi. // The Qi Client Libraries provide QiTypeBuilder which constructs a QiType object // based upon a class you define in your code. Console.WriteLine("Creating a Qi type for WaveData instances"); QiTypeBuilder typeBuilder = new QiTypeBuilder(); QiType sampleType = typeBuilder.Create<WaveData>(); sampleType.Id = sampleTypeId; sampleType = qiMetadataService.GetOrCreateTypeAsync(sampleType).GetAwaiter().GetResult(); DelayForQiConsistency(); // now let's create the stream to contain the events // specify the type id of the QiType created above in the TypeId property of the QiStream object // All events submitted to this stream must be of this type Console.WriteLine("Creating a stream for simple event measurements"); QiStream sampleStream = new QiStream() { Name = "Wave Data Sample Stream", Id = sampleStreamId, TypeId = sampleTypeId, Description = "This is a sample QiStream for storing WaveData type measurements" }; sampleStream = qiMetadataService.GetOrCreateStreamAsync(sampleStream).GetAwaiter().GetResult(); DelayForQiConsistency(); #region CRUD Operations #region Create Events (Insert) Console.WriteLine("Artificially generating 100 events and inserting them into the Qi Service"); // Insert a single event into a stream TimeSpan span = new TimeSpan(0, 1, 0); WaveData waveDataEvent = WaveData.Next(span, 2.0, 0); Console.WriteLine("Inserting the first event"); qiDataService.InsertValueAsync(sampleStreamId, waveDataEvent).GetAwaiter().GetResult(); // Inserting a collection of events into a stream List<WaveData> waveDataEvents = new List<WaveData>(); for (int i = 2; i < 200; i += 2) { waveDataEvent = WaveData.Next(span, 2.0, i); waveDataEvents.Add(waveDataEvent); } Console.WriteLine("Inserting the rest of the events"); qiDataService.InsertValuesAsync(sampleStreamId, waveDataEvents).GetAwaiter().GetResult(); DelayForQiConsistency(); #endregion #region Retrieve events for a time range // use the round trip formatting for time Console.WriteLine("Retrieving the inserted events"); Console.WriteLine("=============================="); IEnumerable<WaveData> foundEvents = qiDataService.GetWindowValuesAsync<WaveData>(sampleStreamId, "0", "198").GetAwaiter().GetResult(); DumpEvents(foundEvents); #endregion #region Update an event Console.WriteLine(); Console.WriteLine("Updating the first event"); // take the first value inserted and update the value using a multiplier of 4, while retaining the order waveDataEvent = foundEvents.First(); waveDataEvent = WaveData.Next(span, 4.0, waveDataEvent.Order); qiDataService.UpdateValueAsync(sampleStreamId, waveDataEvent).GetAwaiter().GetResult(); // update the collection of events (same span, multiplier of 4, retain order) waveDataEvents = new List<WaveData>(); foreach (WaveData evnt in waveDataEvents) { waveDataEvent = WaveData.Next(span, 4.0, evnt.Order); waveDataEvents.Add(waveDataEvent); } Console.WriteLine("Updating the rest of the events"); qiDataService.UpdateValuesAsync(sampleStreamId, waveDataEvents).GetAwaiter().GetResult(); DelayForQiConsistency(); Console.WriteLine("Retrieving the updated values"); Console.WriteLine("============================="); foundEvents = qiDataService.GetWindowValuesAsync<WaveData>(sampleStreamId, "0", "198").GetAwaiter().GetResult(); DumpEvents(foundEvents); // illustrate how stream behaviors modify retrieval // First, pull three items back with GetRangeValues for range values between events. // The default behavior is continuous, so ExactOrCalculated should bring back interpolated values Console.WriteLine(); Console.WriteLine(@"Retrieving three events without a stream behavior"); foundEvents = qiDataService.GetRangeValuesAsync<WaveData>(sampleStreamId, "1", 0, 3, false, QiBoundaryType.ExactOrCalculated).GetAwaiter().GetResult(); DumpEvents(foundEvents); // now, create a stream behavior with Discrete and attach it to the existing stream Console.WriteLine("Creating a QiStreamBehavior"); QiStreamBehavior sampleBehavior = new QiStreamBehavior() { Id = sampleBehaviorId, Mode = QiStreamMode.StepwiseContinuousLeading }; sampleBehavior = qiMetadataService.GetOrCreateBehaviorAsync(sampleBehavior).GetAwaiter().GetResult(); DelayForQiConsistency(); // update the stream to include this behavior Console.WriteLine("Updating the QiStream with the new QiStreamBehaivor"); sampleStream.BehaviorId = sampleBehaviorId; qiMetadataService.UpdateStreamAsync(sampleStreamId, sampleStream).GetAwaiter().GetResult(); DelayForQiConsistency(); // repeat the retrieval Console.WriteLine(); Console.WriteLine("Retrieving three events with a stepwise stream behavior in effect -- compare to last retrieval"); foundEvents = qiDataService.GetRangeValuesAsync<WaveData>(sampleStreamId, "1", 0, 3, false, QiBoundaryType.ExactOrCalculated).GetAwaiter().GetResult(); DumpEvents(foundEvents); #endregion #region Delete events Console.WriteLine(); Console.WriteLine("Deleting first event"); qiDataService.RemoveValueAsync(sampleStreamId, 0).GetAwaiter().GetResult(); Console.WriteLine("Deleting the rest of the events"); qiDataService.RemoveWindowValuesAsync(sampleStreamId, 2, 198).GetAwaiter().GetResult(); DelayForQiConsistency(); Console.WriteLine("Checking for events"); Console.WriteLine("==================="); foundEvents = qiDataService.GetWindowValuesAsync<WaveData>(sampleStreamId, "0", "198").GetAwaiter().GetResult(); DumpEvents(foundEvents); Console.WriteLine("Test ran successfully"); Console.WriteLine("===================="); Console.WriteLine("Press any button to shutdown"); Console.ReadLine(); #endregion #endregion } catch (QiHttpClientException qerr) { PrintError("Error in Qi Service", qerr); } catch (Exception ex) { PrintError("Unknown Error", ex); } finally { // clean up all created entities so you can run this again // all entities are reference counted, so you must delete the stream, then the type it uses Console.WriteLine("Deleting the stream..."); HandleQiCallAsync(async () => await qiMetadataService.DeleteStreamAsync(sampleStreamId)).GetAwaiter().GetResult(); Console.WriteLine("Deleting the behavior..."); HandleQiCallAsync(async () => await qiMetadataService.DeleteBehaviorAsync(sampleBehaviorId)).GetAwaiter().GetResult(); Console.WriteLine("Deleting the type..."); HandleQiCallAsync(async () => await qiMetadataService.DeleteTypeAsync(sampleTypeId)).GetAwaiter().GetResult(); } }
private static void Main(string[] args) { // ==== Client constants ==== var tenant = ConfigurationManager.AppSettings["Tenant"]; var address = ConfigurationManager.AppSettings["Address"]; var resource = ConfigurationManager.AppSettings["Resource"]; var appId = ConfigurationManager.AppSettings["AppId"]; var appKey = ConfigurationManager.AppSettings["AppKey"]; var namespaceId = ConfigurationManager.AppSettings["Namespace"]; // ==== Setup the namespace. The namespace provides isolation within a Tenant. ==== var admin = QiService.GetAdministrationService(new Uri(address), tenant, new QiSecurityHandler(resource, tenant, appId, appKey)); var sampleNamespace = new QiNamespace(namespaceId); sampleNamespace = admin.GetOrCreateNamespaceAsync(sampleNamespace).GetAwaiter().GetResult(); // ==== Setup the type and stream ==== var config = QiService.GetMetadataService(new Uri(address), tenant, namespaceId, new QiSecurityHandler(resource, tenant, appId, appKey)); QiType type = QiTypeBuilder.CreateQiType <WaveData>(); type = config.GetOrCreateTypeAsync(type).GetAwaiter().GetResult(); var stream = new QiStream { Id = Guid.NewGuid().ToString(), Name = "Wave Data Sample", TypeId = type.Id, Description = "This is a sample QiStream for storing WaveData type measurements" }; stream = config.GetOrCreateStreamAsync(stream).GetAwaiter().GetResult(); // ==== Perform a number of CRUD opreations ==== var client = QiService.GetDataService(new Uri(address), tenant, namespaceId, new QiSecurityHandler(resource, tenant, appId, appKey)); // Insert a single event into a stream var wave = GetWave(0, 200, 2); client.InsertValueAsync(stream.Id, wave).GetAwaiter().GetResult(); // Update will add the event as well wave.Order += 1; client.UpdateValueAsync(stream.Id, wave).GetAwaiter().GetResult(); // Inserting a collection of events into a stream (more efficient) var waves = new List <WaveData>(); for (var i = 2; i <= 200; ++i) { waves.Add(GetWave(i, 200, 2)); } client.InsertValuesAsync(stream.Id, waves).GetAwaiter().GetResult(); // Retrieve events for a the range. Indexes are expected in string format. Order property is is the Key IEnumerable <WaveData> retrieved = client.GetWindowValuesAsync <WaveData>(stream.Id, "0", "200").GetAwaiter().GetResult(); Console.WriteLine("Retrieved {0} events", retrieved.Count()); Console.WriteLine("\tfrom {0} {1}", retrieved.First().Order, retrieved.First().Sin); Console.WriteLine("\tto {0} {1}", retrieved.Last().Order, retrieved.Last().Sin); // Update some events UpdateWave(retrieved.First(), 4); client.UpdateValueAsync(stream.Id, retrieved.First()).GetAwaiter().GetResult(); foreach (var value in waves) { UpdateWave(value, 4); } client.UpdateValuesAsync(stream.Id, waves.ToList()).GetAwaiter().GetResult(); retrieved = client.GetWindowValuesAsync <WaveData>(stream.Id, "0", "200").GetAwaiter().GetResult(); Console.WriteLine("Updated {0} events", retrieved.Count()); Console.WriteLine("\tfrom {0} {1}", retrieved.First().Order, retrieved.First().Sin); Console.WriteLine("\tto {0} {1}", retrieved.Last().Order, retrieved.Last().Sin); // Stream behaviors modify retrieval // Retrieve a range of three values using the default behavior. The default behavior is Continuous, // so ExactOrCalculated should bring back interpolated values retrieved = client.GetRangeValuesAsync <WaveData>(stream.Id, "1", 0, 3, false, QiBoundaryType.ExactOrCalculated).GetAwaiter().GetResult(); Console.WriteLine("Default behavior {0} events", retrieved.Count()); foreach (var value in retrieved) { Console.WriteLine("\t{0} {1}", value.Order, value.Sin); } // Modify the stream behavior to StepwiseContinuousLeading var stepwiseContinuousLeading = new QiStreamBehavior { Id = Guid.NewGuid().ToString(), Mode = QiStreamMode.StepwiseContinuousLeading }; stepwiseContinuousLeading = config.GetOrCreateBehaviorAsync(stepwiseContinuousLeading).GetAwaiter().GetResult(); stream.BehaviorId = stepwiseContinuousLeading.Id; config.UpdateStreamAsync(stream.Id, stream).GetAwaiter().GetResult(); retrieved = client.GetRangeValuesAsync <WaveData>(stream.Id, "1", 0, 3, false, QiBoundaryType.ExactOrCalculated).GetAwaiter().GetResult(); Console.WriteLine("StepwiseContinuousLeading behavior {0} events", retrieved.Count()); foreach (var value in retrieved) { Console.WriteLine("\t{0} {1}", value.Order, value.Sin); } // Delete the first event in the stream, the event at index zero client.RemoveValueAsync(stream.Id, 0).GetAwaiter().GetResult(); // Delete the rest of the Events client.RemoveWindowValuesAsync(stream.Id, 1, 200).GetAwaiter().GetResult(); retrieved = client.GetWindowValuesAsync <WaveData>(stream.Id, "0", "200").GetAwaiter().GetResult(); Console.WriteLine("After delete {0} events remain", retrieved.Count()); // Delete the stream and behavior config.DeleteStreamAsync(stream.Id).GetAwaiter().GetResult(); config.DeleteBehaviorAsync(stepwiseContinuousLeading.Id).GetAwaiter().GetResult(); // It is less common to remove the type and namespace config.DeleteTypeAsync(type.Id).GetAwaiter().GetResult(); // admin.DeleteNamespaceAsync(sampleNamespace.Id).GetAwaiter().GetResult(); }
private static void Main(string[] args) { // ==== Create the client ==== var tenant = ConfigurationManager.AppSettings["Tenant"]; var address = ConfigurationManager.AppSettings["Address"]; var aadFormat = ConfigurationManager.AppSettings["AADInstanceFormat"]; var resource = ConfigurationManager.AppSettings["Resource"]; var appId = ConfigurationManager.AppSettings["AppId"]; var appKey = ConfigurationManager.AppSettings["AppKey"]; // A formal client should be wrapped in a retry handler. HttpClient client = HttpClientFactory.Create(new WebRequestHandler(), new AuthenticationHandler(resource, tenant, aadFormat, appId, appKey)); client.BaseAddress = new Uri(address); // ==== Get or create the namespace, type and stream(s) ==== var space = new QiNamespace() { Id = ConfigurationManager.AppSettings["Namespace"] }; HttpResponseMessage response = client.GetAsync($"Qi/{tenant}/Namespaces/{space.Id}").GetAwaiter().GetResult(); if (response.StatusCode == HttpStatusCode.NotFound) { response = client.PostAsJsonAsync($"Qi/{tenant}/Namespaces", space).GetAwaiter().GetResult(); } if (!response.IsSuccessStatusCode) { throw new HttpResponseException(response); } var type = QiTypeBuilder.CreateQiType <WaveData>(); response = client.GetAsync($"Qi/{tenant}/{space.Id}/Types/{type.Id}").GetAwaiter().GetResult(); if (response.StatusCode == HttpStatusCode.NotFound) { response = client.PostAsJsonAsync($"Qi/{tenant}/{space.Id}/Types", type).GetAwaiter().GetResult(); } if (!response.IsSuccessStatusCode) { throw new HttpResponseException(response); } var stream = new QiStream() { Id = Guid.NewGuid().ToString(), Name = typeof(WaveData).Name, Description = "Sample", TypeId = type.Id }; response = client.GetAsync($"Qi/{tenant}/{space.Id}/Streams/{stream.Id}").GetAwaiter().GetResult(); if (response.StatusCode == HttpStatusCode.NotFound) { response = client.PostAsJsonAsync($"Qi/{tenant}/{space.Id}/Streams", stream).GetAwaiter().GetResult(); } if (!response.IsSuccessStatusCode) { throw new HttpResponseException(response); } // ==== Perform basic CRUD optations ==== // insert a single event var wave = GetWave(0, 200, 2); response = client.PutAsJsonAsync($"Qi/{tenant}/{space.Id}/Streams/{stream.Id}/Data/UpdateValue", wave) .GetAwaiter() .GetResult(); if (!response.IsSuccessStatusCode) { throw new HttpResponseException(response); } // Insert another single event using a Post instead of a Put wave.Order += 1; response = client.PostAsJsonAsync($"Qi/{tenant}/{space.Id}/Streams/{stream.Id}/Data/InsertValue", wave) .GetAwaiter() .GetResult(); if (!response.IsSuccessStatusCode) { throw new HttpResponseException(response); } // Insert a collection of events var events = new List <WaveData>(); for (var i = 2; i <= 200; i += 2) { events.Add(GetWave(i, 200, 2)); } response = client.PostAsJsonAsync($"Qi/{tenant}/{space.Id}/Streams/{stream.Id}/Data/InsertValues", events) .GetAwaiter() .GetResult(); if (!response.IsSuccessStatusCode) { throw new HttpResponseException(response); } // retrieve the newly inserted events response = client.GetAsync( $"Qi/{tenant}/{space.Id}/Streams/{stream.Id}/Data/GetValues?startIndex={0}&endIndex={200}&count={100}") .GetAwaiter() .GetResult(); if (!response.IsSuccessStatusCode) { throw new HttpResponseException(response); } var retrievedEvents = response.Content.ReadAsAsync <WaveData[]>().GetAwaiter().GetResult(); // Update the events Array.ForEach(retrievedEvents, w => GetWave(w.Order, 200, 3)); response = client.PutAsJsonAsync($"Qi/{tenant}/{space.Id}/Streams/{stream.Id}/Data/UpdateValues", events) .GetAwaiter() .GetResult(); if (!response.IsSuccessStatusCode) { throw new HttpResponseException(response); } // ==== Clean up ==== // It's not necessary to delete the values if you're deleting the stream response = client.DeleteAsync( $"Qi/{tenant}/{space.Id}/Streams/{stream.Id}/Data/RemoveWindowValues?startIndex={0}&endIndex={200}") .GetAwaiter() .GetResult(); if (!response.IsSuccessStatusCode) { throw new HttpResponseException(response); } response = client.DeleteAsync($"Qi/{tenant}/{space.Id}/Streams/{stream.Id}").GetAwaiter().GetResult(); if (!response.IsSuccessStatusCode) { throw new HttpResponseException(response); } response = client.DeleteAsync($"Qi/{tenant}/{space.Id}/Types/{type.Id}").GetAwaiter().GetResult(); if (!response.IsSuccessStatusCode) { throw new HttpResponseException(response); } }