Пример #1
0
 /// <param name="baseAddress">The OSIsoft Cloud Services HTTP endpoint.</param>
 /// <param name="accountId">The Guid account Id.</param>
 public IngressManagementClient(string baseAddress, string accountId, SdsSecurityHandler sdsSecurityHandler)
 {
     _accountId = accountId;
     sdsSecurityHandler.InnerHandler = new HttpClientHandler();
     _client             = new HttpClient(sdsSecurityHandler);
     _client.BaseAddress = new Uri(baseAddress);
 }
Пример #2
0
        static int Main(string[] args)
        {
            var options = new Options();
            var errors  = new List <Error>();
            var result  = Parser.Default.ParseArguments <Options>(args);

            result.WithParsed(opts => options = opts).WithNotParsed(errs => errors = errs.ToList());
            if (errors.Any())
            {
                foreach (var error in errors)
                {
                    Console.WriteLine(error.Tag);
                }
                return(1);
            }

            NameValueCollection appSettings = ConfigurationManager.AppSettings;
            string accountId         = appSettings["accountId"];
            string namespaceId       = appSettings["namespaceId"];
            string clusterAddress    = appSettings["address"];
            string ingressServiceUrl = clusterAddress + @"/api/omf";

            // Use a client secret, retrieved from the OSIsoft Cloud Services portal for your account, to
            // create a SecurityHandler used to authenticate this app.
            string resource        = appSettings["resource"];
            string clientId        = appSettings["clientId"];
            string clientSecret    = appSettings["clientSecret"];
            var    securityHandler = new SdsSecurityHandler(resource, accountId, clientId, clientSecret);

            // Create a client to manage OSIsoft Cloud Services Ingress resources.
            using (var managementClient = new IngressManagementClient(clusterAddress, accountId, securityHandler))
            {
                // Connect to a PI server and select PI points for which to move data to OCS.
                var piServerName = appSettings["PIDataArchive"];
                var piServer     = new PIServers()[piServerName];
                var points       = PIPoint.FindPIPoints(piServer, options.TagMask).ToList();
                if (!points.Any())
                {
                    Console.WriteLine($"No PI points found matching the tagMask query!");
                    return(1);
                }

                // Create OCS data ingress objects.
                string publisherName    = appSettings["publisherName"];
                string topicName        = appSettings["topicName"];
                string subscriptionName = appSettings["subscriptionName"];
                Console.WriteLine("Setting up OSIsoft Cloud Services OMF ingress objects.");
                string publisherId    = managementClient.GetOrCreatePublisherAsync(publisherName).GetAwaiter().GetResult();
                string producerToken  = managementClient.GetOrCreateToken(publisherId).GetAwaiter().GetResult();
                string topicId        = managementClient.GetOrCreateTopic(topicName, publisherId).GetAwaiter().GetResult();
                string subscriptionId = managementClient.GetOrCreateSubscription(subscriptionName, topicId, namespaceId).GetAwaiter().GetResult();

                // Each PI point type will be written to an OSIsoft Cloud Services(OCS) SDSStream.
                // The structure of each stream is defined by an OCS SDSType. We create this SDSType
                // by posting an OSIsoft Message Format(OMF) type message to OCS.
                // PI point value types need to translate to OCS SDSTypes. We create a limited number
                // of SDSTypes in OCS and then map PI point value types to those SDSTypes.
                // A mapping between PI point value types and the Ids of the SDSType that represents
                // them in OCS is shown below.
                Dictionary <OmfTypeCode, string> typeIdsByOmfType = new Dictionary <OmfTypeCode, string>();
                typeIdsByOmfType.Add(OmfTypeCode.Number, "numberValueAndTimestamp");
                typeIdsByOmfType.Add(OmfTypeCode.Integer, "integerValueAndTimestamp");
                typeIdsByOmfType.Add(OmfTypeCode.String, "stringValueAndTimestamp");
                typeIdsByOmfType.Add(OmfTypeCode.Time, "timeValueAndTimestamp");
                typeIdsByOmfType.Add(OmfTypeCode.ByteArray, "byteArrayValueAndTimestamp");

                using (var client = new IngressClient(ingressServiceUrl, producerToken)
                {
                    UseCompression = true
                })
                {
                    // Create and send OMF Type messages.
                    Console.WriteLine("Creating basic types in OCS to represent the format of PI points.");
                    List <OmfType> types = GetOmfTypes(typeIdsByOmfType);
                    var            omfTypeMessageContent = new OmfTypeMessageContent()
                    {
                        Types = types
                    };
                    client.SendMessageAsync(omfTypeMessageContent.ToByteArray(), MessageType.Type, MessageAction.Create).GetAwaiter().GetResult();

                    // Generate containers for each of the point with the correct OMF message type.
                    List <OmfContainer> containers = GetOmfContainers(points, typeIdsByOmfType);
                    if (options.WriteMode == Options.DataWriteMode.clearExistingData)
                    {
                        // Deleting the OMF container deletes the underlying SDSStream and its data.
                        Console.WriteLine("Deleting OMF containers corresponding to the selected PI points that existed before the sample was run.");
                        var omfContainerMessageContent = new OmfContainerMessageContent()
                        {
                            Containers = containers
                        };
                        client.SendMessageAsync(omfContainerMessageContent.ToByteArray(), MessageType.Container, MessageAction.Delete).GetAwaiter().GetResult();
                    }

                    Console.WriteLine("Creating corresponding containers for the PI points whose data will be written to OCS.");

                    // OSIsoft Cloud Services' OMF Ingress sets a size limit on the request accepted by its external endpoint. We may need to split, or chunk,
                    // containers into multiple OMF messages sent to the endpoint.
                    for (int chunkStartIndex = 0; chunkStartIndex < containers.Count; chunkStartIndex += MaxChunkSize)
                    {
                        int numberOfContainersToSendInThisChunk = Math.Min(containers.Count - chunkStartIndex, MaxChunkSize);
                        var containersToSendInThisChunk         = containers.GetRange(chunkStartIndex, numberOfContainersToSendInThisChunk).ToList();
                        var omfContainerMessageContent          = new OmfContainerMessageContent()
                        {
                            Containers = containersToSendInThisChunk
                        };
                        client.SendMessageAsync(omfContainerMessageContent.ToByteArray(), MessageType.Container, MessageAction.Create).GetAwaiter().GetResult();
                    }

                    // Write data from each PI point to a SDSStream.
                    foreach (PIPoint point in points)
                    {
                        Console.WriteLine($"Writing PI point data for point {point.Name} to OCS.");
                        string   containerId = GetContainerId(point);
                        AFValues values      = point.RecordedValues(new AFTimeRange(options.StartTime, options.EndTime), AFBoundaryType.Inside, null, true);

                        // OSIsoft Cloud Services' OMF Ingress sets a size limit on the request accepted by its external endpoint. We may need to split, or chunk,
                        // events into multiple OMF messages sent to the endpoint.
                        for (int chunkStartIndex = 0; chunkStartIndex < values.Count; chunkStartIndex += MaxChunkSize)
                        {
                            int numberOfEventsToReadForThisChunk = Math.Min(values.Count - chunkStartIndex, MaxChunkSize);

                            // If there are multiple events at a single timestamp for the PI point, the most recently added event will be written to OCS.
                            List <AFValue> distinctValuesInChunk = values.GetRange(chunkStartIndex, numberOfEventsToReadForThisChunk).GroupBy(value => value.Timestamp).Select(valuesAtTimestamp => valuesAtTimestamp.Last()).ToList();
                            List <PIData>  piDataEvents          = GetPIData(distinctValuesInChunk, ToOmfTypeCode(point.PointType));

                            OmfDataMessageContent omfDataMessageContent = new OmfDataMessageContent(containerId, piDataEvents);

                            Console.WriteLine($"Sending PI point data from index {distinctValuesInChunk.First().Timestamp} to index {distinctValuesInChunk.Last().Timestamp} to OCS ({distinctValuesInChunk.Count} values).");
                            client.SendMessageAsync(omfDataMessageContent.ToByteArray(), MessageType.Data, MessageAction.Create).GetAwaiter().GetResult();
                        }
                    }
                }

                // Delete OCS data ingress objects.
                if (options.DeleteIngressObjects)
                {
                    Console.WriteLine($"Deleting subscription with Id {subscriptionId}.");
                    managementClient.DeleteSubscription(subscriptionId).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleting topic with Id {topicId}.");
                    managementClient.DeleteTopicAsync(topicId).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleting publisher with Id {publisherId}.");
                    managementClient.DeletePublisherAsync(publisherId).GetAwaiter().GetResult();
                }
            }

            return(0);
        }
Пример #3
0
        public static async Task MainAsync()
        {
            string tenantId     = ConfigurationManager.AppSettings["Tenant"];
            string namespaceId  = ConfigurationManager.AppSettings["Namespace"];
            string address      = ConfigurationManager.AppSettings["Address"];
            string resource     = ConfigurationManager.AppSettings["Resource"];
            string clientId     = ConfigurationManager.AppSettings["ClientId"];
            string clientSecret = ConfigurationManager.AppSettings["ClientSecret"];

            SdsSecurityHandler securityHandler = new SdsSecurityHandler(resource, tenantId, clientId, clientSecret);
            SdsService         service         = new SdsService(new Uri(address), securityHandler);

            ISdsMetadataService MetadataService = service.GetMetadataService(tenantId, namespaceId);
            ISdsDataService     DataService     = service.GetDataService(tenantId, namespaceId);

            /*
             * The following code provides an implementation for getting all the SdsUom ID's for each quantity.
             * If you are not aware with which SdsUom ID to use, you can uncomment the below code and find out the
             * uom id.
             *
             * e.g. I am using degree_fahrenheit and  degree_celsius UOMS for temperature SdsQuantity.
             *
             *
             * IEnumerable<SdsUomQuantity> sdsUomQuantities = await MetadataService.GetQuantitiesAsync();
             * IEnumerable<SdsUom> sdsUoms = null;
             *
             * foreach (SdsUomQuantity sdsUomQuantity in sdsUomQuantities)
             * {
             *  sdsUoms = await MetadataService.GetQuantityUomsAsync(sdsUomQuantity.Id);
             *
             *  foreach (SdsUom sdsUom in sdsUoms)
             *  {
             *      Console.WriteLine(sdsUom.Id);
             *  }
             * }
             */

            #region stream and type creation

            // Creating a Sdstype
            SdsType sdsType = SdsTypeBuilder.CreateSdsType <Widget>();
            sdsType.Id = TypeId;

            sdsType = await MetadataService.GetOrCreateTypeAsync(sdsType);

            //Creating a Stream overriding the distance property.
            SdsStream sdsStreamOne = new SdsStream()
            {
                Id                = StreamWithPropertyOverriden,
                TypeId            = TypeId,
                Name              = "UomStreamSourceWithPropertyOverridden",
                PropertyOverrides = new List <SdsStreamPropertyOverride>()
            };

            //Overriding the UOM of the distance property to be kilometer instead of mile.
            sdsStreamOne.PropertyOverrides.Add(new SdsStreamPropertyOverride()
            {
                Uom = "kilometer",
                SdsTypePropertyId = "Distance"
            });

            sdsStreamOne = await MetadataService.GetOrCreateStreamAsync(sdsStreamOne);

            //Creating a Stream without overriding properties.
            SdsStream sdsStreamTwo = new SdsStream()
            {
                Id     = StreamWithoutPropertyOverriden,
                TypeId = TypeId,
                Name   = "UomStreamSourceWithNoPropertyOverridden",
            };

            sdsStreamTwo = await MetadataService.GetOrCreateStreamAsync(sdsStreamTwo);

            // Generating data
            IList <Widget> data = new List <Widget>();
            for (int i = 0; i < 10; i++)
            {
                Widget widget = new Widget();
                widget.Time        = DateTime.UtcNow.AddSeconds(i);
                widget.Temperature = Random.Next(1, 100);
                widget.Distance    = Random.Next(1, 100);
                data.Add(widget);
            }

            /* In stream one, the temperature value will be inserted as Fahrenheit since we have defined the
             * default uom as Fahrenheit for Temperature in the Widget class. The distance value will be
             * inserted as kilometer, as we have overridden the Distance property in stream one,
             * regardless of the default uom for Distance in the Widget class.
             */
            await DataService.InsertValuesAsync <Widget>(sdsStreamOne.Id, data);

            /* In stream two, the temperature value will be inserted as Fahrenheit and the distance will be inserted as mile.
             *
             */
            await DataService.InsertValuesAsync <Widget>(sdsStreamTwo.Id, data);

            /*
             * The last value stored in stream one.
             */
            Widget widgetFromStreamOne = await DataService.GetLastValueAsync <Widget>(sdsStreamOne.Id);

            Console.WriteLine($"In stream one, the distance is {widgetFromStreamOne.Distance} kilometers and the temperature is {widgetFromStreamOne.Temperature} degrees fahrenheit");
            Console.WriteLine();

            /*
             * The last value stored in stream two.
             */
            Widget widgetFromStreamTwo = await DataService.GetLastValueAsync <Widget>(sdsStreamTwo.Id);

            Console.WriteLine($"In stream two, the distance is {widgetFromStreamTwo.Distance} miles and the temperature is {widgetFromStreamTwo.Temperature} degrees fahrenheit");
            Console.WriteLine();

            /*
             * If you want your data to be in specified uom, you can override your properties while making a call.
             * In the following, I want the temperature to be in Celsius, and the distance to be in feet.
             *
             * Then you can pass IList<SdsStreamPropertyOverride> to DataService while getting values.
             *
             */
            IList <SdsStreamPropertyOverride> requestOverrides = new List <SdsStreamPropertyOverride>();

            requestOverrides.Add(new SdsStreamPropertyOverride()
            {
                Uom = "degree_celsius",
                SdsTypePropertyId = "Temperature"
            });

            requestOverrides.Add(new SdsStreamPropertyOverride()
            {
                Uom = "foot",
                SdsTypePropertyId = "Distance"
            });

            /*
             * In the following call, data will be converted from Fahrenheit to Celsius for the temperature property,
             * and from kilometer to foot for the distance property.
             *
             * Uoms in Stream one (Temperature : Fahrenheit, Distance : Kilometer)
             *
             */
            widgetFromStreamOne = await DataService.GetLastValueAsync <Widget>(sdsStreamOne.Id, requestOverrides);

            Console.WriteLine($"In stream one, the distance is {widgetFromStreamOne.Distance} foot and the temperature is {widgetFromStreamOne.Temperature} degrees celsius");
            Console.WriteLine();

            /*
             * In the following call, data will be converted from Fahrenheit to Celsius for the temperature property,
             * and from mile to foot for the distance property.
             *
             * Uoms in Stream two (Temperature : Fahrenheit, Distance : Mile)
             *
             */
            widgetFromStreamTwo = await DataService.GetLastValueAsync <Widget>(sdsStreamTwo.Id, requestOverrides);

            Console.WriteLine($"In stream two, the distance is {widgetFromStreamTwo.Distance} foot and the temperature is {widgetFromStreamTwo.Temperature} degrees celsius");
            Console.WriteLine();

            #endregion stream and type creation

            #region Deletion of Streams and type

            await MetadataService.DeleteStreamAsync(sdsStreamOne.Id);

            await MetadataService.DeleteStreamAsync(sdsStreamTwo.Id);

            await MetadataService.DeleteTypeAsync(TypeId);

            #endregion Deletion of Streams and type
        }
Пример #4
0
        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 targetTypeId    = "SampleType_Target";
            string targetIntTypeId = "SampleType_TargetInt";
            string autoViewId      = "SampleAutoView";
            string manualViewId    = "SampleManualView";

            // Get Sds Services to communicate with server
            SdsSecurityHandler securityHandler = new SdsSecurityHandler(resource, tenantId, clientId, clientKey);

            SdsService sdsService      = new SdsService(new Uri(address), securityHandler);
            var        metadataService = sdsService.GetMetadataService(tenantId, namespaceId);
            var        dataService     = sdsService.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($"Sds endpoint at {address}");
            Console.WriteLine();

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

                // create an SdsStream
                Console.WriteLine("Creating an SdsStream");
                var stream = new SdsStream
                {
                    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);

                // 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();

                // 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
                var retrieved = await dataService
                                .GetRangeValuesAsync <WaveData>(stream.Id, "1", 3, SdsBoundaryType.ExactOrCalculated);

                Console.WriteLine("Default (Continuous) requesting data starting at index location '1', where we have not entered data, Sds will interpolate a value for each property:");
                foreach (var value in retrieved)
                {
                    Console.WriteLine($"Order: {value.Order}, Radians: {value.Radians}, Cos: {value.Cos}");
                }
                Console.WriteLine();

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

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

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

                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 (var value in retrieved)
                {
                    Console.WriteLine($"Order: {value.Order}, Radians: {value.Radians}, Cos: {value.Cos}");
                }
                Console.WriteLine();

                // Stream views
                Console.WriteLine("SdsViews");

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

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

                await metadataService.CreateOrUpdateTypeAsync(targetType);

                await metadataService.CreateOrUpdateTypeAsync(targetIntType);

                // create views
                var autoView = new SdsView()
                {
                    Id           = autoViewId,
                    SourceTypeId = typeId,
                    TargetTypeId = targetTypeId
                };

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

                var manualView = new SdsView()
                {
                    Id           = manualViewId,
                    SourceTypeId = typeId,
                    TargetTypeId = targetIntTypeId,
                    Properties   = new List <SdsViewProperty>()
                    {
                        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, SdsBoundaryType.ExactOrCalculated, autoViewId);

                Console.WriteLine("Specifying a view with an SdsType of the same shape returns values that are automatically mapped to the target SdsType'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("SdsViews 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, SdsBoundaryType.ExactOrCalculated, manualViewId);

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

                // get SdsViewMap
                Console.WriteLine("We can query Sds to return the SdsViewMap for our SdsView, here is the one generated automatically:");
                var autoViewMap = await metadataService.GetViewMapAsync(autoViewId);

                PrintViewMapProperties(autoViewMap);

                Console.WriteLine("Here is our explicit mapping, note SdsViewMap will return all properties of the Source Type, even those without a corresponding Target property:");
                var manualViewMap = await metadataService.GetViewMapAsync(manualViewId);

                PrintViewMapProperties(manualViewMap);

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

                await metadataService.UpdateStreamTagsAsync(streamId, tags);

                await metadataService.UpdateStreamMetadataAsync(streamId, metadata);

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

                Console.WriteLine();
                Console.WriteLine($"Tags now associated with {streamId}:");
                foreach (var 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"));
                Console.WriteLine("Metadata key Country: " + await metadataService.GetStreamMetadataValueAsync(streamId, "Country"));
                Console.WriteLine("Metadata key Province: " + await metadataService.GetStreamMetadataValueAsync(streamId, "Province"));

                Console.WriteLine();
                Console.WriteLine("Pausing to allow for search indexing...");
                // allow time for search indexing
                await Task.Delay(15000);

                Console.WriteLine("We can also use our tags to search for streams, let's search for streams tagged with 'periodic':");

                var streams = await metadataService.GetStreamsAsync("periodic");

                foreach (var strm in streams)
                {
                    Console.WriteLine(strm.Id);
                }
                Console.WriteLine();

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

                // 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 and views
                Console.WriteLine("Deleteing stream");
                await metadataService.DeleteStreamAsync(streamId);

                Console.WriteLine("Deleteing views");
                await metadataService.DeleteViewAsync(autoViewId);

                await metadataService.DeleteViewAsync(manualViewId);

                Console.WriteLine("Deleteing types");
                await metadataService.DeleteTypeAsync(typeId);

                await metadataService.DeleteTypeAsync(targetTypeId);

                await metadataService.DeleteTypeAsync(targetIntTypeId);


                Console.WriteLine("done");
                Console.ReadKey();
            }
        }
Пример #5
0
        static async Task MainAsync()
        {
            string resourcePrefix = ConfigurationManager.AppSettings["ResourcePrefix"];
            string tenantId       = ConfigurationManager.AppSettings["Tenant"];
            string namespaceId    = ConfigurationManager.AppSettings["Namespace"];
            string address        = ConfigurationManager.AppSettings["Address"];
            string resource       = ConfigurationManager.AppSettings["Resource"];
            string appId          = ConfigurationManager.AppSettings["ClientId"];
            string appKey         = ConfigurationManager.AppSettings["ClientSecret"];

            // Acquire OSIsoft provided SDS clients w/ appropriate security delegating handler
            SdsSecurityHandler securityHandler = new SdsSecurityHandler(resource, tenantId, appId, appKey);
            SdsService         service         = new SdsService(new Uri(address), securityHandler);

            ISdsMetadataService config = service.GetMetadataService(tenantId, namespaceId);

            // Acquire an HTTP Client, including the Azure Active Directory client credential authentication handler
            // and associated pipeline.
            //
            // The authentication Handler performs the same function as the SDS Security Handler above.  It acquires
            // a token from Azure Active Directory and attaches it as a header to every request sent out of the client.
            //
            // An HttpClient pipeline has to end with a handler that can send requests to appropriate endpoints.
            // HttpClientHandler is that appropriate handler; it is the end of the client pipeline.  Note that we
            // do not allow auto - reidrects.We do so because the HttpClientHandler, like man clients, strips security
            // related headers on redirect.  This results in 401 - unauthorized status indicating that the request
            // failed to authenticate.  We will manage redirects manually.
            //
            // We take some shortcuts with disposable objects.  Because the program ends quickly, we don't bother
            // cleaning up disposables.
            ApplicationAuthenticationHandler authenticationHandler = new ApplicationAuthenticationHandler(resource, tenantId,
                                                                                                          "https://login.windows.net/{0}/oauth2/token", appId, appKey)
            {
                InnerHandler = new HttpClientHandler
                {
                    AllowAutoRedirect = false,
                    UseCookies        = false
                }
            };

            HttpClient httpClient = new HttpClient(authenticationHandler)
            {
                BaseAddress = new Uri($"{address}/api/Tenants/{tenantId}/Namespaces/{namespaceId}/")
            };

            try
            {
                // As we encounter performance counter categories, we will create a bunch of funcs to update individual events
                // If we were concerned aobut performance, we would cache events and update in bulk
                List <Func <Task> > updates = new List <Func <Task> >();

                foreach (string categoryName in Categories)
                {
                    PerformanceCounterCategory category = PerformanceCounterCategory.GetCategories()
                                                          .First(cat => cat.CategoryName == categoryName);

                    // Interrogate the category and create an SdsType based on the counters.  This
                    // strategy will not work for categories with instances that have different
                    // performance counters, like Process.  For those we would need a different strategy.
                    SdsType type = new SdsType()
                    {
                        Id          = $"{resourcePrefix}{category.CategoryName}",
                        Name        = $"{category.CategoryName}",
                        SdsTypeCode = SdsTypeCode.Object,
                        Properties  = new List <SdsTypeProperty>()
                    };
                    type.Properties.Add(new SdsTypeProperty()
                    {
                        Id      = "Time",
                        Name    = "Time",
                        IsKey   = true,
                        SdsType = new SdsType()
                        {
                            SdsTypeCode = SdsTypeCode.DateTime
                        }
                    });

                    PerformanceCounter[] counters;
                    switch (category.CategoryType)
                    {
                    case PerformanceCounterCategoryType.MultiInstance:
                        counters = category.GetCounters(category.GetInstanceNames().First());
                        break;

                    case PerformanceCounterCategoryType.SingleInstance:
                        counters = category.GetCounters();
                        break;

                    default:
                        throw new InvalidOperationException($"Invalid counter category type, {category.CategoryName}");
                    }

                    foreach (PerformanceCounter counter in counters)
                    {
                        // Note that the identifier name is cleaned.  Counters often use characters incompatible with SDS identifiers.
                        type.Properties.Add(new SdsTypeProperty()
                        {
                            Id      = CleanIdentifier(counter.CounterName),
                            Name    = counter.CounterName,
                            SdsType = new SdsType()
                            {
                                SdsTypeCode = SdsTypeCode.Int64
                            }
                        });
                    }

                    type = await config.GetOrCreateTypeAsync(type);

                    // Create a stream and an update func for each instance in the category
                    switch (category.CategoryType)
                    {
                    case PerformanceCounterCategoryType.MultiInstance:
                        foreach (string instanceName in category.GetInstanceNames())
                        {
                            SdsStream stream = new SdsStream()
                            {
                                Id     = $"{resourcePrefix}{category.CategoryName}-{instanceName}",
                                Name   = $"{category.CategoryName} {instanceName}",
                                TypeId = type.Id
                            };
                            stream = await config.GetOrCreateStreamAsync(stream);

                            counters = category.GetCounters(instanceName);

                            updates.Add(GetUpdate(httpClient, counters, stream));
                        }
                        break;

                    case PerformanceCounterCategoryType.SingleInstance:
                    {
                        SdsStream stream = new SdsStream()
                        {
                            Id     = $"{category.CategoryName}",
                            Name   = $"{category.CategoryName}",
                            TypeId = type.Id
                        };
                        stream = await config.GetOrCreateStreamAsync(stream);

                        counters = category.GetCounters();

                        updates.Add(GetUpdate(httpClient, counters, stream));
                    }
                    break;
                    }
                }

                DateTime start = DateTime.UtcNow;

                for (int i = 0; i < 10; i++)
                {
                    await Task.Delay(TimeSpan.FromSeconds(10));

                    List <Task> tasks = new List <Task>();
                    foreach (Func <Task> update in updates)
                    {
                        tasks.Add(update());
                    }
                    await Task.WhenAll(tasks);
                }

                DateTime end = DateTime.UtcNow;

                Console.WriteLine();

                foreach (string categoryName in Categories)
                {
                    PerformanceCounterCategory category = PerformanceCounterCategory.GetCategories()
                                                          .FirstOrDefault(cat => cat.CategoryName == categoryName);

                    foreach (string instanceName in category.GetInstanceNames())
                    {
                        string streamId = $"{category.CategoryName}-{instanceName}";

                        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get,
                                                                            $"Streams/{streamId}/Data/GetWindowValues?startIndex={start.ToString("o")}&endIndex={end.ToString("o")}");

                        HttpResponseMessage response = await httpClient.SendAsync(request);

                        if (response.IsSuccessStatusCode)
                        {
                            Console.WriteLine();
                            Console.WriteLine();
                            Console.WriteLine(streamId);
                            string json = await response.Content.ReadAsStringAsync();

                            Dictionary <string, string>[] values = JsonConvert.DeserializeObject <Dictionary <string, string>[]>(json);
                            foreach (Dictionary <string, string> value in values)
                            {
                                Console.Write("\t");
                                foreach (KeyValuePair <string, string> property in value)
                                {
                                    Console.Write($"{property.Key}:{property.Value}, ");
                                }
                                Console.WriteLine();
                            }
                        }
                        else
                        {
                            Console.WriteLine($"Failed retrieving data from {streamId}, {response.ReasonPhrase}:{response.StatusCode}");
                            if (response.Content != null && response.Content.Headers.ContentLength > 0)
                            {
                                Console.WriteLine(await response.Content.ReadAsStringAsync());
                            }
                        }
                    }
                }

                Console.WriteLine();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            finally
            {
                //TODO can we search for types
                IEnumerable <string> typeIds = from t in (await config.GetTypesAsync())
                                               where Categories.Any(cat => t.Id.StartsWith(cat))
                                               select t.Id;
                foreach (string typeId in typeIds)
                {
                    int offset = 0;

                    //TODO actually search for streams w/ the matching type
                    IEnumerable <SdsStream> streams = await config.GetStreamsAsync(skip : offset, count : 10000);

                    while (streams.Count() > 0)
                    {
                        offset += streams.Count();

                        try
                        {
                            IEnumerable <string> streamIds = from s in streams
                                                             where s.TypeId.Equals(typeId, StringComparison.InvariantCultureIgnoreCase)
                                                             select s.Id;
                            foreach (string streamId in streamIds)
                            {
                                await config.DeleteStreamAsync(streamId);

                                --offset;
                            }
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e);
                        }

                        streams = await config.GetStreamsAsync(skip : offset, count : 100);
                    }

                    try
                    {
                        await config.DeleteTypeAsync(typeId);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }
                }
            }
        }