private static void PrintViewMapProperties(QiViewMap qiViewMap) { foreach (var prop in qiViewMap.Properties) { if (prop.TargetId != null) { Console.WriteLine($"{prop.SourceId} => {prop.TargetId}"); } else { Console.WriteLine($"{prop.SourceId} => Not Mapped"); } } Console.WriteLine(); }
private static async Task MainAsync() { IConfigurationBuilder builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json"); IConfiguration configuration = builder.Build(); // ==== Client constants ==== string tenantId = configuration["TenantId"]; string namespaceId = configuration["NamespaceId"]; string address = configuration["Address"]; string resource = configuration["Resource"]; string clientId = configuration["ClientId"]; string clientKey = configuration["ClientKey"]; string aadInstanceFormat = configuration["AADInstanceFormat"]; // ==== Metadata IDs ==== string StreamId = "WaveStreamId"; string TypeId = "WaveDataTypeId"; string BehaviorId = "WaveStreamBehaviorId"; string TargetTypeId = "WaveDataTargetTypeId"; string TargetIntTypeId = "WaveDataTargetIntTypeId"; string AutoViewId = "WaveDataAutoViewId"; string ManualViewId = "WaveDataManualViewId"; QiSecurityHandler securityHandler = new QiSecurityHandler(resource, tenantId, aadInstanceFormat, clientId, clientKey); HttpClient httpClient = new HttpClient(securityHandler) { BaseAddress = new Uri(address) }; 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 waveType = BuildWaveDataType(TypeId); HttpResponseMessage response = await httpClient.PostAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Types/{waveType.Id}", new StringContent(JsonConvert.SerializeObject(waveType))); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } // create a QiStream Console.WriteLine("Creating a QiStream"); QiStream waveStream = new QiStream { Id = StreamId, Name = "WaveStream", TypeId = waveType.Id }; response = await httpClient.PostAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}", new StringContent(JsonConvert.SerializeObject(waveStream))); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } // insert data Console.WriteLine("Inserting data"); // insert a single event WaveData wave = GetWave(0, 1, 2.0); response = await httpClient.PostAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/InsertValue", new StringContent(JsonConvert.SerializeObject(wave))); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } // insert a list of events List <WaveData> waves = new List <WaveData>(); for (int i = 2; i < 20; i += 2) { WaveData newEvent = GetWave(i, 2, 2.0); waves.Add(newEvent); } response = await httpClient.PostAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/InsertValues", new StringContent(JsonConvert.SerializeObject(waves))); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(); } // get last event Console.WriteLine("Getting latest event"); response = await httpClient.GetAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/GetLastValue"); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } WaveData retrieved = JsonConvert.DeserializeObject <WaveData>(await response.Content.ReadAsStringAsync()); Console.WriteLine(retrieved.ToString()); Console.WriteLine(); // get all events Console.WriteLine("Getting all events"); response = await httpClient.GetAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/GetWindowValues?startIndex=0&endIndex={waves[waves.Count - 1].Order}"); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } List <WaveData> retrievedList = JsonConvert.DeserializeObject <List <WaveData> >(await response.Content.ReadAsStringAsync()); Console.WriteLine($"Total events found: {retrievedList.Count}"); foreach (var evnt in retrievedList) { Console.WriteLine(evnt.ToString()); } Console.WriteLine(); // update events Console.WriteLine("Updating events"); // update one event var updateEvent = retrieved; updateEvent.Sin = 1 / 2.0; updateEvent.Cos = Math.Sqrt(3) / 2; updateEvent.Tan = 1; response = await httpClient.PutAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/UpdateValue", new StringContent(JsonConvert.SerializeObject(updateEvent))); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } // update all events, adding ten more List <WaveData> updateWaves = new List <WaveData>(); for (int i = 0; i < 40; i += 2) { WaveData newEvent = GetWave(i, 4, 6.0); updateWaves.Add(newEvent); } response = await httpClient.PutAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/UpdateValues", new StringContent(JsonConvert.SerializeObject(updateWaves))); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } Console.WriteLine("Getting updated events"); response = await httpClient.GetAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/GetWindowValues?startIndex={updateWaves[0].Order}&endIndex={updateWaves[updateWaves.Count - 1].Order}"); retrievedList = JsonConvert.DeserializeObject <List <WaveData> >(await response.Content.ReadAsStringAsync()); Console.WriteLine($"Total events found: {retrievedList.Count}"); foreach (var evnt in retrievedList) { Console.WriteLine(evnt.ToString()); } Console.WriteLine(); // replacing events Console.WriteLine("Replacing events"); // replace one event var replaceEvent = retrievedList[0]; replaceEvent.Sin = 4 * (Math.Sqrt(2) / 2); replaceEvent.Cos = 4 * (Math.Sqrt(2) / 2); replaceEvent.Tan = 4; response = await httpClient.PutAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/ReplaceValue", new StringContent(JsonConvert.SerializeObject(replaceEvent))); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } // replace all events var replaceEvents = retrievedList; foreach (var evnt in replaceEvents) { evnt.Sin = 6 * (Math.Sqrt(2) / 2); evnt.Cos = 6 * (Math.Sqrt(2) / 2); evnt.Tan = 6; } response = await httpClient.PutAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/ReplaceValues", new StringContent(JsonConvert.SerializeObject(replaceEvents))); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } Console.WriteLine("Getting replaced events"); response = await httpClient.GetAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/GetWindowValues?startIndex={updateWaves[0].Order}&endIndex={updateWaves[updateWaves.Count - 1].Order}"); retrievedList = JsonConvert.DeserializeObject <List <WaveData> >(await response.Content.ReadAsStringAsync()); Console.WriteLine($"Total events found: {retrievedList.Count}"); foreach (var evnt in retrievedList) { 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 response = await httpClient.GetAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/GetRangeValues?startIndex={1}&count={3}&boundaryType={QiBoundaryType.ExactOrCalculated}"); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } List <WaveData> rangeValuesContinuous = JsonConvert.DeserializeObject <List <WaveData> >(await response.Content.ReadAsStringAsync()); Console.WriteLine("Default (Continuous) stream behavior, requesting data starting at index location '1', Qi will interpolate this value:"); foreach (var waveData in rangeValuesContinuous) { Console.WriteLine($"Order: {waveData.Order}, Radians: {waveData.Radians}"); } Console.WriteLine(); // create a Discrete stream behavior QiStreamBehavior waveStreamBehavior = new QiStreamBehavior { Id = BehaviorId, Mode = QiStreamMode.Discrete, Name = "WaveStreamBehavior" }; response = await httpClient.PostAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Behaviors/{BehaviorId}", new StringContent(JsonConvert.SerializeObject(waveStreamBehavior))); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } // update the stream waveStream.BehaviorId = waveStreamBehavior.Id; response = await httpClient.PutAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}", new StringContent(JsonConvert.SerializeObject(waveStream))); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } Console.WriteLine("Discrete stream behavior, Qi does not interpolate and returns the data starting at the next index location containing data:"); response = await httpClient.GetAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/GetRangeValues?startIndex={1}&count={3}&boundaryType={QiBoundaryType.ExactOrCalculated}"); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } List <WaveData> rangeValuesDiscrete = JsonConvert.DeserializeObject <List <WaveData> >(await response.Content.ReadAsStringAsync()); foreach (var waveData in rangeValuesDiscrete) { Console.WriteLine($"Order: {waveData.Order}, Radians: {waveData.Radians}"); } Console.WriteLine(); // Stream views Console.WriteLine("QiViews"); // create target types var targetType = BuildWaveDataTargetType(TargetTypeId); var targetIntType = BuildWaveDataTargetIntType(TargetIntTypeId); HttpResponseMessage targetTypeResponse = await httpClient.PostAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Types/{TargetTypeId}", new StringContent(JsonConvert.SerializeObject(targetType))); if (!targetTypeResponse.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } HttpResponseMessage targetIntTypeResponse = await httpClient.PostAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Types/{TargetIntTypeId}", new StringContent(JsonConvert.SerializeObject(targetIntType))); if (!targetIntTypeResponse.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } // 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 } }; response = await httpClient.PostAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Views/{AutoViewId}", new StringContent(JsonConvert.SerializeObject(autoView))); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } response = await httpClient.PostAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Views/{ManualViewId}", new StringContent(JsonConvert.SerializeObject(manualView))); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } Console.WriteLine("Here is some of our data as it is stored on the server:"); foreach (var evnt in rangeValuesDiscrete) { Console.WriteLine($"Sin: {evnt.Sin}, Cos: {evnt.Cos}, Tan {evnt.Tan}"); } Console.WriteLine(); // get data with autoview response = await httpClient.GetAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/GetRangeValues?startIndex={1}&count={3}&boundaryType={QiBoundaryType.ExactOrCalculated}&viewId={AutoViewId}"); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } List <WaveDataTarget> autoViewData = JsonConvert.DeserializeObject <List <WaveDataTarget> >(await response.Content.ReadAsStringAsync()); 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(); Console.WriteLine("QiViews can also convert certain types of data, here we return integers where the original values were doubles:"); // get data with manualview response = await httpClient.GetAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/GetRangeValues?startIndex={1}&count={3}&boundaryType={QiBoundaryType.ExactOrCalculated}&viewId={ManualViewId}"); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } List <WaveDataInteger> manualViewData = JsonConvert.DeserializeObject <List <WaveDataInteger> >(await response.Content.ReadAsStringAsync()); 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:"); response = await httpClient.GetAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Views/{AutoViewId}/Map"); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } QiViewMap qiViewMap = JsonConvert.DeserializeObject <QiViewMap>(await response.Content.ReadAsStringAsync()); PrintViewMapProperties(qiViewMap); Console.WriteLine("Here is our explicit mapping, note QiViewMap will return all properties of the Source Type, even those without a corresponding Target property:"); response = await httpClient.GetAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Views/{ManualViewId}/Map"); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } qiViewMap = JsonConvert.DeserializeObject <QiViewMap>(await response.Content.ReadAsStringAsync()); PrintViewMapProperties(qiViewMap); Console.WriteLine("Deleting values from the QiStream"); // delete one event response = await httpClient.DeleteAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/RemoveValue?index=0"); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } // delete all Events response = await httpClient.DeleteAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/RemoveWindowValues?startIndex=0&endIndex=40"); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(response.ToString()); } response = await httpClient.GetAsync( $"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{waveStream.Id}/Data/GetWindowValues?startIndex=0&endIndex=40"); retrievedList = JsonConvert.DeserializeObject <List <WaveData> >(await response.Content.ReadAsStringAsync()); if (retrievedList.Count == 0) { Console.WriteLine("All values deleted successfully!"); } Console.WriteLine(); } catch (Exception e) { Console.WriteLine(e.Message); } finally { Console.WriteLine("Cleaning up"); // Delete the stream, types, views and behavior Console.WriteLine("Deleteing stream"); await httpClient.DeleteAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Streams/{StreamId}"); Console.WriteLine("Deleteing types"); await httpClient.DeleteAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Types/{TypeId}"); await httpClient.DeleteAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Types/{TargetTypeId}"); await httpClient.DeleteAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Types/{TargetIntTypeId}"); Console.WriteLine("Deleteing views"); await httpClient.DeleteAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Views/{AutoViewId}"); await httpClient.DeleteAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Views/{ManualViewId}"); Console.WriteLine("Deleteing behavior"); await httpClient.DeleteAsync($"api/Tenants/{tenantId}/Namespaces/{namespaceId}/Behaviors/{BehaviorId}"); Console.WriteLine("done"); } Console.ReadKey(); }