static void Main(string[] args) { Console.WriteLine("Creating a .NET Qi Client..."); string server = Constants.QiServerUrl; QiType evtType = null; QiHttpClientFactory <IQiServer> clientFactory = new QiHttpClientFactory <IQiServer>(); clientFactory.ProxyTimeout = new TimeSpan(0, 1, 0); IQiServer qiclient = clientFactory.CreateChannel(new Uri(server)); IQiClientProxy proxy = (IQiClientProxy)qiclient; proxy.OnBeforeInvoke((handler) => { string token = AcquireAuthToken(); if (proxy.Client.DefaultHeaders.Contains("Authorization")) { proxy.Client.DefaultHeaders.Remove("Authorization"); } proxy.Client.DefaultHeaders.Add("Authorization", new AuthenticationHeaderValue("Bearer", token).ToString()); }); try { // 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(); evtType = typeBuilder.Create <WaveData>(); evtType.Id = "WaveType"; QiType tp = qiclient.GetOrCreateType(evtType); // 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(); sampleStream.Name = "evtStream"; sampleStream.Id = "evtStream"; sampleStream.TypeId = tp.Id; sampleStream.Description = "This is a sample stream for storing WaveData type measurements"; QiStream strm = qiclient.GetOrCreateStream(sampleStream); #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 evt = WaveData.Next(span, 2.0, 0); qiclient.InsertValue("evtStream", evt); // Inserting a collection of events into a stream List <WaveData> events = new List <WaveData>(); for (int i = 2; i < 200; i += 2) { WaveData newEvt = WaveData.Next(span, 2.0, i); events.Add(newEvt); Thread.Sleep(400); } qiclient.InsertValues("evtStream", events); Thread.Sleep(2000); #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> foundEvts = qiclient.GetWindowValues <WaveData>("evtStream", "0", "198"); DumpEvents(foundEvts); #endregion #region Update an event Console.WriteLine(); Console.WriteLine("Updating values"); // take the first value inserted and update the value using a multiplier of 4, while retaining the order evt = foundEvts.First(); evt = WaveData.Next(span, 4.0, evt.Order); qiclient.UpdateValue("evtStream", evt); // update the collection of events (same span, multiplier of 4, retain order) List <WaveData> newEvents = new List <WaveData>(); foreach (WaveData evnt in events) { WaveData newEvt = WaveData.Next(span, 4.0, evnt.Order); newEvents.Add(newEvt); Thread.Sleep(500); } qiclient.UpdateValues("evtStream", newEvents); Thread.Sleep(2000); Console.WriteLine("Retrieving the updated values"); Console.WriteLine("============================="); foundEvts = qiclient.GetWindowValues <WaveData>("evtStream", "0", "198"); DumpEvents(foundEvts); // 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"); foundEvts = qiclient.GetRangeValues <WaveData>("evtStream", "1", 0, 3, false, QiBoundaryType.ExactOrCalculated); DumpEvents(foundEvts); // now, create a stream behavior with Discrete and attach it to the existing stream QiStreamBehavior behavior = new QiStreamBehavior(); behavior.Id = "evtStreamStepLeading"; behavior.Mode = QiStreamMode.StepwiseContinuousLeading; behavior = qiclient.GetOrCreateBehavior(behavior); // update the stream to include this behavior sampleStream.BehaviorId = behavior.Id; qiclient.UpdateStream("evtStream", sampleStream); // repeat the retrieval Console.WriteLine(); Console.WriteLine("Retrieving three events with a stepwise stream behavior in effect -- compare to last retrieval"); foundEvts = qiclient.GetRangeValues <WaveData>("evtStream", "1", 0, 3, false, QiBoundaryType.ExactOrCalculated); DumpEvents(foundEvts); #endregion #region Delete events Console.WriteLine(); Console.WriteLine("Deleting events"); qiclient.RemoveValue("evtStream", 0); qiclient.RemoveWindowValues("evtStream", 2, 198); Thread.Sleep(2000); Console.WriteLine("Checking for events"); Console.WriteLine("==================="); foundEvts = qiclient.GetWindowValues <WaveData>("evtStream", "0", "198"); DumpEvents(foundEvts); Console.WriteLine("Test ran successfully"); Console.WriteLine("===================="); Console.WriteLine("Press any button to shutdown"); Console.ReadLine(); #endregion #endregion } catch (QiHttpClientException qiex) { Console.WriteLine("Error in Qi Service Client: " + qiex.Message); } catch (Exception ex) { Console.WriteLine("Other error: " + ex.Message); } 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 try { qiclient.DeleteStream("evtStream"); qiclient.DeleteBehavior("evtStreamStepLeading"); qiclient.DeleteType(evtType.Id); } catch (Exception) { } } }
private static async Task MainAsync() { IConfigurationBuilder builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json"); IConfiguration configuration = builder.Build(); // ==== Client constants ==== var tenantId = configuration["TenantId"]; var namespaceId = configuration["NamespaceId"]; var address = configuration["Address"]; var resource = configuration["Resource"]; var clientId = configuration["ClientId"]; var clientKey = configuration["ClientKey"]; // ==== Metadata IDs ==== string streamId = "SampleStream"; string typeId = "SampleType"; string behaviorId = "SampleBehavior"; string targetTypeId = "SampleType_Target"; string targetIntTypeId = "SampleType_TargetInt"; string autoViewId = "SampleAutoView"; string manualViewId = "SampleManualView"; // Get Qi Services to communicate with server QiSecurityHandler securityHandler = new QiSecurityHandler(resource, tenantId, clientId, clientKey); QiService qiService = new QiService(new Uri(address), securityHandler); var metadataService = qiService.GetMetadataService(tenantId, namespaceId); var dataService = qiService.GetDataService(tenantId, namespaceId); LoggerCallbackHandler.UseDefaultLogging = false; Console.WriteLine(@"---------------------------------------------------"); Console.WriteLine(@"________ .__ _______ ______________________"); Console.WriteLine(@"\_____ \ |__| \ \ \_ _____/\__ ___/"); Console.WriteLine(@" / / \ \| | / | \ | __)_ | | "); Console.WriteLine(@"/ \_/. \ | / | \| \ | | "); Console.WriteLine(@"\_____\ \_/__| /\ \____|__ /_______ / |____| "); Console.WriteLine(@" \__> \/ \/ \/ "); Console.WriteLine(@"---------------------------------------------------"); Console.WriteLine(); Console.WriteLine($"Qi endpoint at {address}"); Console.WriteLine(); try { // create a QiType Console.WriteLine("Creating a QiType"); QiType type = QiTypeBuilder.CreateQiType <WaveData>(); type.Id = typeId; type = await metadataService.GetOrCreateTypeAsync(type); // create a QiStream Console.WriteLine("Creating a QiStream"); var stream = new QiStream { Id = streamId, Name = "Wave Data Sample", TypeId = type.Id, Description = "This is a sample QiStream for storing WaveData type measurements" }; stream = await metadataService.GetOrCreateStreamAsync(stream); // insert data Console.WriteLine("Inserting data"); // insert a single event var wave = GetWave(0, 200, 2); await dataService.InsertValueAsync(stream.Id, wave); // insert a list of events var waves = new List <WaveData>(); for (var i = 2; i <= 18; i += 2) { waves.Add(GetWave(i, 200, 2)); } await dataService.InsertValuesAsync(stream.Id, waves); // get last event Console.WriteLine("Getting latest event"); var latest = await dataService.GetLastValueAsync <WaveData>(streamId); Console.WriteLine(latest.ToString()); Console.WriteLine(); // get all events Console.WriteLine("Getting all events"); var allEvents = (List <WaveData>) await dataService.GetWindowValuesAsync <WaveData>(streamId, "0", "180"); Console.WriteLine($"Total events found: {allEvents.Count}"); foreach (var evnt in allEvents) { Console.WriteLine(evnt.ToString()); } Console.WriteLine(); // update events Console.WriteLine("Updating events"); // update one event var updatedWave = UpdateWave(allEvents.First(), 4); await dataService.UpdateValueAsync(stream.Id, updatedWave); // update all events, adding ten more var updatedCollection = new List <WaveData>(); for (int i = 2; i < 40; i = i + 2) { updatedCollection.Add(GetWave(i, 400, 4)); } await dataService.UpdateValuesAsync(stream.Id, updatedCollection); allEvents = (List <WaveData>) await dataService.GetWindowValuesAsync <WaveData>(stream.Id, "0", "180"); Console.WriteLine("Getting updated events"); Console.WriteLine($"Total events found: {allEvents.Count}"); foreach (var evnt in allEvents) { Console.WriteLine(evnt.ToString()); } Console.WriteLine(); // replacing events Console.WriteLine("Replacing events"); // replace one event var replaceEvent = allEvents.First(); replaceEvent.Sin = 0.717; replaceEvent.Cos = 0.717; replaceEvent.Tan = Math.Sqrt(2 * (0.717 * 0.717)); await dataService.ReplaceValueAsync <WaveData>(streamId, replaceEvent); // replace all events foreach (var evnt in allEvents) { evnt.Sin = 5.0 / 2; evnt.Cos = 5 * Math.Sqrt(3) / 2; evnt.Tan = 5 / Math.Sqrt(3); } await dataService.ReplaceValuesAsync <WaveData>(streamId, allEvents); Console.WriteLine("Getting replaced events"); var replacedEvents = (List <WaveData>) await dataService.GetWindowValuesAsync <WaveData>(streamId, "0", "180"); Console.WriteLine($"Total events found: {replacedEvents.Count}"); foreach (var evnt in replacedEvents) { Console.WriteLine(evnt.ToString()); } Console.WriteLine(); // Stream behaviors Console.WriteLine("QiStreamBehaviors determine whether Qi interpolates or extrapolates data at the requested index location"); Console.WriteLine(); // Stream behaviors modify retrieval. We will retrieve three events using the default behavior, Continuous var retrieved = await dataService .GetRangeValuesAsync <WaveData>(stream.Id, "1", 3, QiBoundaryType.ExactOrCalculated); Console.WriteLine("Default (Continuous) stream behavior, requesting data starting at index location '1', Qi will interpolate this value:"); foreach (var value in retrieved) { Console.WriteLine($"Order: {value.Order}, Radians: {value.Radians}"); } Console.WriteLine(); // create a Discrete stream behavior var behavior = new QiStreamBehavior { Id = behaviorId, Mode = QiStreamMode.Discrete }; behavior = await metadataService.GetOrCreateBehaviorAsync(behavior); // update the stream stream.BehaviorId = behavior.Id; await metadataService.CreateOrUpdateStreamAsync(stream); retrieved = await dataService .GetRangeValuesAsync <WaveData>(stream.Id, "1", 3, QiBoundaryType.ExactOrCalculated); Console.WriteLine("Discrete stream behavior, Qi does not interpolate and returns the data starting at the next index location containing data:"); foreach (var value in retrieved) { Console.WriteLine($"Order: {value.Order}, Radians: {value.Radians}"); } Console.WriteLine(); // Stream views Console.WriteLine("QiViews"); // create target types var targetType = QiTypeBuilder.CreateQiType <WaveDataTarget>(); targetType.Id = targetTypeId; var targetIntType = QiTypeBuilder.CreateQiType <WaveDataInteger>(); targetIntType.Id = targetIntTypeId; await metadataService.CreateOrUpdateTypeAsync(targetType); await metadataService.CreateOrUpdateTypeAsync(targetIntType); // create views var autoView = new QiView() { Id = autoViewId, SourceTypeId = typeId, TargetTypeId = targetTypeId }; // create explicit mappings var vp1 = new QiViewProperty() { SourceId = "Order", TargetId = "OrderTarget" }; var vp2 = new QiViewProperty() { SourceId = "Sin", TargetId = "SinInt" }; var vp3 = new QiViewProperty() { SourceId = "Cos", TargetId = "CosInt" }; var vp4 = new QiViewProperty() { SourceId = "Tan", TargetId = "TanInt" }; var manualView = new QiView() { Id = manualViewId, SourceTypeId = typeId, TargetTypeId = targetIntTypeId, Properties = new List <QiViewProperty>() { vp1, vp2, vp3, vp4 } }; await metadataService.CreateOrUpdateViewAsync(autoView); await metadataService.CreateOrUpdateViewAsync(manualView); Console.WriteLine("Here is some of our data as it is stored on the server:"); foreach (var evnt in retrieved) { Console.WriteLine($"Sin: {evnt.Sin}, Cos: {evnt.Cos}, Tan {evnt.Tan}"); } Console.WriteLine(); // get autoview data var autoViewData = await dataService.GetRangeValuesAsync <WaveDataTarget>(stream.Id, "1", 3, QiBoundaryType.ExactOrCalculated, autoViewId); Console.WriteLine("Specifying a view with a QiType of the same shape returns values that are automatically mapped to the target QiType's properties:"); foreach (var value in autoViewData) { Console.WriteLine($"SinTarget: {value.SinTarget} CosTarget: {value.CosTarget} TanTarget: {value.TanTarget}"); } Console.WriteLine(); // get manaulview data Console.WriteLine("QiViews can also convert certain types of data, here we return integers where the original values were doubles:"); var manualViewData = await dataService.GetRangeValuesAsync <WaveDataInteger>(stream.Id, "1", 3, QiBoundaryType.ExactOrCalculated, manualViewId); foreach (var value in manualViewData) { Console.WriteLine($"SinInt: {value.SinInt} CosInt: {value.CosInt} TanInt: {value.TanInt}"); } Console.WriteLine(); // get QiViewMap Console.WriteLine("We can query Qi to return the QiViewMap for our QiView, here is the one generated automatically:"); var autoViewMap = await metadataService.GetViewMapAsync(autoViewId); PrintViewMapProperties(autoViewMap); Console.WriteLine("Here is our explicit mapping, note QiViewMap will return all properties of the Source Type, even those without a corresponding Target property:"); var manualViewMap = await metadataService.GetViewMapAsync(manualViewId); PrintViewMapProperties(manualViewMap); // delete values Console.WriteLine("Deleting values from the QiStream"); // delete one event await dataService.RemoveValueAsync(stream.Id, 0); // delete all events await dataService.RemoveWindowValuesAsync(stream.Id, 1, 200); retrieved = await dataService.GetWindowValuesAsync <WaveData>(stream.Id, "0", "200"); if (retrieved.ToList <WaveData>().Count == 0) { Console.WriteLine("All values deleted successfully!"); } Console.WriteLine(); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { Console.WriteLine("Cleaning up"); // Delete the stream, types, views and behavior Console.WriteLine("Deleteing stream"); await metadataService.DeleteStreamAsync(streamId); Console.WriteLine("Deleteing types"); await metadataService.DeleteTypeAsync(typeId); await metadataService.DeleteTypeAsync(targetTypeId); await metadataService.DeleteTypeAsync(targetIntTypeId); Console.WriteLine("Deleteing views"); await metadataService.DeleteViewAsync(autoViewId); await metadataService.DeleteViewAsync(manualViewId); Console.WriteLine("Deleteing behavior"); await metadataService.DeleteBehaviorAsync(behaviorId); Console.WriteLine("done"); Console.ReadKey(); } }
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(); }
static void Main(string[] args) { Console.WriteLine("Creating a .NET Qi Client..."); string server = ConfigurationManager.AppSettings["QiServerUrl"]; QiType evtType = null; ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; QiHttpClientFactory<IQiServer> clientFactory = new QiHttpClientFactory<IQiServer>(); clientFactory.ProxyTimeout = new TimeSpan(0, 1, 0); IQiServer qiclient = clientFactory.CreateChannel(new Uri(server)); IQiClientProxy proxy = (IQiClientProxy)qiclient; proxy.OnBeforeInvoke((handler)=>{ string token = AcquireAuthToken(); if (proxy.Client.DefaultHeaders.Contains("Authorization")) { proxy.Client.DefaultHeaders.Remove("Authorization"); } proxy.Client.DefaultHeaders.Add("Authorization", new AuthenticationHeaderValue("Bearer", token).ToString()); }); try { // Create a Qi Type -- the Qi Libraries let you do this via reflection // First, create a type builder, then pass it the name of the class you are using for events. // This greatly simplifies type creation Console.WriteLine("Creating a Qi type for WaveData instances"); QiTypeBuilder typeBuilder = new QiTypeBuilder(); evtType = typeBuilder.Create<WaveData>(); evtType.Id = "WaveType"; QiType tp = qiclient.GetOrCreateType(evtType); Console.WriteLine("Creating a stream in this tenant for simple event measurements"); QiStream sampleStream = new QiStream(); sampleStream.Name = "evtStream"; sampleStream.Id = "evtStream"; // set the TypeId property to the value of the Id property of the type you submitted // All events submitted to this stream must be of this type // Note there are Async versions of the client methods, too, using .NET TPL sampleStream.TypeId = tp.Id; sampleStream.Description = "This is a sample stream for storing WaveData type measurements"; QiStream strm = qiclient.GetOrCreateStream(sampleStream); #region CRUD Operations #region Create Events (Insert) Console.WriteLine("Artificially generating 100 events and inserting them into the Qi Service"); // How to insert a single event TimeSpan span = new TimeSpan(0, 1, 0); WaveData evt = WaveData.Next(span, 2.0, 0); qiclient.InsertValue("evtStream", evt); List<WaveData> events = new List<WaveData>(); // how to insert an a collection of events for (int i = 2; i < 200; i+=2) { WaveData newEvt = WaveData.Next(span, 2.0, i); events.Add(newEvt); Thread.Sleep(400); } qiclient.InsertValues<WaveData>("evtStream", events); Thread.Sleep(2000); #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> foundEvts = qiclient.GetWindowValues<WaveData>("evtStream", "0", "198"); DumpEvents(foundEvts); #endregion #region Update an event Console.WriteLine(); Console.WriteLine("Updating values"); // take the first value inserted and update the value using a multiplier of 4, while retaining the order evt = foundEvts.First<WaveData>(); evt = WaveData.Next(span, 4.0, evt.Order); qiclient.UpdateValue<WaveData>("evtStream", evt); // update the collection of events (same span, multiplier of 4, retain order) List<WaveData> newEvents = new List<WaveData>(); foreach (WaveData evnt in events) { WaveData newEvt = WaveData.Next(span, 4.0, evnt.Order); newEvents.Add(newEvt); Thread.Sleep(500); } qiclient.UpdateValues<WaveData>("evtStream", newEvents); Thread.Sleep(2000); Console.WriteLine("Retrieving the updated values"); Console.WriteLine("============================="); foundEvts = qiclient.GetWindowValues<WaveData>("evtStream", "0", "198"); DumpEvents(foundEvts); // 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"); foundEvts = qiclient.GetRangeValues<WaveData>("evtStream", "1", 0, 3, false, QiBoundaryType.ExactOrCalculated); DumpEvents(foundEvts); // now, create a stream behavior with Discrete and attach it to the existing stream QiStreamBehavior behavior = new QiStreamBehavior(); behavior.Id = "evtStreamStepLeading"; behavior.Mode = QiStreamMode.StepwiseContinuousLeading; behavior = qiclient.GetOrCreateBehavior(behavior); // update the stream to include this behavior sampleStream.BehaviorId = behavior.Id; qiclient.UpdateStream("evtStream", sampleStream); // repeat the retrieval Console.WriteLine(); Console.WriteLine("Retrieving three events with a stepwise stream behavior in effect -- compare to last retrieval"); foundEvts = qiclient.GetRangeValues<WaveData>("evtStream", "1", 0, 3, false, QiBoundaryType.ExactOrCalculated); DumpEvents(foundEvts); #endregion #region Delete events Console.WriteLine(); Console.WriteLine("Deleting events"); qiclient.RemoveValue<int>("evtStream", 0); qiclient.RemoveWindowValues<int>("evtStream", 2, 198); Thread.Sleep(2000); Console.WriteLine("Checking for events"); Console.WriteLine("==================="); foundEvts = qiclient.GetWindowValues<WaveData>("evtStream", "0", "198"); DumpEvents(foundEvts); #endregion #endregion } catch (QiHttpClientException qiex) { Console.WriteLine("Error in Qi Service Client: " + qiex.Message); } catch (Exception ex) { Console.WriteLine("Other error: " + ex.Message); } 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 try { qiclient.DeleteStream("evtStream"); qiclient.DeleteBehavior("evtStreamStepLeading"); qiclient.DeleteType(evtType.Id); } catch (Exception) { } } }
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(); } }
static void Main(string[] args) { Console.WriteLine("Creating a .NET Qi Client..."); string server = ConfigurationManager.AppSettings["QiServerUrl"]; QiType evtType = null; // acquire an authentication token from Azure AD string token = AcquireAuthToken(); // set up a client to the Qi Service -- it is essential that you set the QiTenant header QiHttpClientFactory <IQiServer> clientFactory = new QiHttpClientFactory <IQiServer>(); clientFactory.ProxyTimeout = new TimeSpan(0, 1, 0); clientFactory.OnCreated((p) => p.DefaultHeaders.Add("Authorization", new AuthenticationHeaderValue("Bearer", token).ToString())); IQiServer qiclient = clientFactory.CreateChannel(new Uri(server)); try { // Create a Qi Type -- the Qi Libraries let you do this via reflection // First, create a type builder, then pass it the name of the class you are using for events. // This greatly simplifies type creation Console.WriteLine("Creating a Qi type for WaveData instances"); QiTypeBuilder typeBuilder = new QiTypeBuilder(); evtType = typeBuilder.Create <WaveData>(); evtType.Id = "WaveType"; QiType tp = qiclient.GetOrCreateType(evtType); Console.WriteLine("Creating a stream in this tenant for simple event measurements"); QiStream sampleStream = new QiStream(); sampleStream.Name = "evtStream"; sampleStream.Id = "evtStream"; // set the TypeId property to the value of the Id property of the type you submitted // All events submitted to this stream must be of this type // Note there are Async versions of the client methods, too, using .NET TPL sampleStream.TypeId = tp.Id; sampleStream.Description = "This is a sample stream for storing WaveData type measurements"; QiStream strm = qiclient.GetOrCreateStream(sampleStream); #region CRUD Operations #region Create Events (Insert) Console.WriteLine("Artificially generating 100 events and inserting them into the Qi Service"); // How to insert a single event TimeSpan span = new TimeSpan(0, 1, 0); WaveData evt = WaveData.Next(span, 2.0, 0); qiclient.InsertValue("evtStream", evt); List <WaveData> events = new List <WaveData>(); // how to insert an a collection of events for (int i = 2; i < 200; i += 2) { WaveData newEvt = WaveData.Next(span, 2.0, i); events.Add(newEvt); Thread.Sleep(400); } qiclient.InsertValues <WaveData>("evtStream", events); Thread.Sleep(2000); #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> foundEvts = qiclient.GetWindowValues <WaveData>("evtStream", "0", "198"); DumpEvents(foundEvts); #endregion #region Update an event Console.WriteLine(); Console.WriteLine("Updating values"); // take the first value inserted and update the value using a multiplier of 4, while retaining the order evt = foundEvts.First <WaveData>(); evt = WaveData.Next(span, 4.0, evt.Order); qiclient.UpdateValue <WaveData>("evtStream", evt); // update the collection of events (same span, multiplier of 4, retain order) List <WaveData> newEvents = new List <WaveData>(); foreach (WaveData evnt in events) { WaveData newEvt = WaveData.Next(span, 4.0, evnt.Order); newEvents.Add(newEvt); Thread.Sleep(500); } qiclient.UpdateValues <WaveData>("evtStream", newEvents); Thread.Sleep(2000); Console.WriteLine("Retrieving the updated values"); Console.WriteLine("============================="); foundEvts = qiclient.GetWindowValues <WaveData>("evtStream", "0", "198"); DumpEvents(foundEvts); // 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"); foundEvts = qiclient.GetRangeValues <WaveData>("evtStream", "1", 0, 3, false, QiBoundaryType.ExactOrCalculated); DumpEvents(foundEvts); // now, create a stream behavior with Discrete and attach it to the existing stream QiStreamBehavior behavior = new QiStreamBehavior(); behavior.Id = "evtStreamStepLeading"; behavior.Mode = QiStreamMode.StepwiseContinuousLeading; behavior = qiclient.GetOrCreateBehavior(behavior); // update the stream to include this behavior sampleStream.BehaviorId = behavior.Id; qiclient.UpdateStream("evtStream", sampleStream); // repeat the retrieval Console.WriteLine(); Console.WriteLine("Retrieving three events with a stepwise stream behavior in effect -- compare to last retrieval"); foundEvts = qiclient.GetRangeValues <WaveData>("evtStream", "1", 0, 3, false, QiBoundaryType.ExactOrCalculated); DumpEvents(foundEvts); #endregion #region Delete events Console.WriteLine(); Console.WriteLine("Deleting events"); qiclient.RemoveValue <int>("evtStream", 0); qiclient.RemoveWindowValues <int>("evtStream", 2, 198); Thread.Sleep(2000); Console.WriteLine("Checking for events"); Console.WriteLine("==================="); foundEvts = qiclient.GetWindowValues <WaveData>("evtStream", "0", "198"); DumpEvents(foundEvts); #endregion #endregion } catch (QiHttpClientException qiex) { Console.WriteLine("Error in Qi Service Client: " + qiex.Message); } catch (Exception ex) { Console.WriteLine("Other error: " + ex.Message); } 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 try { qiclient.DeleteStream("evtStream"); qiclient.DeleteBehavior("evtStreamStepLeading"); qiclient.DeleteType(evtType.Id); } catch (Exception) { } } }