/// <summary> /// Register with the server certificate. /// </summary> /// <param name="serverCertificate"></param> /// <param name="endpointUrl"></param> /// <param name="onConnectionWaiting"></param> public Registration( X509Certificate2 serverCertificate, Uri endpointUrl, EventHandler <ConnectionWaitingEventArgs> onConnectionWaiting) : this(endpointUrl, onConnectionWaiting) { ServerUri = X509Utils.GetApplicationUriFromCertificate(serverCertificate); }
public async void CreateCertificate() { ApplicationInstance application = new ApplicationInstance { ApplicationType = ApplicationType.Client, ConfigSectionName = "Opc.Ua.SampleClient" }; if (Device.RuntimePlatform == "Android") { string currentFolder = DependencyService.Get <IPathService>().PublicExternalFolder.ToString(); string filename = application.ConfigSectionName + ".Config.xml"; string content = DependencyService.Get <IAssetService>().LoadFile(filename); File.WriteAllText(currentFolder + filename, content); // load the application configuration. config = await application.LoadApplicationConfiguration(currentFolder + filename, false); } else { // load the application configuration. config = await application.LoadApplicationConfiguration(false); } // check the application certificate. haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0); switch (Device.RuntimePlatform) { case "Android": config.ApplicationName = "OPC UA Xamarin Sample Client Android"; break; case "UWP": config.ApplicationName = "OPC UA Xamarin Sample Client UWP"; break; case "iOS": config.ApplicationName = "OPC UA Xamarin Sample Client IOS"; break; } if (haveAppCertificate) { config.ApplicationUri = X509Utils.GetApplicationUriFromCertificate(config.SecurityConfiguration.ApplicationCertificate.Certificate); config.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_CertificateValidation); } }
/// <summary> /// Create OPC UA client configuration /// </summary> /// <returns></returns> /// <param name="clientName"></param> /// <param name="configPath"></param> /// <exception cref="ArgumentNullException"></exception> public async Task <ApplicationConfiguration> CreateOpcUaConfiguration(string clientName, string configPath) { if (string.IsNullOrWhiteSpace(clientName)) { throw new ArgumentNullException(nameof(clientName)); } if (string.IsNullOrWhiteSpace(configPath)) { throw new ArgumentNullException(nameof(configPath)); } var application = new ApplicationInstance { ApplicationName = clientName, ApplicationType = ApplicationType.Client, ConfigSectionName = clientName, }; var clientApplicationConfig = await application.LoadApplicationConfiguration(filePath : configPath, silent : false); var haveAppCertificate = await application.CheckApplicationInstanceCertificate(silent : false, minimumKeySize : 0); if (!haveAppCertificate) { throw new Exception(Text.InvalidCertificate); } clientApplicationConfig.ApplicationUri = X509Utils.GetApplicationUriFromCertificate(certificate: clientApplicationConfig.SecurityConfiguration.ApplicationCertificate.Certificate); clientApplicationConfig.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(this.SessionAutoAcceptCertificate_Event); return(clientApplicationConfig); }
/// <summary> /// Creates an application instance certificate if one does not already exist. /// </summary> private static async Task <bool> CheckApplicationInstanceCertificate( ApplicationConfiguration configuration, X509Certificate2 certificate, bool silent, ushort minimumKeySize) { if (certificate == null) { return(false); } Utils.Trace(Utils.TraceMasks.Information, "Checking application instance certificate. {0}", certificate.Subject); try { // validate certificate. configuration.CertificateValidator.Validate(certificate); } catch (Exception ex) { string message = Utils.Format( "Error validating certificate. Exception: {0}. Use certificate anyway?", ex.Message); if (!await ApproveMessage(message, silent)) { return(false); } } // check key size. int keySize = X509Utils.GetRSAPublicKeySize(certificate); if (minimumKeySize > keySize) { string message = Utils.Format( "The key size ({0}) in the certificate is less than the minimum provided ({1}). Use certificate anyway?", keySize, minimumKeySize); if (!await ApproveMessage(message, silent)) { return(false); } } // check domains. if (configuration.ApplicationType != ApplicationType.Client) { if (!await CheckDomainsInCertificate(configuration, certificate, silent)) { return(false); } } // check uri. string applicationUri = X509Utils.GetApplicationUriFromCertificate(certificate); if (String.IsNullOrEmpty(applicationUri)) { string message = "The Application URI could not be read from the certificate. Use certificate anyway?"; if (!await ApproveMessage(message, silent)) { return(false); } } else { configuration.ApplicationUri = applicationUri; } // update configuration. configuration.SecurityConfiguration.ApplicationCertificate.Certificate = certificate; return(true); }
private async Task ConsoleClient() { Log(conn_name + " - " + "Create an Application Configuration..."); exitCode = ExitCode.ErrorCreateApplication; ApplicationInstance application = new ApplicationInstance { ApplicationName = "JSON-SCADA OPC-UA Client", ApplicationType = ApplicationType.Client, ConfigSectionName = "", }; bool haveAppCertificate = false; ApplicationConfiguration config = null; try { // load the application configuration. Log(conn_name + " - " + "Load config from " + OPCUA_conn.configFileName); config = await application.LoadApplicationConfiguration(OPCUA_conn.configFileName, false); // config.SecurityConfiguration.AutoAcceptUntrustedCertificates = true; // check the application certificate. haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0); if (!haveAppCertificate) { Log(conn_name + " - " + "FATAL: Application instance certificate invalid!", LogLevelNoLog); Environment.Exit(1); } if (haveAppCertificate) { config.ApplicationUri = X509Utils.GetApplicationUriFromCertificate(config.SecurityConfiguration.ApplicationCertificate.Certificate); if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates) { autoAccept = true; } config.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_CertificateValidation); } else { Log(conn_name + " - " + "WARN: missing application certificate, using unsecure connection."); } } catch (Exception e) { Log(conn_name + " - WARN: " + e.Message); } if (config == null) { Log(conn_name + " - " + "FATAL: error in XML config file!", LogLevelNoLog); Environment.Exit(1); } try { Log(conn_name + " - " + "Discover endpoints of " + OPCUA_conn.endpointURLs[0]); exitCode = ExitCode.ErrorDiscoverEndpoints; var selectedEndpoint = CoreClientUtils.SelectEndpoint(OPCUA_conn.endpointURLs[0], haveAppCertificate && OPCUA_conn.useSecurity, 15000); Log(conn_name + " - " + "Selected endpoint uses: " + selectedEndpoint.SecurityPolicyUri.Substring(selectedEndpoint.SecurityPolicyUri.LastIndexOf('#') + 1)); Log(conn_name + " - " + "Create a session with OPC UA server."); exitCode = ExitCode.ErrorCreateSession; var endpointConfiguration = EndpointConfiguration.Create(config); var endpoint = new ConfiguredEndpoint(null, selectedEndpoint, endpointConfiguration); await Task.Delay(50); session = await Session.Create(config, endpoint, false, "OPC UA Console Client", 60000, new UserIdentity(new AnonymousIdentityToken()), null); // Log("" + session.KeepAliveInterval); // default is 5000 session.KeepAliveInterval = System.Convert.ToInt32(OPCUA_conn.timeoutMs); // register keep alive handler session.KeepAlive += Client_KeepAlive; } catch (Exception e) { Log(conn_name + " - WARN: " + e.Message); } if (session == null) { Log(conn_name + " - " + "FATAL: error creating session!", LogLevelNoLog); Environment.Exit(1); } Log(conn_name + " - " + "Browsing the OPC UA server namespace."); exitCode = ExitCode.ErrorBrowseNamespace; await FindObjects(session, ObjectIds.ObjectsFolder); await Task.Delay(50); Log(conn_name + " - " + "Add a list of items (server current time and status) to the subscription."); exitCode = ExitCode.ErrorMonitoredItem; ListMon.ForEach(i => i.Notification += OnNotification); //ListMon.ForEach(i => i.SamplingInterval = System.Convert.ToInt32(System.Convert.ToDouble(OPCUA_conn.autoCreateTagSamplingInterval) * 1000); // ListMon.ForEach(i => Log(conn_name + " - " + i.DisplayName)); Log(conn_name + " - " + ListMon.Count + " Objects found"); Log(conn_name + " - " + "Create a subscription with publishing interval of " + System.Convert.ToDouble(OPCUA_conn.autoCreateTagPublishingInterval) + "seconds"); exitCode = ExitCode.ErrorCreateSubscription; var subscription = new Subscription(session.DefaultSubscription) { PublishingInterval = System.Convert.ToInt32(System.Convert.ToDouble(OPCUA_conn.autoCreateTagPublishingInterval) * 1000), PublishingEnabled = true }; await Task.Delay(50); subscription.AddItems(ListMon); await Task.Delay(50); Log(conn_name + " - " + "Add the subscription to the session."); Log(conn_name + " - " + subscription.MonitoredItemCount + " Monitored items"); exitCode = ExitCode.ErrorAddSubscription; session.AddSubscription(subscription); subscription.Create(); subscription.ApplyChanges(); Log(conn_name + " - " + "Running..."); exitCode = ExitCode.ErrorRunning; }
public static void VerifySignedApplicationCert(ApplicationTestData testApp, byte[] rawSignedCert, byte[][] rawIssuerCerts) { X509Certificate2 signedCert = new X509Certificate2(rawSignedCert); X509Certificate2 issuerCert = new X509Certificate2(rawIssuerCerts[0]); TestContext.Out.WriteLine($"Signed cert: {signedCert}"); TestContext.Out.WriteLine($"Issuer cert: {issuerCert}"); Assert.NotNull(signedCert); Assert.False(signedCert.HasPrivateKey); Assert.True(X509Utils.CompareDistinguishedName(testApp.Subject, signedCert.Subject)); Assert.False(X509Utils.CompareDistinguishedName(signedCert.Issuer, signedCert.Subject)); Assert.True(X509Utils.CompareDistinguishedName(signedCert.Issuer, issuerCert.Subject)); TestContext.Out.WriteLine($"Signed Subject: {signedCert.Subject}"); TestContext.Out.WriteLine($"Issuer Subject: {issuerCert.Subject}"); // test basic constraints X509BasicConstraintsExtension constraints = X509Extensions.FindExtension <X509BasicConstraintsExtension>(signedCert); Assert.NotNull(constraints); TestContext.Out.WriteLine($"Constraints: {constraints.Format(true)}"); Assert.True(constraints.Critical); Assert.False(constraints.CertificateAuthority); Assert.False(constraints.HasPathLengthConstraint); // key usage X509KeyUsageExtension keyUsage = X509Extensions.FindExtension <X509KeyUsageExtension>(signedCert); Assert.NotNull(keyUsage); TestContext.Out.WriteLine($"KeyUsage: {keyUsage.Format(true)}"); Assert.True(keyUsage.Critical); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.CrlSign) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DataEncipherment) == X509KeyUsageFlags.DataEncipherment); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DecipherOnly) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == X509KeyUsageFlags.DigitalSignature); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.EncipherOnly) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyAgreement) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyCertSign) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyEncipherment) == X509KeyUsageFlags.KeyEncipherment); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == X509KeyUsageFlags.NonRepudiation); // enhanced key usage X509EnhancedKeyUsageExtension enhancedKeyUsage = X509Extensions.FindExtension <X509EnhancedKeyUsageExtension>(signedCert); Assert.NotNull(enhancedKeyUsage); TestContext.Out.WriteLine($"Enhanced Key Usage: {enhancedKeyUsage.Format(true)}"); Assert.True(enhancedKeyUsage.Critical); // test for authority key X509AuthorityKeyIdentifierExtension authority = X509Extensions.FindExtension <X509AuthorityKeyIdentifierExtension>(signedCert); Assert.NotNull(authority); TestContext.Out.WriteLine($"Authority Key Identifier: {authority.Format(true)}"); Assert.NotNull(authority.SerialNumber); Assert.NotNull(authority.KeyIdentifier); Assert.NotNull(authority.Issuer); Assert.AreEqual(issuerCert.SubjectName.RawData, authority.Issuer.RawData); Assert.AreEqual(issuerCert.SubjectName.RawData, authority.Issuer.RawData); // verify authority key in signed cert X509SubjectKeyIdentifierExtension subjectKeyId = X509Extensions.FindExtension <X509SubjectKeyIdentifierExtension>(issuerCert); TestContext.Out.WriteLine($"Issuer Subject Key Identifier: {subjectKeyId}"); Assert.AreEqual(subjectKeyId.SubjectKeyIdentifier, authority.KeyIdentifier); Assert.AreEqual(issuerCert.SerialNumber, authority.SerialNumber); X509SubjectAltNameExtension subjectAlternateName = X509Extensions.FindExtension <X509SubjectAltNameExtension>(signedCert); Assert.NotNull(subjectAlternateName); TestContext.Out.WriteLine($"Issuer Subject Alternate Name: {subjectAlternateName}"); Assert.False(subjectAlternateName.Critical); var domainNames = X509Utils.GetDomainsFromCertficate(signedCert); foreach (var domainName in testApp.DomainNames) { Assert.True(domainNames.Contains(domainName, StringComparer.OrdinalIgnoreCase)); } Assert.True(subjectAlternateName.Uris.Count == 1); var applicationUri = X509Utils.GetApplicationUriFromCertificate(signedCert); Assert.True(testApp.ApplicationRecord.ApplicationUri == applicationUri); }
/// <summary> /// Creates an application instance certificate if one does not already exist. /// </summary> private async Task <bool> CheckApplicationInstanceCertificate( ApplicationConfiguration configuration, X509Certificate2 certificate, bool silent, ushort minimumKeySize) { if (certificate == null) { return(false); } // set suppressible errors var certValidator = new CertValidationSuppressibleStatusCodes( new StatusCode[] { StatusCodes.BadCertificateUntrusted, StatusCodes.BadCertificateTimeInvalid, StatusCodes.BadCertificateHostNameInvalid, StatusCodes.BadCertificateRevocationUnknown, StatusCodes.BadCertificateIssuerRevocationUnknown, }); Utils.LogCertificate("Check application instance certificate.", certificate); try { // validate certificate. configuration.CertificateValidator.CertificateValidation += certValidator.OnCertificateValidation; configuration.CertificateValidator.Validate(certificate.HasPrivateKey ? new X509Certificate2(certificate.RawData) : certificate); } catch (Exception ex) { string message = Utils.Format( "Error validating certificate. Exception: {0}. Use certificate anyway?", ex.Message); if (!await ApproveMessage(message, silent).ConfigureAwait(false)) { return(false); } } finally { configuration.CertificateValidator.CertificateValidation -= certValidator.OnCertificateValidation; } // check key size. int keySize = X509Utils.GetRSAPublicKeySize(certificate); if (minimumKeySize > keySize) { string message = Utils.Format( "The key size ({0}) in the certificate is less than the minimum allowed ({1}). Use certificate anyway?", keySize, minimumKeySize); if (!await ApproveMessage(message, silent).ConfigureAwait(false)) { return(false); } } // check domains. if (configuration.ApplicationType != ApplicationType.Client) { if (!await CheckDomainsInCertificate(configuration, certificate, silent).ConfigureAwait(false)) { return(false); } } // check uri. string applicationUri = X509Utils.GetApplicationUriFromCertificate(certificate); if (String.IsNullOrEmpty(applicationUri)) { string message = "The Application URI could not be read from the certificate. Use certificate anyway?"; if (!await ApproveMessage(message, silent).ConfigureAwait(false)) { return(false); } } else if (!configuration.ApplicationUri.Equals(applicationUri, StringComparison.InvariantCulture)) { Utils.LogInfo("Updated the ApplicationUri: {0} --> {1}", configuration.ApplicationUri, applicationUri); configuration.ApplicationUri = applicationUri; } Utils.LogInfo("Using the ApplicationUri: {0}", applicationUri); // update configuration. configuration.SecurityConfiguration.ApplicationCertificate.Certificate = certificate; return(true); }
public static void VerifyApplicationCert(ApplicationTestData testApp, X509Certificate2 cert, X509Certificate2 issuerCert = null) { bool signedCert = issuerCert != null; if (issuerCert == null) { issuerCert = cert; } TestContext.Out.WriteLine($"{nameof(VerifyApplicationCert)}:"); Assert.NotNull(cert); TestContext.Out.WriteLine(cert); Assert.False(cert.HasPrivateKey); Assert.True(X509Utils.CompareDistinguishedName(testApp.Subject, cert.Subject)); Assert.True(X509Utils.CompareDistinguishedName(issuerCert.Subject, cert.Issuer)); // test basic constraints X509BasicConstraintsExtension constraints = X509Extensions.FindExtension <X509BasicConstraintsExtension>(cert); Assert.NotNull(constraints); TestContext.Out.WriteLine(constraints.Format(true)); Assert.True(constraints.Critical); if (signedCert) { Assert.False(constraints.CertificateAuthority); Assert.False(constraints.HasPathLengthConstraint); } else { Assert.True(constraints.CertificateAuthority); Assert.True(constraints.HasPathLengthConstraint); Assert.AreEqual(0, constraints.PathLengthConstraint); } // key usage X509KeyUsageExtension keyUsage = X509Extensions.FindExtension <X509KeyUsageExtension>(cert); Assert.NotNull(keyUsage); TestContext.Out.WriteLine(keyUsage.Format(true)); Assert.True(keyUsage.Critical); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.CrlSign) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DataEncipherment) == X509KeyUsageFlags.DataEncipherment); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DecipherOnly) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == X509KeyUsageFlags.DigitalSignature); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.EncipherOnly) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyAgreement) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyCertSign) == (signedCert ? 0 : X509KeyUsageFlags.KeyCertSign)); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyEncipherment) == X509KeyUsageFlags.KeyEncipherment); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == X509KeyUsageFlags.NonRepudiation); // enhanced key usage X509EnhancedKeyUsageExtension enhancedKeyUsage = X509Extensions.FindExtension <X509EnhancedKeyUsageExtension>(cert); Assert.NotNull(enhancedKeyUsage); TestContext.Out.WriteLine(enhancedKeyUsage.Format(true)); Assert.True(enhancedKeyUsage.Critical); // test for authority key X509AuthorityKeyIdentifierExtension authority = X509Extensions.FindExtension <X509AuthorityKeyIdentifierExtension>(cert); Assert.NotNull(authority); TestContext.Out.WriteLine(authority.Format(true)); Assert.NotNull(authority.SerialNumber); Assert.NotNull(authority.KeyIdentifier); Assert.NotNull(authority.Issuer); if (issuerCert == null) { Assert.AreEqual(cert.SubjectName.RawData, authority.Issuer.RawData); Assert.True(X509Utils.CompareDistinguishedName(cert.SubjectName.Name, authority.Issuer.Name), $"{cert.SubjectName.Name} != {authority.Issuer.Name}"); } else { Assert.AreEqual(issuerCert.SubjectName.RawData, authority.Issuer.RawData); Assert.True(X509Utils.CompareDistinguishedName(issuerCert.SubjectName.Name, authority.Issuer.Name), $"{cert.SubjectName.Name} != {authority.Issuer.Name}"); } // verify authority key in signed cert X509SubjectKeyIdentifierExtension subjectKeyId = X509Extensions.FindExtension <X509SubjectKeyIdentifierExtension>(cert); TestContext.Out.WriteLine(subjectKeyId.Format(true)); if (signedCert) { var caCertSubjectKeyId = X509Extensions.FindExtension <X509SubjectKeyIdentifierExtension>(issuerCert); Assert.NotNull(caCertSubjectKeyId); Assert.AreEqual(caCertSubjectKeyId.SubjectKeyIdentifier, authority.KeyIdentifier); } else { Assert.AreEqual(subjectKeyId.SubjectKeyIdentifier, authority.KeyIdentifier); } Assert.AreEqual(issuerCert.GetSerialNumber(), authority.GetSerialNumber()); Assert.AreEqual(issuerCert.SerialNumber, authority.SerialNumber); X509SubjectAltNameExtension subjectAlternateName = X509Extensions.FindExtension <X509SubjectAltNameExtension>(cert); Assert.NotNull(subjectAlternateName); TestContext.Out.WriteLine(subjectAlternateName.Format(true)); Assert.False(subjectAlternateName.Critical); var domainNames = X509Utils.GetDomainsFromCertficate(cert); foreach (var domainName in testApp.DomainNames) { Assert.True(domainNames.Contains(domainName, StringComparer.OrdinalIgnoreCase)); } Assert.True(subjectAlternateName.Uris.Count == 1); var applicationUri = X509Utils.GetApplicationUriFromCertificate(cert); TestContext.Out.WriteLine("ApplicationUri: "); TestContext.Out.WriteLine(applicationUri); Assert.AreEqual(testApp.ApplicationUri, applicationUri); }
/// <summary> /// Displays the dialog. /// </summary> public async Task<bool> ShowDialog(CertificateIdentifier certificate) { m_certificate = certificate; CertificateStoreCTRL.StoreType = null; CertificateStoreCTRL.StorePath = null; CertificateStoreCTRL.ReadOnly = true; ApplicationNameTB.Text = null; ApplicationUriTB.Text = null; OrganizationTB.Text = null; DomainsTB.Text = System.Net.Dns.GetHostName(); SubjectNameTB.Text = null; IssuerNameTB.Text = null; ValidFromTB.Text = null; ValidToTB.Text = null; ThumbprintTB.Text = null; if (certificate != null) { CertificateStoreCTRL.StoreType = certificate.StoreType; CertificateStoreCTRL.StorePath = certificate.StorePath; SubjectNameTB.Text = certificate.SubjectName; ThumbprintTB.Text = certificate.Thumbprint; X509Certificate2 data = await certificate.Find(); if (data != null) { // fill in subject name. StringBuilder buffer = new StringBuilder(); foreach (string element in X509Utils.ParseDistinguishedName(data.Subject)) { if (element.StartsWith("CN=")) { ApplicationNameTB.Text = element.Substring(3); } if (element.StartsWith("O=")) { OrganizationTB.Text = element.Substring(2); } if (buffer.Length > 0) { buffer.Append('/'); } buffer.Append(element); } if (buffer.Length > 0) { SubjectNameTB.Text = buffer.ToString(); } // fill in issuer name. buffer = new StringBuilder(); foreach (string element in X509Utils.ParseDistinguishedName(data.Issuer)) { if (buffer.Length > 0) { buffer.Append('/'); } buffer.Append(element); } if (buffer.Length > 0) { IssuerNameTB.Text = buffer.ToString(); } // fill in application uri. string applicationUri = X509Utils.GetApplicationUriFromCertificate(data); if (!String.IsNullOrEmpty(applicationUri)) { ApplicationUriTB.Text = applicationUri; } // fill in domains. buffer = new StringBuilder(); foreach (string domain in X509Utils.GetDomainsFromCertficate(data)) { if (buffer.Length > 0) { buffer.Append(", "); } buffer.Append(domain); } if (buffer.Length > 0) { DomainsTB.Text = buffer.ToString(); } ValidFromTB.Text = data.NotBefore.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); ValidToTB.Text = data.NotAfter.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); ThumbprintTB.Text = data.Thumbprint; } } if (ShowDialog() != DialogResult.OK) { return false; } return true; }
private async Task <Session> ConsoleSampleClient() { var application = new ApplicationInstance { ApplicationType = ApplicationType.Client }; #region Create an Application Configuration Console.WriteLine(" 1 - Create an Application Configuration."); ExitCode = ExitCode.ErrorCreateApplication; // Load the Application Configuration and use the specified config section "Technosoftware.ModelDesignClient" var config = await application.LoadConfigurationAsync("Technosoftware.ModelDesignClient"); // check the application certificate. var haveAppCertificate = await application.CheckApplicationInstanceCertificateAsync(false, CertificateFactory.DefaultKeySize, CertificateFactory.DefaultLifeTime); if (haveAppCertificate) { config.ApplicationUri = X509Utils.GetApplicationUriFromCertificate(config.SecurityConfiguration.ApplicationCertificate.Certificate); if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates) { autoAccept_ = true; } config.CertificateValidator.CertificateValidation += OnCertificateValidation; } else { Console.WriteLine(" WARN: missing application certificate, using unsecured connection."); } #endregion #region Discover endpoints Console.WriteLine(" 2 - Discover endpoints of {0}.", endpointUrl_); ExitCode = ExitCode.ErrorDiscoverEndpoints; var selectedEndpoint = Discover.SelectEndpoint(endpointUrl_, haveAppCertificate, 15000); Console.WriteLine(" Selected endpoint uses: {0}", selectedEndpoint.SecurityPolicyUri.Substring(selectedEndpoint.SecurityPolicyUri.LastIndexOf('#') + 1)); #endregion #region Create a session with OPC UA server Console.WriteLine(" 3 - Create a session with OPC UA server."); ExitCode = ExitCode.ErrorCreateSession; // create the user identity UserIdentity userIdentity; if (String.IsNullOrEmpty(Username) && String.IsNullOrEmpty(Password)) { userIdentity = new UserIdentity(new AnonymousIdentityToken()); } else { userIdentity = new UserIdentity(Username, Password); } // create worker session session_ = await CreateSessionAsync(config, selectedEndpoint, userIdentity).ConfigureAwait(false); // register keep alive handler session_.SessionKeepAliveEvent += OnSessionKeepAliveEvent; #endregion #region Browse the OPC UA Server Console.WriteLine(" 4 - Browse address space."); // Create the browser var browser = new Browser(session_) { BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences, IncludeSubtypes = true, NodeClassMask = 0, ContinueUntilDone = false }; // Browse from the RootFolder var references = browser.Browse(Objects.ObjectsFolder); GetElements(session_, browser, 0, references, Verbose); #endregion #region Read a single value Console.WriteLine(" 5 - Read a single value."); var simulatedDataValue = session_.ReadValue(machine1LevelNodeId_); Console.WriteLine("Measurement Value:" + simulatedDataValue.Value); #endregion #region Create a subscription with publishing interval of 1 second Console.WriteLine(" 6 - Create a subscription with publishing interval of 1 second."); ExitCode = ExitCode.ErrorCreateSubscription; subscription_ = new Subscription(session_.DefaultSubscription) { PublishingInterval = 1000 }; #endregion #region Add all dynamic values and the server time to the subscription Console.WriteLine(" 7 - Add the server time to the subscription."); ExitCode = ExitCode.ErrorMonitoredItem; var list = new List <MonitoredItem> { new MonitoredItem(subscription_.DefaultItem) { DisplayName = "ServerStatusCurrentTime", StartNodeId = "i=" + Variables.Server_ServerStatus_CurrentTime } }; list.ForEach(i => i.MonitoredItemNotificationEvent += OnNotification); subscription_.AddItems(list); #endregion #region Add the subscription to the session Console.WriteLine(" 8 - Add the subscription to the session."); ExitCode = ExitCode.ErrorAddSubscription; session_.AddSubscription(subscription_); subscription_.Create(); #endregion #region Running...Press Ctrl-C to exit... Console.WriteLine(" 9 - Running...Press Ctrl-C to exit..."); ExitCode = ExitCode.ErrorRunning; #endregion return(session_); }
private async Task <Session> ConsoleSampleClient() { Console.WriteLine("1 - Create an Application Configuration."); ExitCode = ExitCode.ErrorCreateApplication; ApplicationInstance application = new ApplicationInstance { ApplicationName = "UA Core Complex Client", ApplicationType = ApplicationType.Client, ConfigSectionName = "Opc.Ua.ComplexClient" }; // load the application configuration. ApplicationConfiguration config = await application.LoadApplicationConfiguration(false).ConfigureAwait(false); // check the application certificate. bool haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0).ConfigureAwait(false); if (!haveAppCertificate) { throw new Exception("Application instance certificate invalid!"); } if (ReverseConnectUri != null) { // start the reverse connection manager m_reverseConnectManager = new ReverseConnectManager(); m_reverseConnectManager.AddEndpoint(ReverseConnectUri); m_reverseConnectManager.StartService(config); } if (haveAppCertificate) { config.ApplicationUri = X509Utils.GetApplicationUriFromCertificate(config.SecurityConfiguration.ApplicationCertificate.Certificate); if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates) { m_autoAccept = true; } config.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_CertificateValidation); } else { Console.WriteLine(" WARN: missing application certificate, using unsecure connection."); } Console.WriteLine("2 - Discover endpoints of {0}.", m_endpointURL); ExitCode = ExitCode.ErrorDiscoverEndpoints; EndpointDescription selectedEndpoint; if (m_reverseConnectManager == null) { selectedEndpoint = CoreClientUtils.SelectEndpoint(m_endpointURL, haveAppCertificate && !SecurityNone, 15000); } else { Console.WriteLine(" Waiting for reverse connection."); ITransportWaitingConnection connection = await m_reverseConnectManager.WaitForConnection( new Uri(m_endpointURL), null, new CancellationTokenSource(60000).Token); if (connection == null) { throw new ServiceResultException(StatusCodes.BadTimeout, "Waiting for a reverse connection timed out."); } selectedEndpoint = CoreClientUtils.SelectEndpoint(config, connection, haveAppCertificate && !SecurityNone, 15000); } Console.WriteLine(" Selected endpoint uses: {0}", selectedEndpoint.SecurityPolicyUri.Substring(selectedEndpoint.SecurityPolicyUri.LastIndexOf('#') + 1)); Console.WriteLine("3 - Create a session with OPC UA server."); ExitCode = ExitCode.ErrorCreateSession; // create the user identity UserIdentity userIdentity; if (String.IsNullOrEmpty(Username) && String.IsNullOrEmpty(Password)) { userIdentity = new UserIdentity(new AnonymousIdentityToken()); } else { userIdentity = new UserIdentity(Username, Password); } // create worker session if (m_reverseConnectManager == null) { m_session = await CreateSession(config, selectedEndpoint, userIdentity).ConfigureAwait(false); } else { Console.WriteLine(" Waiting for reverse connection."); ITransportWaitingConnection connection = await m_reverseConnectManager.WaitForConnection( new Uri(m_endpointURL), null, new CancellationTokenSource(60000).Token).ConfigureAwait(false); if (connection == null) { throw new ServiceResultException(StatusCodes.BadTimeout, "Waiting for a reverse connection timed out."); } m_session = await CreateSession(config, connection, selectedEndpoint, userIdentity).ConfigureAwait(false); } // register keep alive handler m_session.KeepAlive += Client_KeepAlive; Console.WriteLine("4 - Browse for all custom type variables."); ExitCode = ExitCode.ErrorReadComplexTypes; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); var allVariableNodes = BrowseAdddressSpace ? BrowseAllVariables() : new List <INode>(); var allCustomTypeVariables = allVariableNodes.Where(n => ((VariableNode)n).DataType.NamespaceIndex != 0).ToList(); stopWatch.Stop(); Console.WriteLine($" -- Browse all nodes took {stopWatch.ElapsedMilliseconds}ms."); Console.WriteLine($" -- Browsed {allVariableNodes.Count} nodes, from which {allCustomTypeVariables.Count} are custom type variables."); stopWatch.Reset(); // for testing clear the nodecache m_session.NodeCache.Clear(); stopWatch.Start(); if (LoadTypeSystem) { Console.WriteLine("5 - Load the server type dictionary."); ExitCode = ExitCode.ErrorLoadTypeDictionary; stopWatch.Reset(); stopWatch.Start(); var complexTypeSystem = new ComplexTypeSystem(m_session); await complexTypeSystem.Load().ConfigureAwait(false); stopWatch.Stop(); Console.WriteLine($"Load type system took {stopWatch.ElapsedMilliseconds}ms."); Console.WriteLine($"Custom types defined for this session:"); foreach (var type in complexTypeSystem.GetDefinedTypes()) { Console.WriteLine($"{type.Namespace}.{type.Name}"); } Console.WriteLine($"Loaded {m_session.DataTypeSystem.Count} dictionaries:"); foreach (var dictionary in m_session.DataTypeSystem) { Console.WriteLine($" + {dictionary.Value.Name}"); foreach (var type in dictionary.Value.DataTypes) { Console.WriteLine($" -- {type.Key}:{type.Value}"); } } } else { Console.WriteLine("4 - Not loading the server type dictionary."); } foreach (VariableNode variableNode in allCustomTypeVariables) { try { var value = m_session.ReadValue(variableNode.NodeId); CastInt32ToEnum(variableNode, value); Console.WriteLine($" -- {variableNode}:{value}"); if (value.Value is ExtensionObject extensionObject) { if (extensionObject.Body is BaseComplexType complexType) { foreach (var item in complexType.GetPropertyEnumerator()) { if (Verbose) { Console.WriteLine($" -- -- {item.Name}:{complexType[item.Name]}"); } if (WriteComplexInt && item.PropertyType == typeof(Int32)) { var data = complexType[item.Name]; if (data != null) { complexType[item.Name] = (Int32)data + 1; } Console.WriteLine($" -- -- Increment: {item.Name}, {complexType[item.Name]}"); WriteValue(m_session, variableNode.NodeId, value); } } } } if (PrintAsJson) { PrintValueAsJson(variableNode.BrowseName.Name, value); } } catch (ServiceResultException sre) { if (sre.StatusCode == StatusCodes.BadUserAccessDenied) { Console.WriteLine($" -- {variableNode}: Access denied!"); } } } Console.WriteLine("6 - Create test sessions which load only single types as needed."); if (LoadTypeSystem) { foreach (VariableNode variableNode in allCustomTypeVariables) { Session testSession = null; try { Console.WriteLine($"Open session for {variableNode}:"); testSession = await CreateSession(config, selectedEndpoint, userIdentity).ConfigureAwait(false); var complexTypeSystem = new ComplexTypeSystem(testSession); NodeId dataType = variableNode.DataType; Type nullType = testSession.Factory.GetSystemType(dataType); var valueBefore = testSession.ReadValue(variableNode.NodeId); Console.WriteLine($" -- {valueBefore}"); Type systemType = await complexTypeSystem.LoadType(dataType).ConfigureAwait(false); var valueAfter = testSession.ReadValue(variableNode.NodeId); Console.WriteLine($" -- {variableNode}: {systemType} {dataType}"); Console.WriteLine($" -- {valueAfter}"); Console.WriteLine($"Custom types defined for {variableNode}:"); foreach (var type in complexTypeSystem.GetDefinedTypes()) { Console.WriteLine($" -- {type.Namespace}.{type.Name}"); } } catch (ServiceResultException sre) { if (sre.StatusCode == StatusCodes.BadUserAccessDenied) { Console.WriteLine($" -- {variableNode}: Access denied!"); } } finally { testSession?.Close(); } } } else { Console.WriteLine("6 - Not testing to load individual types."); } Console.WriteLine("7 - Create a subscription with publishing interval of 1 second."); ExitCode = ExitCode.ErrorCreateSubscription; var subscription = new Subscription(m_session.DefaultSubscription) { PublishingInterval = 1000 }; Console.WriteLine("8 - Add all custom values and the server time to the subscription."); ExitCode = ExitCode.ErrorMonitoredItem; var list = new List <MonitoredItem> { new MonitoredItem(subscription.DefaultItem) { DisplayName = "ServerStatusCurrentTime", StartNodeId = "i=" + Variables.Server_ServerStatus_CurrentTime.ToString() } }; list.ForEach(i => i.Notification += OnNotification); foreach (var customVariable in allCustomTypeVariables) { var newItem = new MonitoredItem(subscription.DefaultItem) { DisplayName = customVariable.DisplayName.Text, StartNodeId = ExpandedNodeId.ToNodeId(customVariable.NodeId, m_session.NamespaceUris) }; newItem.Notification += OnComplexTypeNotification; list.Add(newItem); } subscription.AddItems(list); Console.WriteLine("9 - Add the subscription to the session."); ExitCode = ExitCode.ErrorAddSubscription; m_session.AddSubscription(subscription); subscription.Create(); Console.WriteLine("10 - Running...Press Ctrl-C to exit..."); ExitCode = ExitCode.ErrorRunning; return(m_session); }
/// <summary> /// Updates an item in the view. /// </summary> protected override void UpdateItem(ListViewItem listItem, object item) { X509Certificate2 certificate = item as X509Certificate2; if (certificate == null) { base.UpdateItem(listItem, item); return; } listItem.SubItems[0].Text = null; listItem.SubItems[1].Text = null; listItem.SubItems[2].Text = null; listItem.SubItems[3].Text = null; listItem.SubItems[4].Text = null; listItem.SubItems[5].Text = null; if (certificate != null) { List <string> fields = X509Utils.ParseDistinguishedName(certificate.Subject); for (int ii = 0; ii < fields.Count; ii++) { if (fields[ii].StartsWith("CN=")) { listItem.SubItems[0].Text = fields[ii].Substring(3); } if (fields[ii].StartsWith("DC=")) { listItem.SubItems[1].Text = fields[ii].Substring(3); } } if (String.IsNullOrEmpty(listItem.SubItems[0].Text)) { listItem.SubItems[0].Text = String.Format("{0}", certificate.Subject); } // determine certificate type. foreach (X509Extension extension in certificate.Extensions) { X509BasicConstraintsExtension basicContraints = extension as X509BasicConstraintsExtension; if (basicContraints != null) { if (basicContraints.CertificateAuthority) { listItem.SubItems[1].Text = "CA"; } else { listItem.SubItems[1].Text = "End-Entity"; } break; } } // check if a private key is available. if (certificate.HasPrivateKey) { listItem.SubItems[2].Text = "Yes"; } else { listItem.SubItems[2].Text = "No"; } // look up domains. IList <string> domains = X509Utils.GetDomainsFromCertficate(certificate); StringBuilder buffer = new StringBuilder(); for (int ii = 0; ii < domains.Count; ii++) { if (buffer.Length > 0) { buffer.Append(";"); } buffer.Append(domains[ii]); } listItem.SubItems[3].Text = buffer.ToString(); listItem.SubItems[4].Text = X509Utils.GetApplicationUriFromCertificate(certificate); listItem.SubItems[5].Text = String.Format("{0:yyyy-MM-dd}", certificate.NotAfter); } listItem.ImageKey = GuiUtils.Icons.Certificate; listItem.Tag = item; }
/// <summary> /// Connects to the OPC server asynchronously. /// </summary> public async Task <bool> ConnectAsync(OpcConnectionOptions connectionOptions, int operationTimeout = -1) { ApplicationInstance application = new ApplicationInstance { ApplicationName = string.Format("DrvOpcUa_{0} Driver", deviceNumStr), ApplicationType = ApplicationType.Client, ConfigSectionName = "Scada.Comm.Drivers.DrvOpcUa" }; // load the application configuration // TODO: use stream instead of file after updating OPCFoundation.NetStandard.Opc.Ua WriteConfigFile(out string configFileName); ApplicationConfiguration config = await application.LoadApplicationConfiguration(configFileName, false); // check the application certificate bool haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0); if (!haveAppCertificate) { throw new ScadaException(Locale.IsRussian ? "Сертификат экземпляра приложения недействителен!" : "Application instance certificate invalid!"); } if (haveAppCertificate) { config.ApplicationUri = X509Utils.GetApplicationUriFromCertificate( config.SecurityConfiguration.ApplicationCertificate.Certificate); if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates) { AutoAccept = true; } config.CertificateValidator.CertificateValidation += CertificateValidator_CertificateValidation; } else { log.WriteLine(Locale.IsRussian ? "Предупреждение: отсутствует сертификат приложения, используется незащищенное соединение." : "Warning: missing application certificate, using unsecure connection."); } // create session EndpointDescription selectedEndpoint = operationTimeout > 0 ? CoreClientUtils.SelectEndpoint(connectionOptions.ServerUrl, haveAppCertificate, operationTimeout) : CoreClientUtils.SelectEndpoint(connectionOptions.ServerUrl, haveAppCertificate); selectedEndpoint.SecurityMode = connectionOptions.SecurityMode; selectedEndpoint.SecurityPolicyUri = connectionOptions.GetSecurityPolicy(); EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(config); ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, selectedEndpoint, endpointConfiguration); UserIdentity userIdentity = connectionOptions.AuthenticationMode == AuthenticationMode.Username ? new UserIdentity(connectionOptions.Username, connectionOptions.Password) : new UserIdentity(new AnonymousIdentityToken()); OpcSession = await Session.Create(config, endpoint, false, "Rapid SCADA DrvOpcUa_" + deviceNumStr, (uint)config.ClientConfiguration.DefaultSessionTimeout, userIdentity, null); log.WriteLine(Locale.IsRussian ? "OPC сессия успешно создана: {0}" : "OPC session created successfully: {0}", connectionOptions.ServerUrl); return(true); }
private async Task <Session> ConsoleSampleClient() { var application = new ApplicationInstance { ApplicationType = ApplicationType.Client }; #region Create an Application Configuration Console.WriteLine(" 1 - Create an Application Configuration."); ExitCode = ExitCode.ErrorCreateApplication; // Load the Application Configuration and use the specified config section "Technosoftware.SimpleClient" var config = await application.LoadConfigurationAsync("Technosoftware.SimpleClient"); // check the application certificate. var haveAppCertificate = await application.CheckApplicationInstanceCertificateAsync(false, CertificateFactory.DefaultKeySize, CertificateFactory.DefaultLifeTime); reverseConnectManager_ = null; if (ReverseConnectUri != null) { // start the reverse connection manager reverseConnectManager_ = new ReverseConnectManager(); reverseConnectManager_.AddEndpoint(ReverseConnectUri); reverseConnectManager_.StartService(config); } if (haveAppCertificate) { config.ApplicationUri = X509Utils.GetApplicationUriFromCertificate(config.SecurityConfiguration.ApplicationCertificate.Certificate); if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates) { autoAccept_ = true; } config.CertificateValidator.CertificateValidation += OnCertificateValidation; } else { Console.WriteLine(" WARN: missing application certificate, using unsecured connection."); } #endregion #region Discover endpoints Console.WriteLine(" 2 - Discover endpoints of {0}.", endpointUrl_); ExitCode = ExitCode.ErrorDiscoverEndpoints; EndpointDescription selectedEndpoint; if (reverseConnectManager_ == null) { selectedEndpoint = Discover.SelectEndpoint(endpointUrl_, haveAppCertificate && !SecurityNone, 15000); } else { Console.WriteLine(" Waiting for reverse connection."); var connection = await reverseConnectManager_.WaitForConnection( new Uri(endpointUrl_), null, new CancellationTokenSource(60000).Token); if (connection == null) { throw new ServiceResultException(StatusCodes.BadTimeout, "Waiting for a reverse connection timed out."); } selectedEndpoint = Discover.SelectEndpoint(config, connection, haveAppCertificate && !SecurityNone, 15000); } Console.WriteLine(" Selected endpoint uses: {0}", selectedEndpoint.SecurityPolicyUri.Substring(selectedEndpoint.SecurityPolicyUri.LastIndexOf('#') + 1)); #endregion #region Create a session with OPC UA server Console.WriteLine(" 3 - Create a session with OPC UA server."); ExitCode = ExitCode.ErrorCreateSession; // create the user identity UserIdentity userIdentity; if (String.IsNullOrEmpty(Username) && String.IsNullOrEmpty(Password)) { userIdentity = new UserIdentity(new AnonymousIdentityToken()); } else { userIdentity = new UserIdentity(Username, Password); } // create worker session if (reverseConnectManager_ == null) { session_ = await CreateSessionAsync(config, selectedEndpoint, userIdentity).ConfigureAwait(false); } else { Console.WriteLine(" Waiting for reverse connection."); // Define the cancellation token. var source = new CancellationTokenSource(60000); var token = source.Token; try { var connection = await reverseConnectManager_.WaitForConnection( new Uri(endpointUrl_), null, token); if (connection == null) { throw new ServiceResultException(StatusCodes.BadTimeout, "Waiting for a reverse connection timed out."); } session_ = await CreateSessionAsync(config, connection, selectedEndpoint, userIdentity) .ConfigureAwait(false); } finally { source.Dispose(); } } // register keep alive handler session_.SessionKeepAliveEvent += OnSessionKeepAliveEvent; #endregion #region Browse the OPC UA Server Console.WriteLine(" 4 - Browse address space."); // Create the browser var browser = new Browser(session_) { BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences, IncludeSubtypes = true, NodeClassMask = 0, ContinueUntilDone = false }; // Browse from the RootFolder var references = browser.Browse(Objects.ObjectsFolder); GetElements(session_, browser, 0, references, Verbose); #endregion #region Read a single value Console.WriteLine(" 5 - Read a single value."); var simulatedDataValue = session_.ReadValue(simulatedDataNodeId_); Console.WriteLine("Node Value:" + simulatedDataValue.Value); #endregion #region Read multiple values Console.WriteLine(" 6 - Read multiple values."); // The input parameters of the ReadValues() method var variableIds = new List <NodeId>(); var expectedTypes = new List <Type>(); // Add a node to the list variableIds.Add(simulatedDataNodeId_); // Add an expected type to the list (null means we get the original type from the server) expectedTypes.Add(null); // Add another node to the list variableIds.Add(staticDataNodeId1_); // Add an expected type to the list (null means we get the original type from the server) expectedTypes.Add(null); // Add another node to the list variableIds.Add(staticDataNodeId2_); // Add an expected type to the list (null means we get the original type from the server) expectedTypes.Add(null); session_.ReadValues(variableIds, expectedTypes, out var values, out var errors); // write the result to the console. for (var i = 0; i < values.Count; i++) { Console.WriteLine("Status of Read of Node {0} is: {1}", variableIds[i].ToString(), errors[i]); } for (var i = 0; i < values.Count; i++) { Console.WriteLine("Value of Read of Node {0} is: Value: {1}", variableIds[i].ToString(), values[i]); } #endregion #region Read multiple values asynchronous Console.WriteLine(" 7 - Read multiple values asynchronous."); // start reading the value (setting a 10 second timeout). session_.BeginReadValues( variableIds, 0, TimestampsToReturn.Both, OnReadComplete, new UserData { Session = session_, NodeIds = variableIds }); #endregion #region Write a value Console.WriteLine(" 8 - Write a value."); short writeInt = 1234; Console.WriteLine("Write Value: " + writeInt); session_.WriteValue(staticDataNodeId1_, new DataValue(writeInt)); // read it again to check the new value Console.WriteLine("Node Value (should be {0}): {1}", session_.ReadValue(staticDataNodeId1_).Value, writeInt); #endregion #region Write multiple values at once Console.WriteLine(" 9 - Write multiple values at once."); writeInt = 5678; var writeDouble = 1234.1234; var nodeIds = new List <NodeId>(); var dataValues = new List <DataValue>(); nodeIds.Add(staticDataNodeId1_); nodeIds.Add(staticDataNodeId2_); dataValues.Add(new DataValue(writeInt)); dataValues.Add(new DataValue(writeDouble)); Console.WriteLine("Write Values: {0} and {1}", writeInt, writeDouble); var statusCodes = session_.WriteValues(nodeIds, dataValues); Console.WriteLine("Returned status codes:"); foreach (var statusCode in statusCodes) { Console.WriteLine("Status: {0}", statusCode.ToString()); } // read it again to check the new value Console.WriteLine("Node Value (should be {0}): {1}", session_.ReadValue(staticDataNodeId1_).Value, writeInt); Console.WriteLine("Node Value (should be {0}): {1}", session_.ReadValue(staticDataNodeId2_).Value, writeDouble); #endregion #region Write multiple values asynchronous Console.WriteLine("10 - Write multiple values asynchronous."); // start writing the values. session_.BeginWriteValues( nodeIds, dataValues, OnWriteComplete, new UserData { Session = session_, NodeIds = nodeIds }); #endregion #region Call a Method Console.WriteLine("11 - Call a Method."); INode node = session_.ReadNode(callHelloMethodNodeId_); if (node is MethodNode) { var methodId = callHelloMethodNodeId_; var objectId = methodsNodeId_; var inputArguments = new VariantCollection { new Variant("from Technosoftware") }; var request = new CallMethodRequest { ObjectId = objectId, MethodId = methodId, InputArguments = inputArguments }; var requests = new CallMethodRequestCollection { request }; var responseHeader = session_.Call( null, requests, out var results, out var diagnosticInfos); if (StatusCode.IsBad(results[0].StatusCode)) { throw new ServiceResultException(new ServiceResult(results[0].StatusCode, 0, diagnosticInfos, responseHeader.StringTable)); } Console.WriteLine("{0}", results[0].OutputArguments[0]); } #endregion #region Create a subscription with publishing interval of 1 second Console.WriteLine("12 - Create a subscription with publishing interval of 1 second."); ExitCode = ExitCode.ErrorCreateSubscription; subscription_ = new Subscription(session_.DefaultSubscription) { PublishingInterval = 1000 }; #endregion #region Add all dynamic values and the server time to the subscription Console.WriteLine("13 - Add all dynamic values and the server time to the subscription."); ExitCode = ExitCode.ErrorMonitoredItem; var list = new List <MonitoredItem> { new MonitoredItem(subscription_.DefaultItem) { DisplayName = "ServerStatusCurrentTime", StartNodeId = "i=" + Variables.Server_ServerStatus_CurrentTime } }; list.ForEach(i => i.MonitoredItemNotificationEvent += OnNotification); var newItem = new MonitoredItem(subscription_.DefaultItem) { DisplayName = "Simulated Data Value", StartNodeId = new NodeId(simulatedDataNodeId_) }; newItem.MonitoredItemNotificationEvent += OnMonitoredItemNotificationEvent; list.Add(newItem); subscription_.AddItems(list); #endregion #region Add the subscription to the session Console.WriteLine("14 - Add the subscription to the session."); ExitCode = ExitCode.ErrorAddSubscription; session_.AddSubscription(subscription_); subscription_.Create(); #endregion #region Running...Press Ctrl-C to exit... Console.WriteLine("15 - Running...Press Ctrl-C to exit..."); ExitCode = ExitCode.ErrorRunning; #endregion return(session_); }