Analysis of OsiSoft’s PI Vision Web Application (Part 2)

When I try to perform screen design by clicking on one of the PI Vision pages I’ve designed, I get an error message as follows:

Timestamp: ‎5‎/‎3‎/‎2018‎ ‎10‎:‎46‎:‎18‎ ‎AM
Severity: Error
Message: Data Error
Details: Could not load file or assembly ‘OSIsoft.PI.Net.Core, Version=, Culture=neutral, PublicKeyToken=c3309f0734ba2805’ or one of its dependencies. The system cannot find the file specified.

After trying to copy the missing file from the original server, the error still there.

Trying to monitor it using ProcessMonitor (Procmon.exe) reveals as follows:

Checking into destination folder reveals that it has a different version called v4.0_1.8.3.0__c3309f0734ba2805. So, why it insists on loading non-existing version ?

Using ILSpy, it is revealed that the required version is referenced from assembly called OSIsoft.AFSDK:

And in version information, I can see that it is indeed version that is required:

Get an updated version of OSIsoft.AFSDK.dll from source to destination, and seems that the web application can get the correct version now:

Let’s whether the error is recurring again by try to perform design, the previous error is solved.

But another came which is Data Error : Could not load file or assembly ‘OSIsoft.PI.Configuration, Version=, Culture=neutral, PublicKeyToken=c3309f0734ba2805’ or one of its dependencies. The system cannot find the file specified.

Perform replace of entire GAC_MSIL folder from source to destination. Let’s try again.

But now I have another error which is Data Error : Retrieving the COM class factory for component with CLSID {7D36BED3-9635-484F-92E0-478369C450EC} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).

Let’s find out in the source server, what kind of the above component is that:

Perform copying of entire folder of PIPC from source server to destination server Then try to perform the COM registration as follows:

D:\Program Files (x86)\PIPC\pisdk>regsvr32 PISDKRegistry.dll

But I have an error the module “PISDKRegistry.dll” failed to load as follows:

Using Dependency Walker program I’ve found as follows:

Since this is the 32 bit application, copy the required file from C:\Windows\SysWOW64 in the source server to destination. After copying all of the required dependencies, now I have:

There are no errors on the PI Vision display now. But when try to click on the data, I have HTTP Error 503. The service is unavailable.

Checking on Event Viewer, I have a crashed w3wp with error below:

Application: w3wp.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
at PISDKRegistry.ISDKServers.get_DefaultServer()
at OSIsoft.PI.Configuration.Schema.PISDKRegistrySchema+<>c__DisplayClass25_0.b__0(PISDKRegistry.IPISDKReg)
at OSIsoft.PI.Configuration.Schema.PISDKRegistrySchema.AccessRegistry(System.Action`1)
at OSIsoft.PI.Configuration.Schema.PISDKRegistrySchema.RunInReaderLock(System.Action`1)
at OSIsoft.PI.Configuration.Schema.PISDKRegistrySchema.get_DefaultServer()
at OSIsoft.PI.Configuration.PISDKRegistryDirectoryProvider.AddDefaultServiceToDomainTable(OSIsoft.PI.Configuration.DomainTable)
at OSIsoft.PI.Configuration.PISDKRegistryDirectoryProvider.GetDomainTable()
at OSIsoft.PI.Configuration.PISDKRegistryDirectoryProvider.GetTable[[System.__Canon, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089]](OSIsoft.PI.Configuration.TableType)

Then in the earlier event I get:

The description for Event ID 5 from source PISDK cannot be found. Either the component that raises this event is not installed on your local computer or the installation is corrupted. You can install or repair the component on the local computer.

If the event originated on another computer, the display information had to be saved with the event.

The following information was included with the event:

Failed to create/open registry key – SOFTWARE\Wow6432Node\PISystem.

Perform registry export from source from indicated location and import it into destination. Next I have this error:

Failed to create/open Symbolic link to ..WOW6432Node\PISystem\PISDK

In the source server, perform examine of registry links using this command below:

The result is there’s a registry link HKLM\Software\PISystem\PI-SDK -> HKLM\SOFTWARE\Wow6432Node\PISystem\PI-SDK

Export the registry from source server for HKLM\Software\PISystem and HKLM\SOFTWARE\Wow6432Node\PISystem and import to destination server. Next is to remove the reference of PI-SDK in HKLM\Software\PISystem, since it is actually a registry key link (REG_LINK) to prevent error when try to create a link.

Then perform registry link using regln-x64 command below:

Now there’s no crashed w3wp.exe and the PI Vision pages can be shown properly. Next, I notice when I try to get the PI AF data, I get an error as follows:

Let’s examine it starting from the UI component that is involved to obtain the data. The above “Internal Server Error” string should contain some PI Asset data. The UI for this data is triggered by clicking on right arrow:

Using inspector, the UI element is called disclosure-indicator with method navIntoChild as follow :

The above element is part of PIVision\Scripts\app\common\breadcrumblist.html with script handler in PIVision\Scripts\app\common\PIVisualization.breadcrumblist-directive.js.

When the right arrow is clicked, it will execute navigate function as follows:

The navigate method is as follow:

The call to scope.getChildren will call to method getChildren method in PIVision\Scripts\app\editor\tools\PIVisualization.tool-search-directive.js. It will then call assetCache.getChildren.

The assetCache object is declared in PIVision\Scripts\app\editor\services\PIVisualization.asset-cache.js.

But first, let’s check the detail of object error in the event of processNavigationError method inside getChildren to see whether there are additional information for the error. But apart from “Internal Server Error” message, there are no other useful clue.

So, by examining getChildren method in assetCache source code, it is found that actually it calls to webServices.getChildAssets(parent.Path). And if you already read the previous article you will find that is is part of PIVision\Scripts\app\common\PIVisualization.web-services.js.

Inside this method it will translate to _callToWs with ‘Navigation/ChildAssets’ among one of its parameter. Then using network monitoring tool in Firefox, I will get information of the complete URL that the web service is trying to call which is\\xxx\yyy

So, when I try to use the above URL, surely there’s the HTTP 500 Internal server error.

Now let’s check the server side handling of this request, which is actually resides in OSIsoft.PIVisualization.Web.Controllers.NavigationController class. This class is compiled in the file called OSIsoft.PIVisualization.WebCommon.dll.

The ChildAssets is handled using method called GetChildAssets with method executions as follows:

From the above routines, you can see that if any of the error condition is fullfilled, it will emit HttpStatusCode.InternalServerError. But let’s check whether the retrieved list can give some helpful information regarding the error, i.e. from the red box above.

The method GetChildAssets is called using async method, so using WinDBG debugger, if you try to perform breakpoint to:


The actual calling method will be translated into something else, and in this case it is transformed into:


The CreateResults above is called using await method, and in the WinDBG debugger, it will call:


And by perform break point after this call inside this method:

The result task structure can be retrieved by querying the contain of rcx register after assigned by memory content of rbp-10h (see above). Task structure object as follows:

The task will contain:

System.Threading.Tasks.Task`1[[System.Collections.Generic.IList`1[[OSIsoft.PIVisualization.Services.Search.RestSearchResult, OSIsoft.PIVisualization.StorageService]], mscorlib]]

The returned list data is placed in object called m_result (see above), it will contain IList of type RestSearchResult:

The RestSearchResult is place inside object called _items:

It contains some data on first element, let’s check it:

The error information is stored in object called Error which has System.String type, let’s examine it:

In this way, I can find an underlying error which is not shown in PI Vision, which contains The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

After performing some more debugging session, it is found that the above error is originated from OSIsoft.Search.DefaultSearch.GetSearchResults. This method resides in OSIsoft.Search.dll.

As usual, since it is run as a task, it is transformed to OSIsoft.Search.DefaultSearch+d__22.MoveNext.

It will use the WebClient object to access this url below:\\xxx\yyy&fields=Name;Description;ItemType;UniqueId;Template;HasChildren;Paths;Plottable&count=1000

But this time, perform testing of the above url using a browser proves to be no problem. Since it is using a WebClient, I try to create a very small ASP.NET web program that is using the above URL for access, and the result is an exception called System.Security.Authentication.AuthenticationException, with error description as The remote certificate is invalid according to the validation procedure.

Using the browser, there will be certificate error message This CA Root certificate is not trusted because it is not in the Trusted Root Certification Authorities store.

So, perform certificate export from source server using IIS in Server Certificates menu and import it into Trusted Root Certification Authorities. And perform WebClient testing again.

But this time, the testing returns The remote server returned an error: (401) Unauthorized. And also try to use the above link to access the PI Asset still returns HTTP 500 Internal server error.

Perform un-remark at near the end of of the file OSIsoft.REST.Host.exe.config in OsiSoft’s WebAPI folder to enable trace data to be written to PIWebAPI.log. Then perform service re-start and re-run the web service request.

The result of log as follows:

OSIsoft.REST.Host.exe Error: 0 : [2018-06-12T06:20:33.9035983Z] Level=Error, Kind=End, Category=’System.Net.Http.Formatting’, Id=af7ccae7-dab9-47db-aee9-870f899fe879, Operation=AFJsonMediaTypeFormatter.WriteToStreamAsync, Status=500 (InternalServerError), Exception=System.Web.Http.HttpResponseException: Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the ‘Response’ property of this exception for details.
at OSIsoft.REST.Formatters.AFJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream stream, Encoding encoding)
at OSIsoft.REST.Formatters.AFJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream stream, HttpContent content, TransportContext context, CancellationToken token)
at System.Net.Http.Formatting.MediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext)
at System.Web.Http.Tracing.Tracers.MediaTypeFormatterTracer.<>c__DisplayClassd.b__c()
at System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEndAsync(ITraceWriter traceWriter, HttpRequestMessage request, String category, TraceLevel level, String operatorName, String operationName, Action`1 beginTrace, Func`1 execute, Action`1 endTrace, Action`1 errorTrace)

This is parallel with the error on client side by examining it in WinDBG with the error The remote server returned an error: (500) Internal Server Error. The CLR exception event filter in WinDBG must be activated after the call to GetChildAssets.

When the first exception is occured, perform series of command below to see the error message:

Although the above message log perform some information about the routine that caused the exception, it is not provide a useful clue of the exact problem. So by performing a debugging session on running OSIsoft.REST.Host.exe I arrive at the source of exception as follows:

Inside PIImpersonationContext routine, there’s some check whether the given identity is an Anonymous user and throws an exception:

Let’s perform check of the Identity given by PIIdentity at the call to PIImpersonationContext when the exception will occur:

You can see that the PI Web API server receives an identity of NT AUTHORITY\ANONYMOUS LOGON, and it will throws exception when it is Anonymous.

Unfortunately there’s no solution to this issue, because it is by design in part of PI Vision access to PI Web API using WebClient.

The consequences is that PI Vision web application can not be placed in separate server location. This is the part of routine that caused the issue below:

You can see from the above picture, that inside OSIsoft.Search.DefaultSearch.GetSearchResults, there’s direct call to OpenReadTaskAsync without any anticipation for some given client’s credential data passing through WebClient object.

If the object in question is outside of local server, the user will always be an Anonymous and the Web API will always throws exception.

This concludes the analysis session.

You can leave a response, or trackback from your own site.

2 Responses to “Analysis of OsiSoft’s PI Vision Web Application (Part 2)”

  1. AR2 says:

    I’d like to find out more? I’d want to find out more details.

  2. Thanks for this sound opinion on what is usually an overlooked topic. Mind if I share this with my followers?

Leave a Reply

Powered by WordPress and Bootstrap4