C# / .NET · recipe
Connect to an OPC UA server in C#
Build an ApplicationConfiguration, select an endpoint, then create a session. The configuration is not boilerplate you can skip: it holds your certificate stores, and a wrong path there is the usual cause of a first-connection failure.
| Stack | OPCFoundation/UA-.NETStandard |
|---|---|
| Version | 1.5.378.156 stable, 2.0.0-preview.2 |
The code
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Configuration;
// Minimal ApplicationConfiguration. In a real project this lives in a .Config.xml file.
static async Task<ApplicationConfiguration> BuildConfigAsync()
{
var config = new ApplicationConfiguration
{
ApplicationName = "MyOpcUaClient",
ApplicationUri = "urn:example:my-opcua-client", // must match the certificate SAN
ApplicationType = ApplicationType.Client,
SecurityConfiguration = new SecurityConfiguration
{
ApplicationCertificate = new CertificateIdentifier
{
StoreType = "Directory",
StorePath = "./pki/own", // persist this in a container
SubjectName = "CN=MyOpcUaClient",
},
TrustedPeerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = "./pki/trusted" },
TrustedIssuerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = "./pki/issuer" },
RejectedCertificateStore = new CertificateTrustList { StoreType = "Directory", StorePath = "./pki/rejected" },
AutoAcceptUntrustedCertificates = false, // never true in production
},
TransportConfigurations = new TransportConfigurationCollection(),
ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 },
};
await config.Validate(ApplicationType.Client);
return config;
}
static async Task Main()
{
var config = await BuildConfigAsync();
// no security for the first diagnostic connection
var endpoint = CoreClientUtils.SelectEndpoint(config, "opc.tcp://opcua.umati.app:4840", useSecurity: false);
var configured = new ConfiguredEndpoint(null, endpoint, EndpointConfiguration.Create(config));
using var session = await Session.Create(
config, configured, updateBeforeConnect: false,
sessionName: "MyOpcUaClient", sessionTimeout: 60000,
identity: new UserIdentity(new AnonymousIdentityToken()), preferredLocales: null);
Console.WriteLine($"connected: {session.Connected}");
Console.WriteLine($"endpoint : {session.ConfiguredEndpoint.EndpointUrl}");
foreach (var (uri, i) in session.NamespaceUris.ToArray().Select((u, i) => (u, i)))
Console.WriteLine($" ns={i} {uri}");
}
What it prints
connected: True
endpoint : opc.tcp://opcua.umati.app:4840
ns=0 http://opcfoundation.org/UA/
ns=1 urn:umati:sample-server
ns=2 http://opcfoundation.org/UA/DI/
ns=3 http://opcfoundation.org/UA/Machinery/
Notes
- The ApplicationUri in the configuration must match the URI entry in your certificate's SAN exactly. Mismatches here produce certificate errors that look like network errors.
- CoreClientUtils.SelectEndpoint picks the strongest endpoint matching your useSecurity flag. Pass false first to prove reachability, then true.
- Dispose the session. The using statement above does it; a leaked session holds server resources until its timeout expires.
- In production, load the configuration from a .Config.xml file rather than building it in code: it is what the tooling and the CTT expect.
What breaks first
The first secure connection is refused after the unsecured one worked
Your certificate is in the server's rejected store. Move it to trusted, and copy the server's certificate into ./pki/trusted on your side.
BadCertificateUntrustedYour certificate is in the server's rejected store. Move it to trusted, and copy the server's certificate into ./pki/trusted on your side.
Other recipes in this stack
Concepts on this page
Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.