8 Replies Latest reply on Mar 29, 2017 12:54 PM by Arco

    PI WebAPI Batch request from C# - System.Net.WebException

    Arco

      Hi all,

       

      I am getting to know the PI WebAPI and am trying to do some Batch requests as explained in the Batch webinar ( PI Developers Club Webinar Series: PI Web API - Batch ).

      I installed Postman as done in the webinar and was able to do Batch requests, so the PI WebAPI is able to do it (version 2016 R2). So far so good.

       

      Now I would like to do a batch request from C# code. I am able to do Post requests via code. I successfully updated a value on a PI Point, so that works.

      But I am stuck at sending a Batch request somehow and I need some help.

      At the point where I am sending my request (Stream dataStream = request.GetRequestStream();) I get the following error:

       

      An exception of type 'System.Net.WebException' occurred in System.dll but was not handled in user code

      Additional information: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

       

      As said, it works for other POST requests

       

      I snitched some code from the OSISoft git repository and adjusted this for my needs.

      Here is my code:

       

      [TestMethod()]
              public void BatchRequest()
              {
                  string controller = @"https://server/piwebapi/batch";
                 
                  dynamic globalBatch = new JObject();
                  globalBatch["1"] = new JObject();
                  globalBatch["1"].Method = "GET";
                  globalBatch["1"].Resource = @"https:/server/piwebapi/streams/P0AAAAAAAAAAAAAAAAAAFz8AEQAAAAUzA4OEE4MjAwXE5JQV9DX0ZQ/value";
      
                  globalBatch["2"] = new JObject();
                  globalBatch["2"].Method = "GET";
                  globalBatch["2"].Resource = "https://server/piwebapi/streams/P0AAAAAAAAAAAAAAAAAAFz8AEQAAAAUzA4OEE4MjAwXE5JQV9DX0ZQ/value";
      
                  string data = JsonConvert.SerializeObject(globalBatch);
      
                  int statusCode;
                  PIWebAPIWrapper.Infrastructure.PIWebAPIConnector.MakePostRequest(controller, data, out statusCode);
              }
      
            //This function is responsable for the HTTP POST request
              public static void MakePostRequest(string url, string postData, out int statusCode)
              {
                  WebRequest request = WebRequest.Create(url);
      
                  //Kerberos Authentication Only
                  request.UseDefaultCredentials = true;
      
                  ((HttpWebRequest)request).UserAgent = ".NET Framework Example Client";
      
                  //The method is "GET" by default.
                  request.Method = "POST";
      
                  //If the content-type is not specified as application/json, your post request won't work.
                  request.ContentType = "application/json";
      
                  //The content length should be present on the request header.
                  byte[] byteArray = Encoding.UTF8.GetBytes(postData);
                  request.ContentLength = byteArray.Length;
                  // Here I get the exception
                  Stream dataStream = request.GetRequestStream();
                  dataStream.Write(byteArray, 0, byteArray.Length);
                  dataStream.Close();
      
                  //Get the response to make sure the value was sent.
                  WebResponse response = request.GetResponse();
      
                  //The StatusCode property is available only if the WebRequest object is converted to HttpWebRequest
                  //The StatusCode will confirm that the operation was executed successfully.
                  statusCode = Convert.ToInt32(((System.Net.HttpWebResponse)(response)).StatusCode);
              }
      

      When I take the postData string from code and use this in Postman, I get the result I am expecting, so the postData seems legit.

      I tried several other batch requests but did not succeed.

       

      Does anyone have an idea what I am doing wrong?

       

       

      PI WebAPI

        • Re: PI WebAPI Batch request from C# problem
          dng

          Hi Arco,

           

          My guess is that certificate verification failed. Are you using a self-signed certificate? When you open up a browser, did you see a certificate warning?

          If so, try to either install the certificate on the machine you are running your C# client, or add code to ignore certificate checks. Only do these if you trust the PI Web API endpoint and in a dev environment.

          In a production environment, the best way is probably to check and fix the certificate.

          2 of 2 people found this helpful
            • Re: PI WebAPI Batch request from C# problem
              Arco

              Hi Daphne,

               

              Yes, we do have a self signed certificate. Installing a proper certificate is done next week.

              But, doing GET requests and other POST requests works without any problems, so I am not seeing the relation with the self signed certificate.

               

              For now I am accepting any certificate:

                public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)

                      {

                          return true;

                      }

               

              And this works for other requests.

               

              Thanks for thinking with me.

                • Re: PI WebAPI Batch request from C# problem
                  dng

                  I am suspecting certificate issue due to the error message you posted:

                  An exception of type 'System.Net.WebException' occurred in System.dll but was not handled in user code

                  Additional information: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

                  Other references:

                  Error: C# The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel - …

                   

                  It is indeed odd that you are not getting errors with other requests. Is there additional information about the error apart from the above text? You could always install the cert into the local trusted cert store just to rule out certificate issue (if it makes no difference, remove the cert after).

                  • Re: PI WebAPI Batch request from C# problem
                    pthivierge

                    Hello Arco,

                     

                    I have talked with Lubos Mlcoch this morning and he shared with me the code you are using.

                     

                    I could reproduce and find a solution to your issue.

                     

                    The thing is when you are working with the Batch feature you are using a different method.  In the code there is:

                    • MakeGetRequest
                    • MakePostRequest

                     

                    The configuration for the callback only exists in the MakeGetRequest.  A quick workaround I created a separate function:

                            public static void init()
                            {
                                ServicePointManager.ServerCertificateValidationCallback = (s, cert, chain, ssl) => true;
                            }
                    

                     

                    And calling the init function in both methods MakeGet and MakePost.

                     

                    This is not ideal, as this would normally be called only once when your application starts that should suffice.  consider this a quick workaround .

                     

                    After this I could work with the batch.

                     

                    Hope this helps,

                    2 of 2 people found this helpful
                      • Re: PI WebAPI Batch request from C# problem
                        Arco

                        Hi Patrice,

                         

                        Thanks for finding a workaround.

                        But, now I will completely bypass the validation of the Webservice Certificate. For now I can continue, will this change in a next release?

                        We installed a certificate on the PI WebAPI Service, makes no sense when we bypass the validation.

                         

                        One more thing. When I use the MakePostRequest function for writing multiple values on a PI Point, the error does not occur. Same code.

                         

                         

                          • Re: PI WebAPI Batch request from C# problem
                            pthivierge

                            I am not sure that I understand what you are saying correctly.

                             

                            You should consider the proposed workaround as for development purpose only.

                            On a production environment, with a valid certificate this issue does not exist.

                             

                            Will this change in a next release?

                            The certificate validation is an internal mechanism implemented by browsers and web clients to ensure security on the web.

                            So this will not change.   In our case here, because your certificate is not valid in the development environment, to be able to test your application, you need to add a callback to bypass the security check. For your production code you should remove them.

                             

                            One more thing. When I use the MakePostRequest function for writing multiple values on a PI Point, the error does not occur. Same code.

                            Can you provide the query?

                            1 of 1 people found this helpful
                              • Re: PI WebAPI Batch request from C# problem
                                Arco

                                Hi Patrice,

                                 

                                if that is the case then all is good. Thanks again.

                                The certificate will be installed on our loadbalancer in the next days.

                                I will get back here to let you know if everything is okay then here.

                                 

                                About the UpdateValues on a PIPoint. It is in the Test Project I sent to Lubos which you have.

                                There is a test method called UpdateValues whcih does this.

                                 

                                This is the method which calls MakePostRequest at the end.

                                 

                                public void UpdateValues(List<AFValue> afValues)
                                        {
                                            string piServer = Properties.Settings.Default.PIServer;
                                            string servername = Properties.Settings.Default.ServerName;
                                
                                            StringBuilder url = new StringBuilder();
                                            url.Append(this.Links.RecordedData);
                                
                                            StringBuilder data = new StringBuilder();
                                            data.Append("[");
                                
                                            foreach (var afValue in afValues)
                                            {
                                                object payload = new
                                                {
                                                    Value = afValue.Value,
                                                    Timestamp = afValue.Timestamp
                                                };
                                                data.Append(JsonConvert.SerializeObject(payload)).Append(",");
                                            }
                                
                                            data.Remove(data.Length - 1, 1);
                                
                                            data.Append("]");
                                
                                            string param = data.ToString();
                                
                                            int statusCode;
                                            PIWebAPIConnector.MakePostRequest(url.ToString(), param, out statusCode);
                                        }
                                
                                  • Re: PI WebAPI Batch request from C# problem
                                    Arco

                                    Just to let you all know. The correct production certificates were finally configured on the two servers where the PI WebAPI is installed.

                                    These two servers were placed under a loadbalancer.

                                    I removed the temporary workaround and am now validating the certificate properly and now the certificate validation problems are indeed gone.

                                     

                                    Thanks again for the help.

                                    1 of 1 people found this helpful