如何将OPC客户端接收的输出参数二进制数据转换为服务器定义数据类型
Hey there! Let's sort out that custom data type conversion problem you're hitting with your OPC UA client. You’ve already crushed the connection setup, method calls, and basic data fetching—nice work getting to this stage!
Understanding the Problem
You’ve successfully called the server method and got back outputArguments, where the 2nd item holds data that needs converting to a custom type defined on the server (NodeId: ns=2;i=15205). OPC UA uses ExtensionObject to transport custom structured types, so the key here is decoding that object using the server’s type definition.
Step-by-Step Solution
Here’s how to convert that output data properly, using the Unified Automation client library you’re working with:
Keep the Session Connected (for now)
First, adjust your code order: don’t callAppSession.Disconnect()right after the method call. You’ll need an active session to fetch the type definition and decode the data.Extract the Target Variant from Output Arguments
Grab the 2nd element (index 1, since lists are 0-indexed) from youroutputArgumentslist:// Get the target data from output arguments Variant targetDataVariant = outputArguments[1];Check for ExtensionObject (the usual carrier for custom types)
Custom structured types in OPC UA are typically wrapped in anExtensionObject. Validate this and extract it:if (targetDataVariant.Value is ExtensionObject customTypeExtension) { // Proceed with conversion here }Fetch the Server’s Type Definition
Use the NodeId of the custom type (ns=2;i=15205) to retrieve its structure definition from the server. TheNodeCachein your session can help with this:NodeId customTypeId = NodeId.Parse("ns=2;i=15205"); StructureDefinition customTypeDefinition = AppSession.NodeCache.GetStructureDefinition(customTypeId);Decode the ExtensionObject to a .NET Object
Use the session’s message context and the type definition to decode the extension object into a usable .NET instance:object convertedCustomData = customTypeExtension.Decode(customTypeDefinition, AppSession.MessageContext);(Optional) Strongly Type the Result
If you have a .NET class that matches the server’s custom type (you can generate this using tools like Unified Automation’s UaModeler by importing the server’s address space), you can cast the result directly:// Replace MyServerCustomType with your actual generated class name MyServerCustomType typedResult = (MyServerCustomType)convertedCustomData;Disconnect the Session (after processing)
Once you’ve converted and used the data, you can safely disconnect the session:AppSession.Disconnect();
Full Updated Code Snippet
Putting it all together with your existing code:
public void Connect(string endpointUrl) { AppSession.UserIdentity = new UserIdentity(); AppSession.SessionName = "urn:ACGIDT053:UnifiedAutomation:UaExpert"; AppSession.Connect(endpointUrl, SecuritySelection.None); ICertificate certificateServer = SecurityUtils.LoadCertificate(AppSession.EndpointDescription.ServerCertificate); AppSession.Application.TrustedStore.Add(certificateServer, true); // Step 1: Prepare method call NodeId objectId = NodeId.Parse("ns=2;i=15108"); NodeId methodId = NodeId.Parse("ns=2;i=15057"); List<ExtensionObject> ar = new List<ExtensionObject>(); List<Variant> inputArguments = new List<Variant> { new Variant(string.Empty, TypeInfo.Scalars.String), new Variant((UInt32)1, TypeInfo.Scalars.UInt32), new Variant(string.Empty, TypeInfo.Scalars.String), new Variant(ar.ToArray(), TypeInfo.Arrays.ExtensionObject), new Variant(string.Empty, TypeInfo.Scalars.String) }; // Step 2: Call the method List<StatusCode> inputArgumentErrors; List<Variant> outputArguments = null; StatusCode error = AppSession.Call( objectId, methodId, inputArguments, out inputArgumentErrors, out outputArguments); // Step 3: Convert the custom data type if (outputArguments != null && outputArguments.Count > 1) { Variant targetDataVariant = outputArguments[1]; if (targetDataVariant.Value is ExtensionObject customTypeExtension) { NodeId customTypeId = NodeId.Parse("ns=2;i=15205"); StructureDefinition customTypeDefinition = AppSession.NodeCache.GetStructureDefinition(customTypeId); object convertedData = customTypeExtension.Decode(customTypeDefinition, AppSession.MessageContext); // Use convertedData as needed, or cast to your generated class // MyServerCustomType result = (MyServerCustomType)convertedData; } } // Step 4: Disconnect after processing AppSession.Disconnect(); }
Key Notes
- Generate Strongly Typed Classes: Using a tool like UaModeler to generate .NET classes from the server’s address space will make working with custom types much smoother—no manual decoding needed beyond casting.
- Session Lifecycle: Always ensure the session is active when fetching type definitions or decoding extension objects; disconnect only after you’ve processed all necessary data.
内容的提问来源于stack exchange,提问作者Anurag Patil

