Skip to content

fix: emit configured mtconnect release in header.version (#127)#141

Draft
ottobolyos wants to merge 18 commits intoTrakHound:masterfrom
ottobolyos:fix/issue-127
Draft

fix: emit configured mtconnect release in header.version (#127)#141
ottobolyos wants to merge 18 commits intoTrakHound:masterfrom
ottobolyos:fix/issue-127

Conversation

@ottobolyos
Copy link
Copy Markdown

@ottobolyos ottobolyos commented Apr 25, 2026

Summary

Fixes #127Header.version emitted the library assembly version (6.9.0.0) instead of the configured MTConnect Standard release.

  • Route the configured MTConnect release (MTConnectAgent.MTConnectVersion) into Header.Version for every envelope produced by MTConnectAgentBroker (Devices, Streams, Assets, Error). A new private FormatHeaderVersion helper emits the four-segment shape (e.g. 2.5.0.0) so the value round-trips with the cppagent reference.
  • Cache the formatted Header.Version per release so repeated envelope construction does not re-format the same MTConnectVersions constant.
  • Drop the six redundant header.Version = Version.ToString() overwrites in the response-document construction methods now that the four header builders carry the correct value.
  • Add an optional Version mtconnectVersion parameter to the previously-parameterless GetErrorHeader so the two GetErrorResponseDocument overloads route the configured release through the Error envelope as well.
  • Use C# 7.3-compatible syntax in the broker so the file compiles on the legacy TFMs (netstandard2.0 / net48).
  • Keep MTConnectAgent.Version (library assembly version) as a legitimate diagnostic surface; public API unchanged.
  • Add NUnit regression coverage pinning the new behavior across every MTConnectVersions constant for Devices / Assets / Error envelope kinds plus the explicit-version override, a repo-wide guard that rejects any wire-format envelope containing the library assembly version, and XML round-trip cases asserting the wire shape via XmlDevicesResponseDocument.ToXmlStream.

Routes MTConnectAgent.MTConnectVersion (the configured MTConnect
Standard release the agent serves) into Header.Version for every
response envelope produced by MTConnectAgentBroker — Devices,
Streams, Assets, Error.

The four header builders previously wrote the bare `Version`
identifier, which resolves through inheritance to the
MTConnectAgent.Version library-assembly version
(`Assembly.GetExecutingAssembly().GetName().Version`). With the
current VersionPrefix=6.9.0 in Directory.Build.props, every wire
envelope emitted Header.version="6.9.0.0" regardless of the
DefaultVersion setting in AgentConfiguration.

The MTConnect Standard (Part 1.0 §3 Header) defines the
Header.version attribute as the MTConnect release the agent serves;
the cppagent reference reports it as a four-segment string
(e.g. "2.7.0.0" for v2.7). MTConnectVersions constants are
constructed with major+minor only, so the new FormatHeaderVersion
helper builds a fresh Version with build+revision padded to zero,
yielding the expected "<major>.<minor>.0.0" shape across every
supported release.

Also drops six redundant `header.Version = Version.ToString()`
overwrites in the response-document construction methods that
re-assigned the same incorrect value after the builder ran. The
GetErrorHeader signature gains an optional Version parameter so
the two GetErrorResponseDocument overloads can route the configured
release through the Error envelope as well.

MTConnectAgent.Version (the library assembly version) is unchanged
and remains a documented diagnostic surface; nothing else in the
library, agent, or adapter sources references it for wire output.

Closes TrakHound#127
The pre-existing default Agent device (MTConnect.Devices.Agent)
declares MinimumVersion = v1.7, which causes the broker's
Devices response to be null when the configured MTConnect release
is below v1.7. The matrix's explicit-version test path was
therefore reporting NullReferenceException-style failures for
v1.0 through v1.6, masking what would otherwise be a clean assertion
on Header.version for those versions.

Add a vanilla Device (MinimumVersion = v1.0) to the broker fixture
so every row of the matrix yields a populated response document.
This is a fixture correction; the production-code fix is
independent.
Adds a parametric NUnit fixture that drives a real
MTConnectAgentBroker through XmlDevicesResponseDocument.ToXmlStream
and asserts the resulting XML payload's `Header.version` attribute
equals the configured MTConnect Standard release. Pins the
wire-format end of the issue: the original defect was visible to
consumers as `version="6.9.0.0"` in the XML envelope regardless of
DefaultVersion; the new test rejects any future regression that
re-introduces that shape.

Run across every release in MTConnectVersions (15 cases today;
auto-extends as new constants land).
The previous helper relied on the Device default constructor populating
Id / Name / Uuid. Explicit construction keeps the test forward-compatible
with revisions that strip those defaults (per the XSD uuid "for entire
life" identity contract).
The parametric matrix on `HeaderVersionXmlRoundTripTests` previously
reflected over `MTConnectVersions` to enumerate every public static
`System.Version` constant. When the library declares a new version
constant whose XML namespace and schema-location mappings have not yet
been added to `libraries/MTConnect.NET-XML/Namespaces.cs` and
`Schemas.cs`, the parametric test case throws
"Cannot use a prefix with an empty namespace" on the wire emission
(the XML writer is handed a null namespace URI).

Hardcode the version set the XML library currently maps. Future
versions require matching `Namespaces.cs` / `Schemas.cs` entries
before they can be added to this list, surfacing the wire-format gap
at the test edit rather than silently throwing on serialization.
The docs/testing/issue-127/ subtree carried phase-by-phase campaign writeups that
referenced internal tooling (CONVENTIONS rule-book, internal section
numbers, extra-files.user/ paths, internal tracker terminology). Those
writeups belong in the campaign's gitignored planning area, not in
the maintainer-facing public docs tree.
MTConnectAgentBroker.FormatHeaderVersion is invoked on every Devices,
Streams, Assets and Error response and currently allocates a new
Version instance plus a fresh ToString() on each call. Add a fixture
that pins the desired contract: repeated calls (and calls with
distinct-but-equal Version instances) must return the same cached
string instance.
FormatHeaderVersion ran on every Devices/Streams/Assets/Error response
and allocated a fresh Version + ToString() each call. Memoize the
formatted four-segment string in a ConcurrentDictionary keyed on the
configured MTConnect Standard release so the hot path becomes a single
hash lookup.
The Header.version cache landed in commit 33dab49 used C# 9 features —
target-typed `new()` and `static` lambda — which only compile on
LangVersion>=9.0. MTConnect.NET-Common multi-targets net461/471/472 and
netstandard2.0 in Release where the default LangVersion is 7.3, so the
Release build failed with CS8370.

Replace `new()` with the explicit `new ConcurrentDictionary<Version, string>()`
and drop the `static` keyword from the lambda. Behaviour is identical;
the cache still keys on Version equality and the lambda is closure-free
either way.

Surfaced via `dotnet pack -c Release` from the integration branch.
The test-helper comment in HeaderVersionXmlRoundTripTests describing the
XSD uuid identity contract used the British spelling "honour"; switch to
the American "honor" so the prose lines up with the rest of the test
tree.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Header.version reports library assembly version instead of MTConnect release

1 participant