Here are some questions that we already answered to the TECH SUPPORT FOLKS, just to save time:
1. How many users are accessing the web application? Do they all have proper trusts/mappings set up to get access to the PI server?
The application is deployed on IIS server. We are not using trusts. We are using PI User accounts. The IIS server connects to the PI Server using these accounts. We have created about 20 PI User accounts. We are NOT doing Windows Active Directory security at this point. We will do this for future release as our AD environment is not ready.
2. Do you have multiple Server connection windows open?
We call Server.Open() in the code to open a connection to the PI server.
3. Is this a custom-built application?
4. Do you have a trust set up for this application?
No. WE ARE NOT DOING PI TRUST
5. What versions of PI-SDK and PI Server are you using? 32-bit or 64-bit?
PI SDK 22.214.171.1248 (32 bit)
PI Server 3.4.380.36 (64 bit)
Scenario when this error happens:
User 1: Launches a web page & queries a report. This calls our .NET method GetServer() to return a PI Server object. Using this object, we query PI data
User 2: Launches a web page & queries a report. This calls our .NET method GetServer() to return a PI Server object. This is when we encounter the error.
May I ask why aren't you using the ServerManager object as exposed in the PI SDK help instead of using the PISDK object?
We used the the ServerManager object in the beginning. But, we learnt that it works with Active Directory. This was why we used the PISDK object. We are authenticating users with PI User account. We will eventually move away once we have Active Directory setup on our Process Network production environment.
First I'd like to clear up one of the misconceptions above. The ServerManager object supports both PI Trusts and Windows Security. It was actually added to PI SDK years back, and is used by multiuser products such as PI WebParts and PI Web Services. Here is what the SDK manual says about ServerManager -
The ServerManager is a creatable collection object whose purpose is to provide a pool of open server connections to PI3.3 servers. Web based business objects can provide improved performance while maintaining security by creating a single ServerManager as an application level object. The ServerManager uses the PI3.3 PITrust table, maintained on the PI server, to validate connected domain users and provides open connections as trusted PI users.
The PI-SDK object hierarchy derives significant performance benefits from caching Server information as it is retrieved over time. Typical PI-SDK client/server applications maintain a small number of connections over the execution of the application, reaping the benefits of cached data. In a “connectionless” Web environment, reestablishing a PI-SDK hierarchy with each client access is prohibitively slow. The ServerManager solves this problem by storing open Server objects and providing secure access to them as required.
That said, it looks like there are a few possible solutions (least to most effort):
- Continue to use existing Server/Servers collection but close connection each time before re-opening. This is probably not viable for a web application, due to performance considerations.
- Create a separate thread with its own SDK object for each user request. This would allow explicit login for each user, but may be a major effort since you would handle all the connection management like ServerManager.
- Change code to use the ServerManager collection to establish a separate SDK object with unique user credentials.
- Change code to use PI Web Services. This may seem like a significant change at this stage in your development, but may in fact be an easier solution since it would likely mean less custom SDK code to test and manage.
The last two approaches are the recommended solutions, with nod towards PI Web Services in long term...
As an alternative, you could change the security model so that the application connects as a specific user (i.e. service account). This account has access to all PI data. Then implement security at the application layer and ensure that only authenticated/authorized users can access the application. Of course this would effectively bypass PI security and shift the burden to the application, but it might be feasible given security features in ASP.NET such as Forms Authentication.
The best approach would likely be to combine security at both the application level and the PI System level, similar to how SharePoint and PI WebParts work. For example, SharePoint leverages Active Directory to authenticate users and authorize them to access a site/page, and PI WebParts passes these Windows credentials to PI System to ensure users only see the data they have access to. So hopefully this issue helps folks understand why we also recommend that customers and partners consider developing on Microsoft SharePoint/PI WebParts infrastructure, if possible.
Thanks for your detailed reply. I have some more questions to understand this a bit better...
You had mentioned about ServerManager object and that it supports PI trust and windows security. We eventually would like to go to windows security for our future release. Our understanding was that PI Trust would expose all tags to the trusted user.
We have around 20 business groups at our company & there is requirement that we allow users to access Tags that they're allowed to see. This was why we created 20 PI User accounts. When a web based user tries to query PI data, we would like to connect to PI with the corresponding user account. We thought that we could accomplish this via PISDK Server object.
Does the ServerManager object support the use of PI User accounts ?
Can we get some sample code for solution 3 ?
We were using the following code when we had plans to do windows authentication. We didnt know that we could pass user credentials to do a "server_manager.get_Item(ref pi_server)".
ServerManager server_manager = (ServerManager)System.Web.HttpContext.Current.Application["ServerManager"];
if (server_manager == null)
server_manager = new ServerManager();
System.Web.HttpContext.Current.Application["ServerManager"] = server_manager;
if (ConfigurationManager.AppSettings["PIServer"] == null) throw new Exception("Error connecting to PI server. Missing server name in the configuration file");
object pi_server = ConfigurationManager.AppSettings["PIServer"];
return server_manager.get_Item(ref pi_server);
No, ServerManager does not support explicit login (i.e. cannot use PI user accounts directly).
I believe what you want to do can be accomplished using ServerManager and PI Trusts. This will require minor code changes and configuring the trust table, but this is a fairly small effort and is probably the fastest path to a solution...
I recommend you review the topic on "Trust Login Security" in the PI Server 3.4.375 System Management Guide. Note, you will need to download that version from TS site because this content is no longer available in later releases.
If you still have questions regarding PI Trusts, feel free to contact Technical Support for help.
Our understanding was that PI Trust would expose all tags to the trusted user
This is not the case, because PI Trust is an authentication mechanism and it does not determine the privileges of user in the PI Server.
The way that PI Trust works is that the incoming connection will be trusted as a PI User, based on the credentials of the connection (like hostname, IP, application name, username of the user running the application, etc). Eventually the privileges that the user have is determined by which PI User the connection is trusted as.
Same case if you are using Windows Integrated Security to map Windows (or Domain) user or group to a PI Identity. The mapping simply determines which PI Identity the connections is mapped to. And the privilege is determined by the PI Identity with respect to the PISDK objects in a PI Server.
Like what Jay has suggested, you can use ServerManager with authentication mechanism like PI Trust and Identity Mapping (Windows Integrated Security, WIS). As long as the users are authenticated as the appropriate PI User (or PI Identity), that have the approriate access privilege.
FYI, we also have an upcoming webinar that talks about PI System Security, and we will be talking more about these security configurations.
To give some more background about our environment:
Our Web application is deployed on Corporate Environment. However, our Production PI Servers are NOT setup as part of a Active Directory Domain. They are in a workgroup under a DMZ environment. In the future, we will have Active Directory setup for our PI Server Environment.
I am afraid that the idea of setting up a PI Trust may not work in this environment as we are not passing the user's Windows Identity to the PI server.
Ok, I think user name will only work in your environment if you create user accounts in the workgroup which match the exact same user accounts in your domain. The downside of this approach is keeping the accounts in sync...
However, as Cristobal mentioned PI Trusts support multiple credentials including host name (i.e. computer name), IP address, application name, as well as user name. Perhaps you can consider using the other credentials to identify users who are accessing your application? This info would be passed down to the PI Server and you could setup appropriate PI Trusts to ensure the appropriate access to your PI data.
We have a large user base falling under different business groups within our company. If we go for PI Trust, then we will have to setup trust based on user name. This was why we created PI User account for each business group.
On the web application side, we figure out which Active Directory group the user belongs. Based on that AD group, we get the PI User Account from our SQL Server db. Once we have the PI User Account we use PISDK server.open() to get a connection to the PI server.
Can I create a collection of PISDK Server objects - one object per PI User and manage within the application ?
My apologies, it occurred to me afterwards that in your multitier environment that the web application will always connect to the PI Server with the same IP address and host name (web server), and same application name (w3wp.exe).
I think your other suggestion of using a collection of Server objects matches my #2 above.
Are there any examples for implementing Server Object collection ?
Just to close the loop and for everyone's benefit, we discussed the following path forward:
1. Configure IIS to use Basic authentication (to avoid the double-hop scenario)
2. Use ServerManager and Windows security (NTLM) to connect to the PI Server
3. Create matching local Windows groups on both the web server and PI Server
For example, users could login with shared credentials for the "Area 1" Windows group, and those users would get access to certain tags. There would also be groups for "Area 2" and so on, up to the number of different groups which need to be segregated. Fortunately, they have a small number of business groups so this is a fairly manageable task. Note, PI Server with Windows security supports multiple identities in an ACL so this allows some tags to be shared across multiple business groups.
Of course this is just a temporary approach until they can use AD and Kerberos to pass the user credentials all the way from the business domain to PI Server. The best part is, if done properly, all they would have to do once they have AD domain for the PI Server is change the mappings from the local Windows group to the AD group that already exists. In other words, only configuration changes are required with no additional code modifications.
Perhaps Biju can comment on any other changes they made and if they were successful...
I'm using Pi SDK 1.3.8 and there is no Item property on ServerManager so thread is not up to date?
I'm trying to get multiple connections to same Pi server from one application running under one user. Is this possible at all?
I've read through forum and saw some suggestions to instantiate PiSDK on each thread and so on but all tests I did are not confirming this.
Is there any example how to do this? ServerMnager would be ideal if I know how to use it (or if there is some doc showing this).
When you get a call from IIS, create an STA thread which may live until iisreset. On your STA thread, create ServerManager and keep the object around. When your STA worker thread handles a call, first impersonate the calling user, then use ServerManager.Item to get a connected server object(s). Now do your work based on those authenticated Server connections.
@Noam Arbel: just curious, did you find the information you needed or do you need further assistance with this?
Found something but we still have problem to "load" Pi
Could you post your problem as a new thread (unless of course it is the same issue)?
I just realized that one of your questions above was not answered:
"I'm trying to get multiple connections to same Pi server from one application running under one user. Is this possible at all?"
From a given application, there is only one connection to a given PI Server. The connection is fully asynchronous and thus may handle a significant stream of data. From the programming point of view, you should attempt to use the asynchronous modes when possible, and possible a thread pool to give more throughput.
Noam, can you please elaborate what you mean by "we still have problem to load Pi". Perhaps you initiated a Tech Support call?
From a given application, there is only one connection to a given PI Server
Please clarify. Does this mean that suggestions of creating different connections in different threads will NOT work?