Introduction

 

Today we release our first version of the PI Web API client libraries for .NET Framework and .NET Core. Those libraries were generated using the Swagger specification available on PI Web API 2017+.

 

Although PI AF SDK still remains the best choice in case performance is a must, there are a lot of scenarios where it makes sense to develop your .NET applications using with those libraries:

 

  • You cannot install PI AF SDK on the machine which would run your application.
  • You are developing a web application using Azure Web Apps, which doesn't allow you to remote in and install OSIsoft products.
  • Your PI System is hosted in the cloud. Therefore, it makes to expose the data through a public endpoint of PI Web API.
  • You want to create applications that are compatible with Linux and macOS.
  • You want to use the most modern technology of the market.

 

The first two reasons of the list above applies when you are developing custom .NET Framework apps.  The last 3 items from this list applies for .NET Core. But what is .NET Core exactly?

 

What is .NET Core?

 

According to the .NET blog, .NET Core is a cross-platform, open source, and modular .NET platform for creating modern web apps, microservices, libraries and console applications. Because it is cross-platform, you can run your .NET Core apps on Windows, Linux and macOS. Users can use the command-line tools to manage their project.

 

.NET Core is composed by 3 parts: .NET runtime, a set of framework libraries and a set of SDK tools. This new technology can be need as a cross-platform version of the .NET Framework.

 

.NET Core and PI Developer Technologies

 

.NET Core is not compatible with .NET Framework libraries like PI AF SDK. OSIsoft's product management and development teams have ongoing investigations into creating a PI AF SDK version compatible with .NET Core, but at this point there is no timeline for release. Although the PI AF SDK is faster than PI Web API, the performance of our RESTful web service is sufficient for many use cases.  The PI Web API team is committed to improving performance and adding features to each new release.

 

 

If you are developing a long running service or an application that retrieves large amounts of PI data, our suggestion is to develop on top of PI AF SDK and .NET Framework. If this is not the case, using this new client library for developing .NET Core apps should suffice your needs.

 

 

Requirements

 

  • PI Web API 2017 installed within your domain using Kerberos or Basic Authentication.
  • If you are using the .NET Framework version of this library, you should have .NET Framework 4.5 installed on your machine.
  • If you are using the .NET Core version of this library, you should have .NET Core 1.1 installed on your machine.

 

Installation

 

  • Download this source code
  • Create a new folder under %PIHOME% named WebAPIClient, if it doesn't exist.
  • Create a new folder under WebAPIClient named DotNetCore, if it doesn't exist.
  • Copy the unique file from the dist folder to %PIHOME%\WebAPIClient\DotNetCore (.NET Core) or %PIHOME%\WebAPIClient\DotNetCore (.NET Framework).

 

Usage

 

.NET Framework

 

Create a new .NET Framework project (Console Application for instance). On the Solution Explorer, right click on Dependencies and then "Add Reference...". Click on the Browse button and navigate to the %PIHOME%\WebAPIClient\DotNet folder. Finally, add the OSIsoft.PIDevClub.PIWebApiClient.dll to your VS project.

 

.NET Core

 

Create a new .NET Core project (Console Application for instance). Open the Package Manager Console and run the following command to add this library to your .NET Core project.:

 

Install-Package OSIsoft.PIDevClub.PIWebApiClient -Source %PIHOME%\WebAPIClient\DotNetCore

 

Source Code

 

The Visual Studio solution that generates the final library is available on the src folder. You might want to add or edit a method and rebuild the solution in order to generate custom assemblies. The links from both GitHub repositories are below:

 

 

Documentation

 

Once the library was added to your project, you can start writing code. The beauty of this library is that you don't need to know about writing code to make HTTP requests. The library will do that under the hood. All actions and methods from all the controllers of PI Web API 2017 are available on this client library. You just have to create the PI Web API top level object and access its properties. Each property maps a PI Web API controller which has methods which maps the actions from the RESTful web service. Therefore if you want to access the GetByPath action from the Point controller just call piwebapi.Point.GetByPath().

 

All classes and methods are described on here. Even interally both libraries are different, they have the same classes and methods from the user perspective.

 

Examples

 

Please check the Program.cs from the LibraryTest project from the Visual Studio solution of this repository. Below there are also code snippets written in C# for you to get started using this library:

 

Create an instance of the PI Web API top level object.

 

     PIWebApiClient client = new PIWebApiClient("https://marc-web-sql.marc.net/piwebapi", true);  

If you want to use basic authentication instead of Kerberos, set useKerberos to false and set the username and password accordingly.

 

Get the PI Data Archive WebId

 

    PIDataServer dataServer = client.DataServer.GetByPath("\\\\MARC-PI2016");

 

Create a new PI Point

 

    PIPoint newPIPoint = new PIPoint(); newPIPoint.Name = "MyNewPIPoint" newPIPoint.Descriptor = "Point created for wrapper test" newPIPoint.PointClass = "classic" newPIPoint.PointType = "Float32" ApiResponseObject response = client.dataServer.CreatePointWithHttpInfo(dataServer.webId, newPIPoint)

 

Get PI Points WebIds

 

    PIPoint point1 = client.Point.GetByPath("\\\\marc-pi2016\\sinusoid"); PIPoint point2 = client.Point.GetByPath("\\\\marc-pi2016\\sinusoidu"); PIPoint point3 = client.Point.GetByPath("\\\\marc-pi2016\\cdt158");

 

Get recorded values in bulk using the StreamSet/GetRecordedAdHoc

 

    List<string> webIds = new List<string>() { point1.WebId, point2.WebId, point3.WebId }; PIItemsStreamValues piItemsStreamValues = client.StreamSet.GetRecordedAdHoc(webIds, startTime: "*-3d", endTime: "*");

 

Send values in bulk using the StreamSet/UpdateValuesAdHoc

 

     var streamValuesItems = new PIItemsStreamValues(); var streamValue1 = new PIStreamValues(); var streamValue2 = new PIStreamValues(); var streamValue3 = new PIStreamValues(); var value1 = new PITimedValue(); var value2 = new PITimedValue(); var value3 = new PITimedValue(); var value4 = new PITimedValue(); var value5 = new PITimedValue(); var value6 = new PITimedValue(); value1.Value = 2; value1.Timestamp = "*-1d"; value2.Value = 3; value2.Timestamp = "*-2d"; value3.Value = 4; value3.Timestamp = "*-1d"; value4.Value = 5; value4.Timestamp = "*-2d"; value5.Value = 6; value5.Timestamp = "*-1d"; value6.Value = 7; value6.Timestamp = "*-2d"; streamValue1.WebId = point1.WebId; streamValue1.Items = new List<PITimedValue>(); streamValue1.Items.Add(value1); streamValue1.Items.Add(value2); streamValue2.WebId = point2.WebId; streamValue2.Items = new List<PITimedValue>(); streamValue2.Items.Add(value3); streamValue2.Items.Add(value4); streamValue3.WebId = point2.WebId; streamValue3.Items = new List<PITimedValue>(); streamValue3.Items.Add(value5); streamValue3.Items.Add(value6); ApiResponse<PIItemsItemsSubstatus> response2 = client.StreamSet.UpdateValuesAdHocWithHttpInfo(new List<PIStreamValues>() { streamValue1, streamValue2, streamValue3 });

 

Get element and its attributes given an AF Element path

 

     PIElement myElement = client.Element.GetByPath("\\\\MARC-PI2016\\CrossPlatformLab\\marc.adm"); PIItemsAttribute attributes = client.Element.GetAttributes(myElement.WebId, null, 1000, null, false);

 

Get current value given an AF Attribute path

 

     PIAttribute attribute = client.Attribute.GetByPath(string.Format("{0}|{1}", "\\\\MARC-PI2016\\CrossPlatformLab\\marc.adm", attributes.Items[0].Name)); PITimedValue value = client.Stream.GetEnd(attribute.WebId);

 

Get Event Frames given an AF Database path

 

    PIAssetDatabase db = client.AssetData.GetByPath(path); PIItemsEventFrame efs = client.AssetData.GetEventFrames(db.WebId, referencedElementNameFilter: "myElement", referencedElementTemplateName:

 

Final Remarks

 

As you could realize by looking at the example, it is pretty easy to use this client library on your apps. Please provide your feedback by posting your comments below!