C# / .NET · recipe
Read historical data in C#
Use HistoryRead with a ReadRawModifiedDetails and bound the window. Check the server claims a historical facet first, and ask for aggregates when a shift summary is what you actually want.
| Stack | OPCFoundation/UA-.NETStandard |
|---|---|
| Version | 1.5.378.156 stable, 2.0.0-preview.2 |
The code
var details = new ReadRawModifiedDetails
{
StartTime = DateTime.UtcNow.AddMinutes(-10),
EndTime = DateTime.UtcNow,
NumValuesPerNode = 5, // always bound the request
IsReadModified = false,
ReturnBounds = true,
};
var nodesToRead = new HistoryReadValueIdCollection
{
new HistoryReadValueId { NodeId = new NodeId("Dynamic/RandomDouble", (ushort)nsIndex) },
};
session.HistoryRead(null, new ExtensionObject(details), TimestampsToReturn.Both,
releaseContinuationPoints: false, nodesToRead,
out HistoryReadResultCollection results, out _);
foreach (var result in results)
{
if (StatusCode.IsBad(result.StatusCode))
{
Console.WriteLine($"history read failed: {result.StatusCode}");
continue;
}
var data = ExtensionObject.ToEncodeable(result.HistoryData) as HistoryData;
foreach (var dv in data.DataValues)
Console.WriteLine($"{dv.SourceTimestamp:O} {dv.Value} [{dv.StatusCode}]");
}
What it prints
2026-09-08T03:35:00.0010000Z 41.2 [Good]
2026-09-08T03:36:00.0020000Z 43.8 [Good]
2026-09-08T03:37:00.0010000Z 39.1 [Good]
2026-09-08T03:38:00.0030000Z 44.6 [Good]
2026-09-08T03:39:00.0010000Z 42.0 [Good]
Notes
- Set NumValuesPerNode or a short window. An unbounded read against a production historian is an incident waiting to happen.
- Release continuation points you abandon, or you will exhaust the server's supply.
- For OEE, use ReadProcessedDetails with an aggregate such as TimeAverage or PercentGood instead of pulling raw values. Server-side aggregation is far cheaper.
- ReturnBounds gives you the values either side of your window, which you need to interpolate state at the boundary correctly.
What breaks first
The history read returns a bad status for the node
Check ServerProfileArray for a historical access facet. If it is absent, collect via subscription and store the data yourself.
BadHistoryOperationUnsupportedCheck ServerProfileArray for a historical access facet. If it is absent, collect via subscription and store the data yourself.
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.