Skip to content

Conversation

@marcschier
Copy link
Collaborator

@marcschier marcschier commented Feb 9, 2026

Change built in types to readonly structs
Update localized text implementation to use JSON text serializer
Status code with symbolic names
Immutable node ids - no boxing for int identifiers (in nodeId struct)
No boxing for all built in types <= 8 bytes in Variant.
Split user identity token and token handling via token handler Add migration guide for breaking changes

Proposed changes

Describe the changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.

Related Issues

Types of changes

What types of changes does your code introduce?
Put an x in the boxes that apply. You can also fill these out after creating the PR.

  • Bugfix (non-breaking change which fixes an issue)
  • Enhancement (non-breaking change which adds functionality)
  • Test enhancement (non-breaking change to increase test coverage)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected, requires version increase of Nuget packages)
  • Documentation Update (if none of the other choices apply)

Checklist

Put an x in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.

  • I have read the CONTRIBUTING doc.
  • I have signed the CLA.
  • I ran tests locally with my changes, all passed.
  • I fixed all failing tests in the CI pipelines.
  • I fixed all introduced issues with CodeQL and LGTM.
  • I have added tests that prove my fix is effective or that my feature works and increased code coverage.
  • I have added necessary documentation (if appropriate).
  • Any dependent changes have been merged and published in downstream modules.

Further comments

If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...

Change built in types to readonly structs
  Update localized text implementation to use JSON text serializer
  Status code with symbolic names
  Immutable node ids
  No boxing for all built in types <= 8 bytes in Variant.
Split user identity token and token handling via token handler
Add migration guide for breaking changes
@marcschier marcschier changed the title TESTING/DRAFT Generate stack and application code using source generators TESTING/DRAFT Immutable built in types and code generation Feb 9, 2026
@marcschier marcschier self-assigned this Feb 9, 2026
return predefinedNode;
}

private ServiceResult OnAddSelfAdminRolePermissions(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you explain the benefit and reasoning of this change?
I dont really get what change made this necessary

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ValidateRolePermissions checks whether a node has permissions for a roleId. This happens before even "calling". The ones defined by the standard do not include the SelfAdmin RoleId, so that validation fails because i=0 role id (self admin) has no permission of Call.

It is important to expose the SelfAdmin role on the node so that the role permission check passes, hence this code to inject into RolePermissions and into the UserRolePermissions (if the user has the SelfAdmin RoleId).

My assumption why this is needed now is that the RolePermissions for nodes where not generated by model compiler so there were no roles and no roles means anyone can call without a role, and then all checks where happening via AuthorizationHelper "inside the call callback" later.

Another fix could have been to override ValidateRolePermission method which is virtual. But I think this way is best. But tbd.

Comment out exception throwing for idempotent decoding failure.

// TODO: this loads opc ua assembly, but this should not be needed.
// but otherwise encoderfactory currently does not get all types.
var temp = new AlarmConditionState(null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still required?

throw new InvalidOperationException(Utils.Format(
"Idempotent 3rd gen decoding failed. Type={0}.",
encodeableTypeName));
// throw new InvalidOperationException(Utils.Format(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't need this exception anymore we should delete the whole if statement

],
// values to assign
[structureDefinition.DefaultEncodingId?
[structureDefinition.DefaultEncodingId
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is DefaultEncodingId, complexTypeId, binaryEncodingId and xmlEncodingId now guranteed to be not null?

return WriteBatchedAsync(requestHeader, nodesToWrite, operationLimit, ct);

async Task<WriteResponse> WriteBatchedAsync(
async ValueTask<WriteResponse> WriteBatchedAsync(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least this method uses await, should we really change that to ValueTask?

- `UserNameIdentityTokenHandler`
- `X509IdentityTokenHandler`
- `IssuedIdentityTokenHandler`

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a chapter regarding to AsBoxedObject?

/// <inheritdoc/>
public void Dispose()
{
// TODOL Utils.SilentDispose(m_certificate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here we are potential leaking native memory

@@ -314,7 +314,7 @@ public bool CompareDateTime(DateTime value1, DateTime value2)
/// <param name="value2">Second Value.</param>
/// <returns>True in case of equal values.
/// False or ServiceResultException in case of unequal values.</returns>
public bool CompareUuid(Uuid value1, Uuid value2)
public bool CompareGuid(Uuid value1, Uuid value2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why renamed to CompareGuid?

@@ -827,19 +822,11 @@ public DateTime GetRandomDateTime()
}

/// <inheritdoc/>
public Guid GetRandomGuid()
public Uuid GetRandomGuid()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we call ed GetRandomUuid for consistency?

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.

3 participants