diff --git a/.azurepipelines/preview.yml b/.azurepipelines/preview.yml
index 5693e201c..aafb51e28 100644
--- a/.azurepipelines/preview.yml
+++ b/.azurepipelines/preview.yml
@@ -34,10 +34,10 @@ jobs:
value: '.azurepipelines/signlist${{parameters.config}}.txt'
steps:
- task: UseDotNet@2
- displayName: 'Install .NET 6.0'
+ displayName: 'Install .NET 8.0'
inputs:
packageType: 'sdk'
- version: '6.0.x'
+ version: '8.0.x'
includePreviewVersions: false
- task: DownloadSecureFile@1
name: strongnamefile
diff --git a/.azurepipelines/signlistDebug.txt b/.azurepipelines/signlistDebug.txt
index cf6e91d62..d408a09fd 100644
--- a/.azurepipelines/signlistDebug.txt
+++ b/.azurepipelines/signlistDebug.txt
@@ -2,38 +2,48 @@ Stack\Opc.Ua.Core\bin\Debug\netstandard2.0\Opc.Ua.Core.dll
Stack\Opc.Ua.Core\bin\Debug\netstandard2.1\Opc.Ua.Core.dll
Stack\Opc.Ua.Core\bin\Debug\net48\Opc.Ua.Core.dll
Stack\Opc.Ua.Core\bin\Debug\net6.0\Opc.Ua.Core.dll
+Stack\Opc.Ua.Core\bin\Debug\net8.0\Opc.Ua.Core.dll
Stack\Opc.Ua.Bindings.Https\bin\Debug\netstandard2.0\Opc.Ua.Bindings.Https.dll
Stack\Opc.Ua.Bindings.Https\bin\Debug\netcoreapp3.1\Opc.Ua.Bindings.Https.dll
Stack\Opc.Ua.Bindings.Https\bin\Debug\net48\Opc.Ua.Bindings.Https.dll
Stack\Opc.Ua.Bindings.Https\bin\Debug\net6.0\Opc.Ua.Bindings.Https.dll
+Stack\Opc.Ua.Bindings.Https\bin\Debug\net8.0\Opc.Ua.Bindings.Https.dll
Libraries\Opc.Ua.Server\bin\Debug\netstandard2.0\Opc.Ua.Server.dll
Libraries\Opc.Ua.Server\bin\Debug\netstandard2.1\Opc.Ua.Server.dll
Libraries\Opc.Ua.Server\bin\Debug\net48\Opc.Ua.Server.dll
Libraries\Opc.Ua.Server\bin\Debug\net6.0\Opc.Ua.Server.dll
+Libraries\Opc.Ua.Server\bin\Debug\net8.0\Opc.Ua.Server.dll
Libraries\Opc.Ua.Client\bin\Debug\netstandard2.0\Opc.Ua.Client.dll
Libraries\Opc.Ua.Client\bin\Debug\netstandard2.1\Opc.Ua.Client.dll
Libraries\Opc.Ua.Client\bin\Debug\net48\Opc.Ua.Client.dll
Libraries\Opc.Ua.Client\bin\Debug\net6.0\Opc.Ua.Client.dll
+Libraries\Opc.Ua.Client\bin\Debug\net8.0\Opc.Ua.Client.dll
Libraries\Opc.Ua.Client.ComplexTypes\bin\Debug\netstandard2.1\Opc.Ua.Client.ComplexTypes.dll
Libraries\Opc.Ua.Client.ComplexTypes\bin\Debug\net48\Opc.Ua.Client.ComplexTypes.dll
Libraries\Opc.Ua.Client.ComplexTypes\bin\Debug\net6.0\Opc.Ua.Client.ComplexTypes.dll
+Libraries\Opc.Ua.Client.ComplexTypes\bin\Debug\net8.0\Opc.Ua.Client.ComplexTypes.dll
Libraries\Opc.Ua.Configuration\bin\Debug\netstandard2.0\Opc.Ua.Configuration.dll
Libraries\Opc.Ua.Configuration\bin\Debug\netstandard2.1\Opc.Ua.Configuration.dll
Libraries\Opc.Ua.Configuration\bin\Debug\net48\Opc.Ua.Configuration.dll
Libraries\Opc.Ua.Configuration\bin\Debug\net6.0\Opc.Ua.Configuration.dll
+Libraries\Opc.Ua.Configuration\bin\Debug\net8.0\Opc.Ua.Configuration.dll
Libraries\Opc.Ua.Gds.Client.Common\bin\Debug\netstandard2.0\Opc.Ua.Gds.Client.Common.dll
Libraries\Opc.Ua.Gds.Client.Common\bin\Debug\netstandard2.1\Opc.Ua.Gds.Client.Common.dll
Libraries\Opc.Ua.Gds.Client.Common\bin\Debug\net48\Opc.Ua.Gds.Client.Common.dll
Libraries\Opc.Ua.Gds.Client.Common\bin\Debug\net6.0\Opc.Ua.Gds.Client.Common.dll
+Libraries\Opc.Ua.Gds.Client.Common\bin\Debug\net8.0\Opc.Ua.Gds.Client.Common.dll
Libraries\Opc.Ua.Gds.Server.Common\bin\Debug\netstandard2.0\Opc.Ua.Gds.Server.Common.dll
Libraries\Opc.Ua.Gds.Server.Common\bin\Debug\netstandard2.1\Opc.Ua.Gds.Server.Common.dll
Libraries\Opc.Ua.Gds.Server.Common\bin\Debug\net48\Opc.Ua.Gds.Server.Common.dll
Libraries\Opc.Ua.Gds.Server.Common\bin\Debug\net6.0\Opc.Ua.Gds.Server.Common.dll
+Libraries\Opc.Ua.Gds.Server.Common\bin\Debug\net8.0\Opc.Ua.Gds.Server.Common.dll
Libraries\Opc.Ua.Security.Certificates\bin\Debug\netstandard2.0\Opc.Ua.Security.Certificates.dll
Libraries\Opc.Ua.Security.Certificates\bin\Debug\netstandard2.1\Opc.Ua.Security.Certificates.dll
Libraries\Opc.Ua.Security.Certificates\bin\Debug\net48\Opc.Ua.Security.Certificates.dll
Libraries\Opc.Ua.Security.Certificates\bin\Debug\net6.0\Opc.Ua.Security.Certificates.dll
+Libraries\Opc.Ua.Security.Certificates\bin\Debug\net8.0\Opc.Ua.Security.Certificates.dll
Libraries\Opc.Ua.PubSub\bin\Debug\netstandard2.0\Opc.Ua.PubSub.dll
Libraries\Opc.Ua.PubSub\bin\Debug\netstandard2.1\Opc.Ua.PubSub.dll
Libraries\Opc.Ua.PubSub\bin\Debug\net48\Opc.Ua.PubSub.dll
Libraries\Opc.Ua.PubSub\bin\Debug\net6.0\Opc.Ua.PubSub.dll
+Libraries\Opc.Ua.PubSub\bin\Debug\net8.0\Opc.Ua.PubSub.dll
diff --git a/.azurepipelines/signlistRelease.txt b/.azurepipelines/signlistRelease.txt
index 096da79e4..6ec934498 100644
--- a/.azurepipelines/signlistRelease.txt
+++ b/.azurepipelines/signlistRelease.txt
@@ -2,38 +2,48 @@ Stack\Opc.Ua.Core\bin\Release\netstandard2.0\Opc.Ua.Core.dll
Stack\Opc.Ua.Core\bin\Release\netstandard2.1\Opc.Ua.Core.dll
Stack\Opc.Ua.Core\bin\Release\net48\Opc.Ua.Core.dll
Stack\Opc.Ua.Core\bin\Release\net6.0\Opc.Ua.Core.dll
+Stack\Opc.Ua.Core\bin\Release\net8.0\Opc.Ua.Core.dll
Stack\Opc.Ua.Bindings.Https\bin\Release\netstandard2.0\Opc.Ua.Bindings.Https.dll
Stack\Opc.Ua.Bindings.Https\bin\Release\netcoreapp3.1\Opc.Ua.Bindings.Https.dll
Stack\Opc.Ua.Bindings.Https\bin\Release\net48\Opc.Ua.Bindings.Https.dll
Stack\Opc.Ua.Bindings.Https\bin\Release\net6.0\Opc.Ua.Bindings.Https.dll
+Stack\Opc.Ua.Bindings.Https\bin\Release\net8.0\Opc.Ua.Bindings.Https.dll
Libraries\Opc.Ua.Server\bin\Release\netstandard2.0\Opc.Ua.Server.dll
Libraries\Opc.Ua.Server\bin\Release\netstandard2.1\Opc.Ua.Server.dll
Libraries\Opc.Ua.Server\bin\Release\net48\Opc.Ua.Server.dll
Libraries\Opc.Ua.Server\bin\Release\net6.0\Opc.Ua.Server.dll
+Libraries\Opc.Ua.Server\bin\Release\net8.0\Opc.Ua.Server.dll
Libraries\Opc.Ua.Client\bin\Release\netstandard2.0\Opc.Ua.Client.dll
Libraries\Opc.Ua.Client\bin\Release\netstandard2.1\Opc.Ua.Client.dll
Libraries\Opc.Ua.Client\bin\Release\net48\Opc.Ua.Client.dll
Libraries\Opc.Ua.Client\bin\Release\net6.0\Opc.Ua.Client.dll
+Libraries\Opc.Ua.Client\bin\Release\net8.0\Opc.Ua.Client.dll
Libraries\Opc.Ua.Client.ComplexTypes\bin\Release\netstandard2.1\Opc.Ua.Client.ComplexTypes.dll
Libraries\Opc.Ua.Client.ComplexTypes\bin\Release\net48\Opc.Ua.Client.ComplexTypes.dll
Libraries\Opc.Ua.Client.ComplexTypes\bin\Release\net6.0\Opc.Ua.Client.ComplexTypes.dll
+Libraries\Opc.Ua.Client.ComplexTypes\bin\Release\net8.0\Opc.Ua.Client.ComplexTypes.dll
Libraries\Opc.Ua.Configuration\bin\Release\netstandard2.0\Opc.Ua.Configuration.dll
Libraries\Opc.Ua.Configuration\bin\Release\netstandard2.1\Opc.Ua.Configuration.dll
Libraries\Opc.Ua.Configuration\bin\Release\net48\Opc.Ua.Configuration.dll
Libraries\Opc.Ua.Configuration\bin\Release\net6.0\Opc.Ua.Configuration.dll
+Libraries\Opc.Ua.Configuration\bin\Release\net8.0\Opc.Ua.Configuration.dll
Libraries\Opc.Ua.Gds.Client.Common\bin\Release\netstandard2.0\Opc.Ua.Gds.Client.Common.dll
Libraries\Opc.Ua.Gds.Client.Common\bin\Release\netstandard2.1\Opc.Ua.Gds.Client.Common.dll
Libraries\Opc.Ua.Gds.Client.Common\bin\Release\net48\Opc.Ua.Gds.Client.Common.dll
Libraries\Opc.Ua.Gds.Client.Common\bin\Release\net6.0\Opc.Ua.Gds.Client.Common.dll
+Libraries\Opc.Ua.Gds.Client.Common\bin\Release\net8.0\Opc.Ua.Gds.Client.Common.dll
Libraries\Opc.Ua.Gds.Server.Common\bin\Release\netstandard2.0\Opc.Ua.Gds.Server.Common.dll
Libraries\Opc.Ua.Gds.Server.Common\bin\Release\netstandard2.1\Opc.Ua.Gds.Server.Common.dll
Libraries\Opc.Ua.Gds.Server.Common\bin\Release\net48\Opc.Ua.Gds.Server.Common.dll
Libraries\Opc.Ua.Gds.Server.Common\bin\Release\net6.0\Opc.Ua.Gds.Server.Common.dll
+Libraries\Opc.Ua.Gds.Server.Common\bin\Release\net8.0\Opc.Ua.Gds.Server.Common.dll
Libraries\Opc.Ua.Security.Certificates\bin\Release\netstandard2.0\Opc.Ua.Security.Certificates.dll
Libraries\Opc.Ua.Security.Certificates\bin\Release\netstandard2.1\Opc.Ua.Security.Certificates.dll
Libraries\Opc.Ua.Security.Certificates\bin\Release\net48\Opc.Ua.Security.Certificates.dll
Libraries\Opc.Ua.Security.Certificates\bin\Release\net6.0\Opc.Ua.Security.Certificates.dll
+Libraries\Opc.Ua.Security.Certificates\bin\Release\net8.0\Opc.Ua.Security.Certificates.dll
Libraries\Opc.Ua.PubSub\bin\Release\netstandard2.0\Opc.Ua.PubSub.dll
Libraries\Opc.Ua.PubSub\bin\Release\netstandard2.1\Opc.Ua.PubSub.dll
Libraries\Opc.Ua.PubSub\bin\Release\net48\Opc.Ua.PubSub.dll
Libraries\Opc.Ua.PubSub\bin\Release\net6.0\Opc.Ua.PubSub.dll
+Libraries\Opc.Ua.PubSub\bin\Release\net8.0\Opc.Ua.PubSub.dll
diff --git a/.azurepipelines/test.yml b/.azurepipelines/test.yml
index 178d3e8ef..2eb67f2cd 100644
--- a/.azurepipelines/test.yml
+++ b/.azurepipelines/test.yml
@@ -6,6 +6,7 @@ parameters:
framework: net6.0
agents: '@{}'
jobnamesuffix: ''
+ customtestarget: ''
jobs:
- job: testprep${{ parameters.jobnamesuffix }}
displayName: Prepare Test Jobs ${{ parameters.configuration }} (${{ parameters.framework }})
@@ -30,21 +31,25 @@ jobs:
variables:
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+ CustomTestTarget: ${{ parameters.customtestarget }}
+ ${{ if eq( parameters.customtestarget, '' ) }}:
+ DotCliCommandline: '--framework ${{ parameters.framework }}'
+ ${{ else }}:
+ DotCliCommandline: '/p:CustomTestTarget=${{ parameters.customtestarget }}'
pool:
vmImage: $(poolImage)
steps:
- task: UseDotNet@2
- displayName: 'Install .NET Core 3.1'
- condition: eq('${{parameters.framework}}', 'netcoreapp3.1')
+ displayName: 'Install .NET 6.0'
+ condition: eq('${{parameters.framework}}', 'net6.0')
inputs:
packageType: 'sdk'
- version: '3.1.x'
+ version: '6.0.x'
- task: UseDotNet@2
- displayName: 'Install .NET 6.0'
- condition: or(eq('${{parameters.framework}}', 'netcoreapp3.1'), and(eq('${{parameters.framework}}', 'net6.0'), ne(variables['poolImage'], 'windows-2022')))
+ displayName: 'Install .NET 8.0'
inputs:
packageType: 'sdk'
- version: '6.0.x'
+ version: '8.0.x'
- task: NuGetToolInstaller@1
inputs:
versionSpec: '>=5.8.x'
@@ -58,11 +63,11 @@ jobs:
inputs:
command: restore
projects: '**/*.Tests.csproj'
- arguments: '--framework ${{ parameters.framework }} --configuration ${{ parameters.configuration }}'
+ arguments: '${{ variables.DotCliCommandline }} --configuration ${{ parameters.configuration }}'
- task: DotNetCoreCLI@2
displayName: Test ${{ parameters.configuration }}
timeoutInMinutes: 45
inputs:
command: test
projects: '**/*.Tests.csproj'
- arguments: '--no-restore --framework ${{ parameters.framework }} --configuration ${{ parameters.configuration }}'
+ arguments: '--no-restore ${{ variables.DotCliCommandline }} --configuration ${{ parameters.configuration }}'
diff --git a/.azurepipelines/testcc.yml b/.azurepipelines/testcc.yml
index 7cc539aee..601f7192c 100644
--- a/.azurepipelines/testcc.yml
+++ b/.azurepipelines/testcc.yml
@@ -7,6 +7,7 @@ parameters:
agent: 'linux'
poolImage: 'ubuntu-22.04'
jobnamesuffix: 'net60cc'
+ customtestarget: ''
jobs:
- job: testcc${{ parameters.jobnamesuffix }}
displayName: Coverage ${{ parameters.agent }} ${{ parameters.configuration }}
@@ -14,16 +15,25 @@ jobs:
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
disable.coverage.autogenerate: true
+ CustomTestTarget: ${{ parameters.customtestarget }}
+ ${{ if eq( parameters.customtestarget, '' ) }}:
+ DotCliCommandline: '--framework ${{ parameters.framework }}'
+ ${{ else }}:
+ DotCliCommandline: '/p:CustomTestTarget=${{ parameters.customtestarget }}'
pool:
vmImage: ${{ parameters.poolImage }}
steps:
- task: UseDotNet@2
displayName: 'Install .NET 6.0'
- condition: and(eq('${{parameters.framework}}', 'net6.0'), ne(variables['poolImage'], 'windows-2022'))
+ condition: eq('${{parameters.framework}}', 'net6.0')
inputs:
packageType: 'sdk'
version: '6.0.x'
- includePreviewVersions: true
+ - task: UseDotNet@2
+ displayName: 'Install .NET 8.0'
+ inputs:
+ packageType: 'sdk'
+ version: '8.0.x'
- task: NuGetToolInstaller@1
inputs:
versionSpec: '>=5.8.x'
@@ -37,7 +47,7 @@ jobs:
inputs:
command: restore
projects: 'UA Core Library.sln'
- arguments: '--framework ${{ parameters.framework }} --configuration ${{ parameters.configuration }}'
+ arguments: '${{ variables.DotCliCommandline }} --configuration ${{ parameters.configuration }}'
- task: DotNetCoreCLI@2
displayName: Test ${{ parameters.framework }}
timeoutInMinutes: 45
@@ -45,7 +55,7 @@ jobs:
command: test
projects: 'UA Core Library.sln'
# note: /p:CollectCoverage=true is only used to disable deterministc builds
- arguments: '--no-restore --framework ${{ parameters.framework }} --configuration ${{ parameters.configuration }} /p:CollectCoverage=true --collect:"XPlat Code Coverage" --settings ./Tests/coverlet.runsettings.xml --results-directory $(Agent.TempDirectory)'
+ arguments: '--no-restore ${{ variables.DotCliCommandline }} --configuration ${{ parameters.configuration }} /p:CollectCoverage=true --collect:"XPlat Code Coverage" --settings ./Tests/coverlet.runsettings.xml --results-directory $(Agent.TempDirectory)'
publishTestResults: false
- script: |
bash <(curl -s https://codecov.io/bash) -s $(Agent.TempDirectory)
diff --git a/.editorconfig b/.editorconfig
index 8beb94ddb..6de1ac41a 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -324,3 +324,13 @@ dotnet_diagnostic.IDE0049.severity =
# CA1507: Use nameof in place of string
dotnet_diagnostic.CA1507.severity = warning
+# exclude generated code
+[**/Generated/*.cs]
+generated_code = true
+dotnet_diagnostic.severity = none
+dotnet_analyzer.severity = none
+
+[*.{Classes,DataTypes,Constants}.cs]
+generated_code = true
+dotnet_diagnostic.severity = none
+dotnet_analyzer.severity = none
diff --git a/.github/workflows/buildandtest.yml b/.github/workflows/buildandtest.yml
index f7c5132a0..bb9f510aa 100644
--- a/.github/workflows/buildandtest.yml
+++ b/.github/workflows/buildandtest.yml
@@ -1,4 +1,4 @@
-name: Build and Test .NET 6.0
+name: Build and Test .NET 8.0
on:
push:
@@ -25,9 +25,10 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest]
csproj: [Security.Certificates, Core, Server, Client, Client.ComplexTypes, PubSub, Configuration, Gds]
include:
- - framework: 'net6.0'
- dotnet-version: '6.0.x'
+ - framework: 'net8.0'
+ dotnet-version: '8.0.x'
configuration: 'Release'
+ customtesttarget: net8.0
env:
OS: ${{ matrix.os }}
@@ -38,12 +39,12 @@ jobs:
TESTRESULTS: "TestResults-${{matrix.csproj}}-${{matrix.os}}-${{matrix.framework}}-${{matrix.configuration}}"
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET ${{ matrix.dotnet-version }}
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ matrix.dotnet-version }}
@@ -52,11 +53,11 @@ jobs:
run: ./.azurepipelines/set-version.ps1
- name: Build
- run: dotnet build ${{ env.CSPROJECT }} --force --framework ${{ matrix.framework }} --configuration ${{ matrix.configuration }}
+ run: dotnet build ${{ env.CSPROJECT }} --force --framework ${{ matrix.framework }} --configuration ${{ matrix.configuration }} /p:CustomTestTarget=${{ matrix.customtesttarget }}
- name: Test
# note: /p:CollectCoverage=true is only used to disable deterministc builds
- run: dotnet test ${{ env.CSPROJECT }} --no-build --framework ${{ matrix.framework }} --logger trx --configuration ${{ matrix.configuration }} /p:CollectCoverage=true --collect:"XPlat Code Coverage" --settings ./Tests/coverlet.runsettings.xml --results-directory ${{ env.TESTRESULTS }}
+ run: dotnet test ${{ env.CSPROJECT }} --no-build --framework ${{ matrix.framework }} --logger trx --configuration ${{ matrix.configuration }} /p:CollectCoverage=true /p:CustomTestTarget=${{ matrix.customtesttarget }} --collect:"XPlat Code Coverage" --settings ./Tests/coverlet.runsettings.xml --results-directory ${{ env.TESTRESULTS }}
- name: Upload test results
uses: actions/upload-artifact@v3
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index fe35d1000..0983b3aa3 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -32,7 +32,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
@@ -45,9 +45,9 @@ jobs:
# queries: ./path/to/local/query, your-org/your-repo/queries@main
- name: Set up .NET
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
- dotnet-version: '6.x'
+ dotnet-version: '8.x'
# Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
- name: Setup MSBuild.exe
diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
index 06189f7fc..12fbe6ead 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image.yml
@@ -34,14 +34,14 @@ jobs:
id-token: write
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- - name: Set up .NET 6
- uses: actions/setup-dotnet@v3
+ - name: Set up .NET 8
+ uses: actions/setup-dotnet@v4
with:
- dotnet-version: '6.x'
+ dotnet-version: '8.x'
- name: Set Version
shell: pwsh
@@ -57,13 +57,13 @@ jobs:
# https://github.com/docker/build-push-action
- name: Setup Docker buildx
- uses: docker/setup-buildx-action@v2
+ uses: docker/setup-buildx-action@v3
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
- uses: docker/login-action@v2
+ uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -93,18 +93,18 @@ jobs:
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
- uses: docker/metadata-action@v4
+ uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_REPOSITORY }}
- name: Set up QEMU
- uses: docker/setup-qemu-action@v2
+ uses: docker/setup-qemu-action@v3
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
- name: Build and push Docker image
id: build-and-push
- uses: docker/build-push-action@v4
+ uses: docker/build-push-action@v5
with:
context: .
build-args: |
@@ -113,7 +113,7 @@ jobs:
InformationalVersion=${{ env.NBGV_AssemblyInformationalVersion }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ env.TAG_BRANCH }},${{ env.TAG_LATEST }}${{ env.TAG_RELEASE }}
- platforms: linux/amd64,linux/arm64
+ platforms: linux/amd64,linux/arm64/v8
file: ./Applications/ConsoleReferenceServer/Dockerfile
labels: ${{ steps.meta.outputs.labels }}
provenance: false
diff --git a/Applications/ClientControls.Net4/ClientUtils.cs b/Applications/ClientControls.Net4/ClientUtils.cs
index 87de94feb..525ca6c8e 100644
--- a/Applications/ClientControls.Net4/ClientUtils.cs
+++ b/Applications/ClientControls.Net4/ClientUtils.cs
@@ -281,9 +281,9 @@ public static string GetAttributeDisplayText(Session session, uint attributeId,
}
// check for byte strings.
- if (value.Value is byte[])
+ if (value.Value is byte[] byteArray)
{
- return Utils.ToHexString(value.Value as byte[]);
+ return Utils.ToHexString(byteArray);
}
// use default format.
diff --git a/Applications/ClientControls.Net4/Common/Client/EditComplexValueCtrl.cs b/Applications/ClientControls.Net4/Common/Client/EditComplexValueCtrl.cs
index 06b72364c..413619734 100644
--- a/Applications/ClientControls.Net4/Common/Client/EditComplexValueCtrl.cs
+++ b/Applications/ClientControls.Net4/Common/Client/EditComplexValueCtrl.cs
@@ -246,9 +246,8 @@ public void SetArraySize()
TypeInfo currentType = info.TypeInfo;
object currentValue = info.Value;
- if (info.Value is Variant)
+ if (info.Value is Variant variant)
{
- Variant variant = (Variant)info.Value;
currentValue = variant.Value;
if (currentValue != null)
@@ -395,9 +394,8 @@ public void SetType(BuiltInType builtInType)
currentValue = TypeInfo.GetDefaultValue(currentType.BuiltInType);
}
- if (info.Value is Variant)
+ if (info.Value is Variant variant)
{
- Variant variant = (Variant)info.Value;
currentValue = variant.Value;
if (currentValue != null)
@@ -680,9 +678,8 @@ private void ShowValueNoNotify(AccessInfo parent)
TypeInfo typeInfo = parent.TypeInfo;
object value = parent.Value;
- if (value is Variant)
+ if (value is Variant variant)
{
- Variant variant = (Variant)value;
value = variant.Value;
if (value != null)
@@ -797,58 +794,58 @@ private void ShowValueNoNotify(AccessInfo parent)
}
// check for XmlElements.
- if (structure is XmlElement)
+ if (structure is XmlElement xmlElement)
{
- ShowTextValue((XmlElement)structure);
+ ShowTextValue((XmlElement)xmlElement);
return;
}
// check for ByteString.
- if (structure is byte[])
+ if (structure is byte[] byteString)
{
- ShowTextValue((byte[])structure);
+ ShowTextValue(byteString);
return;
}
// check for NodeId.
- if (structure is NodeId)
+ if (structure is NodeId nodeId)
{
- ShowTextValue(((NodeId)structure).ToString());
+ ShowTextValue(nodeId.ToString());
return;
}
// check for ExpandedNodeId.
- if (structure is ExpandedNodeId)
+ if (structure is ExpandedNodeId expandedNodeId)
{
- ShowTextValue(((ExpandedNodeId)structure).ToString());
+ ShowTextValue(expandedNodeId.ToString());
return;
}
// check for QualifiedName.
- if (structure is QualifiedName)
+ if (structure is QualifiedName qualifiedName)
{
- ShowTextValue(((QualifiedName)structure).ToString());
+ ShowTextValue(qualifiedName.ToString());
return;
}
// check for Guid.
- if (structure is Guid)
+ if (structure is Guid guid)
{
- ShowTextValue(((Guid)structure).ToString());
+ ShowTextValue(guid.ToString());
return;
}
// check for Uuid.
- if (structure is Uuid)
+ if (structure is Uuid uuid)
{
- ShowTextValue(((Uuid)structure).ToString());
+ ShowTextValue(uuid.ToString());
return;
}
// check for StatusCode.
- if (structure is StatusCode)
+ if (structure is StatusCode statusCode)
{
- ShowTextValue(Utils.Format("0x{0:X8}", ((StatusCode)structure).Code));
+ ShowTextValue(Utils.Format("0x{0:X8}", statusCode.Code));
return;
}
@@ -1008,15 +1005,13 @@ private Type GetDataType(AccessInfo accessInfo)
if (accessInfo.Parent != null)
{
- if (accessInfo.Parent.Value is Array)
+ if (accessInfo.Parent.Value is Array array)
{
- Array array = (Array)accessInfo.Parent.Value;
return array.GetType().GetElementType();
}
- if (accessInfo.Parent.Value is IList)
+ if (accessInfo.Parent.Value is IList list)
{
- IList list = (IList)accessInfo.Parent.Value;
return GetListElementType(list);
}
}
@@ -1179,9 +1174,8 @@ private string ValueToString(object value, TypeInfo typeInfo)
return String.Empty;
}
- if (value is Variant)
+ if (value is Variant variant)
{
- Variant variant = (Variant)value;
value = variant.Value;
if (value != null)
diff --git a/Applications/ClientControls.Net4/Configuration/Common (OLD)/ClipboardHack.cs b/Applications/ClientControls.Net4/Configuration/Common (OLD)/ClipboardHack.cs
index bafaae01e..53dd5d791 100644
--- a/Applications/ClientControls.Net4/Configuration/Common (OLD)/ClipboardHack.cs
+++ b/Applications/ClientControls.Net4/Configuration/Common (OLD)/ClipboardHack.cs
@@ -146,7 +146,7 @@ private static void SetClipboardPrivate()
#endregion
#region Private Fields
- private static object m_lock = new object();
+ private static readonly object m_lock = new object();
private static string m_format = null;
private static object m_data = null;
private static Exception m_error = null;
diff --git a/Applications/ClientControls.Net4/Endpoints/UsernameTokenDlg.cs b/Applications/ClientControls.Net4/Endpoints/UsernameTokenDlg.cs
index f630083bf..30a6f1c9b 100644
--- a/Applications/ClientControls.Net4/Endpoints/UsernameTokenDlg.cs
+++ b/Applications/ClientControls.Net4/Endpoints/UsernameTokenDlg.cs
@@ -73,7 +73,7 @@ public bool ShowDialog(UserNameIdentityToken token)
if (token.Password != null && token.Password.Length > 0)
{
- PasswordTB.Text = new UTF8Encoding().GetString(token.Password);
+ PasswordTB.Text = Encoding.UTF8.GetString(token.Password);
}
}
@@ -86,7 +86,7 @@ public bool ShowDialog(UserNameIdentityToken token)
if (!String.IsNullOrEmpty(PasswordTB.Text))
{
- token.Password = new UTF8Encoding().GetBytes(PasswordTB.Text);
+ token.Password = Encoding.UTF8.GetBytes(PasswordTB.Text);
}
else
{
diff --git a/Applications/ConsoleReferenceClient/ClientSamples.cs b/Applications/ConsoleReferenceClient/ClientSamples.cs
index 8c8efc8a0..4aee8c0a7 100644
--- a/Applications/ConsoleReferenceClient/ClientSamples.cs
+++ b/Applications/ConsoleReferenceClient/ClientSamples.cs
@@ -376,7 +376,7 @@ public void SubscribeToDataChanges(ISession session, uint minLifeTime)
/// Adds the root node to the result.
/// Filters nodes from namespace 0 from the result.
/// The list of nodes on the server.
- public IList FetchAllNodesNodeCache(
+ public async Task> FetchAllNodesNodeCacheAsync(
IUAClient uaClient,
NodeId startingNode,
bool fetchTree = false,
@@ -398,13 +398,13 @@ public IList FetchAllNodesNodeCache(
{
// clear NodeCache to fetch all nodes from server
uaClient.Session.NodeCache.Clear();
- FetchReferenceIdTypes(uaClient.Session);
+ await FetchReferenceIdTypesAsync(uaClient.Session).ConfigureAwait(false);
}
// add root node
if (addRootNode)
{
- var rootNode = uaClient.Session.NodeCache.Find(startingNode);
+ var rootNode = await uaClient.Session.NodeCache.FindAsync(startingNode).ConfigureAwait(false);
nodeDictionary[rootNode.NodeId] = rootNode;
}
@@ -419,11 +419,11 @@ public IList FetchAllNodesNodeCache(
searchDepth++;
Utils.LogInfo("{0}: Find {1} references after {2}ms", searchDepth, nodesToBrowse.Count, stopwatch.ElapsedMilliseconds);
- IList response = uaClient.Session.NodeCache.FindReferences(
+ IList response = await uaClient.Session.NodeCache.FindReferencesAsync(
nodesToBrowse,
references,
false,
- true);
+ true).ConfigureAwait(false);
var nextNodesToBrowse = new ExpandedNodeIdCollection();
int duplicates = 0;
@@ -466,7 +466,7 @@ public IList FetchAllNodesNodeCache(
}
else
{
- nodeDictionary[node.NodeId] = node; ;
+ nodeDictionary[node.NodeId] = node;
}
}
else
@@ -511,10 +511,11 @@ public IList FetchAllNodesNodeCache(
/// The UAClient with a session to use.
/// The node where the browse operation starts.
/// An optional BrowseDescription to use.
- public ReferenceDescriptionCollection BrowseFullAddressSpace(
+ public async Task BrowseFullAddressSpaceAsync(
IUAClient uaClient,
NodeId startingNode = null,
- BrowseDescription browseDescription = null)
+ BrowseDescription browseDescription = null,
+ CancellationToken ct = default)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
@@ -563,9 +564,10 @@ public ReferenceDescriptionCollection BrowseFullAddressSpace(
repeatBrowse = false;
try
{
- _ = uaClient.Session.Browse(null, null,
- kMaxReferencesPerNode, browseCollection,
- out browseResultCollection, out diagnosticsInfoCollection);
+ var browseResponse = await uaClient.Session.BrowseAsync(null, null,
+ kMaxReferencesPerNode, browseCollection, ct).ConfigureAwait(false);
+ browseResultCollection = browseResponse.Results;
+ diagnosticsInfoCollection = browseResponse.DiagnosticInfos;
ClientBase.ValidateResponse(browseResultCollection, browseCollection);
ClientBase.ValidateDiagnosticInfos(diagnosticsInfoCollection, browseCollection);
@@ -629,8 +631,9 @@ public ReferenceDescriptionCollection BrowseFullAddressSpace(
}
Utils.LogInfo("BrowseNext {0} continuation points.", continuationPoints.Count);
- _ = uaClient.Session.BrowseNext(null, false, continuationPoints,
- out var browseNextResultCollection, out diagnosticsInfoCollection);
+ var browseNextResult = await uaClient.Session.BrowseNextAsync(null, false, continuationPoints, ct).ConfigureAwait(false);
+ var browseNextResultCollection = browseNextResult.Results;
+ diagnosticsInfoCollection = browseNextResult.DiagnosticInfos;
ClientBase.ValidateResponse(browseNextResultCollection, continuationPoints);
ClientBase.ValidateDiagnosticInfos(diagnosticsInfoCollection, continuationPoints);
allBrowseResults.AddRange(browseNextResultCollection);
@@ -696,7 +699,7 @@ public ReferenceDescriptionCollection BrowseFullAddressSpace(
/// Outputs elapsed time information for perf testing and lists all
/// types that were successfully added to the session encodeable type factory.
///
- public async Task LoadTypeSystem(ISession session)
+ public async Task LoadTypeSystemAsync(ISession session)
{
m_output.WriteLine("Load the server type system.");
@@ -742,7 +745,7 @@ public async Task LoadTypeSystem(ISession session)
/// The NodeCache needs this information to function properly with subtypes of hierarchical calls.
///
/// The session to use
- void FetchReferenceIdTypes(ISession session)
+ Task FetchReferenceIdTypesAsync(ISession session)
{
// fetch the reference types first, otherwise browse for e.g. hierarchical references with subtypes won't work
var bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
@@ -750,7 +753,7 @@ void FetchReferenceIdTypes(ISession session)
var referenceTypes = typeof(ReferenceTypeIds)
.GetFields(bindingFlags)
.Select(field => NodeId.ToExpandedNodeId((NodeId)field.GetValue(null), namespaceUris));
- session.FetchTypeTree(new ExpandedNodeIdCollection(referenceTypes));
+ return session.FetchTypeTreeAsync(new ExpandedNodeIdCollection(referenceTypes));
}
#endregion
@@ -897,7 +900,7 @@ public async Task SubscribeAllValuesAsync(
StartNodeId = item.NodeId,
AttributeId = Attributes.Value,
SamplingInterval = samplingInterval,
- DisplayName = item.DisplayName.Text ?? item.BrowseName.Name,
+ DisplayName = item.DisplayName?.Text ?? item.BrowseName.Name,
QueueSize = queueSize,
DiscardOldest = true,
MonitoringMode = MonitoringMode.Reporting,
@@ -907,7 +910,7 @@ public async Task SubscribeAllValuesAsync(
}
// Create the monitored items on Server side
- subscription.ApplyChanges();
+ await subscription.ApplyChangesAsync().ConfigureAwait(false);
m_output.WriteLine("MonitoredItems {0} created for SubscriptionId = {1}.", subscription.MonitoredItemCount, subscription.Id);
}
catch (Exception ex)
diff --git a/Applications/ConsoleReferenceClient/ConsoleReferenceClient.csproj b/Applications/ConsoleReferenceClient/ConsoleReferenceClient.csproj
index d7a11680b..79e7956c5 100644
--- a/Applications/ConsoleReferenceClient/ConsoleReferenceClient.csproj
+++ b/Applications/ConsoleReferenceClient/ConsoleReferenceClient.csproj
@@ -24,9 +24,9 @@
-
-
-
+
+
+
diff --git a/Applications/ConsoleReferenceClient/Program.cs b/Applications/ConsoleReferenceClient/Program.cs
index e586a373f..16450caf6 100644
--- a/Applications/ConsoleReferenceClient/Program.cs
+++ b/Applications/ConsoleReferenceClient/Program.cs
@@ -129,8 +129,7 @@ public static async Task Main(string[] args)
// Define the UA Client application
ApplicationInstance.MessageDlg = new ApplicationMessageDlg(output);
CertificatePasswordProvider PasswordProvider = new CertificatePasswordProvider(password);
- ApplicationInstance application = new ApplicationInstance
- {
+ ApplicationInstance application = new ApplicationInstance {
ApplicationName = applicationName,
ApplicationType = ApplicationType.Client,
ConfigSectionName = configSectionName,
@@ -220,7 +219,7 @@ public static async Task Main(string[] args)
var samples = new ClientSamples(output, ClientBase.ValidateResponse, quitEvent, verbose);
if (loadTypes)
{
- await samples.LoadTypeSystem(uaClient.Session).ConfigureAwait(false);
+ await samples.LoadTypeSystemAsync(uaClient.Session).ConfigureAwait(false);
}
if (browseall || fetchall || jsonvalues)
@@ -230,7 +229,7 @@ public static async Task Main(string[] args)
if (browseall)
{
referenceDescriptions =
- samples.BrowseFullAddressSpace(uaClient, Objects.RootFolder);
+ await samples.BrowseFullAddressSpaceAsync(uaClient, Objects.RootFolder).ConfigureAwait(false);
variableIds = new NodeIdCollection(referenceDescriptions
.Where(r => r.NodeClass == NodeClass.Variable && r.TypeDefinition.NamespaceIndex != 0)
.Select(r => ExpandedNodeId.ToNodeId(r.NodeId, uaClient.Session.NamespaceUris)));
@@ -239,8 +238,7 @@ public static async Task Main(string[] args)
IList allNodes = null;
if (fetchall)
{
- allNodes = samples.FetchAllNodesNodeCache(
- uaClient, Objects.RootFolder, true, true, false);
+ allNodes = await samples.FetchAllNodesNodeCacheAsync(uaClient, Objects.RootFolder, true, true, false).ConfigureAwait(false);
variableIds = new NodeIdCollection(allNodes
.Where(r => r.NodeClass == NodeClass.Variable && r is VariableNode && ((VariableNode)r).DataType.NamespaceIndex != 0)
.Select(r => ExpandedNodeId.ToNodeId(r.NodeId, uaClient.Session.NamespaceUris)));
@@ -248,7 +246,7 @@ public static async Task Main(string[] args)
if (jsonvalues && variableIds != null)
{
- await samples.ReadAllValuesAsync(uaClient, variableIds).ConfigureAwait(false);
+ var (allValues, results) = await samples.ReadAllValuesAsync(uaClient, variableIds).ConfigureAwait(false);
}
if (subscribe && (browseall || fetchall))
diff --git a/Applications/ConsoleReferenceClient/UAClient.cs b/Applications/ConsoleReferenceClient/UAClient.cs
index cb1190c50..51c49193e 100644
--- a/Applications/ConsoleReferenceClient/UAClient.cs
+++ b/Applications/ConsoleReferenceClient/UAClient.cs
@@ -99,7 +99,7 @@ public void Dispose()
///
/// The reconnect period to be used in ms.
///
- public int ReconnectPeriod { get; set; } = 5000;
+ public int ReconnectPeriod { get; set; } = 1000;
///
/// The reconnect period exponential backoff to be used in ms.
@@ -178,11 +178,7 @@ public async Task ConnectAsync(string serverUrl, bool useSecurity = true,
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration);
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
-#if NET6_0_OR_GREATER
var sessionFactory = TraceableSessionFactory.Instance;
-#else
- var sessionFactory = DefaultSessionFactory.Instance;
-#endif
// Create the session
var session = await sessionFactory.CreateAsync(
@@ -274,7 +270,7 @@ private void Session_KeepAlive(ISession session, KeepAliveEventArgs e)
try
{
// check for events from discarded sessions.
- if (!Object.ReferenceEquals(session, m_session))
+ if (!m_session.Equals(session))
{
return;
}
@@ -298,6 +294,9 @@ private void Session_KeepAlive(ISession session, KeepAliveEventArgs e)
Utils.LogInfo("KeepAlive status {0}, reconnect status {1}.", e.Status, state);
}
+ // cancel sending a new keep alive request, because reconnect is triggered.
+ e.CancelKeepAlive = true;
+
return;
}
}
@@ -380,7 +379,7 @@ protected virtual void CertificateValidation(CertificateValidator sender, Certif
#endregion
#region Private Fields
- private object m_lock = new object();
+ private readonly object m_lock = new object();
private ReverseConnectManager m_reverseConnectManager;
private ApplicationConfiguration m_configuration;
private SessionReconnectHandler m_reconnectHandler;
diff --git a/Applications/ConsoleReferencePublisher/Program.cs b/Applications/ConsoleReferencePublisher/Program.cs
index af4c7cf18..fb5d4781e 100644
--- a/Applications/ConsoleReferencePublisher/Program.cs
+++ b/Applications/ConsoleReferencePublisher/Program.cs
@@ -61,7 +61,7 @@ public static void Main(string[] args)
{ "u|udp_uadp", "Use UDP with UADP encoding Profile", v => useUdpUadp = v != null },
{ "url|publisher_url=", "Publisher Url Address", v => publisherUrl = v},
};
-
+
try
{
IList extraArgs = options.Parse(args);
@@ -125,7 +125,7 @@ public static void Main(string[] args)
// Create configuration using MQTT protocol and JSON Encoding
pubSubConfiguration = CreatePublisherConfiguration_MqttJson(publisherUrl);
Console.WriteLine("The PubSub Connection was initialized using MQTT & JSON Profile.");
- }
+ }
}
// Create the UA Publisher application using configuration file
@@ -226,7 +226,7 @@ private static PubSubConfigurationDataType CreatePublisherConfiguration_UdpUadp(
dataSetWriter1.DataSetFieldContentMask = (uint)DataSetFieldContentMask.RawData;
dataSetWriter1.DataSetName = "Simple";
dataSetWriter1.KeyFrameCount = 1;
- UadpDataSetWriterMessageDataType uadpDataSetWriterMessage = new UadpDataSetWriterMessageDataType() {
+ UadpDataSetWriterMessageDataType uadpDataSetWriterMessage = new UadpDataSetWriterMessageDataType() {
NetworkMessageNumber = 1,
DataSetMessageContentMask = (uint)(UadpDataSetMessageContentMask.Status | UadpDataSetMessageContentMask.SequenceNumber),
};
@@ -242,7 +242,7 @@ private static PubSubConfigurationDataType CreatePublisherConfiguration_UdpUadp(
dataSetWriter2.DataSetFieldContentMask = (uint)DataSetFieldContentMask.RawData;
dataSetWriter2.DataSetName = "AllTypes";
dataSetWriter2.KeyFrameCount = 1;
- uadpDataSetWriterMessage = new UadpDataSetWriterMessageDataType() {
+ uadpDataSetWriterMessage = new UadpDataSetWriterMessageDataType() {
NetworkMessageNumber = 1,
DataSetMessageContentMask = (uint)(UadpDataSetMessageContentMask.Status | UadpDataSetMessageContentMask.SequenceNumber),
};
@@ -301,7 +301,7 @@ private static PubSubConfigurationDataType CreatePublisherConfiguration_MqttJson
string brokerMetaData = "$Metadata";
#region Define WriterGroup1 - Json
-
+
WriterGroupDataType writerGroup1 = new WriterGroupDataType();
writerGroup1.Name = "WriterGroup 1";
writerGroup1.Enabled = true;
@@ -369,8 +369,7 @@ private static PubSubConfigurationDataType CreatePublisherConfiguration_MqttJson
};
dataSetWriter2.MessageSettings = new ExtensionObject(jsonDataSetWriterMessage);
- jsonDataSetWriterTransport = new BrokerDataSetWriterTransportDataType()
- {
+ jsonDataSetWriterTransport = new BrokerDataSetWriterTransportDataType() {
QueueName = brokerQueueName,
RequestedDeliveryGuarantee = BrokerTransportQualityOfService.BestEffort,
MetaDataQueueName = $"{brokerQueueName}/{brokerMetaData}",
diff --git a/Applications/ConsoleReferencePublisher/PublishedValuesWrites.cs b/Applications/ConsoleReferencePublisher/PublishedValuesWrites.cs
index fee710264..1c2acc093 100644
--- a/Applications/ConsoleReferencePublisher/PublishedValuesWrites.cs
+++ b/Applications/ConsoleReferencePublisher/PublishedValuesWrites.cs
@@ -309,8 +309,7 @@ private void IncrementValue(FieldMetaData variable, ushort namespaceIndex, long
}
else if (variable.ValueRank == ValueRanks.OneDimension)
{
- uint[] values = dataValue.Value as uint[];
- if (values != null)
+ if (dataValue.Value is uint[] values)
{
for (int i = 0; i < values.Length; i++)
{
diff --git a/Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj b/Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj
index 914c63b60..28c81fb76 100644
--- a/Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj
+++ b/Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj
@@ -30,12 +30,12 @@
-
-
+
+
-
-
-
+
+
+
diff --git a/Applications/ConsoleReferenceServer/Dockerfile b/Applications/ConsoleReferenceServer/Dockerfile
index 24bc58665..45ba81180 100644
--- a/Applications/ConsoleReferenceServer/Dockerfile
+++ b/Applications/ConsoleReferenceServer/Dockerfile
@@ -1,7 +1,7 @@
-FROM mcr.microsoft.com/dotnet/runtime:6.0-bullseye-slim AS base
+FROM mcr.microsoft.com/dotnet/runtime:8.0-jammy AS base
WORKDIR /app
-FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim AS build
+FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build
WORKDIR /src
# copy csproj and restore as distinct layers
@@ -12,16 +12,18 @@ COPY ["Libraries/Opc.Ua.Security.Certificates/Opc.Ua.Security.Certificates.cspro
COPY ["Libraries/Opc.Ua.Configuration/Opc.Ua.Configuration.csproj", "Libraries/Opc.Ua.Configuration/"]
COPY ["Libraries/Opc.Ua.Server/Opc.Ua.Server.csproj", "Libraries/Opc.Ua.Server/"]
COPY ["Applications/Quickstarts.Servers/Quickstarts.Servers.csproj", "Applications/Quickstarts.Servers/"]
-RUN dotnet restore "Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj" --force -p:NoHttps=true
+ENV DOTNET_EnableWriteXorExecute=0
+RUN dotnet restore "Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj" --force -p:NoHttps=true -p:CustomTestTarget=net8.0
COPY . .
WORKDIR "/src/Applications/ConsoleReferenceServer"
ARG Version
ARG SimpleVersion
ARG InformationalVersion
-ENV OPTIONS="-c Release -f net6.0 -p:NoHttps=true -p:Dockerbuild=true -p:Version=${Version} -p:AssemblyVersion=${SimpleVersion} -p:FileVersion=${Version} -p:InformationalVersion=${InformationalVersion}"
+ENV OPTIONS="-c Release -f net8.0 -p:NoHttps=true -p:Dockerbuild=true -p:Version=${Version} -p:AssemblyVersion=${SimpleVersion} -p:FileVersion=${Version} -p:InformationalVersion=${InformationalVersion} -p:CustomTestTarget=net8.0"
FROM build AS publish
+ENV DOTNET_EnableWriteXorExecute=0
RUN dotnet publish "ConsoleReferenceServer.csproj" --no-restore ${OPTIONS} -o /app/publish
FROM base AS final
diff --git a/Applications/ConsoleReferenceSubscriber/Program.cs b/Applications/ConsoleReferenceSubscriber/Program.cs
index 7e76faeb5..db5c9abfe 100644
--- a/Applications/ConsoleReferenceSubscriber/Program.cs
+++ b/Applications/ConsoleReferenceSubscriber/Program.cs
@@ -535,7 +535,7 @@ private static PubSubConfigurationDataType CreateSubscriberConfiguration_MqttJso
dataSetReaderAllTypes.Enabled = true;
dataSetReaderAllTypes.DataSetFieldContentMask = (uint)DataSetFieldContentMask.RawData;// RawData encoding;
dataSetReaderAllTypes.KeyFrameCount = 1;
-
+
jsonDataSetReaderMessage = new JsonDataSetReaderMessageDataType() {
NetworkMessageContentMask = (uint)(JsonNetworkMessageContentMask.NetworkMessageHeader
| JsonNetworkMessageContentMask.DataSetMessageHeader
diff --git a/Applications/Quickstarts.Servers/Alarms/AlarmHolders/AlarmConditionTypeHolder.cs b/Applications/Quickstarts.Servers/Alarms/AlarmHolders/AlarmConditionTypeHolder.cs
index 45dd04876..616c60ba4 100644
--- a/Applications/Quickstarts.Servers/Alarms/AlarmHolders/AlarmConditionTypeHolder.cs
+++ b/Applications/Quickstarts.Servers/Alarms/AlarmHolders/AlarmConditionTypeHolder.cs
@@ -200,9 +200,9 @@ protected override bool GetRetainState()
return retainState;
}
- protected override void SetActive(BaseEventState baseEvent, bool activeState)
+ protected override void SetActive(BaseEventState state, bool activeState)
{
- AlarmConditionState alarm = GetAlarm(baseEvent);
+ AlarmConditionState alarm = GetAlarm(state);
alarm.SetActiveState(SystemContext, activeState);
}
diff --git a/Applications/Quickstarts.Servers/Alarms/AlarmNodeManager.cs b/Applications/Quickstarts.Servers/Alarms/AlarmNodeManager.cs
index 9c0b29494..52ed5b532 100644
--- a/Applications/Quickstarts.Servers/Alarms/AlarmNodeManager.cs
+++ b/Applications/Quickstarts.Servers/Alarms/AlarmNodeManager.cs
@@ -577,7 +577,11 @@ private AlarmHolder GetAlarmHolder(NodeId node)
string unmodifiedName = node.Identifier.ToString();
// This is bad, but I'm not sure why the NodeName is being attached with an underscore, it messes with this lookup.
+#if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER
+ string name = unmodifiedName.Replace("Alarms_", "Alarms.", StringComparison.Ordinal);
+#else
string name = unmodifiedName.Replace("Alarms_", "Alarms.");
+#endif
string mapName = name;
if (name.EndsWith(AlarmDefines.TRIGGER_EXTENSION) || name.EndsWith(AlarmDefines.ALARM_EXTENSION))
@@ -663,7 +667,11 @@ public string GetSourceNameFromNodeId(NodeId nodeId)
// Alarms.UnitName.AnalogSource
if (splitString.Length >= 2)
{
+#if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER
+ sourceName = splitString[splitString.Length - 1].Replace("Source", "", StringComparison.Ordinal);
+#else
sourceName = splitString[splitString.Length - 1].Replace("Source", "");
+#endif
}
}
diff --git a/Applications/Quickstarts.Servers/Boiler/Boiler.NodeSet2.xml b/Applications/Quickstarts.Servers/Boiler/Boiler.NodeSet2.xml
index f5e210b37..8e764d624 100644
--- a/Applications/Quickstarts.Servers/Boiler/Boiler.NodeSet2.xml
+++ b/Applications/Quickstarts.Servers/Boiler/Boiler.NodeSet2.xml
@@ -1,10 +1,10 @@
-
+
http://opcfoundation.org/UA/Boiler/
-
+
diff --git a/Applications/Quickstarts.Servers/Boiler/Boiler.Types.xsd b/Applications/Quickstarts.Servers/Boiler/Boiler.Types.xsd
index 4c321c10a..e2c6d129f 100644
--- a/Applications/Quickstarts.Servers/Boiler/Boiler.Types.xsd
+++ b/Applications/Quickstarts.Servers/Boiler/Boiler.Types.xsd
@@ -7,7 +7,7 @@
>
-
+
diff --git a/Applications/Quickstarts.Servers/MemoryBuffer/MemoryBuffer.NodeSet2.xml b/Applications/Quickstarts.Servers/MemoryBuffer/MemoryBuffer.NodeSet2.xml
index 92343e315..537c3a2a1 100644
--- a/Applications/Quickstarts.Servers/MemoryBuffer/MemoryBuffer.NodeSet2.xml
+++ b/Applications/Quickstarts.Servers/MemoryBuffer/MemoryBuffer.NodeSet2.xml
@@ -1,10 +1,10 @@
-
+
http://samples.org/UA/MemoryBuffer
-
+
diff --git a/Applications/Quickstarts.Servers/MemoryBuffer/MemoryBuffer.Types.xsd b/Applications/Quickstarts.Servers/MemoryBuffer/MemoryBuffer.Types.xsd
index 599f40e5c..58dd18637 100644
--- a/Applications/Quickstarts.Servers/MemoryBuffer/MemoryBuffer.Types.xsd
+++ b/Applications/Quickstarts.Servers/MemoryBuffer/MemoryBuffer.Types.xsd
@@ -7,7 +7,7 @@
>
-
+
diff --git a/Applications/Quickstarts.Servers/MemoryBuffer/MemoryBufferState.cs b/Applications/Quickstarts.Servers/MemoryBuffer/MemoryBufferState.cs
index 4f16b8f79..a1f9f83c9 100644
--- a/Applications/Quickstarts.Servers/MemoryBuffer/MemoryBufferState.cs
+++ b/Applications/Quickstarts.Servers/MemoryBuffer/MemoryBufferState.cs
@@ -678,7 +678,7 @@ void PublishTimer_Tick(object sender, EventArgs e)
#endregion
#region Private Fields
- private object m_dataLock = new object();
+ private readonly object m_dataLock = new object();
private IServerInternal m_server;
private INodeManager m_nodeManager;
private MemoryBufferMonitoredItem[][] m_monitoringTable;
diff --git a/Applications/Quickstarts.Servers/SampleNodeManager/DataChangeMonitoredItem.cs b/Applications/Quickstarts.Servers/SampleNodeManager/DataChangeMonitoredItem.cs
index b91b4a916..c03661639 100644
--- a/Applications/Quickstarts.Servers/SampleNodeManager/DataChangeMonitoredItem.cs
+++ b/Applications/Quickstarts.Servers/SampleNodeManager/DataChangeMonitoredItem.cs
@@ -837,7 +837,7 @@ private void Publish(
#endregion
#region Private Fields
- private object m_lock = new object();
+ private readonly object m_lock = new object();
private MonitoredNode m_source;
private ISubscription m_subscription;
private uint m_id;
diff --git a/Applications/Quickstarts.Servers/SampleNodeManager/SampleNodeManager.cs b/Applications/Quickstarts.Servers/SampleNodeManager/SampleNodeManager.cs
index c7721dcc1..3b94e5d02 100644
--- a/Applications/Quickstarts.Servers/SampleNodeManager/SampleNodeManager.cs
+++ b/Applications/Quickstarts.Servers/SampleNodeManager/SampleNodeManager.cs
@@ -3088,7 +3088,7 @@ protected virtual void OnSetMonitoringMode(
#endregion
#region Private Fields
- private object m_lock = new object();
+ private readonly object m_lock = new object();
private IServerInternal m_server;
private ServerSystemContext m_systemContext;
private IList m_namespaceUris;
diff --git a/Applications/Quickstarts.Servers/TestData/ArrayValueObjectState.cs b/Applications/Quickstarts.Servers/TestData/ArrayValueObjectState.cs
index 872d27566..18df5a97a 100644
--- a/Applications/Quickstarts.Servers/TestData/ArrayValueObjectState.cs
+++ b/Applications/Quickstarts.Servers/TestData/ArrayValueObjectState.cs
@@ -74,6 +74,9 @@ protected override void OnAfterCreate(ISystemContext context, NodeState node)
InitializeVariable(context, IntegerValue, TestData.Variables.ArrayValueObjectType_IntegerValue);
InitializeVariable(context, UIntegerValue, TestData.Variables.ArrayValueObjectType_UIntegerValue);
InitializeVariable(context, VectorValue, TestData.Variables.ArrayValueObjectType_VectorValue);
+ InitializeVariable(context, VectorUnionValue, TestData.Variables.ArrayValueObjectType_VectorUnionValue);
+ InitializeVariable(context, VectorWithOptionalFieldsValue, TestData.Variables.ArrayValueObjectType_VectorWithOptionalFieldsValue);
+ InitializeVariable(context, MultipleVectorsValue, TestData.Variables.ArrayValueObjectType_MultipleVectorsValue);
}
#endregion
@@ -123,6 +126,9 @@ protected override ServiceResult OnGenerateValues(
GenerateValue(system, IntegerValue);
GenerateValue(system, UIntegerValue);
GenerateValue(system, VectorValue);
+ GenerateValue(system, VectorUnionValue);
+ GenerateValue(system, VectorWithOptionalFieldsValue);
+ GenerateValue(system, MultipleVectorsValue);
return base.OnGenerateValues(context, method, objectId, count);
}
diff --git a/Applications/Quickstarts.Servers/TestData/HistoryArchive.cs b/Applications/Quickstarts.Servers/TestData/HistoryArchive.cs
index f91fbf7f0..e54c6afbe 100644
--- a/Applications/Quickstarts.Servers/TestData/HistoryArchive.cs
+++ b/Applications/Quickstarts.Servers/TestData/HistoryArchive.cs
@@ -190,7 +190,7 @@ private void OnUpdate(object state)
#endregion
#region Private Fields
- private object m_lock = new object();
+ private readonly object m_lock = new object();
private Timer m_updateTimer;
private Dictionary m_records;
#endregion
diff --git a/Applications/Quickstarts.Servers/TestData/HistoryFile.cs b/Applications/Quickstarts.Servers/TestData/HistoryFile.cs
index ace1d7560..33eff0c66 100644
--- a/Applications/Quickstarts.Servers/TestData/HistoryFile.cs
+++ b/Applications/Quickstarts.Servers/TestData/HistoryFile.cs
@@ -146,7 +146,7 @@ public DataValue NextRaw(DateTime lastTime, bool isForward, bool isReadModified,
#endregion
#region Private Fields
- private object m_lock = new object();
+ private readonly object m_lock = new object();
private List m_entries;
#endregion
}
diff --git a/Applications/Quickstarts.Servers/TestData/NodeStateComparer.cs b/Applications/Quickstarts.Servers/TestData/NodeStateComparer.cs
index da849b6a0..2de893c86 100644
--- a/Applications/Quickstarts.Servers/TestData/NodeStateComparer.cs
+++ b/Applications/Quickstarts.Servers/TestData/NodeStateComparer.cs
@@ -59,14 +59,14 @@ public bool Equals(NodeState x, NodeState y)
}
///
- public int GetHashCode(NodeState node)
+ public int GetHashCode(NodeState obj)
{
- if (ReferenceEquals(node, null))
+ if (ReferenceEquals(obj, null))
{
return 0;
}
- return node.NodeId.GetHashCode();
+ return obj.NodeId.GetHashCode();
}
}
}
diff --git a/Applications/Quickstarts.Servers/TestData/ScalarValueObjectState.cs b/Applications/Quickstarts.Servers/TestData/ScalarValueObjectState.cs
index b444abae2..f8aa7127a 100644
--- a/Applications/Quickstarts.Servers/TestData/ScalarValueObjectState.cs
+++ b/Applications/Quickstarts.Servers/TestData/ScalarValueObjectState.cs
@@ -74,6 +74,9 @@ protected override void OnAfterCreate(ISystemContext context, NodeState node)
InitializeVariable(context, IntegerValue, TestData.Variables.ScalarValueObjectType_IntegerValue);
InitializeVariable(context, UIntegerValue, TestData.Variables.ScalarValueObjectType_UIntegerValue);
InitializeVariable(context, VectorValue, TestData.Variables.ScalarValueObjectType_VectorValue);
+ InitializeVariable(context, VectorUnionValue, TestData.Variables.ScalarValueObjectType_VectorUnionValue);
+ InitializeVariable(context, VectorWithOptionalFieldsValue, TestData.Variables.ScalarValueObjectType_VectorWithOptionalFieldsValue);
+ InitializeVariable(context, MultipleVectorsValue, TestData.Variables.ScalarValueObjectType_MultipleVectorsValue);
}
#endregion
@@ -123,6 +126,9 @@ protected override ServiceResult OnGenerateValues(
GenerateValue(system, IntegerValue);
GenerateValue(system, UIntegerValue);
GenerateValue(system, VectorValue);
+ GenerateValue(system, VectorUnionValue);
+ GenerateValue(system, VectorWithOptionalFieldsValue);
+ GenerateValue(system, MultipleVectorsValue);
return base.OnGenerateValues(context, method, objectId, count);
}
diff --git a/Applications/Quickstarts.Servers/TestData/TestData.Classes.cs b/Applications/Quickstarts.Servers/TestData/TestData.Classes.cs
index 038c82f0c..65452619b 100644
--- a/Applications/Quickstarts.Servers/TestData/TestData.Classes.cs
+++ b/Applications/Quickstarts.Servers/TestData/TestData.Classes.cs
@@ -4606,7 +4606,7 @@ protected override void InitializeOptionalChildren(ISystemContext context)
#region Initialization String
private const string InitializationString =
"AQAAABgAAABodHRwOi8vdGVzdC5vcmcvVUEvRGF0YS//////BGCAAgEAAAABAB0AAABTY2FsYXJWYWx1" +
- "ZU9iamVjdFR5cGVJbnN0YW5jZQEBXAQBAVwEXAQAAAEAAAAAJAABAWAEHwAAADVgiQoCAAAAAQAQAAAA" +
+ "ZU9iamVjdFR5cGVJbnN0YW5jZQEBXAQBAVwEXAQAAAEAAAAAJAABAWAEIgAAADVgiQoCAAAAAQAQAAAA" +
"U2ltdWxhdGlvbkFjdGl2ZQEBXQQDAAAAAEcAAABJZiB0cnVlIHRoZSBzZXJ2ZXIgd2lsbCBwcm9kdWNl" +
"IG5ldyB2YWx1ZXMgZm9yIGVhY2ggbW9uaXRvcmVkIHZhcmlhYmxlLgAuAERdBAAAAAH/////AQH/////" +
"AAAAAARhggoEAAAAAQAOAAAAR2VuZXJhdGVWYWx1ZXMBAV4EAC8BAfkDXgQAAAEB/////wEAAAAXYKkK" +
@@ -4673,7 +4673,10 @@ protected override void InitializeOptionalChildren(ISystemContext context)
"Z2VyVmFsdWUBAbUEAC8AP7UEAAAAHP////8BAf////8AAAAAFWCJCgIAAAABAAsAAABWZWN0b3JWYWx1" +
"ZQEBtgQALwEBYQe2BAAAAQFgB/////8BAf////8DAAAAFWCJCgIAAAABAAEAAABYAQG3BAAuAES3BAAA" +
"AAv/////AQH/////AAAAABVgiQoCAAAAAQABAAAAWQEBuAQALgBEuAQAAAAL/////wEB/////wAAAAAV" +
- "YIkKAgAAAAEAAQAAAFoBAbkEAC4ARLkEAAAAC/////8BAf////8AAAAA";
+ "YIkKAgAAAAEAAQAAAFoBAbkEAC4ARLkEAAAAC/////8BAf////8AAAAAFWCJCgIAAAABABAAAABWZWN0" +
+ "b3JVbmlvblZhbHVlAQH+DQAvAD/+DQAAAQEADv////8BAf////8AAAAAFWCJCgIAAAABAB0AAABWZWN0" +
+ "b3JXaXRoT3B0aW9uYWxGaWVsZHNWYWx1ZQEB/w0ALwA//w0AAAEBAQ7/////AQH/////AAAAABVgiQoC" +
+ "AAAAAQAUAAAATXVsdGlwbGVWZWN0b3JzVmFsdWUBAR4OAC8APx4OAAABAR8O/////wEB/////wAAAAA=";
#endregion
#endif
#endregion
@@ -5210,6 +5213,63 @@ public VectorVariableState VectorValue
m_vectorValue = value;
}
}
+
+ ///
+ public BaseDataVariableState VectorUnionValue
+ {
+ get
+ {
+ return m_vectorUnionValue;
+ }
+
+ set
+ {
+ if (!Object.ReferenceEquals(m_vectorUnionValue, value))
+ {
+ ChangeMasks |= NodeStateChangeMasks.Children;
+ }
+
+ m_vectorUnionValue = value;
+ }
+ }
+
+ ///
+ public BaseDataVariableState VectorWithOptionalFieldsValue
+ {
+ get
+ {
+ return m_vectorWithOptionalFieldsValue;
+ }
+
+ set
+ {
+ if (!Object.ReferenceEquals(m_vectorWithOptionalFieldsValue, value))
+ {
+ ChangeMasks |= NodeStateChangeMasks.Children;
+ }
+
+ m_vectorWithOptionalFieldsValue = value;
+ }
+ }
+
+ ///
+ public BaseDataVariableState MultipleVectorsValue
+ {
+ get
+ {
+ return m_multipleVectorsValue;
+ }
+
+ set
+ {
+ if (!Object.ReferenceEquals(m_multipleVectorsValue, value))
+ {
+ ChangeMasks |= NodeStateChangeMasks.Children;
+ }
+
+ m_multipleVectorsValue = value;
+ }
+ }
#endregion
#region Overridden Methods
@@ -5358,6 +5418,21 @@ public override void GetChildren(
children.Add(m_vectorValue);
}
+ if (m_vectorUnionValue != null)
+ {
+ children.Add(m_vectorUnionValue);
+ }
+
+ if (m_vectorWithOptionalFieldsValue != null)
+ {
+ children.Add(m_vectorWithOptionalFieldsValue);
+ }
+
+ if (m_multipleVectorsValue != null)
+ {
+ children.Add(m_multipleVectorsValue);
+ }
+
base.GetChildren(context, children);
}
@@ -5964,6 +6039,69 @@ protected override BaseInstanceState FindChild(
instance = VectorValue;
break;
}
+
+ case TestData.BrowseNames.VectorUnionValue:
+ {
+ if (createOrReplace)
+ {
+ if (VectorUnionValue == null)
+ {
+ if (replacement == null)
+ {
+ VectorUnionValue = new BaseDataVariableState(this);
+ }
+ else
+ {
+ VectorUnionValue = (BaseDataVariableState)replacement;
+ }
+ }
+ }
+
+ instance = VectorUnionValue;
+ break;
+ }
+
+ case TestData.BrowseNames.VectorWithOptionalFieldsValue:
+ {
+ if (createOrReplace)
+ {
+ if (VectorWithOptionalFieldsValue == null)
+ {
+ if (replacement == null)
+ {
+ VectorWithOptionalFieldsValue = new BaseDataVariableState(this);
+ }
+ else
+ {
+ VectorWithOptionalFieldsValue = (BaseDataVariableState)replacement;
+ }
+ }
+ }
+
+ instance = VectorWithOptionalFieldsValue;
+ break;
+ }
+
+ case TestData.BrowseNames.MultipleVectorsValue:
+ {
+ if (createOrReplace)
+ {
+ if (MultipleVectorsValue == null)
+ {
+ if (replacement == null)
+ {
+ MultipleVectorsValue = new BaseDataVariableState(this);
+ }
+ else
+ {
+ MultipleVectorsValue = (BaseDataVariableState)replacement;
+ }
+ }
+ }
+
+ instance = MultipleVectorsValue;
+ break;
+ }
}
if (instance != null)
@@ -6004,6 +6142,9 @@ protected override BaseInstanceState FindChild(
private BaseDataVariableState m_integerValue;
private BaseDataVariableState m_uIntegerValue;
private VectorVariableState m_vectorValue;
+ private BaseDataVariableState m_vectorUnionValue;
+ private BaseDataVariableState m_vectorWithOptionalFieldsValue;
+ private BaseDataVariableState m_multipleVectorsValue;
#endregion
}
#endif
@@ -7543,7 +7684,7 @@ protected override void InitializeOptionalChildren(ISystemContext context)
#region Initialization String
private const string InitializationString =
"AQAAABgAAABodHRwOi8vdGVzdC5vcmcvVUEvRGF0YS//////BGCAAgEAAAABABwAAABBcnJheVZhbHVl" +
- "T2JqZWN0VHlwZUluc3RhbmNlAQGwBQEBsAWwBQAAAQAAAAAkAAEBtAUfAAAANWCJCgIAAAABABAAAABT" +
+ "T2JqZWN0VHlwZUluc3RhbmNlAQGwBQEBsAWwBQAAAQAAAAAkAAEBtAUiAAAANWCJCgIAAAABABAAAABT" +
"aW11bGF0aW9uQWN0aXZlAQGxBQMAAAAARwAAAElmIHRydWUgdGhlIHNlcnZlciB3aWxsIHByb2R1Y2Ug" +
"bmV3IHZhbHVlcyBmb3IgZWFjaCBtb25pdG9yZWQgdmFyaWFibGUuAC4ARLEFAAAAAf////8BAf////8A" +
"AAAABGGCCgQAAAABAA4AAABHZW5lcmF0ZVZhbHVlcwEBsgUALwEB+QOyBQAAAQH/////AQAAABdgqQoC" +
@@ -7612,7 +7753,10 @@ protected override void InitializeOptionalChildren(ISystemContext context)
"//8AAAAAF2CJCgIAAAABAAwAAABJbnRlZ2VyVmFsdWUBAQgGAC8APwgGAAAAGwEAAAABAAAAAAAAAAEB" +
"/////wAAAAAXYIkKAgAAAAEADQAAAFVJbnRlZ2VyVmFsdWUBAQkGAC8APwkGAAAAHAEAAAABAAAAAAAA" +
"AAEB/////wAAAAAXYIkKAgAAAAEACwAAAFZlY3RvclZhbHVlAQEKBgAvAD8KBgAAAQFgBwEAAAABAAAA" +
- "AAAAAAEB/////wAAAAA=";
+ "AAAAAAEB/////wAAAAAXYIkKAgAAAAEAEAAAAFZlY3RvclVuaW9uVmFsdWUBARgOAC8APxgOAAABAQAO" +
+ "AQAAAAEAAAAAAAAAAQH/////AAAAABdgiQoCAAAAAQAdAAAAVmVjdG9yV2l0aE9wdGlvbmFsRmllbGRz" +
+ "VmFsdWUBARkOAC8APxkOAAABAQEOAQAAAAEAAAAAAAAAAQH/////AAAAABdgiQoCAAAAAQAUAAAATXVs" +
+ "dGlwbGVWZWN0b3JzVmFsdWUBASsOAC8APysOAAABAR8OAQAAAAEAAAAAAAAAAQH/////AAAAAA==";
#endregion
#endif
#endregion
@@ -8149,6 +8293,63 @@ public BaseDataVariableState VectorValue
m_vectorValue = value;
}
}
+
+ ///
+ public BaseDataVariableState VectorUnionValue
+ {
+ get
+ {
+ return m_vectorUnionValue;
+ }
+
+ set
+ {
+ if (!Object.ReferenceEquals(m_vectorUnionValue, value))
+ {
+ ChangeMasks |= NodeStateChangeMasks.Children;
+ }
+
+ m_vectorUnionValue = value;
+ }
+ }
+
+ ///
+ public BaseDataVariableState VectorWithOptionalFieldsValue
+ {
+ get
+ {
+ return m_vectorWithOptionalFieldsValue;
+ }
+
+ set
+ {
+ if (!Object.ReferenceEquals(m_vectorWithOptionalFieldsValue, value))
+ {
+ ChangeMasks |= NodeStateChangeMasks.Children;
+ }
+
+ m_vectorWithOptionalFieldsValue = value;
+ }
+ }
+
+ ///
+ public BaseDataVariableState MultipleVectorsValue
+ {
+ get
+ {
+ return m_multipleVectorsValue;
+ }
+
+ set
+ {
+ if (!Object.ReferenceEquals(m_multipleVectorsValue, value))
+ {
+ ChangeMasks |= NodeStateChangeMasks.Children;
+ }
+
+ m_multipleVectorsValue = value;
+ }
+ }
#endregion
#region Overridden Methods
@@ -8297,6 +8498,21 @@ public override void GetChildren(
children.Add(m_vectorValue);
}
+ if (m_vectorUnionValue != null)
+ {
+ children.Add(m_vectorUnionValue);
+ }
+
+ if (m_vectorWithOptionalFieldsValue != null)
+ {
+ children.Add(m_vectorWithOptionalFieldsValue);
+ }
+
+ if (m_multipleVectorsValue != null)
+ {
+ children.Add(m_multipleVectorsValue);
+ }
+
base.GetChildren(context, children);
}
@@ -8903,6 +9119,69 @@ protected override BaseInstanceState FindChild(
instance = VectorValue;
break;
}
+
+ case TestData.BrowseNames.VectorUnionValue:
+ {
+ if (createOrReplace)
+ {
+ if (VectorUnionValue == null)
+ {
+ if (replacement == null)
+ {
+ VectorUnionValue = new BaseDataVariableState(this);
+ }
+ else
+ {
+ VectorUnionValue = (BaseDataVariableState)replacement;
+ }
+ }
+ }
+
+ instance = VectorUnionValue;
+ break;
+ }
+
+ case TestData.BrowseNames.VectorWithOptionalFieldsValue:
+ {
+ if (createOrReplace)
+ {
+ if (VectorWithOptionalFieldsValue == null)
+ {
+ if (replacement == null)
+ {
+ VectorWithOptionalFieldsValue = new BaseDataVariableState(this);
+ }
+ else
+ {
+ VectorWithOptionalFieldsValue = (BaseDataVariableState)replacement;
+ }
+ }
+ }
+
+ instance = VectorWithOptionalFieldsValue;
+ break;
+ }
+
+ case TestData.BrowseNames.MultipleVectorsValue:
+ {
+ if (createOrReplace)
+ {
+ if (MultipleVectorsValue == null)
+ {
+ if (replacement == null)
+ {
+ MultipleVectorsValue = new BaseDataVariableState(this);
+ }
+ else
+ {
+ MultipleVectorsValue = (BaseDataVariableState)replacement;
+ }
+ }
+ }
+
+ instance = MultipleVectorsValue;
+ break;
+ }
}
if (instance != null)
@@ -8943,6 +9222,9 @@ protected override BaseInstanceState FindChild(
private BaseDataVariableState
+
+ Variable_2
+
+ ns=1;i=3600
+
+
+ 1
+ VectorUnion
+
+
+ i=47
+
+
+ i=69
+
+ 3600
+
+
+ //xs:element[@name='VectorUnion']
+
+
+
+ i=12
+
+ -1
+ 1
+ 1
+
+
+ Variable_2
+
+ ns=1;i=3603
+
+
+ 1
+ VectorWithOptionalFields
+
+
+ i=47
+
+
+ i=69
+
+ 3603
+
+
+ //xs:element[@name='VectorWithOptionalFields']
+
+
+
+ i=12
+
+ -1
+ 1
+ 1
+
+
+ Variable_2
+
+ ns=1;i=3623
+
+
+ 1
+ MultipleVectors
+
+
+ i=47
+
+
+ i=69
+
+ 3623
+
+
+ //xs:element[@name='MultipleVectors']
+
+
+
+ i=12
+
+ -1
+ 1
+ 1
+
Variable_2
@@ -41278,6 +42366,81 @@ czplbGVtZW50Pg0KDQo8L3hzOnNjaGVtYT4=
+
+ Object_1
+
+ ns=1;i=3606
+
+
+ 0
+ Default JSON
+
+
+ i=76
+
+ 3606
+
+
+
+ i=38
+
+ true
+
+ ns=1;i=3584
+
+
+
+
+
+ Object_1
+
+ ns=1;i=3607
+
+
+ 0
+ Default JSON
+
+
+ i=76
+
+ 3607
+
+
+
+ i=38
+
+ true
+
+ ns=1;i=3585
+
+
+
+
+
+ Object_1
+
+ ns=1;i=3626
+
+
+ 0
+ Default JSON
+
+
+ i=76
+
+ 3626
+
+
+
+ i=38
+
+ true
+
+ ns=1;i=3615
+
+
+
+
Object_1
diff --git a/Applications/Quickstarts.Servers/TestData/TestData.Types.bsd b/Applications/Quickstarts.Servers/TestData/TestData.Types.bsd
index a2fc611e2..9b0f82f19 100644
--- a/Applications/Quickstarts.Servers/TestData/TestData.Types.bsd
+++ b/Applications/Quickstarts.Servers/TestData/TestData.Types.bsd
@@ -239,6 +239,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Applications/Quickstarts.Servers/TestData/TestData.Types.xsd b/Applications/Quickstarts.Servers/TestData/TestData.Types.xsd
index 5d6b17cf8..abf2afc54 100644
--- a/Applications/Quickstarts.Servers/TestData/TestData.Types.xsd
+++ b/Applications/Quickstarts.Servers/TestData/TestData.Types.xsd
@@ -7,7 +7,7 @@
>
-
+
@@ -235,6 +235,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Applications/Quickstarts.Servers/TestData/TestDataDesign.csv b/Applications/Quickstarts.Servers/TestData/TestDataDesign.csv
index d61bd615a..f21636eff 100644
--- a/Applications/Quickstarts.Servers/TestData/TestDataDesign.csv
+++ b/Applications/Quickstarts.Servers/TestData/TestDataDesign.csv
@@ -2579,3 +2579,51 @@ UserArrayValueDataType_Encoding_DefaultJson,3578,Object
Vector_Encoding_DefaultJson,3579,Object
WorkOrderStatusType_Encoding_DefaultJson,3580,Object
WorkOrderType_Encoding_DefaultJson,3581,Object
+ScalarValueObjectType_VectorUnionValue,3582,Variable
+ScalarValueObjectType_VectorWithOptionalFieldsValue,3583,Variable
+VectorUnion,3584,DataType
+VectorWithOptionalFields,3585,DataType
+Data_Static_Scalar_VectorUnionValue,3586,Variable
+Data_Static_Scalar_VectorWithOptionalFieldsValue,3587,Variable
+Data_Dynamic_Scalar_VectorUnionValue,3588,Variable
+Data_Dynamic_Scalar_VectorWithOptionalFieldsValue,3589,Variable
+VectorUnion_Encoding_DefaultBinary,3590,Object
+VectorWithOptionalFields_Encoding_DefaultBinary,3591,Object
+TestData_BinarySchema_VectorUnion,3592,Variable
+TestData_BinarySchema_VectorUnion_DataTypeVersion,3593,Variable
+TestData_BinarySchema_VectorUnion_DictionaryFragment,3594,Variable
+TestData_BinarySchema_VectorWithOptionalFields,3595,Variable
+TestData_BinarySchema_VectorWithOptionalFields_DataTypeVersion,3596,Variable
+TestData_BinarySchema_VectorWithOptionalFields_DictionaryFragment,3597,Variable
+VectorUnion_Encoding_DefaultXml,3598,Object
+VectorWithOptionalFields_Encoding_DefaultXml,3599,Object
+TestData_XmlSchema_VectorUnion,3600,Variable
+TestData_XmlSchema_VectorUnion_DataTypeVersion,3601,Variable
+TestData_XmlSchema_VectorUnion_DictionaryFragment,3602,Variable
+TestData_XmlSchema_VectorWithOptionalFields,3603,Variable
+TestData_XmlSchema_VectorWithOptionalFields_DataTypeVersion,3604,Variable
+TestData_XmlSchema_VectorWithOptionalFields_DictionaryFragment,3605,Variable
+VectorUnion_Encoding_DefaultJson,3606,Object
+VectorWithOptionalFields_Encoding_DefaultJson,3607,Object
+ArrayValueObjectType_VectorUnionValue,3608,Variable
+ArrayValueObjectType_VectorWithOptionalFieldsValue,3609,Variable
+Data_Static_Array_VectorUnionValue,3610,Variable
+Data_Static_Array_VectorWithOptionalFieldsValue,3611,Variable
+Data_Dynamic_Array_VectorUnionValue,3612,Variable
+Data_Dynamic_Array_VectorWithOptionalFieldsValue,3613,Variable
+ScalarValueObjectType_MultipleVectorsValue,3614,Variable
+MultipleVectors,3615,DataType
+Data_Static_Scalar_MultipleVectorsValue,3616,Variable
+Data_Dynamic_Scalar_MultipleVectorsValue,3617,Variable
+MultipleVectors_Encoding_DefaultBinary,3618,Object
+TestData_BinarySchema_MultipleVectors,3619,Variable
+TestData_BinarySchema_MultipleVectors_DataTypeVersion,3620,Variable
+TestData_BinarySchema_MultipleVectors_DictionaryFragment,3621,Variable
+MultipleVectors_Encoding_DefaultXml,3622,Object
+TestData_XmlSchema_MultipleVectors,3623,Variable
+TestData_XmlSchema_MultipleVectors_DataTypeVersion,3624,Variable
+TestData_XmlSchema_MultipleVectors_DictionaryFragment,3625,Variable
+MultipleVectors_Encoding_DefaultJson,3626,Object
+ArrayValueObjectType_MultipleVectorsValue,3627,Variable
+Data_Static_Array_MultipleVectorsValue,3628,Variable
+Data_Dynamic_Array_MultipleVectorsValue,3629,Variable
diff --git a/Applications/Quickstarts.Servers/TestData/TestDataDesign.xml b/Applications/Quickstarts.Servers/TestData/TestDataDesign.xml
index ed59e1d03..aa85572dd 100644
--- a/Applications/Quickstarts.Servers/TestData/TestDataDesign.xml
+++ b/Applications/Quickstarts.Servers/TestData/TestDataDesign.xml
@@ -258,6 +258,9 @@
+
+
+
@@ -417,6 +420,9 @@
+
+
+
@@ -643,7 +649,7 @@
- spec V1.03 released in 2015
+- 1.4.x.x --> spec V1.04 released in 2017
+- 1.5.x.x --> spec V1.05 released in 2022
+
+The OPC UA spec is committed to backward compatibility, so the 1.04 releases work also with 1.03 certified servers and clients.
+Once the UA working group releases the spec V1.05.03, the Nuget packages will be updated to be based on a 1.05 Nodeset (ETA Q1 2024), which can still be used to certify a V1.04 UA application.
+
+The next digits in the Nuget package version represent the API level and the build number.
+An API level is mapped to a dedicated branch for a release, e.g. [release/1.4.372](https://github.com/OPCFoundation/UA-.NETStandard/tree/release/1.4.372).
+Thus for hotfixes, a released API level can easily receive cherry picks or security updates from the main branch.
+An API level remains in itself consistent, that it should not receive breaking changes that would require code changes in applications.
+However, internal improvements or even small features which extend existing APIs that may not require application changes may be included in build updates.
+In fact the versioning doesn't map to the MAJOR.MINOR.PATCH semantic versioning. The build number corresponds to a mix of MINOR and PATCH, the API level corresponds to MAJOR (breaking changes). The spec version prefix however is guaranteed to be downwards compatible, and it should be possible to certify a UA Server that is built with a 1.5 library with a 1.4 certification test.
+
+Currently the released Nuget packages support a wide variety of .NET platforms:
+
+The following .NET versions are currently supported by the class libraries
+- .NET Standard 2.0
+- .NET Standard 2.1
+- .NET Framework 4.8 *
+- .NET 6.0 *
+- .NET 8.0 **
+
+The following platform is deprecated but can still be built and tested:
+- .NET Framework 4.6.2
+
+To reduce the ci build overhead and the number of tests to be run in Visual Studio, only the tagged versions (* and **) are part of a qualifying ci build to pass a pull request.
+All other platforms are only tested in weekly scheduled or manual ci builds.
+
+By default, in Visual Studio only the platforms tagged with (*) are tested. In order to test the other platforms in a command line window or in VS, there is a custom build variable defined to target a specific build. E.g. to target a .NETStandard2.0 build, the test runners are compiled with .NET 6.0 but the class libraries target only netstandard2.0, to force the use of that target.
+Another option is to test run such a custom target in a command window with a batch file [CustomTest.bat](../Tests/customtest.bat) which is provided to clean up, restore the project and to run the tests. To run the custom tests in Visual Studio a section in [target.props](../targets.props) needs to be uncommented and the target platform value must be set.
+
+```xml
+
+
+
+ netstandard2.0
+
+```
+
+Due to the limitations of the build system it is recommended to run the CustomTest batch file as well to force a clean build of the project for the test target.
+
+
+## Further information on the supported Nuget packages
+
+The OPCFoundation prefix is reserved and the assemblies and the Nuget packages are signed by the OPC Foundation.
+
+For improved source level debugging in Visual Studio, symbol packages are available on Nuget.org in the 'snupkg' format. A reference to the Nuget symbol server may have to be added in Visual Studio to enable the source level debug support.
+In addition packages compiled as Debug are available on Nuget.org with a '.Debug' extension to the package name.
+
+[OPCFoundation.NetStandard.Opc.Ua](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua/)
+
+This is a wrapper package to include all the available packages from this repository, except PubSub. It is recommended to rather include the individual packages as below to reduce the number of dependencies.
+
+[OPCFoundation.NetStandard.Opc.Ua.Core](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Core/)
+[OPCFoundation.NetStandard.Opc.Ua.Security.Certificates](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Security.Certificates/)
+
+Core and Certificates are required for Client and Server projects.
+
+[OPCFoundation.NetStandard.Opc.Ua.Configuration](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Configuration/)
+
+The configuration contains a helper class to configure a UA application from file or with a fluent API.
+
+[OPCFoundation.NetStandard.Opc.Ua.Server](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Server/)
+
+The server library is used to build a UA server.
+
+[OPCFoundation.NetStandard.Opc.Ua.Client](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Client/)
+[OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes/)
+
+The client is used to build a client. The complex type library extends the client with support for complex types.
+
+[OPCFoundation.NetStandard.Opc.Ua.Bindings.Https](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Bindings.Https/)
+
+The Https binding is an optional component to support UA over Https for 'opc.https' endpoints.
+
+[OPCFoundation.NetStandard.Opc.Ua.PubSub](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.PubSub/) (Beta)
+
+The PubSub library can be used to implement the publisher subscriber model.
+
+For the licenses please see the information in the packages.
diff --git a/Docs/README.md b/Docs/README.md
index 0630e1901..1f57280a1 100644
--- a/Docs/README.md
+++ b/Docs/README.md
@@ -5,6 +5,7 @@
Here is a list of available documentation for different topics:
UA Core stack related:
+* About [.NET platform](PlatformBuild.md) support, Nuget packages and versioning.
* How X.509 [Certificates](Certificates.md) are used in the certificate stores.
* Using the [Reverse Connect](ReverseConnect.md) for the UA-TCP transport.
* Support for the [TransferSubscriptions](TransferSubscription.md) service set.
diff --git a/Libraries/Opc.Ua.Client.ComplexTypes/ComplexTypeSystem.cs b/Libraries/Opc.Ua.Client.ComplexTypes/ComplexTypeSystem.cs
index b685528d1..dc3d64c85 100644
--- a/Libraries/Opc.Ua.Client.ComplexTypes/ComplexTypeSystem.cs
+++ b/Libraries/Opc.Ua.Client.ComplexTypes/ComplexTypeSystem.cs
@@ -29,8 +29,8 @@
using System;
using System.Collections.Generic;
-using System.ComponentModel;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using static Opc.Ua.Utils;
@@ -114,14 +114,14 @@ private void Initialize(
/// For servers without DataTypeDefinition support, all
/// custom types are loaded.
///
- public async Task LoadType(ExpandedNodeId nodeId, bool subTypes = false, bool throwOnError = false)
+ public async Task LoadType(ExpandedNodeId nodeId, bool subTypes = false, bool throwOnError = false, CancellationToken ct = default)
{
try
{
// add fast path, if no subTypes are requested
if (!subTypes)
{
- var systemType = GetSystemType(nodeId);
+ Type systemType = GetSystemType(nodeId);
if (systemType != null)
{
return systemType;
@@ -129,25 +129,25 @@ public async Task LoadType(ExpandedNodeId nodeId, bool subTypes = false, b
}
// cache the server type system
- m_complexTypeResolver.LoadDataTypes(DataTypeIds.BaseDataType, true);
- var subTypeNodes = m_complexTypeResolver.LoadDataTypes(nodeId, subTypes, true);
- var subTypeNodesWithoutKnownTypes = RemoveKnownTypes(subTypeNodes);
+ _ = await m_complexTypeResolver.LoadDataTypesAsync(DataTypeIds.BaseDataType, true, ct: ct).ConfigureAwait(false);
+ IList subTypeNodes = await m_complexTypeResolver.LoadDataTypesAsync(nodeId, subTypes, true, ct: ct).ConfigureAwait(false);
+ IList subTypeNodesWithoutKnownTypes = RemoveKnownTypes(subTypeNodes);
if (subTypeNodesWithoutKnownTypes.Count > 0)
{
IList serverEnumTypes = new List();
IList serverStructTypes = new List();
- foreach (var node in subTypeNodesWithoutKnownTypes)
+ foreach (INode node in subTypeNodesWithoutKnownTypes)
{
- AddEnumerationOrStructureType(node, serverEnumTypes, serverStructTypes);
+ await AddEnumerationOrStructureTypeAsync(node, serverEnumTypes, serverStructTypes, ct).ConfigureAwait(false);
}
// load server types
- if (DisableDataTypeDefinition || !LoadBaseDataTypes(serverEnumTypes, serverStructTypes))
+ if (DisableDataTypeDefinition || !await LoadBaseDataTypesAsync(serverEnumTypes, serverStructTypes, ct).ConfigureAwait(false))
{
if (!DisableDataTypeDictionary)
{
- await LoadDictionaryDataTypes(serverEnumTypes, serverStructTypes, false).ConfigureAwait(false);
+ await LoadDictionaryDataTypes(serverEnumTypes, serverStructTypes, false, ct).ConfigureAwait(false);
}
}
}
@@ -173,7 +173,7 @@ public async Task LoadType(ExpandedNodeId nodeId, bool subTypes = false, b
/// For servers without DataTypeDefinition support all
/// custom types are loaded.
///
- public async Task LoadNamespace(string nameSpace, bool throwOnError = false)
+ public async Task LoadNamespace(string nameSpace, bool throwOnError = false, CancellationToken ct = default)
{
try
{
@@ -183,20 +183,20 @@ public async Task LoadNamespace(string nameSpace, bool throwOnError = fals
throw new ServiceResultException($"Bad argument {nameSpace}. Namespace not found.");
}
ushort nameSpaceIndex = (ushort)index;
- m_complexTypeResolver.LoadDataTypes(DataTypeIds.BaseDataType, true);
- var serverEnumTypes = m_complexTypeResolver.LoadDataTypes(DataTypeIds.Enumeration);
- var serverStructTypes = m_complexTypeResolver.LoadDataTypes(DataTypeIds.Structure, true);
+ _ = await m_complexTypeResolver.LoadDataTypesAsync(DataTypeIds.BaseDataType, true, ct: ct).ConfigureAwait(false);
+ IList serverEnumTypes = await m_complexTypeResolver.LoadDataTypesAsync(DataTypeIds.Enumeration, ct: ct).ConfigureAwait(false);
+ IList serverStructTypes = await m_complexTypeResolver.LoadDataTypesAsync(DataTypeIds.Structure, true, ct: ct).ConfigureAwait(false);
// filter for namespace
serverEnumTypes = serverEnumTypes.Where(rd => rd.NodeId.NamespaceIndex == nameSpaceIndex).ToList();
serverStructTypes = serverStructTypes.Where(rd => rd.NodeId.NamespaceIndex == nameSpaceIndex).ToList();
// load types
- if (DisableDataTypeDefinition || !LoadBaseDataTypes(serverEnumTypes, serverStructTypes))
+ if (DisableDataTypeDefinition || !await LoadBaseDataTypesAsync(serverEnumTypes, serverStructTypes, ct).ConfigureAwait(false))
{
if (DisableDataTypeDictionary)
{
return false;
}
- return await LoadDictionaryDataTypes(serverEnumTypes, serverStructTypes, false).ConfigureAwait(false);
+ return await LoadDictionaryDataTypes(serverEnumTypes, serverStructTypes, false, ct).ConfigureAwait(false);
}
return true;
}
@@ -228,21 +228,22 @@ public async Task LoadNamespace(string nameSpace, bool throwOnError = fals
/// - Create all structured types from the dictionaries using the converted DataTypeDefinion attribute..
///
/// true if all DataTypes were loaded.
- public async Task Load(bool onlyEnumTypes = false, bool throwOnError = false)
+ public async Task Load(bool onlyEnumTypes = false, bool throwOnError = false, CancellationToken ct = default)
{
try
{
// load server types in cache
- m_complexTypeResolver.LoadDataTypes(DataTypeIds.BaseDataType, true);
- IList serverEnumTypes = m_complexTypeResolver.LoadDataTypes(DataTypeIds.Enumeration);
- IList serverStructTypes = onlyEnumTypes ? new List() : m_complexTypeResolver.LoadDataTypes(DataTypeIds.Structure, true);
- if (DisableDataTypeDefinition || !LoadBaseDataTypes(serverEnumTypes, serverStructTypes))
+ await m_complexTypeResolver.LoadDataTypesAsync(DataTypeIds.BaseDataType, true, ct: ct).ConfigureAwait(false);
+ IList serverEnumTypes = await m_complexTypeResolver.LoadDataTypesAsync(DataTypeIds.Enumeration, ct: ct).ConfigureAwait(false);
+ IList serverStructTypes = onlyEnumTypes ? new List() :
+ await m_complexTypeResolver.LoadDataTypesAsync(DataTypeIds.Structure, true, ct: ct).ConfigureAwait(false);
+ if (DisableDataTypeDefinition || !await LoadBaseDataTypesAsync(serverEnumTypes, serverStructTypes, ct).ConfigureAwait(false))
{
if (DisableDataTypeDictionary)
{
return false;
}
- return await LoadDictionaryDataTypes(serverEnumTypes, serverStructTypes, true).ConfigureAwait(false);
+ return await LoadDictionaryDataTypes(serverEnumTypes, serverStructTypes, true, ct).ConfigureAwait(false);
}
return true;
}
@@ -298,7 +299,7 @@ void CollectAllDataTypeDefinitions(NodeId nodeId, NodeIdDictionary
+ /// Clear references in datatype cache.
+ ///
+ public void ClearDataTypeCache()
+ {
+ m_dataTypeDefinitionCache.Clear();
+ }
#endregion Public Members
#region Internal Properties
@@ -343,18 +351,19 @@ void CollectAllDataTypeDefinitions(NodeId nodeId, NodeIdDictionary LoadDictionaryDataTypes(
IList serverEnumTypes,
IList serverStructTypes,
- bool fullTypeList
+ bool fullTypeList,
+ CancellationToken ct = default
)
{
// build a type dictionary with all known new types
- var allEnumTypes = fullTypeList ? serverEnumTypes : m_complexTypeResolver.LoadDataTypes(DataTypeIds.Enumeration);
+ var allEnumTypes = fullTypeList ? serverEnumTypes : await m_complexTypeResolver.LoadDataTypesAsync(DataTypeIds.Enumeration, ct: ct).ConfigureAwait(false);
var typeDictionary = new Dictionary();
// strip known types from list
serverEnumTypes = RemoveKnownTypes(allEnumTypes);
// load the binary schema dictionaries from the server
- var typeSystem = await m_complexTypeResolver.LoadDataTypeSystem().ConfigureAwait(false);
+ Dictionary typeSystem = await m_complexTypeResolver.LoadDataTypeSystem(ct: ct).ConfigureAwait(false);
// sort dictionaries with import dependencies to the end of the list
var sortedTypeSystem = typeSystem.OrderBy(t => t.Value.TypeDictionary?.Import?.Length).ToList();
@@ -362,18 +371,18 @@ bool fullTypeList
bool allTypesLoaded = true;
// create custom types for all dictionaries
- foreach (var dictionaryId in sortedTypeSystem)
+ foreach (KeyValuePair dictionaryId in sortedTypeSystem)
{
try
{
- var dictionary = dictionaryId.Value;
+ DataDictionary dictionary = dictionaryId.Value;
if (dictionary.TypeDictionary == null ||
dictionary.TypeDictionary.Items == null)
{
continue;
}
- var targetDictionaryNamespace = dictionary.TypeDictionary.TargetNamespace;
- var targetNamespaceIndex = m_complexTypeResolver.NamespaceUris.GetIndex(targetDictionaryNamespace);
+ string targetDictionaryNamespace = dictionary.TypeDictionary.TargetNamespace;
+ int targetNamespaceIndex = m_complexTypeResolver.NamespaceUris.GetIndex(targetDictionaryNamespace);
var structureList = new List();
var enumList = new List();
@@ -382,13 +391,13 @@ bool fullTypeList
SplitAndSortDictionary(dictionary, structureList, enumList);
// create assembly for all types in the same module
- var complexTypeBuilder = m_complexTypeBuilderFactory.Create(
+ IComplexTypeBuilder complexTypeBuilder = m_complexTypeBuilderFactory.Create(
targetDictionaryNamespace,
targetNamespaceIndex,
dictionary.Name);
// Add all unknown enumeration types in dictionary
- AddEnumTypes(complexTypeBuilder, typeDictionary, enumList, allEnumTypes, serverEnumTypes);
+ await AddEnumTypesAsync(complexTypeBuilder, typeDictionary, enumList, allEnumTypes, serverEnumTypes, ct).ConfigureAwait(false);
// handle structures
int loopCounter = 0;
@@ -401,7 +410,7 @@ bool fullTypeList
lastStructureCount = structureList.Count;
var retryStructureList = new List();
// build structured types
- foreach (var item in structureList)
+ foreach (Schema.Binary.TypeDescription item in structureList)
{
if (item is Schema.Binary.StructuredType structuredObject)
{
@@ -413,16 +422,10 @@ bool fullTypeList
}
// find the data type node and the binary encoding id
- ExpandedNodeId typeId;
- ExpandedNodeId binaryEncodingId;
- DataTypeNode dataTypeNode;
- bool newTypeDescription = m_complexTypeResolver.BrowseTypeIdsForDictionaryComponent(
- nodeId,
- out typeId,
- out binaryEncodingId,
- out dataTypeNode);
-
- if (!newTypeDescription)
+ (ExpandedNodeId typeId, ExpandedNodeId binaryEncodingId, DataTypeNode dataTypeNode) =
+ await m_complexTypeResolver.BrowseTypeIdsForDictionaryComponentAsync(nodeId, ct).ConfigureAwait(false);
+
+ if (dataTypeNode == null)
{
Utils.LogError(TraceMasks.Error, "Skip the type definition of {0} because the data type node was not found.", item.Name);
continue;
@@ -430,7 +433,7 @@ bool fullTypeList
if (GetSystemType(typeId) != null)
{
- var qName = structuredObject.QName ?? new XmlQualifiedName(structuredObject.Name, targetDictionaryNamespace);
+ XmlQualifiedName qName = structuredObject.QName ?? new XmlQualifiedName(structuredObject.Name, targetDictionaryNamespace);
typeDictionary[qName] = ExpandedNodeId.ToNodeId(typeId, m_complexTypeResolver.NamespaceUris);
Utils.LogInfo("Skip the type definition of {0} because the type already exists.", item.Name);
continue;
@@ -469,20 +472,22 @@ bool fullTypeList
Type complexType = null;
if (structureDefinition != null)
{
- var encodingIds = m_complexTypeResolver.BrowseForEncodings(typeId, m_supportedEncodings,
- out binaryEncodingId, out ExpandedNodeId xmlEncodingId);
+ IList encodingIds;
+ ExpandedNodeId xmlEncodingId;
+ (encodingIds, binaryEncodingId, xmlEncodingId) = await m_complexTypeResolver.BrowseForEncodingsAsync(
+ typeId, m_supportedEncodings, ct).ConfigureAwait(false);
try
{
// build the actual .NET structured type in assembly
- complexType = AddStructuredType(
+ (complexType, missingTypeIds) = await AddStructuredTypeAsync(
complexTypeBuilder,
structureDefinition,
dataTypeNode.BrowseName,
typeId,
binaryEncodingId,
xmlEncodingId,
- out missingTypeIds
- );
+ ct
+ ).ConfigureAwait(false);
}
catch (DataTypeNotSupportedException typeNotSupportedException)
{
@@ -500,7 +505,7 @@ out missingTypeIds
AddEncodeableType(encodingId, complexType);
}
AddEncodeableType(typeId, complexType);
- var qName = structuredObject.QName ?? new XmlQualifiedName(structuredObject.Name, targetDictionaryNamespace);
+ XmlQualifiedName qName = structuredObject.QName ?? new XmlQualifiedName(structuredObject.Name, targetDictionaryNamespace);
typeDictionary[qName] = ExpandedNodeId.ToNodeId(typeId, m_complexTypeResolver.NamespaceUris);
}
}
@@ -529,15 +534,16 @@ out missingTypeIds
/// Load all custom types with DataTypeDefinition into the type factory.
///
/// true if all types were loaded, false otherwise
- private bool LoadBaseDataTypes(
+ private async Task LoadBaseDataTypesAsync(
IList serverEnumTypes,
- IList serverStructTypes
+ IList serverStructTypes,
+ CancellationToken ct = default
)
{
- bool repeatDataTypeLoad = false;
IList enumTypesToDoList = new List();
IList structTypesToDoList = new List();
+ bool repeatDataTypeLoad;
do
{
// strip known types
@@ -547,19 +553,19 @@ IList serverStructTypes
repeatDataTypeLoad = false;
try
{
- enumTypesToDoList = LoadBaseEnumDataTypes(serverEnumTypes);
- structTypesToDoList = LoadBaseStructureDataTypes(serverStructTypes);
+ enumTypesToDoList = await LoadBaseEnumDataTypesAsync(serverEnumTypes, ct).ConfigureAwait(false);
+ structTypesToDoList = await LoadBaseStructureDataTypesAsync(serverStructTypes, ct).ConfigureAwait(false);
}
catch (DataTypeNotFoundException dtnfex)
{
Utils.LogWarning(dtnfex.Message);
- foreach (var nodeId in dtnfex.NodeIds)
+ foreach (ExpandedNodeId nodeId in dtnfex.NodeIds)
{
// add missing types to list
- var dataTypeNode = m_complexTypeResolver.Find(nodeId);
+ var dataTypeNode = await m_complexTypeResolver.FindAsync(nodeId, ct).ConfigureAwait(false);
if (dataTypeNode != null)
{
- AddEnumerationOrStructureType(dataTypeNode, serverEnumTypes, serverStructTypes);
+ await AddEnumerationOrStructureTypeAsync(dataTypeNode, serverEnumTypes, serverStructTypes, ct).ConfigureAwait(false);
repeatDataTypeLoad = true;
}
else
@@ -578,8 +584,9 @@ IList serverStructTypes
/// Load all custom types with DataTypeDefinition into the type factory.
///
/// true if all types were loaded, false otherwise
- private IList LoadBaseEnumDataTypes(
- IList serverEnumTypes
+ private async Task> LoadBaseEnumDataTypesAsync(
+ IList serverEnumTypes,
+ CancellationToken ct = default
)
{
// strip known types
@@ -603,9 +610,9 @@ IList serverEnumTypes
targetNamespace,
(int)i);
}
- foreach (var enumType in enumTypes)
+ foreach (INode enumType in enumTypes)
{
- var newType = AddEnumType(complexTypeBuilder, enumType as DataTypeNode);
+ Type newType = await AddEnumTypeAsync(complexTypeBuilder, enumType as DataTypeNode, ct).ConfigureAwait(false);
if (newType != null)
{
// match namespace and add to type factory
@@ -627,8 +634,9 @@ IList serverEnumTypes
/// Load all structure custom types with DataTypeDefinition into the type factory.
///
/// true if all types were loaded, false otherwise
- private IList LoadBaseStructureDataTypes(
- IList serverStructTypes
+ private async Task> LoadBaseStructureDataTypesAsync(
+ IList serverStructTypes,
+ CancellationToken ct = default
)
{
// strip known types
@@ -639,11 +647,11 @@ IList serverStructTypes
bool retryAddStructType;
var structTypesToDoList = new List();
- var structTypesWorkList = serverStructTypes;
+ IList structTypesWorkList = serverStructTypes;
// allow the loader to cache the encodings
IList nodeIds = serverStructTypes.Select(n => n.NodeId).ToList();
- m_complexTypeResolver.BrowseForEncodings(nodeIds, m_supportedEncodings);
+ _ = await m_complexTypeResolver.BrowseForEncodingsAsync(nodeIds, m_supportedEncodings, ct).ConfigureAwait(false);
// create structured types for all namespaces
int loopCounter = 0;
@@ -673,40 +681,41 @@ IList serverStructTypes
continue;
}
- var structureDefinition = GetStructureDefinition(dataTypeNode);
+ StructureDefinition structureDefinition = GetStructureDefinition(dataTypeNode);
if (structureDefinition != null)
{
- var encodingIds = m_complexTypeResolver.BrowseForEncodings(structType.NodeId, m_supportedEncodings,
- out ExpandedNodeId binaryEncodingId, out ExpandedNodeId xmlEncodingId);
+ (IList encodingIds, ExpandedNodeId binaryEncodingId, ExpandedNodeId xmlEncodingId)
+ = await m_complexTypeResolver.BrowseForEncodingsAsync(structType.NodeId, m_supportedEncodings, ct).ConfigureAwait(false);
try
{
ExpandedNodeId typeId = NormalizeExpandedNodeId(structType.NodeId);
- newType = AddStructuredType(
+ ExpandedNodeIdCollection missingTypeIds;
+ (newType, missingTypeIds) = await AddStructuredTypeAsync(
complexTypeBuilder,
structureDefinition,
dataTypeNode.BrowseName,
typeId,
binaryEncodingId,
xmlEncodingId,
- out ExpandedNodeIdCollection missingTypeIds
- );
+ ct
+ ).ConfigureAwait(false);
if (missingTypeIds?.Count > 0)
{
var missingTypeIdsFromWorkList = new ExpandedNodeIdCollection();
- foreach (var missingTypeId in missingTypeIds)
+ foreach (ExpandedNodeId missingTypeId in missingTypeIds)
{
- var typeMatch = structTypesWorkList.FirstOrDefault(n => n.NodeId == missingTypeId);
+ INode typeMatch = structTypesWorkList.FirstOrDefault(n => n.NodeId == missingTypeId);
if (typeMatch == null)
{
missingTypeIdsFromWorkList.Add(missingTypeId);
}
}
- foreach (var id in missingTypeIdsFromWorkList)
+ foreach (ExpandedNodeId id in missingTypeIdsFromWorkList)
{
if (!structTypesToDoList.Where(n => n.NodeId == id).Any())
{
- structTypesToDoList.Add(m_complexTypeResolver.Find(id));
+ structTypesToDoList.Add(await m_complexTypeResolver.FindAsync(id, ct).ConfigureAwait(false));
}
retryAddStructType = true;
}
@@ -724,7 +733,7 @@ out ExpandedNodeIdCollection missingTypeIds
if (newType != null)
{
- foreach (var encodingId in encodingIds)
+ foreach (NodeId encodingId in encodingIds)
{
AddEncodeableType(encodingId, newType);
}
@@ -778,7 +787,7 @@ private StructureDefinition GetStructureDefinition(DataTypeNode dataTypeNode)
return null;
}
// Validate the structure according to Part3, Table 36
- foreach (var field in structureDefinition.Fields)
+ foreach (StructureField field in structureDefinition.Fields)
{
// validate if the DataTypeDefinition is correctly
// filled out, some servers don't do it yet...
@@ -814,12 +823,12 @@ private ExpandedNodeId NormalizeExpandedNodeId(ExpandedNodeId expandedNodeId)
///
/// Add data type to enumeration or structure base type list depending on supertype.
///
- private void AddEnumerationOrStructureType(INode dataTypeNode, IList serverEnumTypes, IList serverStructTypes)
+ private async Task AddEnumerationOrStructureTypeAsync(INode dataTypeNode, IList serverEnumTypes, IList serverStructTypes, CancellationToken ct = default)
{
NodeId superType = ExpandedNodeId.ToNodeId(dataTypeNode.NodeId, m_complexTypeResolver.NamespaceUris);
while (true)
{
- superType = m_complexTypeResolver.FindSuperType(superType);
+ superType = await m_complexTypeResolver.FindSuperTypeAsync(superType, ct).ConfigureAwait(false);
if (superType.IsNullNodeId)
{
throw new ServiceResultException(StatusCodes.BadNodeIdInvalid, $"SuperType for {dataTypeNode.NodeId} not found.");
@@ -865,14 +874,15 @@ private Type GetSystemType(ExpandedNodeId nodeId)
///
/// Add an enum type defined in a binary schema dictionary.
///
- private void AddEnumTypes(
+ private async Task AddEnumTypesAsync(
IComplexTypeBuilder complexTypeBuilder,
Dictionary typeDictionary,
IList enumList,
IList allEnumerationTypes,
- IList enumerationTypes)
+ IList enumerationTypes,
+ CancellationToken ct = default)
{
- foreach (var item in enumList)
+ foreach (Schema.Binary.TypeDescription item in enumList)
{
Type newType = null;
DataTypeNode enumDescription = null;
@@ -899,8 +909,8 @@ private void AddEnumTypes(
if (newType == null)
{
// 2. use node cache
- var dataTypeNode = m_complexTypeResolver.Find(enumType.NodeId) as DataTypeNode;
- newType = AddEnumType(complexTypeBuilder, dataTypeNode);
+ var dataTypeNode = await m_complexTypeResolver.FindAsync(enumType.NodeId, ct).ConfigureAwait(false) as DataTypeNode;
+ newType = await AddEnumTypeAsync(complexTypeBuilder, dataTypeNode, ct).ConfigureAwait(false);
}
}
else
@@ -933,7 +943,7 @@ private void AddEncodeableType(ExpandedNodeId nodeId, Type type)
{
return;
}
- var internalNodeId = NormalizeExpandedNodeId(nodeId);
+ ExpandedNodeId internalNodeId = NormalizeExpandedNodeId(nodeId);
Utils.LogDebug("Adding Type {0} as: {1}", type.FullName, internalNodeId);
m_complexTypeResolver.Factory.AddEncodeableType(internalNodeId, type);
}
@@ -941,9 +951,10 @@ private void AddEncodeableType(ExpandedNodeId nodeId, Type type)
///
/// Add an enum type defined in a DataType node.
///
- private Type AddEnumType(
+ private async Task AddEnumTypeAsync(
IComplexTypeBuilder complexTypeBuilder,
- DataTypeNode enumTypeNode
+ DataTypeNode enumTypeNode,
+ CancellationToken ct = default
)
{
Type newType = null;
@@ -956,7 +967,7 @@ DataTypeNode enumTypeNode
!(enumTypeNode.DataTypeDefinition?.Body is EnumDefinition enumDefinition))
{
// browse for EnumFields or EnumStrings property
- object enumTypeArray = m_complexTypeResolver.GetEnumTypeArray(enumTypeNode.NodeId);
+ object enumTypeArray = await m_complexTypeResolver.GetEnumTypeArrayAsync(enumTypeNode.NodeId, ct).ConfigureAwait(false);
if (enumTypeArray is ExtensionObject[] extensionObject)
{
// 2. use EnumValues
@@ -988,18 +999,18 @@ DataTypeNode enumTypeNode
///
/// Add structured type to assembly with StructureDefinition.
///
- private Type AddStructuredType(
+ private async Task<(Type structureType, ExpandedNodeIdCollection missingTypes)> AddStructuredTypeAsync(
IComplexTypeBuilder complexTypeBuilder,
StructureDefinition structureDefinition,
QualifiedName typeName,
ExpandedNodeId complexTypeId,
ExpandedNodeId binaryEncodingId,
ExpandedNodeId xmlEncodingId,
- out ExpandedNodeIdCollection missingTypes
+ CancellationToken ct = default
)
{
// init missing type list
- missingTypes = null;
+ ExpandedNodeIdCollection missingTypes = null;
var localDataTypeId = ExpandedNodeId.ToNodeId(complexTypeId, m_complexTypeResolver.NamespaceUris);
bool allowSubTypes = IsAllowSubTypes(structureDefinition);
@@ -1008,7 +1019,7 @@ out ExpandedNodeIdCollection missingTypes
var typeList = new List();
foreach (StructureField field in structureDefinition.Fields)
{
- Type newType = GetFieldType(field, allowSubTypes);
+ Type newType = await GetFieldTypeAsync(field, allowSubTypes, ct).ConfigureAwait(false);
if (newType == null &&
!IsRecursiveDataType(localDataTypeId, field.DataType))
{
@@ -1029,13 +1040,13 @@ out ExpandedNodeIdCollection missingTypes
if (missingTypes != null)
{
- return null;
+ return (null, missingTypes);
}
// Add StructureDefinition to cache
m_dataTypeDefinitionCache[localDataTypeId] = structureDefinition;
- var fieldBuilder = complexTypeBuilder.AddStructuredType(
+ IComplexTypeFieldBuilder fieldBuilder = complexTypeBuilder.AddStructuredType(
typeName,
structureDefinition
);
@@ -1043,7 +1054,7 @@ out ExpandedNodeIdCollection missingTypes
fieldBuilder.AddTypeIdAttribute(complexTypeId, binaryEncodingId, xmlEncodingId);
int order = 1;
- var typeListEnumerator = typeList.GetEnumerator();
+ List.Enumerator typeListEnumerator = typeList.GetEnumerator();
foreach (StructureField field in structureDefinition.Fields)
{
typeListEnumerator.MoveNext();
@@ -1051,7 +1062,7 @@ out ExpandedNodeIdCollection missingTypes
// check for recursive data type:
// field has the same data type as the parent structure
var nodeId = ExpandedNodeId.ToNodeId(complexTypeId, m_complexTypeResolver.NamespaceUris);
- var isRecursiveDataType = IsRecursiveDataType(nodeId, field.DataType);
+ bool isRecursiveDataType = IsRecursiveDataType(nodeId, field.DataType);
if (isRecursiveDataType)
{
fieldBuilder.AddField(field, fieldBuilder.GetStructureType(field.ValueRank), order);
@@ -1063,7 +1074,7 @@ out ExpandedNodeIdCollection missingTypes
order++;
}
- return fieldBuilder.CreateType();
+ return (fieldBuilder.CreateType(), missingTypes);
}
bool IsAllowSubTypes(StructureDefinition structureDefinition)
@@ -1077,9 +1088,9 @@ bool IsAllowSubTypes(StructureDefinition structureDefinition)
return false;
}
- private bool IsAbstractType(NodeId fieldDataType)
+ private async Task IsAbstractTypeAsync(NodeId fieldDataType, CancellationToken ct = default)
{
- var dataTypeNode = m_complexTypeResolver.Find(fieldDataType) as DataTypeNode;
+ var dataTypeNode = await m_complexTypeResolver.FindAsync(fieldDataType, ct).ConfigureAwait(false) as DataTypeNode;
return dataTypeNode?.IsAbstract == true;
}
@@ -1089,7 +1100,7 @@ private bool IsRecursiveDataType(NodeId structureDataType, NodeId fieldDataType)
///
/// Determine the type of a field in a StructureField definition.
///
- private Type GetFieldType(StructureField field, bool allowSubTypes)
+ private async Task GetFieldTypeAsync(StructureField field, bool allowSubTypes, CancellationToken ct = default)
{
if (field.ValueRank != ValueRanks.Scalar &&
field.ValueRank < ValueRanks.OneDimension)
@@ -1103,11 +1114,11 @@ private Type GetFieldType(StructureField field, bool allowSubTypes)
if (fieldType == null)
{
- var superType = GetBuiltInSuperType(field.DataType, allowSubTypes, field.IsOptional);
+ NodeId superType = await GetBuiltInSuperTypeAsync(field.DataType, allowSubTypes, field.IsOptional, ct).ConfigureAwait(false);
if (superType?.IsNullNodeId == false)
{
field.DataType = superType;
- return GetFieldType(field, allowSubTypes);
+ return await GetFieldTypeAsync(field, allowSubTypes, ct).ConfigureAwait(false);
}
return null;
}
@@ -1127,12 +1138,15 @@ private Type GetFieldType(StructureField field, bool allowSubTypes)
///
/// Find superType for a datatype.
///
- private NodeId GetBuiltInSuperType(NodeId dataType, bool allowSubTypes, bool isOptional)
+ private async Task GetBuiltInSuperTypeAsync(NodeId dataType, bool allowSubTypes, bool isOptional, CancellationToken ct = default)
{
+ const int MaxSuperTypes = 100;
+
+ int iterations = 0;
NodeId superType = dataType;
- while (true)
+ while (iterations++ < MaxSuperTypes)
{
- superType = m_complexTypeResolver.FindSuperType(superType);
+ superType = await m_complexTypeResolver.FindSuperTypeAsync(superType, ct).ConfigureAwait(false);
if (superType?.IsNullNodeId != false)
{
return null;
@@ -1156,7 +1170,7 @@ private NodeId GetBuiltInSuperType(NodeId dataType, bool allowSubTypes, bool isO
// in such case the encoding as ExtensionObject is undetermined and not specified
if ((dataType != DataTypeIds.Structure) &&
((allowSubTypes && !isOptional) || !allowSubTypes) &&
- IsAbstractType(dataType))
+ await IsAbstractTypeAsync(dataType, ct).ConfigureAwait(false))
{
throw new DataTypeNotSupportedException("Invalid definition of a abstract subtype of a structure.");
}
@@ -1167,10 +1181,21 @@ private NodeId GetBuiltInSuperType(NodeId dataType, bool allowSubTypes, bool isO
}
return null;
}
- break;
+ // end search if a valid BuiltInType is found. Treat type as opaque.
+ else if (superType.IdType == IdType.Numeric &&
+ (uint)superType.Identifier >= (uint)BuiltInType.Boolean &&
+ (uint)superType.Identifier <= (uint)BuiltInType.DiagnosticInfo)
+ {
+ return superType;
+ }
+ // no valid supertype found
+ else if (superType == DataTypeIds.BaseDataType)
+ {
+ break;
+ }
}
}
- return superType;
+ return null;
}
///
@@ -1184,11 +1209,11 @@ private void SplitAndSortDictionary(
List enumList
)
{
- foreach (var item in dictionary.TypeDictionary.Items)
+ foreach (Schema.Binary.TypeDescription item in dictionary.TypeDictionary.Items)
{
if (item is Schema.Binary.StructuredType structuredObject)
{
- var dependentFields = structuredObject.Field.Where(f => f.TypeName.Namespace == dictionary.TypeDictionary.TargetNamespace);
+ IEnumerable dependentFields = structuredObject.Field.Where(f => f.TypeName.Namespace == dictionary.TypeDictionary.TargetNamespace);
if (!dependentFields.Any())
{
structureList.Insert(0, structuredObject);
diff --git a/Libraries/Opc.Ua.Client.ComplexTypes/IComplexTypeResolver.cs b/Libraries/Opc.Ua.Client.ComplexTypes/IComplexTypeResolver.cs
index ef31ad695..293b92b55 100644
--- a/Libraries/Opc.Ua.Client.ComplexTypes/IComplexTypeResolver.cs
+++ b/Libraries/Opc.Ua.Client.ComplexTypes/IComplexTypeResolver.cs
@@ -2,7 +2,7 @@
* Copyright (c) 2005-2021 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
- *
+ *
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
@@ -11,7 +11,7 @@
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
- *
+ *
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
@@ -30,6 +30,7 @@
using System;
using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
namespace Opc.Ua.Client.ComplexTypes
@@ -53,7 +54,10 @@ public interface IComplexTypeResolver
/// Loads all dictionaries of the OPC binary or Xml schema type system.
///
/// The type system. Defaults to OPC Binary schema.
- Task> LoadDataTypeSystem(NodeId dataTypeSystem = null);
+ ///
+ Task> LoadDataTypeSystem(
+ NodeId dataTypeSystem = null,
+ CancellationToken ct = default);
///
/// Browse for the type and encoding id for a dictionary component.
@@ -64,20 +68,16 @@ public interface IComplexTypeResolver
/// and data type dictionary.
/// To find the typeId and encodingId for a dictionary type definition:
/// i) inverse browse the description to get the encodingid
- /// ii) from the description inverse browse for encoding
- /// to get the subtype typeid
- /// iii) load the DataType node
+ /// ii) from the description inverse browse for encoding
+ /// to get the subtype typeid
+ /// iii) load the DataType node
///
///
- ///
- ///
- ///
- /// true if successful, false otherwise
- bool BrowseTypeIdsForDictionaryComponent(
+ ///
+ /// type id, encoding id and data type node if successful, null otherwise
+ Task<(ExpandedNodeId typeId, ExpandedNodeId encodingId, DataTypeNode dataTypeNode)> BrowseTypeIdsForDictionaryComponentAsync(
ExpandedNodeId nodeId,
- out ExpandedNodeId typeId,
- out ExpandedNodeId encodingId,
- out DataTypeNode dataTypeNode);
+ CancellationToken ct = default);
///
/// Browse for the encodings of a datatype list.
@@ -85,38 +85,42 @@ bool BrowseTypeIdsForDictionaryComponent(
///
/// Is called to allow for caching of encoding information on the client.
///
- IList BrowseForEncodings(
+ Task> BrowseForEncodingsAsync(
IList nodeIds,
- string[] supportedEncodings);
-
+ string[] supportedEncodings,
+ CancellationToken ct = default);
+
///
/// Browse for the encodings of a type.
///
///
/// Browse for binary encoding of a structure datatype.
///
- IList BrowseForEncodings(
+ Task<(IList encodings, ExpandedNodeId binaryEncodingId, ExpandedNodeId xmlEncodingId)> BrowseForEncodingsAsync(
ExpandedNodeId nodeId,
string[] supportedEncodings,
- out ExpandedNodeId binaryEncodingId,
- out ExpandedNodeId xmlEncodingId);
+ CancellationToken ct = default);
///
/// Load all subTypes and optionally nested subtypes of a type definition.
/// Filter for all subtypes or only subtypes outside the default namespace.
///
- IList LoadDataTypes(
+ Task> LoadDataTypesAsync(
ExpandedNodeId dataType,
bool nestedSubTypes = false,
bool addRootNode = false,
- bool filterUATypes = true);
+ bool filterUATypes = true,
+ CancellationToken ct = default);
///
/// Finds a node in the node set.
///
/// The node identifier.
+ ///
/// Returns null if the node does not exist.
- INode Find(ExpandedNodeId nodeId);
+ Task FindAsync(
+ ExpandedNodeId nodeId,
+ CancellationToken ct = default);
///
/// Reads the enum type array of a enum type definition node.
@@ -126,19 +130,21 @@ IList LoadDataTypes(
/// reference of the enum type NodeId
///
/// The enum type nodeId which has an enum array in the property.
+ ///
///
/// The value of the nodeId, which can be an array of
/// or of .
- /// null if the enum type array does not exist.
+ /// null if the enum type array does not exist.
///
- object GetEnumTypeArray(ExpandedNodeId nodeId);
+ Task GetEnumTypeArrayAsync(ExpandedNodeId nodeId, CancellationToken ct = default);
///
/// Returns the immediate supertype for the type.
///
/// The type identifier.
+ ///
/// The immediate supertype identifier for
- NodeId FindSuperType(NodeId typeId);
+ Task FindSuperTypeAsync(NodeId typeId, CancellationToken ct = default);
}
}//namespace
diff --git a/Libraries/Opc.Ua.Client.ComplexTypes/TypeBuilder/AttributeExtensions.cs b/Libraries/Opc.Ua.Client.ComplexTypes/TypeBuilder/AttributeExtensions.cs
index 53ebf6d7b..c7f1bd493 100644
--- a/Libraries/Opc.Ua.Client.ComplexTypes/TypeBuilder/AttributeExtensions.cs
+++ b/Libraries/Opc.Ua.Client.ComplexTypes/TypeBuilder/AttributeExtensions.cs
@@ -282,7 +282,8 @@ private static BuiltInType GetBuiltInType(NodeId datatypeId)
// supertypes of numbers
case DataTypes.Integer:
case DataTypes.UInteger:
- case DataTypes.Number: return BuiltInType.Variant;
+ case DataTypes.Number:
+ case DataTypes.Decimal: return BuiltInType.Variant;
}
return TypeInfo.GetBuiltInType(datatypeId);
diff --git a/Libraries/Opc.Ua.Client.ComplexTypes/TypeBuilder/ComplexTypeBuilder.cs b/Libraries/Opc.Ua.Client.ComplexTypes/TypeBuilder/ComplexTypeBuilder.cs
index 472b2e55e..455132113 100644
--- a/Libraries/Opc.Ua.Client.ComplexTypes/TypeBuilder/ComplexTypeBuilder.cs
+++ b/Libraries/Opc.Ua.Client.ComplexTypes/TypeBuilder/ComplexTypeBuilder.cs
@@ -117,7 +117,7 @@ public IComplexTypeFieldBuilder AddStructuredType(
}
var structureBuilder = m_moduleBuilder.DefineType(
GetFullQualifiedTypeName(name),
- TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable,
+ TypeAttributes.Public | TypeAttributes.Class,
baseType);
structureBuilder.DataContractAttribute(m_targetNamespace);
structureBuilder.StructureDefinitionAttribute(structureDefinition);
diff --git a/Libraries/Opc.Ua.Client.ComplexTypes/TypeResolver/NodeCacheResolver.cs b/Libraries/Opc.Ua.Client.ComplexTypes/TypeResolver/NodeCacheResolver.cs
index 05472f5ec..72750c96f 100644
--- a/Libraries/Opc.Ua.Client.ComplexTypes/TypeResolver/NodeCacheResolver.cs
+++ b/Libraries/Opc.Ua.Client.ComplexTypes/TypeResolver/NodeCacheResolver.cs
@@ -2,7 +2,7 @@
* Copyright (c) 2005-2021 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
- *
+ *
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
@@ -11,7 +11,7 @@
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
- *
+ *
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
@@ -32,6 +32,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
namespace Opc.Ua.Client.ComplexTypes
@@ -65,106 +66,107 @@ private void Initialize(ISession session)
public IEncodeableFactory Factory => m_session.Factory;
///
- public Task> LoadDataTypeSystem(NodeId dataTypeSystem = null)
+ public Task> LoadDataTypeSystem(
+ NodeId dataTypeSystem = null,
+ CancellationToken ct = default)
{
- return m_session.LoadDataTypeSystem(dataTypeSystem);
+ return m_session.LoadDataTypeSystem(dataTypeSystem, ct);
}
///
- public IList BrowseForEncodings(
+ public async Task> BrowseForEncodingsAsync(
IList nodeIds,
- string[] supportedEncodings
- )
+ string[] supportedEncodings,
+ CancellationToken ct = default)
{
// cache type encodings
- var encodings = m_session.NodeCache.FindReferences(
+ IList encodings = await m_session.NodeCache.FindReferencesAsync(
nodeIds,
new NodeIdCollection { ReferenceTypeIds.HasEncoding },
false,
- false
- );
+ false,
+ ct).ConfigureAwait(false);
// cache dictionary descriptions
nodeIds = encodings.Select(r => r.NodeId).ToList();
- var descriptions = m_session.NodeCache.FindReferences(
+ IList descriptions = await m_session.NodeCache.FindReferencesAsync(
nodeIds,
new NodeIdCollection { ReferenceTypeIds.HasDescription },
false,
- false
- );
+ false,
+ ct).ConfigureAwait(false);
return encodings.Where(r => supportedEncodings.Contains(r.BrowseName.Name))
.Select(r => ExpandedNodeId.ToNodeId(r.NodeId, m_session.NamespaceUris)).ToList();
}
///
- public IList BrowseForEncodings(
+ public async Task<(IList encodings, ExpandedNodeId binaryEncodingId, ExpandedNodeId xmlEncodingId)> BrowseForEncodingsAsync(
ExpandedNodeId nodeId,
string[] supportedEncodings,
- out ExpandedNodeId binaryEncodingId,
- out ExpandedNodeId xmlEncodingId)
+ CancellationToken ct = default)
{
- var references = m_session.NodeCache.FindReferences(
- nodeId,
- ReferenceTypeIds.HasEncoding,
- false,
- false
- );
+ IList references = await m_session.NodeCache.FindReferencesAsync(
+ nodeId,
+ ReferenceTypeIds.HasEncoding,
+ false,
+ false,
+ ct).ConfigureAwait(false);
- binaryEncodingId = references.FirstOrDefault(r => r.BrowseName.Name == BrowseNames.DefaultBinary)?.NodeId;
+ ExpandedNodeId binaryEncodingId = references.FirstOrDefault(r => r.BrowseName.Name == BrowseNames.DefaultBinary)?.NodeId;
binaryEncodingId = NormalizeExpandedNodeId(binaryEncodingId);
- xmlEncodingId = references.FirstOrDefault(r => r.BrowseName.Name == BrowseNames.DefaultXml)?.NodeId;
+ ExpandedNodeId xmlEncodingId = references.FirstOrDefault(r => r.BrowseName.Name == BrowseNames.DefaultXml)?.NodeId;
xmlEncodingId = NormalizeExpandedNodeId(xmlEncodingId);
- return references.Where(r => supportedEncodings.Contains(r.BrowseName.Name))
- .Select(r => ExpandedNodeId.ToNodeId(r.NodeId, m_session.NamespaceUris)).ToList();
+ return (references
+ .Where(r => supportedEncodings.Contains(r.BrowseName.Name))
+ .Select(r => ExpandedNodeId.ToNodeId(r.NodeId, m_session.NamespaceUris))
+ .ToList(), binaryEncodingId, xmlEncodingId);
}
///
- public bool BrowseTypeIdsForDictionaryComponent(
+ public async Task<(ExpandedNodeId typeId, ExpandedNodeId encodingId, DataTypeNode dataTypeNode)> BrowseTypeIdsForDictionaryComponentAsync(
ExpandedNodeId nodeId,
- out ExpandedNodeId typeId,
- out ExpandedNodeId encodingId,
- out DataTypeNode dataTypeNode)
+ CancellationToken ct = default)
{
- typeId = ExpandedNodeId.Null;
- encodingId = ExpandedNodeId.Null;
- dataTypeNode = null;
+ ExpandedNodeId encodingId;
+ DataTypeNode dataTypeNode;
- var references = m_session.NodeCache.FindReferences(
+ IList references = await m_session.NodeCache.FindReferencesAsync(
nodeId,
ReferenceTypeIds.HasDescription,
true,
- false
- );
+ false,
+ ct).ConfigureAwait(false);
if (references.Count == 1)
{
encodingId = references[0].NodeId;
- references = m_session.NodeCache.FindReferences(
+ references = await m_session.NodeCache.FindReferencesAsync(
encodingId,
ReferenceTypeIds.HasEncoding,
true,
- false
- );
+ false,
+ ct).ConfigureAwait(false);
encodingId = NormalizeExpandedNodeId(encodingId);
if (references.Count == 1)
{
- typeId = references[0].NodeId;
+ ExpandedNodeId typeId = references[0].NodeId;
dataTypeNode = m_session.NodeCache.Find(typeId) as DataTypeNode;
typeId = NormalizeExpandedNodeId(typeId);
- return true;
+ return (typeId, encodingId, dataTypeNode);
}
}
- return false;
+ return (null, null, null);
}
///
- public IList LoadDataTypes(
+ public async Task> LoadDataTypesAsync(
ExpandedNodeId dataType,
bool nestedSubTypes = false,
bool addRootNode = false,
- bool filterUATypes = true)
+ bool filterUATypes = true,
+ CancellationToken ct = default)
{
var result = new List();
var nodesToBrowse = new ExpandedNodeIdCollection {
@@ -178,7 +180,7 @@ public IList LoadDataTypes(
if (addRootNode)
{
- var rootNode = m_session.NodeCache.Find(dataType);
+ INode rootNode = await m_session.NodeCache.FindAsync(dataType, ct).ConfigureAwait(false);
if (!(rootNode is DataTypeNode))
{
throw new ServiceResultException("Root Node is not a DataType node.");
@@ -188,11 +190,12 @@ public IList LoadDataTypes(
while (nodesToBrowse.Count > 0)
{
- var response = m_session.NodeCache.FindReferences(
+ IList response = await m_session.NodeCache.FindReferencesAsync(
nodesToBrowse,
new NodeIdCollection { ReferenceTypeIds.HasSubtype },
false,
- false);
+ false,
+ ct).ConfigureAwait(false);
var nextNodesToBrowse = new ExpandedNodeIdCollection();
if (nestedSubTypes)
@@ -221,35 +224,35 @@ public IList LoadDataTypes(
}
///
- public INode Find(ExpandedNodeId nodeId)
+ public Task FindAsync(ExpandedNodeId nodeId, CancellationToken ct)
{
- return m_session.NodeCache.Find(nodeId);
+ return m_session.NodeCache.FindAsync(nodeId, ct);
}
///
- public object GetEnumTypeArray(ExpandedNodeId nodeId)
+ public async Task GetEnumTypeArrayAsync(ExpandedNodeId nodeId, CancellationToken ct = default)
{
// find the property reference for the enum type
- var references = m_session.NodeCache.FindReferences(
+ IList references = await m_session.NodeCache.FindReferencesAsync(
nodeId,
ReferenceTypeIds.HasProperty,
false,
- false
- );
- var property = references.FirstOrDefault();
+ false,
+ ct).ConfigureAwait(false);
+ INode property = references.FirstOrDefault();
if (property != null)
{
// read the enum type array
- DataValue value = m_session.ReadValue(ExpandedNodeId.ToNodeId(property.NodeId, NamespaceUris));
+ DataValue value = await m_session.ReadValueAsync(ExpandedNodeId.ToNodeId(property.NodeId, NamespaceUris), ct).ConfigureAwait(false);
return value?.Value;
}
return null;
}
///
- public NodeId FindSuperType(NodeId typeId)
+ public Task FindSuperTypeAsync(NodeId typeId, CancellationToken ct = default)
{
- return m_session.NodeCache.FindSuperType(typeId);
+ return m_session.NodeCache.FindSuperTypeAsync(typeId, ct);
}
#endregion IComplexTypeResolver
diff --git a/Libraries/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs b/Libraries/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs
index c7f78e2cb..9b3da52ef 100644
--- a/Libraries/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs
+++ b/Libraries/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs
@@ -147,14 +147,14 @@ public override void Decode(IDecoder decoder)
}
///
- public override bool IsEqual(IEncodeable equalValue)
+ public override bool IsEqual(IEncodeable encodeable)
{
- if (Object.ReferenceEquals(this, equalValue))
+ if (Object.ReferenceEquals(this, encodeable))
{
return true;
}
- if (!(equalValue is UnionComplexType valueBaseType))
+ if (!(encodeable is UnionComplexType valueBaseType))
{
return false;
}
diff --git a/Libraries/Opc.Ua.Client/DataDictionary.cs b/Libraries/Opc.Ua.Client/DataDictionary.cs
index e6e024e2e..e1d407879 100644
--- a/Libraries/Opc.Ua.Client/DataDictionary.cs
+++ b/Libraries/Opc.Ua.Client/DataDictionary.cs
@@ -2,7 +2,7 @@
* Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
- *
+ *
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
@@ -11,7 +11,7 @@
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
- *
+ *
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
@@ -32,6 +32,7 @@
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
+using System.Threading;
using System.Threading.Tasks;
using Opc.Ua.Schema;
@@ -102,20 +103,20 @@ private void Initialize()
///
/// Loads the dictionary identified by the node id.
///
- public Task Load(INode dictionary)
+ public void Load(INode dictionary)
{
if (dictionary == null)
{
throw new ArgumentNullException(nameof(dictionary));
}
NodeId dictionaryId = ExpandedNodeId.ToNodeId(dictionary.NodeId, m_session.NamespaceUris);
- return Load(dictionaryId, dictionary.ToString());
+ Load(dictionaryId, dictionary.ToString());
}
///
/// Loads the dictionary identified by the node id.
///
- public async Task Load(NodeId dictionaryId, string name, byte[] schema = null, IDictionary imports = null)
+ public void Load(NodeId dictionaryId, string name, byte[] schema = null, IDictionary imports = null)
{
if (dictionaryId == null)
{
@@ -141,7 +142,7 @@ public async Task Load(NodeId dictionaryId, string name, byte[] schema = null, I
Array.Resize(ref schema, zeroTerminator);
}
- await Validate(schema, imports).ConfigureAwait(false);
+ Validate(schema, imports);
ReadDataTypes(dictionaryId);
@@ -225,7 +226,10 @@ private void ReadDataTypes(NodeId dictionaryId)
///
/// Reads the contents of multiple data dictionaries.
///
- public static async Task> ReadDictionaries(ISessionClientMethods session, IList dictionaryIds)
+ public static async Task> ReadDictionaries(
+ ISessionClientMethods session,
+ IList dictionaryIds,
+ CancellationToken ct = default)
{
ReadValueIdCollection itemsToRead = new ReadValueIdCollection();
foreach (var nodeId in dictionaryIds)
@@ -240,17 +244,28 @@ public static async Task> ReadDictionaries(ISessionC
itemsToRead.Add(itemToRead);
}
+#if CLIENT_ASYNC
// read values.
ReadResponse readResponse = await session.ReadAsync(
null,
0,
TimestampsToReturn.Neither,
itemsToRead,
- System.Threading.CancellationToken.None).ConfigureAwait(false);
+ ct).ConfigureAwait(false);
DataValueCollection values = readResponse.Results;
DiagnosticInfoCollection diagnosticInfos = readResponse.DiagnosticInfos;
-
+ ResponseHeader response = readResponse.ResponseHeader;
+#else
+ // read values.
+ ResponseHeader response = session.Read(
+ null,
+ 0,
+ TimestampsToReturn.Neither,
+ itemsToRead,
+ out DataValueCollection values,
+ out DiagnosticInfoCollection diagnosticInfos);
+#endif
ClientBase.ValidateResponse(values, itemsToRead);
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, itemsToRead);
@@ -262,7 +277,7 @@ public static async Task> ReadDictionaries(ISessionC
// check for error.
if (StatusCode.IsBad(values[ii].StatusCode))
{
- ServiceResult sr = ClientBase.GetResult(values[ii].StatusCode, 0, diagnosticInfos, readResponse.ResponseHeader);
+ ServiceResult sr = ClientBase.GetResult(values[ii].StatusCode, 0, diagnosticInfos, response);
throw new ServiceResultException(sr);
}
@@ -322,9 +337,9 @@ public byte[] ReadDictionary(NodeId dictionaryId)
///
/// The encoded dictionary to validate.
/// Throw if an error occurred.
- internal Task Validate(byte[] dictionary, bool throwOnError)
+ internal void Validate(byte[] dictionary, bool throwOnError)
{
- return Validate(dictionary, null, throwOnError);
+ Validate(dictionary, null, throwOnError);
}
///
@@ -333,7 +348,7 @@ internal Task Validate(byte[] dictionary, bool throwOnError)
/// The encoded dictionary to validate.
/// A table of imported namespace schemas.
/// Throw if an error occurred.
- internal async Task Validate(byte[] dictionary, IDictionary imports = null, bool throwOnError = false)
+ internal void Validate(byte[] dictionary, IDictionary imports = null, bool throwOnError = false)
{
MemoryStream istrm = new MemoryStream(dictionary);
@@ -362,7 +377,7 @@ internal async Task Validate(byte[] dictionary, IDictionary impo
var validator = new Schema.Binary.BinarySchemaValidator(imports);
try
{
- await validator.Validate(istrm).ConfigureAwait(false);
+ validator.Validate(istrm);
}
catch (Exception e)
{
@@ -377,7 +392,7 @@ internal async Task Validate(byte[] dictionary, IDictionary impo
TypeDictionary = validator.Dictionary;
}
}
- #endregion
+#endregion
#region Private Members
private ISession m_session;
diff --git a/Libraries/Opc.Ua.Client/DefaultSessionFactory.cs b/Libraries/Opc.Ua.Client/DefaultSessionFactory.cs
index 5f2788717..a498a8484 100644
--- a/Libraries/Opc.Ua.Client/DefaultSessionFactory.cs
+++ b/Libraries/Opc.Ua.Client/DefaultSessionFactory.cs
@@ -2,7 +2,7 @@
* Copyright (c) 2005-2022 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
- *
+ *
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
@@ -11,7 +11,7 @@
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
- *
+ *
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
@@ -38,7 +38,7 @@ namespace Opc.Ua.Client
///
/// Object that creates instances of an Opc.Ua.Client.Session object.
///
- public class DefaultSessionFactory : ISessionFactory
+ public class DefaultSessionFactory : ISessionFactory, ISessionInstantiator
{
///
/// The default instance of the factory.
@@ -54,7 +54,7 @@ protected DefaultSessionFactory()
#region ISessionFactory Members
///
- public async virtual Task CreateAsync(
+ public virtual Task CreateAsync(
ApplicationConfiguration configuration,
ConfiguredEndpoint endpoint,
bool updateBeforeConnect,
@@ -64,8 +64,7 @@ public async virtual Task CreateAsync(
IList preferredLocales,
CancellationToken ct = default)
{
- return await Session.Create(configuration, endpoint, updateBeforeConnect, false,
- sessionName, sessionTimeout, identity, preferredLocales).ConfigureAwait(false);
+ return CreateAsync(configuration, endpoint, updateBeforeConnect, false, sessionName, sessionTimeout, identity, preferredLocales, ct);
}
///
@@ -80,7 +79,7 @@ public async virtual Task CreateAsync(
IList preferredLocales,
CancellationToken ct = default)
{
- return await Session.Create(configuration, (ITransportWaitingConnection)null, endpoint,
+ return await Session.Create(this, configuration, (ITransportWaitingConnection)null, endpoint,
updateBeforeConnect, checkDomain, sessionName, sessionTimeout,
identity, preferredLocales, ct).ConfigureAwait(false);
}
@@ -98,7 +97,7 @@ public async virtual Task CreateAsync(
IList preferredLocales,
CancellationToken ct = default)
{
- return await Session.Create(configuration, connection, endpoint,
+ return await Session.Create(this, configuration, connection, endpoint,
updateBeforeConnect, checkDomain, sessionName, sessionTimeout,
identity, preferredLocales, ct
).ConfigureAwait(false);
@@ -166,7 +165,7 @@ public virtual ISession Create(
EndpointDescriptionCollection availableEndpoints = null,
StringCollection discoveryProfileUris = null)
{
- return Session.Create(configuration, channel, endpoint, clientCertificate, availableEndpoints, discoveryProfileUris);
+ return Session.Create(this, configuration, channel, endpoint, clientCertificate, availableEndpoints, discoveryProfileUris);
}
///
@@ -182,35 +181,58 @@ public virtual Task CreateChannelAsync(
}
///
- public virtual Task RecreateAsync(ISession sessionTemplate, CancellationToken ct = default)
+ public virtual async Task RecreateAsync(ISession sessionTemplate, CancellationToken ct = default)
{
if (!(sessionTemplate is Session template))
{
throw new ArgumentOutOfRangeException(nameof(sessionTemplate), "The ISession provided is not of a supported type.");
}
- return Task.FromResult((ISession)Session.Recreate(template));
+ return await Session.RecreateAsync(template, ct).ConfigureAwait(false);
}
///
- public virtual Task RecreateAsync(ISession sessionTemplate, ITransportWaitingConnection connection, CancellationToken ct = default)
+ public virtual async Task RecreateAsync(ISession sessionTemplate, ITransportWaitingConnection connection, CancellationToken ct = default)
{
if (!(sessionTemplate is Session template))
{
throw new ArgumentOutOfRangeException(nameof(sessionTemplate), "The ISession provided is not of a supported type");
}
- return Task.FromResult((ISession)Session.Recreate(template, connection));
+ return await Session.RecreateAsync(template, connection, ct).ConfigureAwait(false);
}
///
- public virtual Task RecreateAsync(ISession sessionTemplate, ITransportChannel transportChannel, CancellationToken ct = default)
+ public virtual async Task RecreateAsync(ISession sessionTemplate, ITransportChannel transportChannel, CancellationToken ct = default)
{
if (!(sessionTemplate is Session template))
{
throw new ArgumentOutOfRangeException(nameof(sessionTemplate), "The ISession provided is not of a supported type");
}
- return Task.FromResult((ISession)Session.Recreate(template, transportChannel));
+ return await Session.RecreateAsync(template, transportChannel, ct).ConfigureAwait(false);
+ }
+ #endregion
+
+ #region ISessionInstantiator Members
+ ///
+ public virtual Session Create(
+ ISessionChannel channel,
+ ApplicationConfiguration configuration,
+ ConfiguredEndpoint endpoint)
+ {
+ return new Session(channel, configuration, endpoint);
+ }
+
+ ///
+ public virtual Session Create(
+ ITransportChannel channel,
+ ApplicationConfiguration configuration,
+ ConfiguredEndpoint endpoint,
+ X509Certificate2 clientCertificate,
+ EndpointDescriptionCollection availableEndpoints = null,
+ StringCollection discoveryProfileUris = null)
+ {
+ return new Session(channel, configuration, endpoint, clientCertificate, availableEndpoints, discoveryProfileUris);
}
#endregion
}
diff --git a/Libraries/Opc.Ua.Client/INodeCache.cs b/Libraries/Opc.Ua.Client/INodeCache.cs
index b3c6e7301..d507a3607 100644
--- a/Libraries/Opc.Ua.Client/INodeCache.cs
+++ b/Libraries/Opc.Ua.Client/INodeCache.cs
@@ -2,7 +2,7 @@
* Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
- *
+ *
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
@@ -11,7 +11,7 @@
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
- *
+ *
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
@@ -28,6 +28,8 @@
* ======================================================================*/
using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
namespace Opc.Ua.Client
{
@@ -64,6 +66,44 @@ public interface INodeCache : INodeTable, ITypeTable
///
IList FetchNodes(IList nodeIds);
+#if (CLIENT_ASYNC)
+ ///
+ /// Finds a set of nodes in the nodeset,
+ /// fetches missing nodes from server.
+ ///
+ /// The node identifier.
+ ///
+ Task FindAsync(ExpandedNodeId nodeId, CancellationToken ct = default);
+
+ ///
+ /// Finds a set of nodes in the nodeset,
+ /// fetches missing nodes from server.
+ ///
+ /// The node identifier collection.
+ ///
+ Task> FindAsync(IList nodeIds, CancellationToken ct = default);
+
+ ///
+ /// Fetches a node from the server and updates the cache.
+ ///
+ /// Node id to fetch.
+ ///
+ Task FetchNodeAsync(ExpandedNodeId nodeId, CancellationToken ct = default);
+
+ ///
+ /// Fetches a node collection from the server and updates the cache.
+ ///
+ /// The node identifier collection.
+ ///
+ Task> FetchNodesAsync(IList nodeIds, CancellationToken ct = default);
+
+ ///
+ /// Adds the supertypes of the node to the cache.
+ ///
+ /// Node id to fetch.
+ ///
+ Task FetchSuperTypesAsync(ExpandedNodeId nodeId, CancellationToken ct = default);
+#endif
///
/// Adds the supertypes of the node to the cache.
///
@@ -79,6 +119,18 @@ public interface INodeCache : INodeTable, ITypeTable
///
IList FindReferences(IList nodeIds, IList referenceTypeIds, bool isInverse, bool includeSubtypes);
+#if (CLIENT_ASYNC)
+ ///
+ /// Returns the references of the specified node that meet the criteria specified.
+ ///
+ Task> FindReferencesAsync(ExpandedNodeId nodeId, NodeId referenceTypeId, bool isInverse, bool includeSubtypes, CancellationToken ct = default);
+
+ ///
+ /// Returns the references of the specified nodes that meet the criteria specified.
+ ///
+ Task> FindReferencesAsync(IList nodeIds, IList referenceTypeIds, bool isInverse, bool includeSubtypes, CancellationToken ct = default);
+#endif
+
///
/// Returns a display name for a node.
///
diff --git a/Libraries/Opc.Ua.Client/ISession.cs b/Libraries/Opc.Ua.Client/ISession.cs
index ff37758db..cd6c4cbff 100644
--- a/Libraries/Opc.Ua.Client/ISession.cs
+++ b/Libraries/Opc.Ua.Client/ISession.cs
@@ -2,7 +2,7 @@
* Copyright (c) 2005-2022 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
- *
+ *
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
@@ -11,7 +11,7 @@
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
- *
+ *
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
@@ -23,7 +23,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * The complete license agreement can be found here:
+ * The complete license agreement can be found here:
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/
@@ -63,7 +63,7 @@ namespace Opc.Ua.Client
///
/// Manages a session with a server.
///
- public interface ISession : ISessionClient, IDisposable
+ public interface ISession : ISessionClient
{
#region Events
///
@@ -99,7 +99,7 @@ public interface ISession : ISessionClient, IDisposable
event PublishErrorEventHandler PublishError;
///
- /// Raised when a publish request is about to acknolegde sequence numbers.
+ /// Raised when a publish request is about to acknowledge sequence numbers.
///
///
/// If the client chose to defer acknowledge of sequenece numbers, it is responsible
@@ -219,7 +219,7 @@ public interface ISession : ISessionClient, IDisposable
int SubscriptionCount { get; }
///
- /// If the subscriptions are deleted when a session is closed.
+ /// If the subscriptions are deleted when a session is closed.
///
bool DeleteSubscriptionsOnClose { get; set; }
@@ -277,12 +277,12 @@ public interface ISession : ISessionClient, IDisposable
OperationLimits OperationLimits { get; }
///
- /// If the subscriptions are transferred when a session is reconnected.
+ /// If the subscriptions are transferred when a session is reconnected.
///
///
/// Default false, set to true if subscriptions should
/// be transferred after reconnect. Service must be supported by server.
- ///
+ ///
bool TransferSubscriptionsOnReconnect { get; set; }
///
@@ -314,37 +314,57 @@ public interface ISession : ISessionClient, IDisposable
///
void Reconnect(ITransportChannel channel);
+#if (CLIENT_ASYNC)
+ ///
+ /// Reconnects to the server after a network failure.
+ ///
+ Task ReconnectAsync(CancellationToken ct = default);
+
+ ///
+ /// Reconnects to the server after a network failure using a waiting connection.
+ ///
+ Task ReconnectAsync(ITransportWaitingConnection connection, CancellationToken ct = default);
+
+ ///
+ /// Reconnects to the server using a new channel.
+ ///
+ Task ReconnectAsync(ITransportChannel channel, CancellationToken ct = default);
+#endif
+
///
/// Saves all the subscriptions of the session.
///
/// The file path.
- void Save(string filePath);
+ ///
+ void Save(string filePath, IEnumerable knownTypes = null);
///
/// Saves a set of subscriptions to a stream.
///
- void Save(Stream stream, IEnumerable subscriptions);
+ void Save(Stream stream, IEnumerable subscriptions, IEnumerable knownTypes = null);
///
/// Saves a set of subscriptions to a file.
///
- void Save(string filePath, IEnumerable subscriptions);
+ void Save(string filePath, IEnumerable subscriptions, IEnumerable knownTypes = null);
///
/// Load the list of subscriptions saved in a stream.
///
/// The stream.
/// Load the subscriptions for transfer after load.
+ /// Additional known types that may be needed to read the saved subscriptions.
/// The list of loaded subscriptions
- IEnumerable Load(Stream stream, bool transferSubscriptions = false);
+ IEnumerable Load(Stream stream, bool transferSubscriptions = false, IEnumerable knownTypes = null);
///
/// Load the list of subscriptions saved in a file.
///
/// The file path.
/// Load the subscriptions for transfer after load.
+ /// Additional known types that may be needed to read the saved subscriptions.
/// The list of loaded subscriptions
- IEnumerable Load(string filePath, bool transferSubscriptions = false);
+ IEnumerable Load(string filePath, bool transferSubscriptions = false, IEnumerable knownTypes = null);
///
/// Returns the active session configuration and writes it to a stream.
@@ -378,6 +398,30 @@ public interface ISession : ISessionClient, IDisposable
///
void FetchTypeTree(ExpandedNodeIdCollection typeIds);
+#if (CLIENT_ASYNC)
+ ///
+ /// Updates the local copy of the server's namespace uri and server uri tables.
+ ///
+ /// The cancellation token.
+ Task FetchNamespaceTablesAsync(CancellationToken ct = default);
+
+ ///
+ /// Updates the cache with the type and its subtypes.
+ ///
+ ///
+ /// This method can be used to ensure the TypeTree is populated.
+ ///
+ Task FetchTypeTreeAsync(ExpandedNodeId typeId, CancellationToken ct = default);
+
+ ///
+ /// Updates the cache with the types and its subtypes.
+ ///
+ ///
+ /// This method can be used to ensure the TypeTree is populated.
+ ///
+ Task FetchTypeTreeAsync(ExpandedNodeIdCollection typeIds, CancellationToken ct = default);
+#endif
+
///
/// Returns the available encodings for a node
///
@@ -390,11 +434,13 @@ public interface ISession : ISessionClient, IDisposable
/// The encoding Id.
ReferenceDescription FindDataDescription(NodeId encodingId);
+#if (CLIENT_ASYNC)
///
/// Returns the data dictionary that contains the description.
///
/// The description id.
- Task FindDataDictionary(NodeId descriptionId);
+ ///
+ Task FindDataDictionary(NodeId descriptionId, CancellationToken ct = default);
///
/// Returns the data dictionary that contains the description.
@@ -402,13 +448,19 @@ public interface ISession : ISessionClient, IDisposable
/// The dictionary id.
///
/// The dictionary.
- Task LoadDataDictionary(ReferenceDescription dictionaryNode, bool forceReload = false);
+ DataDictionary LoadDataDictionary(
+ ReferenceDescription dictionaryNode,
+ bool forceReload = false);
///
/// Loads all dictionaries of the OPC binary or Xml schema type system.
///
/// The type system.
- Task> LoadDataTypeSystem(NodeId dataTypeSystem = null);
+ ///
+ Task> LoadDataTypeSystem(
+ NodeId dataTypeSystem = null,
+ CancellationToken ct = default);
+#endif
///
/// Reads the values for the node attributes and returns a node object.
@@ -488,6 +540,23 @@ public interface ISession : ISessionClient, IDisposable
/// The errors reported by the server.
void FetchReferences(IList nodeIds, out IList referenceDescriptions, out IList errors);
+#if (CLIENT_ASYNC)
+ ///
+ /// Fetches all references for the specified node.
+ ///
+ /// The node id.
+ ///
+ Task FetchReferencesAsync(NodeId nodeId, CancellationToken ct);
+
+ ///
+ /// Fetches all references for the specified nodes.
+ ///
+ /// The node id collection.
+ ///
+ /// A list of reference collections and the errors reported by the server.
+ Task<(IList, IList)> FetchReferencesAsync(IList nodeIds, CancellationToken ct);
+#endif
+
///
/// Establishes a session with the server.
///
@@ -547,6 +616,35 @@ public interface ISession : ISessionClient, IDisposable
void ReadDisplayName(IList nodeIds, out IList displayNames, out IList errors);
#if (CLIENT_ASYNC)
+ ///
+ /// Establishes a session with the server.
+ ///
+ /// The name to assign to the session.
+ /// The user identity.
+ /// The cancellation token.
+ Task OpenAsync(string sessionName, IUserIdentity identity, CancellationToken ct);
+
+ ///
+ /// Establishes a session with the server.
+ ///
+ /// The name to assign to the session.
+ /// The session timeout.
+ /// The user identity.
+ /// The list of preferred locales.
+ /// The cancellation token.
+ Task OpenAsync(string sessionName, uint sessionTimeout, IUserIdentity identity, IList preferredLocales, CancellationToken ct);
+
+ ///
+ /// Establishes a session with the server.
+ ///
+ /// The name to assign to the session.
+ /// The session timeout.
+ /// The user identity.
+ /// The list of preferred locales.
+ /// If set to true then the domain in the certificate must match the endpoint used.
+ /// The cancellation token.
+ Task OpenAsync(string sessionName, uint sessionTimeout, IUserIdentity identity, IList preferredLocales, bool checkDomain, CancellationToken ct);
+
///
/// Reads the values for the node attributes and returns a node object collection.
///
@@ -853,6 +951,11 @@ ResponseHeader EndBrowseNext(
bool ResendData(IEnumerable subscriptions, out IList errors);
#if CLIENT_ASYNC
+ ///
+ /// Sends a republish request.
+ ///
+ Task RepublishAsync(uint subscriptionId, uint sequenceNumber, CancellationToken ct = default);
+
///
/// Call the ResendData method on the server for all subscriptions.
///
diff --git a/Libraries/Opc.Ua.Client/ISessionFactory.cs b/Libraries/Opc.Ua.Client/ISessionFactory.cs
index 93d1ede1d..ed7f917bd 100644
--- a/Libraries/Opc.Ua.Client/ISessionFactory.cs
+++ b/Libraries/Opc.Ua.Client/ISessionFactory.cs
@@ -175,27 +175,27 @@ Task CreateAsync(
///
/// Recreates a session based on a specified template.
///
- /// The ISession object to use as template
+ /// The ISession object to use as template
/// The cancellation token.
/// The new session object.
- Task RecreateAsync(ISession template, CancellationToken ct = default);
+ Task RecreateAsync(ISession sessionTemplate, CancellationToken ct = default);
///
/// Recreates a session based on a specified template.
///
- /// The ISession object to use as template
+ /// The ISession object to use as template
/// The waiting reverse connection.
/// The cancellation token.
/// The new session object.
- Task RecreateAsync(ISession template, ITransportWaitingConnection connection, CancellationToken ct = default);
+ Task RecreateAsync(ISession sessionTemplate, ITransportWaitingConnection connection, CancellationToken ct = default);
///
/// Recreates a session based on a specified template using the provided channel.
///
- /// The Session object to use as template
+ /// The Session object to use as template
/// The channel to use to recreate the session.
/// The cancellation token.
/// The new session object.
- Task RecreateAsync(ISession template, ITransportChannel transportChannel, CancellationToken ct = default);
+ Task RecreateAsync(ISession sessionTemplate, ITransportChannel transportChannel, CancellationToken ct = default);
}
}
diff --git a/Libraries/Opc.Ua.Client/ISessionInstantiator.cs b/Libraries/Opc.Ua.Client/ISessionInstantiator.cs
new file mode 100644
index 000000000..d9ab2af0a
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/ISessionInstantiator.cs
@@ -0,0 +1,62 @@
+/* ========================================================================
+ * Copyright (c) 2005-2023 The OPC Foundation, Inc. All rights reserved.
+ *
+ * OPC Foundation MIT License 1.00
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The complete license agreement can be found here:
+ * http://opcfoundation.org/License/MIT/1.00/
+ * ======================================================================*/
+
+using System.Security.Cryptography.X509Certificates;
+
+namespace Opc.Ua.Client
+{
+ ///
+ /// Object that creates an instance of a Session object.
+ /// It can be used to subclass enhanced Session
+ /// classes which survive reconnect handling etc.
+ ///
+ public interface ISessionInstantiator
+ {
+ #region Constructors
+ ///
+ /// Constructs a new instance of the class.
+ ///
+ Session Create(
+ ISessionChannel channel,
+ ApplicationConfiguration configuration,
+ ConfiguredEndpoint endpoint);
+
+ ///
+ /// Constructs a new instance of the class.
+ ///
+ Session Create(
+ ITransportChannel channel,
+ ApplicationConfiguration configuration,
+ ConfiguredEndpoint endpoint,
+ X509Certificate2 clientCertificate,
+ EndpointDescriptionCollection availableEndpoints = null,
+ StringCollection discoveryProfileUris = null);
+ #endregion
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/MonitoredItem.cs b/Libraries/Opc.Ua.Client/MonitoredItem.cs
index 0bc056ffd..bd4f8face 100644
--- a/Libraries/Opc.Ua.Client/MonitoredItem.cs
+++ b/Libraries/Opc.Ua.Client/MonitoredItem.cs
@@ -143,7 +143,7 @@ public MonitoredItem(MonitoredItem template, bool copyEventHandlers, bool copyCl
/// Called by the .NET framework during deserialization.
///
[OnDeserializing]
- private void Initialize(StreamingContext context)
+ protected void Initialize(StreamingContext context)
{
// object initializers are not called during deserialization.
m_cache = new object();
@@ -686,6 +686,15 @@ public virtual object Clone()
{
return new MonitoredItem(this);
}
+
+ ///
+ /// Clones a monitored item or the subclass with an option to copy event handlers.
+ ///
+ /// A cloned instance of the monitored item or a subclass.
+ public virtual MonitoredItem CloneMonitoredItem(bool copyEventHandlers, bool copyClientHandle)
+ {
+ return new MonitoredItem(this, copyEventHandlers, copyClientHandle);
+ }
#endregion
#region Public Methods
diff --git a/Libraries/Opc.Ua.Client/NodeCache.cs b/Libraries/Opc.Ua.Client/NodeCache.cs
index 2f57f4491..f8724386a 100644
--- a/Libraries/Opc.Ua.Client/NodeCache.cs
+++ b/Libraries/Opc.Ua.Client/NodeCache.cs
@@ -2,7 +2,7 @@
* Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
- *
+ *
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
@@ -11,7 +11,7 @@
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
- *
+ *
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
@@ -38,7 +38,7 @@ namespace Opc.Ua.Client
///
/// An implementation of a client side nodecache.
///
- public class NodeCache : INodeCache
+ public partial class NodeCache : INodeCache, IDisposable
{
#region Constructors
///
@@ -54,17 +54,27 @@ public NodeCache(ISession session)
m_uaTypesLoaded = false;
m_cacheLock = new ReaderWriterLockSlim();
}
+ #endregion
+ #region IDisposable
///
- /// Destructor to clean up.
+ /// An overrideable version of the Dispose.
///
- ~NodeCache()
+ protected virtual void Dispose(bool disposing)
{
- if (m_cacheLock != null)
+ if (disposing)
{
- m_cacheLock.Dispose();
+ m_session = null;
+ m_cacheLock?.Dispose();
}
}
+
+ ///
+ public void Dispose()
+ {
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
#endregion
#region INodeTable Members
@@ -870,7 +880,6 @@ public IList FetchNodes(IList nodeIds)
m_session.ReadNodes(localIds, out IList sourceNodes, out IList readErrors);
m_session.FetchReferences(localIds, out IList referenceCollectionList, out IList fetchErrors);
-
int ii = 0;
for (ii = 0; ii < count; ii++)
{
diff --git a/Libraries/Opc.Ua.Client/NodeCacheAsync.cs b/Libraries/Opc.Ua.Client/NodeCacheAsync.cs
new file mode 100644
index 000000000..95cd3f19b
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/NodeCacheAsync.cs
@@ -0,0 +1,468 @@
+/* ========================================================================
+ * Copyright (c) 2005-2023 The OPC Foundation, Inc. All rights reserved.
+ *
+ * OPC Foundation MIT License 1.00
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The complete license agreement can be found here:
+ * http://opcfoundation.org/License/MIT/1.00/
+ * ======================================================================*/
+
+#if CLIENT_ASYNC
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Opc.Ua.Client
+{
+ ///
+ /// An implementation of a client side nodecache.
+ ///
+ public partial class NodeCache : INodeCache
+ {
+ ///
+ public async Task FindAsync(ExpandedNodeId nodeId, CancellationToken ct = default)
+ {
+ // check for null.
+ if (NodeId.IsNull(nodeId))
+ {
+ return null;
+ }
+
+ INode node;
+ try
+ {
+ m_cacheLock.EnterReadLock();
+
+ // check if node alredy exists.
+ node = m_nodes.Find(nodeId);
+ }
+ finally
+ {
+ m_cacheLock.ExitReadLock();
+ }
+
+ if (node != null)
+ {
+ // do not return temporary nodes created after a Browse().
+ if (node.GetType() != typeof(Node))
+ {
+ return node;
+ }
+ }
+
+ // fetch node from server.
+ try
+ {
+ return await FetchNodeAsync(nodeId, ct).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ Utils.LogError("Could not fetch node from server: NodeId={0}, Reason='{1}'.", nodeId, e.Message);
+ // m_nodes[nodeId] = null;
+ return null;
+ }
+ }
+
+ ///
+ public async Task> FindAsync(IList nodeIds, CancellationToken ct = default)
+ {
+ // check for null.
+ if (nodeIds == null || nodeIds.Count == 0)
+ {
+ return new List();
+ }
+
+ int count = nodeIds.Count;
+ IList nodes = new List(count);
+ var fetchNodeIds = new ExpandedNodeIdCollection();
+
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ INode node;
+ try
+ {
+ m_cacheLock.EnterReadLock();
+
+ // check if node already exists.
+ node = m_nodes.Find(nodeIds[ii]);
+ }
+ finally
+ {
+ m_cacheLock.ExitReadLock();
+ }
+
+ // do not return temporary nodes created after a Browse().
+ if (node != null &&
+ node?.GetType() != typeof(Node))
+ {
+ nodes.Add(node);
+ }
+ else
+ {
+ nodes.Add(null);
+ fetchNodeIds.Add(nodeIds[ii]);
+ }
+ }
+
+ if (fetchNodeIds.Count == 0)
+ {
+ return nodes;
+ }
+
+ // fetch missing nodes from server.
+ IList fetchedNodes;
+ try
+ {
+ fetchedNodes = await FetchNodesAsync(fetchNodeIds, ct).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ Utils.LogError("Could not fetch nodes from server: Reason='{0}'.", e.Message);
+ // m_nodes[nodeId] = null;
+ return nodes;
+ }
+
+ ii = 0;
+ foreach (Node fetchedNode in fetchedNodes)
+ {
+ while (ii < count && nodes[ii] != null)
+ {
+ ii++;
+ }
+ if (ii < count && nodes[ii] == null)
+ {
+ nodes[ii++] = fetchedNode;
+ }
+ else
+ {
+ Utils.LogError("Inconsistency fetching nodes from server. Not all nodes could be assigned.");
+ break;
+ }
+ }
+
+ return nodes;
+ }
+
+ #region ITypeTable Methods
+ ///
+ public async Task FindSuperTypeAsync(ExpandedNodeId typeId, CancellationToken ct)
+ {
+ INode type = await FindAsync(typeId, ct).ConfigureAwait(false);
+
+ if (type == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ m_cacheLock.EnterReadLock();
+
+ return m_typeTree.FindSuperType(typeId);
+ }
+ finally
+ {
+ m_cacheLock.ExitReadLock();
+ }
+ }
+
+ ///
+ public async Task FindSuperTypeAsync(NodeId typeId, CancellationToken ct = default)
+ {
+ INode type = await FindAsync(typeId, ct).ConfigureAwait(false);
+
+ if (type == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ m_cacheLock.EnterReadLock();
+
+ return m_typeTree.FindSuperType(typeId);
+ }
+ finally
+ {
+ m_cacheLock.ExitReadLock();
+ }
+ }
+ #endregion
+
+ #region INodeCache Methods
+ ///
+ public async Task FetchNodeAsync(ExpandedNodeId nodeId, CancellationToken ct)
+ {
+ NodeId localId = ExpandedNodeId.ToNodeId(nodeId, m_session.NamespaceUris);
+
+ if (localId == null)
+ {
+ return null;
+ }
+
+ // fetch node from server.
+ Node source = await m_session.ReadNodeAsync(localId, ct).ConfigureAwait(false);
+
+ try
+ {
+ // fetch references from server.
+ ReferenceDescriptionCollection references = await m_session.FetchReferencesAsync(localId, ct).ConfigureAwait(false);
+
+ try
+ {
+ m_cacheLock.EnterUpgradeableReadLock();
+
+ foreach (ReferenceDescription reference in references)
+ {
+ // create a placeholder for the node if it does not already exist.
+ if (!m_nodes.Exists(reference.NodeId))
+ {
+ // transform absolute identifiers.
+ if (reference.NodeId != null && reference.NodeId.IsAbsolute)
+ {
+ reference.NodeId = ExpandedNodeId.ToNodeId(reference.NodeId, NamespaceUris);
+ }
+
+ Node target = new Node(reference);
+
+ InternalWriteLockedAttach(target);
+ }
+
+ // add the reference.
+ source.ReferenceTable.Add(reference.ReferenceTypeId, !reference.IsForward, reference.NodeId);
+ }
+ }
+ finally
+ {
+ m_cacheLock.ExitUpgradeableReadLock();
+ }
+ }
+ catch (Exception e)
+ {
+ Utils.LogError("Could not fetch references for valid node with NodeId = {0}. Error = {1}", nodeId, e.Message);
+ }
+
+ InternalWriteLockedAttach(source);
+
+ return source;
+ }
+
+ ///
+ public async Task> FetchNodesAsync(IList nodeIds, CancellationToken ct)
+ {
+ int count = nodeIds.Count;
+ if (count == 0)
+ {
+ return new List();
+ }
+
+ NodeIdCollection localIds = new NodeIdCollection(
+ nodeIds.Select(nodeId => ExpandedNodeId.ToNodeId(nodeId, m_session.NamespaceUris)));
+
+ // fetch nodes and references from server.
+ (IList sourceNodes, IList readErrors) = await m_session.ReadNodesAsync(localIds, NodeClass.Unspecified, ct: ct).ConfigureAwait(false);
+ (IList referenceCollectionList, IList fetchErrors) = await m_session.FetchReferencesAsync(localIds, ct).ConfigureAwait(false); ;
+
+
+ int ii = 0;
+ for (ii = 0; ii < count; ii++)
+ {
+ if (ServiceResult.IsBad(readErrors[ii]))
+ {
+ continue;
+ }
+
+ if (!ServiceResult.IsBad(fetchErrors[ii]))
+ {
+ // fetch references from server.
+ ReferenceDescriptionCollection references = referenceCollectionList[ii];
+
+ foreach (ReferenceDescription reference in references)
+ {
+ try
+ {
+ m_cacheLock.EnterUpgradeableReadLock();
+
+ // create a placeholder for the node if it does not already exist.
+ if (!m_nodes.Exists(reference.NodeId))
+ {
+ // transform absolute identifiers.
+ if (reference.NodeId != null && reference.NodeId.IsAbsolute)
+ {
+ reference.NodeId = ExpandedNodeId.ToNodeId(reference.NodeId, NamespaceUris);
+ }
+
+ Node target = new Node(reference);
+
+ InternalWriteLockedAttach(target);
+ }
+ }
+ finally
+ {
+ m_cacheLock.ExitUpgradeableReadLock();
+ }
+
+ // add the reference.
+ sourceNodes[ii].ReferenceTable.Add(reference.ReferenceTypeId, !reference.IsForward, reference.NodeId);
+ }
+ }
+
+ InternalWriteLockedAttach(sourceNodes[ii]);
+ }
+
+ return sourceNodes;
+ }
+
+ ///
+ public async Task> FindReferencesAsync(
+ ExpandedNodeId nodeId,
+ NodeId referenceTypeId,
+ bool isInverse,
+ bool includeSubtypes,
+ CancellationToken ct)
+ {
+ IList targets = new List();
+
+ Node source = await FindAsync(nodeId, ct).ConfigureAwait(false) as Node;
+
+ if (source == null)
+ {
+ return targets;
+ }
+
+ IList references;
+ try
+ {
+ m_cacheLock.EnterReadLock();
+
+ references = source.ReferenceTable.Find(referenceTypeId, isInverse, includeSubtypes, m_typeTree);
+ }
+ finally
+ {
+ m_cacheLock.ExitReadLock();
+ }
+
+ var targetIds = new ExpandedNodeIdCollection(
+ references.Select(reference => reference.TargetId));
+
+ IList result = await FindAsync(targetIds, ct).ConfigureAwait(false);
+
+ foreach (INode target in result)
+ {
+ if (target != null)
+ {
+ targets.Add(target);
+ }
+ }
+ return targets;
+ }
+
+ ///
+ public async Task> FindReferencesAsync(
+ IList nodeIds,
+ IList referenceTypeIds,
+ bool isInverse,
+ bool includeSubtypes,
+ CancellationToken ct)
+ {
+ IList targets = new List();
+ if (nodeIds.Count == 0 || referenceTypeIds.Count == 0)
+ {
+ return targets;
+ }
+ ExpandedNodeIdCollection targetIds = new ExpandedNodeIdCollection();
+ IList sources = await FindAsync(nodeIds, ct).ConfigureAwait(false);
+ foreach (INode source in sources)
+ {
+ if (!(source is Node node))
+ {
+ continue;
+ }
+
+ foreach (var referenceTypeId in referenceTypeIds)
+ {
+ IList references;
+ try
+ {
+ m_cacheLock.EnterReadLock();
+
+ references = node.ReferenceTable.Find(referenceTypeId, isInverse, includeSubtypes, m_typeTree);
+ }
+ finally
+ {
+ m_cacheLock.ExitReadLock();
+ }
+
+ targetIds.AddRange(
+ references.Select(reference => reference.TargetId));
+ }
+ }
+
+ IList result = await FindAsync(targetIds, ct).ConfigureAwait(false);
+ foreach (INode target in result)
+ {
+ if (target != null)
+ {
+ targets.Add(target);
+ }
+ }
+
+ return targets;
+ }
+
+ ///
+ public async Task FetchSuperTypesAsync(ExpandedNodeId nodeId, CancellationToken ct)
+ {
+ // find the target node,
+ ILocalNode source = await FindAsync(nodeId, ct).ConfigureAwait(false) as ILocalNode;
+
+ if (source == null)
+ {
+ return;
+ }
+
+ // follow the tree.
+ ILocalNode subType = source;
+
+ while (subType != null)
+ {
+ ILocalNode superType = null;
+
+ IList references = subType.References.Find(ReferenceTypeIds.HasSubtype, true, true, this);
+
+ if (references != null && references.Count > 0)
+ {
+ superType = await FindAsync(references[0].TargetId, ct).ConfigureAwait(false) as ILocalNode;
+ }
+
+ subType = superType;
+ }
+ }
+ #endregion
+ }
+}
+#endif
diff --git a/Libraries/Opc.Ua.Client/Opc.Ua.Client.csproj b/Libraries/Opc.Ua.Client/Opc.Ua.Client.csproj
index 10cf86589..a808f4a19 100644
--- a/Libraries/Opc.Ua.Client/Opc.Ua.Client.csproj
+++ b/Libraries/Opc.Ua.Client/Opc.Ua.Client.csproj
@@ -21,7 +21,7 @@
$(PackageId).Debug
-
+
diff --git a/Libraries/Opc.Ua.Client/ReverseConnectManager.cs b/Libraries/Opc.Ua.Client/ReverseConnectManager.cs
index 3d1246720..91441ab2a 100644
--- a/Libraries/Opc.Ua.Client/ReverseConnectManager.cs
+++ b/Libraries/Opc.Ua.Client/ReverseConnectManager.cs
@@ -189,7 +189,6 @@ public ReverseConnectManager()
{
m_state = ReverseConnectManagerState.New;
m_registrations = new List();
- m_registrationsLock = new object();
m_endpointUrls = new Dictionary();
m_cts = new CancellationTokenSource();
}
@@ -466,7 +465,7 @@ public void ClearWaitingConnections()
public async Task WaitForConnection(
Uri endpointUrl,
string serverUri,
- CancellationToken ct = default(CancellationToken))
+ CancellationToken ct = default)
{
var tcs = new TaskCompletionSource();
int hashCode = RegisterWaitingConnection(endpointUrl, serverUri,
@@ -474,7 +473,7 @@ public async Task WaitForConnection(
ReverseConnectStrategy.Once);
Func listenForCancelTaskFnc = async () => {
- if (ct == default(CancellationToken))
+ if (ct == default)
{
var waitTimeout = m_configuration.WaitTimeout > 0 ? m_configuration.WaitTimeout : DefaultWaitTimeout;
await Task.Delay(waitTimeout).ConfigureAwait(false);
diff --git a/Libraries/Opc.Ua.Client/Session.cs b/Libraries/Opc.Ua.Client/Session.cs
index 84c2bcad8..89c2cc336 100644
--- a/Libraries/Opc.Ua.Client/Session.cs
+++ b/Libraries/Opc.Ua.Client/Session.cs
@@ -44,7 +44,7 @@ namespace Opc.Ua.Client
///
/// Manages a session with a server.
///
- public partial class Session : SessionClientBatched, ISession, IDisposable
+ public partial class Session : SessionClientBatched, ISession
{
#region Constructors
///
@@ -137,7 +137,7 @@ public Session(ITransportChannel channel, Session template, bool copyEventHandle
foreach (Subscription subscription in template.Subscriptions)
{
- AddSubscription(new Subscription(subscription, copyEventHandlers));
+ AddSubscription(subscription.CloneSubscription(copyEventHandlers));
}
}
#endregion
@@ -374,12 +374,14 @@ protected override void Dispose(bool disposing)
{
if (disposing)
{
- Utils.SilentDispose(m_keepAliveTimer);
- m_keepAliveTimer = null;
+ StopKeepAliveTimer();
Utils.SilentDispose(m_defaultSubscription);
m_defaultSubscription = null;
+ Utils.SilentDispose(m_nodeCache);
+ m_nodeCache = null;
+
IList subscriptions = null;
lock (SyncRoot)
{
@@ -683,12 +685,12 @@ public int SubscriptionCount
}
///
- /// If the subscriptions are deleted when a session is closed.
+ /// If the subscriptions are deleted when a session is closed.
///
///
/// Default true, set to false if subscriptions need to
/// be transferred or for durable subscriptions.
- ///
+ ///
public bool DeleteSubscriptionsOnClose
{
get { return m_deleteSubscriptionsOnClose; }
@@ -696,12 +698,12 @@ public bool DeleteSubscriptionsOnClose
}
///
- /// If the subscriptions are transferred when a session is reconnected.
+ /// If the subscriptions are transferred when a session is reconnected.
///
///
/// Default false, set to true if subscriptions should
/// be transferred after reconnect. Service must be supported by server.
- ///
+ ///
public bool TransferSubscriptionsOnReconnect
{
get { return m_transferSubscriptionsOnReconnect; }
@@ -920,7 +922,6 @@ public static Task Create(
/// The certificate to use for the client.
/// The list of available endpoints returned by server in GetEndpoints() response.
/// The value of profileUris used in GetEndpoints() request.
- ///
public static Session Create(
ApplicationConfiguration configuration,
ITransportChannel channel,
@@ -929,7 +930,30 @@ public static Session Create(
EndpointDescriptionCollection availableEndpoints = null,
StringCollection discoveryProfileUris = null)
{
- return new Session(channel, configuration, endpoint, clientCertificate, availableEndpoints, discoveryProfileUris);
+ return Create(DefaultSessionFactory.Instance, configuration, channel, endpoint, clientCertificate, availableEndpoints, discoveryProfileUris);
+ }
+
+ ///
+ /// Creates a new session with a server using the specified channel by invoking the CreateSession service.
+ /// With the sessionInstantiator subclasses of Sessions can be created.
+ ///
+ /// The Session constructor to use to create the session.
+ /// The configuration for the client application.
+ /// The channel for the server.
+ /// The endpoint for the server.
+ /// The certificate to use for the client.
+ /// The list of available endpoints returned by server in GetEndpoints() response.
+ /// The value of profileUris used in GetEndpoints() request.
+ public static Session Create(
+ ISessionInstantiator sessionInstantiator,
+ ApplicationConfiguration configuration,
+ ITransportChannel channel,
+ ConfiguredEndpoint endpoint,
+ X509Certificate2 clientCertificate,
+ EndpointDescriptionCollection availableEndpoints = null,
+ StringCollection discoveryProfileUris = null)
+ {
+ return sessionInstantiator.Create(channel, configuration, endpoint, clientCertificate, availableEndpoints, discoveryProfileUris);
}
///
@@ -937,7 +961,7 @@ public static Session Create(
///
/// The application configuration.
/// The client endpoint for the reverse connect.
- /// A configured endpoint to connect to.
+ /// A configured endpoint to connect to.
/// Update configuration based on server prior connect.
/// Check that the certificate specifies a valid domain (computer) name.
/// The cancellation token.
@@ -1033,7 +1057,38 @@ public static async Task CreateChannelAsync(
/// The preferred locales.
/// The cancellation token.
/// The new session object.
+ public static Task Create(
+ ApplicationConfiguration configuration,
+ ITransportWaitingConnection connection,
+ ConfiguredEndpoint endpoint,
+ bool updateBeforeConnect,
+ bool checkDomain,
+ string sessionName,
+ uint sessionTimeout,
+ IUserIdentity identity,
+ IList preferredLocales,
+ CancellationToken ct = default)
+ {
+ return Create(DefaultSessionFactory.Instance, configuration, connection, endpoint, updateBeforeConnect, checkDomain, sessionName, sessionTimeout, identity, preferredLocales, ct);
+ }
+
+ ///
+ /// Creates a new communication session with a server using a reverse connection.
+ ///
+ /// The Session constructor to use to create the session.
+ /// The configuration for the client application.
+ /// The client endpoint for the reverse connect.
+ /// The endpoint for the server.
+ /// If set to true the discovery endpoint is used to update the endpoint description before connecting.
+ /// If set to true then the domain in the certificate must match the endpoint used.
+ /// The name to assign to the session.
+ /// The timeout period for the session.
+ /// The user identity to associate with the session.
+ /// The preferred locales.
+ /// The cancellation token.
+ /// The new session object.
public static async Task Create(
+ ISessionInstantiator sessionInstantiator,
ApplicationConfiguration configuration,
ITransportWaitingConnection connection,
ConfiguredEndpoint endpoint,
@@ -1049,12 +1104,12 @@ public static async Task Create(
ITransportChannel channel = await Session.CreateChannelAsync(configuration, connection, endpoint, updateBeforeConnect, checkDomain, ct).ConfigureAwait(false);
// create the session object.
- Session session = new Session(channel, configuration, endpoint, null);
+ Session session = sessionInstantiator.Create(channel, configuration, endpoint, null);
// create the session.
try
{
- session.Open(sessionName, sessionTimeout, identity, preferredLocales, checkDomain);
+ await session.OpenAsync(sessionName, sessionTimeout, identity, preferredLocales, checkDomain, ct).ConfigureAwait(false);
}
catch (Exception)
{
@@ -1079,7 +1134,39 @@ public static async Task Create(
/// The preferred locales.
/// The cancellation token.
/// The new session object.
+ public static Task Create(
+ ApplicationConfiguration configuration,
+ ReverseConnectManager reverseConnectManager,
+ ConfiguredEndpoint endpoint,
+ bool updateBeforeConnect,
+ bool checkDomain,
+ string sessionName,
+ uint sessionTimeout,
+ IUserIdentity userIdentity,
+ IList preferredLocales,
+ CancellationToken ct = default
+ )
+ {
+ return Create(DefaultSessionFactory.Instance, configuration, reverseConnectManager, endpoint, updateBeforeConnect, checkDomain, sessionName, sessionTimeout, userIdentity, preferredLocales, ct);
+ }
+
+ ///
+ /// Creates a new communication session with a server using a reverse connect manager.
+ ///
+ /// The Session constructor to use to create the session.
+ /// The configuration for the client application.
+ /// The reverse connect manager for the client connection.
+ /// The endpoint for the server.
+ /// If set to true the discovery endpoint is used to update the endpoint description before connecting.
+ /// If set to true then the domain in the certificate must match the endpoint used.
+ /// The name to assign to the session.
+ /// The timeout period for the session.
+ /// The user identity to associate with the session.
+ /// The preferred locales.
+ /// The cancellation token.
+ /// The new session object.
public static async Task Create(
+ ISessionInstantiator sessionInstantiator,
ApplicationConfiguration configuration,
ReverseConnectManager reverseConnectManager,
ConfiguredEndpoint endpoint,
@@ -1094,8 +1181,7 @@ public static async Task Create(
{
if (reverseConnectManager == null)
{
- return await Create(configuration, endpoint, updateBeforeConnect,
- checkDomain, sessionName, sessionTimeout, userIdentity, preferredLocales).ConfigureAwait(false);
+ return await Create(sessionInstantiator, configuration, (ITransportWaitingConnection)null, endpoint, updateBeforeConnect, checkDomain, sessionName, sessionTimeout, userIdentity, preferredLocales, ct).ConfigureAwait(false);
}
ITransportWaitingConnection connection = null;
@@ -1111,13 +1197,15 @@ public static async Task Create(
await endpoint.UpdateFromServerAsync(
endpoint.EndpointUrl, connection,
endpoint.Description.SecurityMode,
- endpoint.Description.SecurityPolicyUri).ConfigureAwait(false);
+ endpoint.Description.SecurityPolicyUri,
+ ct).ConfigureAwait(false);
updateBeforeConnect = false;
connection = null;
}
} while (connection == null);
return await Create(
+ sessionInstantiator,
configuration,
connection,
endpoint,
@@ -1151,7 +1239,7 @@ public static Session Recreate(Session template)
messageContext);
// create the session object.
- Session session = new Session(channel, template, true);
+ Session session = template.CloneSession(channel, true);
try
{
@@ -1197,7 +1285,7 @@ public static Session Recreate(Session template, ITransportWaitingConnection con
messageContext);
// create the session object.
- Session session = new Session(channel, template, true);
+ Session session = template.CloneSession(channel, true);
try
{
@@ -1232,7 +1320,7 @@ public static Session Recreate(Session template, ITransportChannel transportChan
messageContext.Factory = template.Factory;
// create the session object.
- Session session = new Session(transportChannel, template, true);
+ Session session = template.CloneSession(transportChannel, true);
try
{
@@ -1297,9 +1385,7 @@ public SessionConfiguration SaveSessionConfiguration(Stream stream = null)
XmlWriterSettings settings = Utils.DefaultXmlWriterSettings();
using (XmlWriter writer = XmlWriter.Create(stream, settings))
{
- DataContractSerializer serializer = new DataContractSerializer(typeof(SessionConfiguration),
- new[] { typeof(UserIdentityToken), typeof(AnonymousIdentityToken), typeof(X509IdentityToken),
- typeof(IssuedIdentityToken), typeof(UserIdentity) });
+ DataContractSerializer serializer = new DataContractSerializer(typeof(SessionConfiguration));
serializer.WriteObject(writer, sessionConfiguration);
}
}
@@ -1308,9 +1394,7 @@ public SessionConfiguration SaveSessionConfiguration(Stream stream = null)
///
public void Reconnect()
- {
- Reconnect(null, null);
- }
+ => Reconnect(null, null);
///
public void Reconnect(ITransportWaitingConnection connection)
@@ -1328,130 +1412,31 @@ private void Reconnect(ITransportWaitingConnection connection, ITransportChannel
bool resetReconnect = false;
try
{
- // check if already connecting.
- if (m_reconnecting)
- {
- Utils.LogWarning("Session is already attempting to reconnect.");
-
- throw ServiceResultException.Create(
- StatusCodes.BadInvalidState,
- "Session is already attempting to reconnect.");
- }
-
- Utils.LogInfo("Session RECONNECT starting.");
+ Utils.LogInfo("Session RECONNECT {0} starting.", SessionId);
m_reconnectLock.Wait();
+ bool reconnecting = m_reconnecting;
m_reconnecting = true;
resetReconnect = true;
m_reconnectLock.Release();
- lock (SyncRoot)
- {
- // stop keep alives.
- Utils.SilentDispose(m_keepAliveTimer);
- m_keepAliveTimer = null;
- }
-
- // create the client signature.
- byte[] dataToSign = Utils.Append(m_serverCertificate != null ? m_serverCertificate.RawData : null, m_serverNonce);
- EndpointDescription endpoint = m_endpoint.Description;
- SignatureData clientSignature = SecurityPolicies.Sign(m_instanceCertificate, endpoint.SecurityPolicyUri, dataToSign);
-
- // check that the user identity is supported by the endpoint.
- UserTokenPolicy identityPolicy = endpoint.FindUserTokenPolicy(m_identity.TokenType, m_identity.IssuedTokenType);
-
- if (identityPolicy == null)
+ // check if already connecting.
+ if (reconnecting)
{
- Utils.LogError("Reconnect: Endpoint does not support the user identity type provided.");
+ Utils.LogWarning("Session is already attempting to reconnect.");
throw ServiceResultException.Create(
- StatusCodes.BadUserAccessDenied,
- "Endpoint does not support the user identity type provided.");
- }
-
- // select the security policy for the user token.
- string securityPolicyUri = identityPolicy.SecurityPolicyUri;
-
- if (String.IsNullOrEmpty(securityPolicyUri))
- {
- securityPolicyUri = endpoint.SecurityPolicyUri;
- }
-
- // need to refresh the identity (reprompt for password, refresh token).
- if (m_RenewUserIdentity != null)
- {
- m_identity = m_RenewUserIdentity(this, m_identity);
+ StatusCodes.BadInvalidState,
+ "Session is already attempting to reconnect.");
}
- // validate server nonce and security parameters for user identity.
- ValidateServerNonce(
- m_identity,
- m_serverNonce,
- securityPolicyUri,
- m_previousServerNonce,
- m_endpoint.Description.SecurityMode);
-
- // sign data with user token.
- UserIdentityToken identityToken = m_identity.GetIdentityToken();
- identityToken.PolicyId = identityPolicy.PolicyId;
- SignatureData userTokenSignature = identityToken.Sign(dataToSign, securityPolicyUri);
-
- // encrypt token.
- identityToken.Encrypt(m_serverCertificate, m_serverNonce, securityPolicyUri);
-
- // send the software certificates assigned to the client.
- SignedSoftwareCertificateCollection clientSoftwareCertificates = GetSoftwareCertificates();
-
- Utils.LogInfo("Session REPLACING channel.");
+ IAsyncResult result = PrepareReconnectBeginActivate(
+ connection,
+ transportChannel);
- if (connection != null)
- {
- // check if the channel supports reconnect.
- if ((TransportChannel.SupportedFeatures & TransportChannelFeatures.Reconnect) != 0)
- {
- TransportChannel.Reconnect(connection);
- }
- else
- {
- // initialize the channel which will be created with the server.
- ITransportChannel channel = SessionChannel.Create(
- m_configuration,
- connection,
- m_endpoint.Description,
- m_endpoint.Configuration,
- m_instanceCertificate,
- m_configuration.SecurityConfiguration.SendCertificateChain ? m_instanceCertificateChain : null,
- MessageContext);
-
- // disposes the existing channel.
- TransportChannel = channel;
- }
- }
- else if (transportChannel != null)
- {
- TransportChannel = transportChannel;
- }
- else
+ if (!result.AsyncWaitHandle.WaitOne(kReconnectTimeout / 2))
{
- // check if the channel supports reconnect.
- if (TransportChannel != null && (TransportChannel.SupportedFeatures & TransportChannelFeatures.Reconnect) != 0)
- {
- TransportChannel.Reconnect();
- }
- else
- {
- // initialize the channel which will be created with the server.
- ITransportChannel channel = SessionChannel.Create(
- m_configuration,
- m_endpoint.Description,
- m_endpoint.Configuration,
- m_instanceCertificate,
- m_configuration.SecurityConfiguration.SendCertificateChain ? m_instanceCertificateChain : null,
- MessageContext);
-
- // disposes the existing channel.
- TransportChannel = channel;
- }
+ Utils.LogWarning("WARNING: ACTIVATE SESSION timed out. {0}/{1}", GoodPublishRequestCount, OutstandingRequestCount);
}
// reactivate session.
@@ -1459,24 +1444,6 @@ private void Reconnect(ITransportWaitingConnection connection, ITransportChannel
StatusCodeCollection certificateResults = null;
DiagnosticInfoCollection certificateDiagnosticInfos = null;
- Utils.LogInfo("Session RE-ACTIVATING session.");
-
- RequestHeader header = new RequestHeader() { TimeoutHint = kReconnectTimeout };
- IAsyncResult result = BeginActivateSession(
- header,
- clientSignature,
- null,
- m_preferredLocales,
- new ExtensionObject(identityToken),
- userTokenSignature,
- null,
- null);
-
- if (!result.AsyncWaitHandle.WaitOne(kReconnectTimeout / 2))
- {
- Utils.LogWarning("WARNING: ACTIVATE SESSION timed out. {0}/{1}", GoodPublishRequestCount, OutstandingRequestCount);
- }
-
EndActivateSession(
result,
out serverNonce,
@@ -1485,9 +1452,10 @@ private void Reconnect(ITransportWaitingConnection connection, ITransportChannel
int publishCount = 0;
+ Utils.LogInfo("Session RECONNECT {0} completed successfully.", SessionId);
+
lock (SyncRoot)
{
- Utils.LogInfo("Session RECONNECT completed successfully.");
m_previousServerNonce = m_serverNonce;
m_serverNonce = serverNonce;
publishCount = GetMinPublishRequestCount(true);
@@ -1520,35 +1488,35 @@ private void Reconnect(ITransportWaitingConnection connection, ITransportChannel
}
///
- public void Save(string filePath)
+ public void Save(string filePath, IEnumerable knownTypes = null)
{
- Save(filePath, Subscriptions);
+ Save(filePath, Subscriptions, knownTypes);
}
///
- public void Save(Stream stream, IEnumerable subscriptions)
+ public void Save(Stream stream, IEnumerable subscriptions, IEnumerable knownTypes = null)
{
SubscriptionCollection subscriptionList = new SubscriptionCollection(subscriptions);
XmlWriterSettings settings = Utils.DefaultXmlWriterSettings();
using (XmlWriter writer = XmlWriter.Create(stream, settings))
{
- DataContractSerializer serializer = new DataContractSerializer(typeof(SubscriptionCollection));
+ DataContractSerializer serializer = new DataContractSerializer(typeof(SubscriptionCollection), knownTypes);
serializer.WriteObject(writer, subscriptionList);
}
}
///
- public void Save(string filePath, IEnumerable subscriptions)
+ public void Save(string filePath, IEnumerable subscriptions, IEnumerable knownTypes = null)
{
using (FileStream stream = new FileStream(filePath, FileMode.Create))
{
- Save(stream, subscriptions);
+ Save(stream, subscriptions, knownTypes);
}
}
///
- public IEnumerable Load(Stream stream, bool transferSubscriptions = false)
+ public IEnumerable Load(Stream stream, bool transferSubscriptions = false, IEnumerable knownTypes = null)
{
// secure settings
XmlReaderSettings settings = Utils.DefaultXmlReaderSettings();
@@ -1556,7 +1524,7 @@ public IEnumerable Load(Stream stream, bool transferSubscriptions
using (XmlReader reader = XmlReader.Create(stream, settings))
{
- DataContractSerializer serializer = new DataContractSerializer(typeof(SubscriptionCollection));
+ DataContractSerializer serializer = new DataContractSerializer(typeof(SubscriptionCollection), knownTypes);
SubscriptionCollection subscriptions = (SubscriptionCollection)serializer.ReadObject(reader);
foreach (Subscription subscription in subscriptions)
{
@@ -1576,37 +1544,21 @@ public IEnumerable Load(Stream stream, bool transferSubscriptions
}
///
- public IEnumerable Load(string filePath, bool transferSubscriptions = false)
+ public IEnumerable Load(string filePath, bool transferSubscriptions = false, IEnumerable knownTypes = null)
{
using (FileStream stream = File.OpenRead(filePath))
{
- return Load(stream, transferSubscriptions);
+ return Load(stream, transferSubscriptions, knownTypes);
}
}
///
public void FetchNamespaceTables()
{
- ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
-
- // request namespace array.
- ReadValueId valueId = new ReadValueId {
- NodeId = Variables.Server_NamespaceArray,
- AttributeId = Attributes.Value
- };
-
- nodesToRead.Add(valueId);
-
- // request server array.
- valueId = new ReadValueId {
- NodeId = Variables.Server_ServerArray,
- AttributeId = Attributes.Value
- };
-
- nodesToRead.Add(valueId);
+ ReadValueIdCollection nodesToRead = PrepareNamespaceTableNodesToRead();
// read from server.
- ResponseHeader responseHeader = this.Read(
+ ResponseHeader responseHeader = base.Read(
null,
0,
TimestampsToReturn.Neither,
@@ -1617,29 +1569,7 @@ public void FetchNamespaceTables()
ValidateResponse(values, nodesToRead);
ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);
- // validate namespace array.
- ServiceResult result = ValidateDataValue(values[0], typeof(string[]), 0, diagnosticInfos, responseHeader);
-
- if (ServiceResult.IsBad(result))
- {
- Utils.LogError("FetchNamespaceTables: Cannot read NamespaceArray node: {0}", result.StatusCode);
- }
- else
- {
- m_namespaceUris.Update((string[])values[0].Value);
- }
-
- // validate server array.
- result = ValidateDataValue(values[1], typeof(string[]), 1, diagnosticInfos, responseHeader);
-
- if (ServiceResult.IsBad(result))
- {
- Utils.LogError("FetchNamespaceTables: Cannot read ServerArray node: {0} ", result.StatusCode);
- }
- else
- {
- m_serverUris.Update((string[])values[1].Value);
- }
+ UpdateNamespaceTable(values, diagnosticInfos, responseHeader);
}
///
@@ -1815,7 +1745,7 @@ public ReferenceDescription FindDataDescription(NodeId encodingId)
}
///
- public async Task FindDataDictionary(NodeId descriptionId)
+ public async Task FindDataDictionary(NodeId descriptionId, CancellationToken ct = default)
{
// check if the dictionary has already been loaded.
foreach (DataDictionary dictionary in m_dictionaries.Values)
@@ -1826,7 +1756,7 @@ public async Task FindDataDictionary(NodeId descriptionId)
}
}
- IList references = this.NodeCache.FindReferences(descriptionId, ReferenceTypeIds.HasComponent, true, false);
+ IList references = await NodeCache.FindReferencesAsync(descriptionId, ReferenceTypeIds.HasComponent, true, false, ct).ConfigureAwait(false);
if (references.Count == 0)
{
throw ServiceResultException.Create(StatusCodes.BadNodeIdInvalid, "Description does not refer to a valid data dictionary.");
@@ -1837,7 +1767,7 @@ public async Task FindDataDictionary(NodeId descriptionId)
DataDictionary dictionaryToLoad = new DataDictionary(this);
- await dictionaryToLoad.Load(references[0]).ConfigureAwait(false);
+ dictionaryToLoad.Load(references[0]);
m_dictionaries[dictionaryId] = dictionaryToLoad;
@@ -1845,7 +1775,7 @@ public async Task FindDataDictionary(NodeId descriptionId)
}
///
- public async Task LoadDataDictionary(ReferenceDescription dictionaryNode, bool forceReload = false)
+ public DataDictionary LoadDataDictionary(ReferenceDescription dictionaryNode, bool forceReload = false)
{
// check if the dictionary has already been loaded.
DataDictionary dictionary;
@@ -1858,13 +1788,13 @@ public async Task LoadDataDictionary(ReferenceDescription dictio
// load the dictionary.
DataDictionary dictionaryToLoad = new DataDictionary(this);
- await dictionaryToLoad.Load(dictionaryId, dictionaryNode.ToString()).ConfigureAwait(false);
+ dictionaryToLoad.Load(dictionaryId, dictionaryNode.ToString());
m_dictionaries[dictionaryId] = dictionaryToLoad;
return dictionaryToLoad;
}
///
- public async Task> LoadDataTypeSystem(NodeId dataTypeSystem = null)
+ public async Task> LoadDataTypeSystem(NodeId dataTypeSystem = null, CancellationToken ct = default)
{
if (dataTypeSystem == null)
{
@@ -1897,7 +1827,7 @@ public async Task> LoadDataTypeSystem(NodeId
var referenceExpandedNodeIds = references
.Select(r => ExpandedNodeId.ToNodeId(r.NodeId, this.NamespaceUris))
.Where(n => n.NamespaceIndex != 0).ToList();
- IDictionary schemas = await DataDictionary.ReadDictionaries(this, referenceExpandedNodeIds).ConfigureAwait(false);
+ IDictionary schemas = await DataDictionary.ReadDictionaries(this, referenceExpandedNodeIds, ct).ConfigureAwait(false);
// read namespace property values
var namespaces = new Dictionary();
@@ -1908,7 +1838,11 @@ public async Task> LoadDataTypeSystem(NodeId
{
if (StatusCode.IsNotBad(errors[ii].StatusCode))
{
- namespaces[((NodeId)referenceNodeIds[ii])] = (string)nameSpaceValues[ii];
+ // servers may optimize space by not returning a dictionary
+ if (nameSpaceValues[ii] != null)
+ {
+ namespaces[((NodeId)referenceNodeIds[ii])] = (string)nameSpaceValues[ii];
+ }
}
else
{
@@ -1940,11 +1874,11 @@ public async Task> LoadDataTypeSystem(NodeId
dictionaryToLoad = new DataDictionary(this);
if (schemas.TryGetValue(dictionaryId, out var schema))
{
- await dictionaryToLoad.Load(dictionaryId, dictionaryId.ToString(), schema, imports).ConfigureAwait(false);
+ dictionaryToLoad.Load(dictionaryId, dictionaryId.ToString(), schema, imports);
}
else
{
- await dictionaryToLoad.Load(dictionaryId, dictionaryId.ToString()).ConfigureAwait(false);
+ dictionaryToLoad.Load(dictionaryId, dictionaryId.ToString());
}
m_dictionaries[dictionaryId] = dictionaryToLoad;
}
@@ -2382,59 +2316,7 @@ public void Open(
IList preferredLocales,
bool checkDomain)
{
- // check connection state.
- lock (SyncRoot)
- {
- if (Connected)
- {
- throw new ServiceResultException(StatusCodes.BadInvalidState, "Already connected to server.");
- }
- }
-
- string securityPolicyUri = m_endpoint.Description.SecurityPolicyUri;
-
- // catch security policies which are not supported by core
- if (SecurityPolicies.GetDisplayName(securityPolicyUri) == null)
- {
- throw ServiceResultException.Create(
- StatusCodes.BadSecurityChecksFailed,
- "The chosen security policy is not supported by the client to connect to the server.");
- }
-
- // get the identity token.
- if (identity == null)
- {
- identity = new UserIdentity();
- }
-
- // get identity token.
- UserIdentityToken identityToken = identity.GetIdentityToken();
-
- // check that the user identity is supported by the endpoint.
- UserTokenPolicy identityPolicy = m_endpoint.Description.FindUserTokenPolicy(identityToken.PolicyId);
-
- if (identityPolicy == null)
- {
- // try looking up by TokenType if the policy id was not found.
- identityPolicy = m_endpoint.Description.FindUserTokenPolicy(identity.TokenType, identity.IssuedTokenType);
-
- if (identityPolicy == null)
- {
- throw ServiceResultException.Create(
- StatusCodes.BadUserAccessDenied,
- "Endpoint does not support the user identity type provided.");
- }
-
- identityToken.PolicyId = identityPolicy.PolicyId;
- }
-
- bool requireEncryption = securityPolicyUri != SecurityPolicies.None;
-
- if (!requireEncryption)
- {
- requireEncryption = identityPolicy.SecurityPolicyUri != SecurityPolicies.None &&
- !String.IsNullOrEmpty(identityPolicy.SecurityPolicyUri);
- }
+ OpenValidateIdentity(ref identity, out var identityToken, out var identityPolicy, out string securityPolicyUri, out bool requireEncryption);
// validate the server certificate /certificate chain.
X509Certificate2 serverCertificate = null;
@@ -2476,27 +2358,14 @@ public void Open(
SignedSoftwareCertificateCollection serverSoftwareCertificates = null;
// send the application instance certificate for the client.
- byte[] clientCertificateData = m_instanceCertificate != null ? m_instanceCertificate.RawData : null;
- byte[] clientCertificateChainData = null;
+ BuildCertificateData(out byte[] clientCertificateData, out byte[] clientCertificateChainData);
- if (m_instanceCertificateChain != null && m_instanceCertificateChain.Count > 0 && m_configuration.SecurityConfiguration.SendCertificateChain)
- {
- List clientCertificateChain = new List();
-
- for (int i = 0; i < m_instanceCertificateChain.Count; i++)
- {
- clientCertificateChain.AddRange(m_instanceCertificateChain[i].RawData);
- }
-
- clientCertificateChainData = clientCertificateChain.ToArray();
- }
-
- ApplicationDescription clientDescription = new ApplicationDescription();
-
- clientDescription.ApplicationUri = m_configuration.ApplicationUri;
- clientDescription.ApplicationName = m_configuration.ApplicationName;
- clientDescription.ApplicationType = ApplicationType.Client;
- clientDescription.ProductUri = m_configuration.ProductUri;
+ ApplicationDescription clientDescription = new ApplicationDescription {
+ ApplicationUri = m_configuration.ApplicationUri,
+ ApplicationName = m_configuration.ApplicationName,
+ ApplicationType = ApplicationType.Client,
+ ProductUri = m_configuration.ProductUri
+ };
if (sessionTimeout == 0)
{
@@ -2561,6 +2430,7 @@ public void Open(
out serverSignature,
out m_maxRequestMessageSize);
}
+
// save session id.
lock (SyncRoot)
{
@@ -2575,200 +2445,16 @@ public void Open(
try
{
// verify that the server returned the same instance certificate.
- if (serverCertificateData != null &&
- m_endpoint.Description.ServerCertificate != null &&
- !Utils.IsEqual(serverCertificateData, m_endpoint.Description.ServerCertificate))
- {
- try
- {
- // verify for certificate chain in endpoint.
- X509Certificate2Collection serverCertificateChain = Utils.ParseCertificateChainBlob(m_endpoint.Description.ServerCertificate);
-
- if (serverCertificateChain.Count > 0 && !Utils.IsEqual(serverCertificateData, serverCertificateChain[0].RawData))
- {
- throw ServiceResultException.Create(
- StatusCodes.BadCertificateInvalid,
- "Server did not return the certificate used to create the secure channel.");
- }
- }
- catch (Exception)
- {
- throw ServiceResultException.Create(
- StatusCodes.BadCertificateInvalid,
- "Server did not return the certificate used to create the secure channel.");
- }
- }
-
- if (serverSignature == null || serverSignature.Signature == null)
- {
- Utils.LogInfo("Server signature is null or empty.");
-
- //throw ServiceResultException.Create(
- // StatusCodes.BadSecurityChecksFailed,
- // "Server signature is null or empty.");
- }
-
- if (m_discoveryServerEndpoints != null && m_discoveryServerEndpoints.Count > 0)
- {
- // Compare EndpointDescriptions returned at GetEndpoints with values returned at CreateSession
- EndpointDescriptionCollection expectedServerEndpoints = null;
-
- if (serverEndpoints != null &&
- m_discoveryProfileUris != null && m_discoveryProfileUris.Count > 0)
- {
- // Select EndpointDescriptions with a transportProfileUri that matches the
- // profileUris specified in the original GetEndpoints() request.
- expectedServerEndpoints = new EndpointDescriptionCollection();
-
- foreach (EndpointDescription serverEndpoint in serverEndpoints)
- {
- if (m_discoveryProfileUris.Contains(serverEndpoint.TransportProfileUri))
- {
- expectedServerEndpoints.Add(serverEndpoint);
- }
- }
- }
- else
- {
- expectedServerEndpoints = serverEndpoints;
- }
-
- if (expectedServerEndpoints == null ||
- m_discoveryServerEndpoints.Count != expectedServerEndpoints.Count)
- {
- throw ServiceResultException.Create(
- StatusCodes.BadSecurityChecksFailed,
- "Server did not return a number of ServerEndpoints that matches the one from GetEndpoints.");
- }
-
- for (int ii = 0; ii < expectedServerEndpoints.Count; ii++)
- {
- EndpointDescription serverEndpoint = expectedServerEndpoints[ii];
- EndpointDescription expectedServerEndpoint = m_discoveryServerEndpoints[ii];
-
- if (serverEndpoint.SecurityMode != expectedServerEndpoint.SecurityMode ||
- serverEndpoint.SecurityPolicyUri != expectedServerEndpoint.SecurityPolicyUri ||
- serverEndpoint.TransportProfileUri != expectedServerEndpoint.TransportProfileUri ||
- serverEndpoint.SecurityLevel != expectedServerEndpoint.SecurityLevel)
- {
- throw ServiceResultException.Create(
- StatusCodes.BadSecurityChecksFailed,
- "The list of ServerEndpoints returned at CreateSession does not match the list from GetEndpoints.");
- }
-
- if (serverEndpoint.UserIdentityTokens.Count != expectedServerEndpoint.UserIdentityTokens.Count)
- {
- throw ServiceResultException.Create(
- StatusCodes.BadSecurityChecksFailed,
- "The list of ServerEndpoints returned at CreateSession does not match the one from GetEndpoints.");
- }
+ ValidateServerCertificateData(serverCertificateData);
- for (int jj = 0; jj < serverEndpoint.UserIdentityTokens.Count; jj++)
- {
- if (!serverEndpoint.UserIdentityTokens[jj].IsEqual(expectedServerEndpoint.UserIdentityTokens[jj]))
- {
- throw ServiceResultException.Create(
- StatusCodes.BadSecurityChecksFailed,
- "The list of ServerEndpoints returned at CreateSession does not match the one from GetEndpoints.");
- }
- }
- }
- }
+ ValidateServerEndpoints(serverEndpoints);
- // find the matching description (TBD - check domains against certificate).
- bool found = false;
- Uri expectedUrl = Utils.ParseUri(m_endpoint.Description.EndpointUrl);
+ ValidateServerSignature(serverCertificate, serverSignature, clientCertificateData, clientCertificateChainData, clientNonce);
- if (expectedUrl != null)
- {
- for (int ii = 0; ii < serverEndpoints.Count; ii++)
- {
- EndpointDescription serverEndpoint = serverEndpoints[ii];
- Uri actualUrl = Utils.ParseUri(serverEndpoint.EndpointUrl);
-
- if (actualUrl != null && actualUrl.Scheme == expectedUrl.Scheme)
- {
- if (serverEndpoint.SecurityPolicyUri == m_endpoint.Description.SecurityPolicyUri)
- {
- if (serverEndpoint.SecurityMode == m_endpoint.Description.SecurityMode)
- {
- // ensure endpoint has up to date information.
- m_endpoint.Description.Server.ApplicationName = serverEndpoint.Server.ApplicationName;
- m_endpoint.Description.Server.ApplicationUri = serverEndpoint.Server.ApplicationUri;
- m_endpoint.Description.Server.ApplicationType = serverEndpoint.Server.ApplicationType;
- m_endpoint.Description.Server.ProductUri = serverEndpoint.Server.ProductUri;
- m_endpoint.Description.TransportProfileUri = serverEndpoint.TransportProfileUri;
- m_endpoint.Description.UserIdentityTokens = serverEndpoint.UserIdentityTokens;
-
- found = true;
- break;
- }
- }
- }
- }
- }
-
- // could be a security risk.
- if (!found)
- {
- throw ServiceResultException.Create(
- StatusCodes.BadSecurityChecksFailed,
- "Server did not return an EndpointDescription that matched the one used to create the secure channel.");
- }
-
- // validate the server's signature.
- byte[] dataToSign = Utils.Append(clientCertificateData, clientNonce);
-
- if (!SecurityPolicies.Verify(serverCertificate, m_endpoint.Description.SecurityPolicyUri, dataToSign, serverSignature))
- {
- // validate the signature with complete chain if the check with leaf certificate failed.
- if (clientCertificateChainData != null)
- {
- dataToSign = Utils.Append(clientCertificateChainData, clientNonce);
-
- if (!SecurityPolicies.Verify(serverCertificate, m_endpoint.Description.SecurityPolicyUri, dataToSign, serverSignature))
- {
- throw ServiceResultException.Create(
- StatusCodes.BadApplicationSignatureInvalid,
- "Server did not provide a correct signature for the nonce data provided by the client.");
- }
- }
- else
- {
- throw ServiceResultException.Create(
- StatusCodes.BadApplicationSignatureInvalid,
- "Server did not provide a correct signature for the nonce data provided by the client.");
- }
- }
-
- // get a validator to check certificates provided by server.
- CertificateValidator validator = m_configuration.CertificateValidator;
-
- // validate software certificates.
- List softwareCertificates = new List();
-
- foreach (SignedSoftwareCertificate signedCertificate in serverSoftwareCertificates)
- {
- SoftwareCertificate softwareCertificate = null;
-
- ServiceResult result = SoftwareCertificate.Validate(
- validator,
- signedCertificate.CertificateData,
- out softwareCertificate);
-
- if (ServiceResult.IsBad(result))
- {
- OnSoftwareCertificateError(signedCertificate, result);
- }
-
- softwareCertificates.Add(softwareCertificate);
- }
-
- // check if software certificates meet application requirements.
- ValidateSoftwareCertificates(softwareCertificates);
+ HandleSignedSoftwareCertificates(serverSoftwareCertificates);
// create the client signature.
- dataToSign = Utils.Append(serverCertificate != null ? serverCertificate.RawData : null, serverNonce);
+ byte[] dataToSign = Utils.Append(serverCertificate != null ? serverCertificate.RawData : null, serverNonce);
SignatureData clientSignature = SecurityPolicies.Sign(m_instanceCertificate, securityPolicyUri, dataToSign);
// select the security policy for the user token.
@@ -3260,6 +2946,38 @@ public void ReadDisplayName(
}
}
}
+
+ ///
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(this, obj)) return true;
+
+ if (obj is ISession session)
+ {
+ if (!m_endpoint.Equals(session.Endpoint)) return false;
+ if (!m_sessionName.Equals(session.SessionName, StringComparison.Ordinal)) return false;
+ if (!SessionId.Equals(session.SessionId)) return false;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(m_endpoint, m_sessionName, SessionId);
+ }
+
+ ///
+ /// An overrideable version of a session clone which is used
+ /// internally to create new subclassed clones from a Session class.
+ ///
+ public virtual Session CloneSession(ITransportChannel channel, bool copyEventHandlers)
+ {
+ return new Session(channel, this, copyEventHandlers);
+ }
#endregion
#region Close Methods
@@ -3291,8 +3009,7 @@ public virtual StatusCode Close(int timeout, bool closeChannel)
StatusCode result = StatusCodes.Good;
// stop the keep alive timer.
- Utils.SilentDispose(m_keepAliveTimer);
- m_keepAliveTimer = null;
+ StopKeepAliveTimer();
// check if currectly connected.
bool connected = Connected;
@@ -3337,9 +3054,9 @@ public virtual StatusCode Close(int timeout, bool closeChannel)
{
// dont throw errors on disconnect, but return them
// so the caller can log the error.
- if (e is ServiceResultException)
+ if (e is ServiceResultException sre)
{
- result = ((ServiceResultException)e).StatusCode;
+ result = sre.StatusCode;
}
else
{
@@ -4027,8 +3744,7 @@ private void StartKeepAliveTimer()
// restart the publish timer.
lock (SyncRoot)
{
- Utils.SilentDispose(m_keepAliveTimer);
- m_keepAliveTimer = null;
+ StopKeepAliveTimer();
// start timer.
m_keepAliveTimer = new Timer(OnKeepAlive, nodesToRead, keepAliveInterval, keepAliveInterval);
@@ -4038,6 +3754,15 @@ private void StartKeepAliveTimer()
OnKeepAlive(nodesToRead);
}
+ ///
+ /// Stops the keep alive timer.
+ ///
+ private void StopKeepAliveTimer()
+ {
+ Utils.SilentDispose(m_keepAliveTimer);
+ m_keepAliveTimer = null;
+ }
+
///
/// Removes a completed async request.
///
@@ -4370,6 +4095,62 @@ private void CreateNodeClassAttributesReadNodesRequest(
}
}
+ ///
+ /// Prepares the list of node ids to read to fetch the namespace table.
+ ///
+ private ReadValueIdCollection PrepareNamespaceTableNodesToRead()
+ {
+ var nodesToRead = new ReadValueIdCollection();
+
+ // request namespace array.
+ ReadValueId valueId = new ReadValueId {
+ NodeId = Variables.Server_NamespaceArray,
+ AttributeId = Attributes.Value
+ };
+
+ nodesToRead.Add(valueId);
+
+ // request server array.
+ valueId = new ReadValueId {
+ NodeId = Variables.Server_ServerArray,
+ AttributeId = Attributes.Value
+ };
+
+ nodesToRead.Add(valueId);
+
+ return nodesToRead;
+ }
+
+ ///
+ /// Updates the NamespaceTable with the result of the read operation.
+ ///
+ private void UpdateNamespaceTable(DataValueCollection values, DiagnosticInfoCollection diagnosticInfos, ResponseHeader responseHeader)
+ {
+ // validate namespace array.
+ ServiceResult result = ValidateDataValue(values[0], typeof(string[]), 0, diagnosticInfos, responseHeader);
+
+ if (ServiceResult.IsBad(result))
+ {
+ Utils.LogError("FetchNamespaceTables: Cannot read NamespaceArray node: {0}", result.StatusCode);
+ }
+ else
+ {
+ m_namespaceUris.Update((string[])values[0].Value);
+ }
+
+ // validate server array.
+ result = ValidateDataValue(values[1], typeof(string[]), 1, diagnosticInfos, responseHeader);
+
+ if (ServiceResult.IsBad(result))
+ {
+ Utils.LogError("FetchNamespaceTables: Cannot read ServerArray node: {0} ", result.StatusCode);
+ }
+ else
+ {
+ m_serverUris.Update((string[])values[1].Value);
+ }
+ }
+
///
/// Creates a read request with attributes determined by the NodeClass.
///
@@ -4429,7 +4210,7 @@ bool optionalAttributes
}
///
- /// Builds the node collection results based on the attribute values of the read response.
+ /// Builds the node collection results based on the attribute values of the read response.
///
/// The collection of all attributes to read passed in the read request.
/// The attributes requested per NodeId
@@ -5283,6 +5064,8 @@ private void OnPublishComplete(IAsyncResult result)
case StatusCodes.BadSessionIdInvalid:
case StatusCodes.BadSecureChannelIdInvalid:
case StatusCodes.BadSecureChannelClosed:
+ case StatusCodes.BadSecurityChecksFailed:
+ case StatusCodes.BadCertificateInvalid:
case StatusCodes.BadServerHalted:
return;
@@ -5348,59 +5131,7 @@ public bool Republish(uint subscriptionId, uint sequenceNumber)
}
catch (Exception e)
{
- ServiceResult error = new ServiceResult(e);
-
- bool result = true;
- switch (error.StatusCode.Code)
- {
- case StatusCodes.BadMessageNotAvailable:
- Utils.LogWarning("Message {0}-{1} no longer available.", subscriptionId, sequenceNumber);
- break;
- // if encoding limits are exceeded, the issue is logged and
- // the published data is acknowledged to prevent the endless republish loop.
- case StatusCodes.BadEncodingLimitsExceeded:
- Utils.LogError(e, "Message {0}-{1} exceeded size limits, ignored.", subscriptionId, sequenceNumber);
- var ack = new SubscriptionAcknowledgement {
- SubscriptionId = subscriptionId,
- SequenceNumber = sequenceNumber
- };
- lock (SyncRoot)
- {
- m_acknowledgementsToSend.Add(ack);
- }
- break;
- default:
- result = false;
- Utils.LogError(e, "Unexpected error sending republish request.");
- break;
- }
-
- PublishErrorEventHandler callback = null;
-
- lock (m_eventLock)
- {
- callback = m_PublishError;
- }
-
- // raise an error event.
- if (callback != null)
- {
- try
- {
- PublishErrorEventArgs args = new PublishErrorEventArgs(
- error,
- subscriptionId,
- sequenceNumber);
-
- callback(this, args);
- }
- catch (Exception e2)
- {
- Utils.LogError(e2, "Session: Unexpected error invoking PublishErrorCallback.");
- }
- }
-
- return result;
+ return ProcessRepublishResponseError(e, subscriptionId, sequenceNumber);
}
}
@@ -5448,6 +5179,506 @@ public bool ResendData(IEnumerable subscriptions, out IList
+ /// Validates the identity for an open call.
+ ///
+ private void OpenValidateIdentity(
+ ref IUserIdentity identity,
+ out UserIdentityToken identityToken,
+ out UserTokenPolicy identityPolicy,
+ out string securityPolicyUri,
+ out bool requireEncryption)
+ {
+ // check connection state.
+ lock (SyncRoot)
+ {
+ if (Connected)
+ {
+ throw new ServiceResultException(StatusCodes.BadInvalidState, "Already connected to server.");
+ }
+ }
+
+ securityPolicyUri = m_endpoint.Description.SecurityPolicyUri;
+
+ // catch security policies which are not supported by core
+ if (SecurityPolicies.GetDisplayName(securityPolicyUri) == null)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadSecurityChecksFailed,
+ "The chosen security policy is not supported by the client to connect to the server.");
+ }
+
+ // get the identity token.
+ if (identity == null)
+ {
+ identity = new UserIdentity();
+ }
+
+ // get identity token.
+ identityToken = identity.GetIdentityToken();
+
+ // check that the user identity is supported by the endpoint.
+ identityPolicy = m_endpoint.Description.FindUserTokenPolicy(identityToken.PolicyId);
+
+ if (identityPolicy == null)
+ {
+ // try looking up by TokenType if the policy id was not found.
+ identityPolicy = m_endpoint.Description.FindUserTokenPolicy(identity.TokenType, identity.IssuedTokenType);
+
+ if (identityPolicy == null)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadUserAccessDenied,
+ "Endpoint does not support the user identity type provided.");
+ }
+
+ identityToken.PolicyId = identityPolicy.PolicyId;
+ }
+
+ requireEncryption = securityPolicyUri != SecurityPolicies.None;
+
+ if (!requireEncryption)
+ {
+ requireEncryption = identityPolicy.SecurityPolicyUri != SecurityPolicies.None &&
+ !String.IsNullOrEmpty(identityPolicy.SecurityPolicyUri);
+ }
+ }
+
+ private void BuildCertificateData(out byte[] clientCertificateData, out byte[] clientCertificateChainData)
+ {
+ // send the application instance certificate for the client.
+ clientCertificateData = m_instanceCertificate != null ? m_instanceCertificate.RawData : null;
+ clientCertificateChainData = null;
+
+ if (m_instanceCertificateChain != null && m_instanceCertificateChain.Count > 0 &&
+ m_configuration.SecurityConfiguration.SendCertificateChain)
+ {
+ List clientCertificateChain = new List();
+
+ for (int i = 0; i < m_instanceCertificateChain.Count; i++)
+ {
+ clientCertificateChain.AddRange(m_instanceCertificateChain[i].RawData);
+ }
+
+ clientCertificateChainData = clientCertificateChain.ToArray();
+ }
+ }
+
+ ///
+ /// Validates the server certificate returned.
+ ///
+ private void ValidateServerCertificateData(byte[] serverCertificateData)
+ {
+ if (serverCertificateData != null &&
+ m_endpoint.Description.ServerCertificate != null &&
+ !Utils.IsEqual(serverCertificateData, m_endpoint.Description.ServerCertificate))
+ {
+ try
+ {
+ // verify for certificate chain in endpoint.
+ X509Certificate2Collection serverCertificateChain = Utils.ParseCertificateChainBlob(m_endpoint.Description.ServerCertificate);
+
+ if (serverCertificateChain.Count > 0 && !Utils.IsEqual(serverCertificateData, serverCertificateChain[0].RawData))
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadCertificateInvalid,
+ "Server did not return the certificate used to create the secure channel.");
+ }
+ }
+ catch (Exception)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadCertificateInvalid,
+ "Server did not return the certificate used to create the secure channel.");
+ }
+ }
+ }
+
+ ///
+ /// Validates the server signature created with the client nonce.
+ ///
+ private void ValidateServerSignature(X509Certificate2 serverCertificate, SignatureData serverSignature,
+ byte[] clientCertificateData, byte[] clientCertificateChainData, byte[] clientNonce)
+ {
+ if (serverSignature == null || serverSignature.Signature == null)
+ {
+ Utils.LogInfo("Server signature is null or empty.");
+
+ //throw ServiceResultException.Create(
+ // StatusCodes.BadSecurityChecksFailed,
+ // "Server signature is null or empty.");
+ }
+
+ // validate the server's signature.
+ byte[] dataToSign = Utils.Append(clientCertificateData, clientNonce);
+
+ if (!SecurityPolicies.Verify(serverCertificate, m_endpoint.Description.SecurityPolicyUri, dataToSign, serverSignature))
+ {
+ // validate the signature with complete chain if the check with leaf certificate failed.
+ if (clientCertificateChainData != null)
+ {
+ dataToSign = Utils.Append(clientCertificateChainData, clientNonce);
+
+ if (!SecurityPolicies.Verify(serverCertificate, m_endpoint.Description.SecurityPolicyUri, dataToSign, serverSignature))
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadApplicationSignatureInvalid,
+ "Server did not provide a correct signature for the nonce data provided by the client.");
+ }
+ }
+ else
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadApplicationSignatureInvalid,
+ "Server did not provide a correct signature for the nonce data provided by the client.");
+ }
+ }
+ }
+
+ ///
+ /// Validates the server endpoints returned.
+ ///
+ private void ValidateServerEndpoints(EndpointDescriptionCollection serverEndpoints)
+ {
+ if (m_discoveryServerEndpoints != null && m_discoveryServerEndpoints.Count > 0)
+ {
+ // Compare EndpointDescriptions returned at GetEndpoints with values returned at CreateSession
+ EndpointDescriptionCollection expectedServerEndpoints = null;
+
+ if (serverEndpoints != null &&
+ m_discoveryProfileUris != null && m_discoveryProfileUris.Count > 0)
+ {
+ // Select EndpointDescriptions with a transportProfileUri that matches the
+ // profileUris specified in the original GetEndpoints() request.
+ expectedServerEndpoints = new EndpointDescriptionCollection();
+
+ foreach (EndpointDescription serverEndpoint in serverEndpoints)
+ {
+ if (m_discoveryProfileUris.Contains(serverEndpoint.TransportProfileUri))
+ {
+ expectedServerEndpoints.Add(serverEndpoint);
+ }
+ }
+ }
+ else
+ {
+ expectedServerEndpoints = serverEndpoints;
+ }
+
+ if (expectedServerEndpoints == null ||
+ m_discoveryServerEndpoints.Count != expectedServerEndpoints.Count)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadSecurityChecksFailed,
+ "Server did not return a number of ServerEndpoints that matches the one from GetEndpoints.");
+ }
+
+ for (int ii = 0; ii < expectedServerEndpoints.Count; ii++)
+ {
+ EndpointDescription serverEndpoint = expectedServerEndpoints[ii];
+ EndpointDescription expectedServerEndpoint = m_discoveryServerEndpoints[ii];
+
+ if (serverEndpoint.SecurityMode != expectedServerEndpoint.SecurityMode ||
+ serverEndpoint.SecurityPolicyUri != expectedServerEndpoint.SecurityPolicyUri ||
+ serverEndpoint.TransportProfileUri != expectedServerEndpoint.TransportProfileUri ||
+ serverEndpoint.SecurityLevel != expectedServerEndpoint.SecurityLevel)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadSecurityChecksFailed,
+ "The list of ServerEndpoints returned at CreateSession does not match the list from GetEndpoints.");
+ }
+
+ if (serverEndpoint.UserIdentityTokens.Count != expectedServerEndpoint.UserIdentityTokens.Count)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadSecurityChecksFailed,
+ "The list of ServerEndpoints returned at CreateSession does not match the one from GetEndpoints.");
+ }
+
+ for (int jj = 0; jj < serverEndpoint.UserIdentityTokens.Count; jj++)
+ {
+ if (!serverEndpoint.UserIdentityTokens[jj].IsEqual(expectedServerEndpoint.UserIdentityTokens[jj]))
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadSecurityChecksFailed,
+ "The list of ServerEndpoints returned at CreateSession does not match the one from GetEndpoints.");
+ }
+ }
+ }
+ }
+
+ // find the matching description (TBD - check domains against certificate).
+ bool found = false;
+ Uri expectedUrl = Utils.ParseUri(m_endpoint.Description.EndpointUrl);
+
+ if (expectedUrl != null)
+ {
+ for (int ii = 0; ii < serverEndpoints.Count; ii++)
+ {
+ EndpointDescription serverEndpoint = serverEndpoints[ii];
+ Uri actualUrl = Utils.ParseUri(serverEndpoint.EndpointUrl);
+
+ if (actualUrl != null && actualUrl.Scheme == expectedUrl.Scheme)
+ {
+ if (serverEndpoint.SecurityPolicyUri == m_endpoint.Description.SecurityPolicyUri)
+ {
+ if (serverEndpoint.SecurityMode == m_endpoint.Description.SecurityMode)
+ {
+ // ensure endpoint has up to date information.
+ m_endpoint.Description.Server.ApplicationName = serverEndpoint.Server.ApplicationName;
+ m_endpoint.Description.Server.ApplicationUri = serverEndpoint.Server.ApplicationUri;
+ m_endpoint.Description.Server.ApplicationType = serverEndpoint.Server.ApplicationType;
+ m_endpoint.Description.Server.ProductUri = serverEndpoint.Server.ProductUri;
+ m_endpoint.Description.TransportProfileUri = serverEndpoint.TransportProfileUri;
+ m_endpoint.Description.UserIdentityTokens = serverEndpoint.UserIdentityTokens;
+
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // could be a security risk.
+ if (!found)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadSecurityChecksFailed,
+ "Server did not return an EndpointDescription that matched the one used to create the secure channel.");
+ }
+ }
+
+ ///
+ /// Helper to prepare the reconnect channel
+ /// and signature data before activate.
+ ///
+ private IAsyncResult PrepareReconnectBeginActivate(
+ ITransportWaitingConnection connection,
+ ITransportChannel transportChannel
+ )
+ {
+ Utils.LogInfo("Session RECONNECT {0} starting.", SessionId);
+
+ lock (SyncRoot)
+ {
+ // stop keep alives.
+ StopKeepAliveTimer();
+ }
+
+ // create the client signature.
+ byte[] dataToSign = Utils.Append(m_serverCertificate != null ? m_serverCertificate.RawData : null, m_serverNonce);
+ EndpointDescription endpoint = m_endpoint.Description;
+ SignatureData clientSignature = SecurityPolicies.Sign(m_instanceCertificate, endpoint.SecurityPolicyUri, dataToSign);
+
+ // check that the user identity is supported by the endpoint.
+ UserTokenPolicy identityPolicy = endpoint.FindUserTokenPolicy(m_identity.TokenType, m_identity.IssuedTokenType);
+
+ if (identityPolicy == null)
+ {
+ Utils.LogError("Reconnect: Endpoint does not support the user identity type provided.");
+
+ throw ServiceResultException.Create(
+ StatusCodes.BadUserAccessDenied,
+ "Endpoint does not support the user identity type provided.");
+ }
+
+ // select the security policy for the user token.
+ string securityPolicyUri = identityPolicy.SecurityPolicyUri;
+
+ if (String.IsNullOrEmpty(securityPolicyUri))
+ {
+ securityPolicyUri = endpoint.SecurityPolicyUri;
+ }
+
+ // need to refresh the identity (reprompt for password, refresh token).
+ if (m_RenewUserIdentity != null)
+ {
+ m_identity = m_RenewUserIdentity(this, m_identity);
+ }
+
+ // validate server nonce and security parameters for user identity.
+ ValidateServerNonce(
+ m_identity,
+ m_serverNonce,
+ securityPolicyUri,
+ m_previousServerNonce,
+ m_endpoint.Description.SecurityMode);
+
+ // sign data with user token.
+ UserIdentityToken identityToken = m_identity.GetIdentityToken();
+ identityToken.PolicyId = identityPolicy.PolicyId;
+ SignatureData userTokenSignature = identityToken.Sign(dataToSign, securityPolicyUri);
+
+ // encrypt token.
+ identityToken.Encrypt(m_serverCertificate, m_serverNonce, securityPolicyUri);
+
+ // send the software certificates assigned to the client.
+ SignedSoftwareCertificateCollection clientSoftwareCertificates = GetSoftwareCertificates();
+
+ Utils.LogInfo("Session REPLACING channel for {0}.", SessionId);
+
+ if (connection != null)
+ {
+ // check if the channel supports reconnect.
+ if ((TransportChannel.SupportedFeatures & TransportChannelFeatures.Reconnect) != 0)
+ {
+ TransportChannel.Reconnect(connection);
+ }
+ else
+ {
+ // initialize the channel which will be created with the server.
+ ITransportChannel channel = SessionChannel.Create(
+ m_configuration,
+ connection,
+ m_endpoint.Description,
+ m_endpoint.Configuration,
+ m_instanceCertificate,
+ m_configuration.SecurityConfiguration.SendCertificateChain ? m_instanceCertificateChain : null,
+ MessageContext);
+
+ // disposes the existing channel.
+ TransportChannel = channel;
+ }
+ }
+ else if (transportChannel != null)
+ {
+ TransportChannel = transportChannel;
+ }
+ else
+ {
+ // check if the channel supports reconnect.
+ if (TransportChannel != null && (TransportChannel.SupportedFeatures & TransportChannelFeatures.Reconnect) != 0)
+ {
+ TransportChannel.Reconnect();
+ }
+ else
+ {
+ // initialize the channel which will be created with the server.
+ ITransportChannel channel = SessionChannel.Create(
+ m_configuration,
+ m_endpoint.Description,
+ m_endpoint.Configuration,
+ m_instanceCertificate,
+ m_configuration.SecurityConfiguration.SendCertificateChain ? m_instanceCertificateChain : null,
+ MessageContext);
+
+ // disposes the existing channel.
+ TransportChannel = channel;
+ }
+ }
+
+ Utils.LogInfo("Session RE-ACTIVATING {0}.", SessionId);
+
+ RequestHeader header = new RequestHeader() { TimeoutHint = kReconnectTimeout };
+ return BeginActivateSession(
+ header,
+ clientSignature,
+ null,
+ m_preferredLocales,
+ new ExtensionObject(identityToken),
+ userTokenSignature,
+ null,
+ null);
+ }
+
+ ///
+ /// Process Republish error response.
+ ///
+ /// The exception that occurred during the republish operation.
+ /// The subscription Id for which the republish was requested.
+ /// The sequencenumber for which the republish was requested.
+ private bool ProcessRepublishResponseError(Exception e, uint subscriptionId, uint sequenceNumber)
+ {
+
+ ServiceResult error = new ServiceResult(e);
+
+ bool result = true;
+ switch (error.StatusCode.Code)
+ {
+ case StatusCodes.BadMessageNotAvailable:
+ Utils.LogWarning("Message {0}-{1} no longer available.", subscriptionId, sequenceNumber);
+ break;
+
+ // if encoding limits are exceeded, the issue is logged and
+ // the published data is acknowledged to prevent the endless republish loop.
+ case StatusCodes.BadEncodingLimitsExceeded:
+ Utils.LogError(e, "Message {0}-{1} exceeded size limits, ignored.", subscriptionId, sequenceNumber);
+ var ack = new SubscriptionAcknowledgement {
+ SubscriptionId = subscriptionId,
+ SequenceNumber = sequenceNumber
+ };
+ lock (SyncRoot)
+ {
+ m_acknowledgementsToSend.Add(ack);
+ }
+ break;
+ default:
+ result = false;
+ Utils.LogError(e, "Unexpected error sending republish request.");
+ break;
+ }
+
+ PublishErrorEventHandler callback = null;
+
+ lock (m_eventLock)
+ {
+ callback = m_PublishError;
+ }
+
+ // raise an error event.
+ if (callback != null)
+ {
+ try
+ {
+ PublishErrorEventArgs args = new PublishErrorEventArgs(
+ error,
+ subscriptionId,
+ sequenceNumber);
+
+ callback(this, args);
+ }
+ catch (Exception e2)
+ {
+ Utils.LogError(e2, "Session: Unexpected error invoking PublishErrorCallback.");
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// Handles the validation of server software certificates and application callback.
+ ///
+ private void HandleSignedSoftwareCertificates(SignedSoftwareCertificateCollection serverSoftwareCertificates)
+ {
+ // get a validator to check certificates provided by server.
+ CertificateValidator validator = m_configuration.CertificateValidator;
+
+ // validate software certificates.
+ List softwareCertificates = new List();
+
+ foreach (SignedSoftwareCertificate signedCertificate in serverSoftwareCertificates)
+ {
+ SoftwareCertificate softwareCertificate = null;
+
+ ServiceResult result = SoftwareCertificate.Validate(
+ validator,
+ signedCertificate.CertificateData,
+ out softwareCertificate);
+
+ if (ServiceResult.IsBad(result))
+ {
+ OnSoftwareCertificateError(signedCertificate, result);
+ }
+
+ softwareCertificates.Add(softwareCertificate);
+ }
+
+ // check if software certificates meet application requirements.
+ ValidateSoftwareCertificates(softwareCertificates);
+ }
+
///
/// Processes the response from a publish request.
///
@@ -5498,7 +5729,7 @@ private void ProcessPublishResponse(
}
#if DEBUG_SEQUENTIALPUBLISHING
- // Checks for debug info only.
+ // Checks for debug info only.
// Once more than a single publish request is queued, the checks are invalid
// because a publish response may not include the latest ack information yet.
@@ -5571,13 +5802,13 @@ private void ProcessPublishResponse(
// Validate publish time and reject old values.
if (notificationMessage.PublishTime.AddMilliseconds(subscription.CurrentPublishingInterval * subscription.CurrentLifetimeCount) < DateTime.UtcNow)
{
- Utils.LogWarning("PublishTime {0} in publish response is too old for SubscriptionId {1}.", notificationMessage.PublishTime.ToLocalTime(), subscription.Id);
+ Utils.LogTrace("PublishTime {0} in publish response is too old for SubscriptionId {1}.", notificationMessage.PublishTime.ToLocalTime(), subscription.Id);
}
// Validate publish time and reject old values.
if (notificationMessage.PublishTime > DateTime.UtcNow.AddMilliseconds(subscription.CurrentPublishingInterval * subscription.CurrentLifetimeCount))
{
- Utils.LogWarning("PublishTime {0} in publish response is newer than actual time for SubscriptionId {1}.", notificationMessage.PublishTime.ToLocalTime(), subscription.Id);
+ Utils.LogTrace("PublishTime {0} in publish response is newer than actual time for SubscriptionId {1}.", notificationMessage.PublishTime.ToLocalTime(), subscription.Id);
}
// update subscription cache.
diff --git a/Libraries/Opc.Ua.Client/SessionAsync.cs b/Libraries/Opc.Ua.Client/SessionAsync.cs
index c2b25bfc7..d5ebf6e3f 100644
--- a/Libraries/Opc.Ua.Client/SessionAsync.cs
+++ b/Libraries/Opc.Ua.Client/SessionAsync.cs
@@ -2,7 +2,7 @@
* Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
- *
+ *
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
@@ -11,7 +11,7 @@
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
- *
+ *
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
@@ -32,8 +32,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
+using Opc.Ua.Bindings;
namespace Opc.Ua.Client
{
@@ -41,8 +44,282 @@ namespace Opc.Ua.Client
/// Manages a session with a server.
/// Contains the async versions of the public session api.
///
- public partial class Session : SessionClientBatched, ISession, IDisposable
+ public partial class Session : SessionClientBatched, ISession
{
+ #region Open Async Methods
+ ///
+ public Task OpenAsync(
+ string sessionName,
+ IUserIdentity identity,
+ CancellationToken ct)
+ {
+ return OpenAsync(sessionName, 0, identity, null, ct);
+ }
+
+ ///
+ public Task OpenAsync(
+ string sessionName,
+ uint sessionTimeout,
+ IUserIdentity identity,
+ IList preferredLocales,
+ CancellationToken ct)
+ {
+ return OpenAsync(sessionName, sessionTimeout, identity, preferredLocales, true, ct);
+ }
+
+ ///
+ public async Task OpenAsync(
+ string sessionName,
+ uint sessionTimeout,
+ IUserIdentity identity,
+ IList preferredLocales,
+ bool checkDomain,
+ CancellationToken ct)
+ {
+ OpenValidateIdentity(ref identity, out var identityToken, out var identityPolicy, out string securityPolicyUri, out bool requireEncryption);
+
+ // validate the server certificate /certificate chain.
+ X509Certificate2 serverCertificate = null;
+ byte[] certificateData = m_endpoint.Description.ServerCertificate;
+
+ if (certificateData != null && certificateData.Length > 0)
+ {
+ X509Certificate2Collection serverCertificateChain = Utils.ParseCertificateChainBlob(certificateData);
+
+ if (serverCertificateChain.Count > 0)
+ {
+ serverCertificate = serverCertificateChain[0];
+ }
+
+ if (requireEncryption)
+ {
+ if (checkDomain)
+ {
+ await m_configuration.CertificateValidator.ValidateAsync(serverCertificateChain, m_endpoint, ct).ConfigureAwait(false);
+ }
+ else
+ {
+ await m_configuration.CertificateValidator.ValidateAsync(serverCertificateChain, ct).ConfigureAwait(false);
+ }
+ // save for reconnect
+ m_checkDomain = checkDomain;
+ }
+ }
+
+ // create a nonce.
+ uint length = (uint)m_configuration.SecurityConfiguration.NonceLength;
+ byte[] clientNonce = Utils.Nonce.CreateNonce(length);
+
+ // send the application instance certificate for the client.
+ BuildCertificateData(out byte[] clientCertificateData, out byte[] clientCertificateChainData);
+
+ ApplicationDescription clientDescription = new ApplicationDescription {
+ ApplicationUri = m_configuration.ApplicationUri,
+ ApplicationName = m_configuration.ApplicationName,
+ ApplicationType = ApplicationType.Client,
+ ProductUri = m_configuration.ProductUri
+ };
+
+ if (sessionTimeout == 0)
+ {
+ sessionTimeout = (uint)m_configuration.ClientConfiguration.DefaultSessionTimeout;
+ }
+
+ bool successCreateSession = false;
+ CreateSessionResponse response = null;
+
+ //if security none, first try to connect without certificate
+ if (m_endpoint.Description.SecurityPolicyUri == SecurityPolicies.None)
+ {
+ //first try to connect with client certificate NULL
+ try
+ {
+ response = await base.CreateSessionAsync(
+ null,
+ clientDescription,
+ m_endpoint.Description.Server.ApplicationUri,
+ m_endpoint.EndpointUrl.ToString(),
+ sessionName,
+ clientNonce,
+ null,
+ sessionTimeout,
+ (uint)MessageContext.MaxMessageSize,
+ ct).ConfigureAwait(false);
+
+ successCreateSession = true;
+ }
+ catch (Exception ex)
+ {
+ Utils.LogInfo("Create session failed with client certificate NULL. " + ex.Message);
+ successCreateSession = false;
+ }
+ }
+
+ if (!successCreateSession)
+ {
+ response = await base.CreateSessionAsync(
+ null,
+ clientDescription,
+ m_endpoint.Description.Server.ApplicationUri,
+ m_endpoint.EndpointUrl.ToString(),
+ sessionName,
+ clientNonce,
+ clientCertificateChainData != null ? clientCertificateChainData : clientCertificateData,
+ sessionTimeout,
+ (uint)MessageContext.MaxMessageSize,
+ ct).ConfigureAwait(false);
+ }
+
+ NodeId sessionId = response.SessionId;
+ NodeId sessionCookie = response.AuthenticationToken;
+ byte[] serverNonce = response.ServerNonce;
+ byte[] serverCertificateData = response.ServerCertificate;
+ SignatureData serverSignature = response.ServerSignature;
+ EndpointDescriptionCollection serverEndpoints = response.ServerEndpoints;
+ SignedSoftwareCertificateCollection serverSoftwareCertificates = response.ServerSoftwareCertificates;
+
+ m_sessionTimeout = response.RevisedSessionTimeout;
+ m_maxRequestMessageSize = response.MaxRequestMessageSize;
+
+ // save session id.
+ lock (SyncRoot)
+ {
+ base.SessionCreated(sessionId, sessionCookie);
+ }
+
+ Utils.LogInfo("Revised session timeout value: {0}. ", m_sessionTimeout);
+ Utils.LogInfo("Max response message size value: {0}. Max request message size: {1} ",
+ MessageContext.MaxMessageSize, m_maxRequestMessageSize);
+
+ //we need to call CloseSession if CreateSession was successful but some other exception is thrown
+ try
+ {
+ // verify that the server returned the same instance certificate.
+ ValidateServerCertificateData(serverCertificateData);
+
+ ValidateServerEndpoints(serverEndpoints);
+
+ ValidateServerSignature(serverCertificate, serverSignature, clientCertificateData, clientCertificateChainData, clientNonce);
+
+ HandleSignedSoftwareCertificates(serverSoftwareCertificates);
+
+ // create the client signature.
+ byte[] dataToSign = Utils.Append(serverCertificate != null ? serverCertificate.RawData : null, serverNonce);
+ SignatureData clientSignature = SecurityPolicies.Sign(m_instanceCertificate, securityPolicyUri, dataToSign);
+
+ // select the security policy for the user token.
+ securityPolicyUri = identityPolicy.SecurityPolicyUri;
+
+ if (String.IsNullOrEmpty(securityPolicyUri))
+ {
+ securityPolicyUri = m_endpoint.Description.SecurityPolicyUri;
+ }
+
+ byte[] previousServerNonce = null;
+
+ if (TransportChannel.CurrentToken != null)
+ {
+ previousServerNonce = TransportChannel.CurrentToken.ServerNonce;
+ }
+
+ // validate server nonce and security parameters for user identity.
+ ValidateServerNonce(
+ identity,
+ serverNonce,
+ securityPolicyUri,
+ previousServerNonce,
+ m_endpoint.Description.SecurityMode);
+
+ // sign data with user token.
+ SignatureData userTokenSignature = identityToken.Sign(dataToSign, securityPolicyUri);
+
+ // encrypt token.
+ identityToken.Encrypt(serverCertificate, serverNonce, securityPolicyUri);
+
+ // send the software certificates assigned to the client.
+ SignedSoftwareCertificateCollection clientSoftwareCertificates = GetSoftwareCertificates();
+
+ // copy the preferred locales if provided.
+ if (preferredLocales != null && preferredLocales.Count > 0)
+ {
+ m_preferredLocales = new StringCollection(preferredLocales);
+ }
+
+ // activate session.
+ ActivateSessionResponse activateResponse = await ActivateSessionAsync(
+ null,
+ clientSignature,
+ clientSoftwareCertificates,
+ m_preferredLocales,
+ new ExtensionObject(identityToken),
+ userTokenSignature,
+ ct).ConfigureAwait(false);
+
+ serverNonce = activateResponse.ServerNonce;
+ StatusCodeCollection certificateResults = activateResponse.Results;
+ DiagnosticInfoCollection certificateDiagnosticInfos = activateResponse.DiagnosticInfos;
+
+ if (certificateResults != null)
+ {
+ for (int i = 0; i < certificateResults.Count; i++)
+ {
+ Utils.LogInfo("ActivateSession result[{0}] = {1}", i, certificateResults[i]);
+ }
+ }
+
+ if (certificateResults == null || certificateResults.Count == 0)
+ {
+ Utils.LogInfo("Empty results were received for the ActivateSession call.");
+ }
+
+ // fetch namespaces.
+ await FetchNamespaceTablesAsync(ct).ConfigureAwait(false);
+
+ lock (SyncRoot)
+ {
+ // save nonces.
+ m_sessionName = sessionName;
+ m_identity = identity;
+ m_previousServerNonce = previousServerNonce;
+ m_serverNonce = serverNonce;
+ m_serverCertificate = serverCertificate;
+
+ // update system context.
+ m_systemContext.PreferredLocales = m_preferredLocales;
+ m_systemContext.SessionId = this.SessionId;
+ m_systemContext.UserIdentity = identity;
+ }
+
+ // fetch operation limits
+ await FetchOperationLimitsAsync(ct).ConfigureAwait(false);
+
+ // start keep alive thread.
+ StartKeepAliveTimer();
+
+ // raise event that session configuration chnaged.
+ IndicateSessionConfigurationChanged();
+ }
+ catch (Exception)
+ {
+ try
+ {
+ await base.CloseSessionAsync(null, false, ct).ConfigureAwait(false);
+ CloseChannel();
+ }
+ catch (Exception e)
+ {
+ Utils.LogError("Cleanup: CloseSession() or CloseChannel() raised exception. " + e.Message);
+ }
+ finally
+ {
+ SessionCreated(null, null);
+ }
+
+ throw;
+ }
+ }
+ #endregion
+
#region Subscription Async Methods
///
public async Task RemoveSubscriptionAsync(Subscription subscription, CancellationToken ct = default)
@@ -108,9 +385,9 @@ public async Task ReactivateSubscriptionsAsync(
if (subscriptionIds.Count > 0)
{
+ await m_reconnectLock.WaitAsync(ct).ConfigureAwait(false);
try
{
- await m_reconnectLock.WaitAsync().ConfigureAwait(false);
m_reconnecting = true;
for (int ii = 0; ii < subscriptions.Count; ii++)
@@ -176,7 +453,7 @@ public async Task ReactivateSubscriptionsAsync(
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, requests);
int ii = 0;
- foreach (var value in results)
+ foreach (CallMethodResult value in results)
{
ServiceResult result = ServiceResult.Good;
if (StatusCode.IsNotGood(value.StatusCode))
@@ -208,9 +485,9 @@ public async Task TransferSubscriptionsAsync(
if (subscriptionIds.Count > 0)
{
+ await m_reconnectLock.WaitAsync(ct).ConfigureAwait(false);
try
{
- await m_reconnectLock.WaitAsync().ConfigureAwait(false);
m_reconnecting = true;
TransferSubscriptionsResponse response = await base.TransferSubscriptionsAsync(null, subscriptionIds, sendInitialValues, ct).ConfigureAwait(false);
@@ -231,12 +508,12 @@ public async Task TransferSubscriptionsAsync(
{
if (StatusCode.IsGood(results[ii].StatusCode))
{
- if (await subscriptions[ii].TransferAsync(this, subscriptionIds[ii], results[ii].AvailableSequenceNumbers).ConfigureAwait(false))
+ if (await subscriptions[ii].TransferAsync(this, subscriptionIds[ii], results[ii].AvailableSequenceNumbers, ct).ConfigureAwait(false))
{
lock (SyncRoot)
{
// create ack for available sequence numbers
- foreach (var sequenceNumber in results[ii].AvailableSequenceNumbers)
+ foreach (uint sequenceNumber in results[ii].AvailableSequenceNumbers)
{
var ack = new SubscriptionAcknowledgement() {
SubscriptionId = subscriptionIds[ii],
@@ -278,6 +555,132 @@ public async Task TransferSubscriptionsAsync(
}
#endregion
+ #region FetchNamespaceTables Async Methods
+ ///
+ public async Task FetchNamespaceTablesAsync(CancellationToken ct = default)
+ {
+ ReadValueIdCollection nodesToRead = PrepareNamespaceTableNodesToRead();
+
+ // read from server.
+ ReadResponse response = await ReadAsync(
+ null,
+ 0,
+ TimestampsToReturn.Neither,
+ nodesToRead,
+ ct).ConfigureAwait(false);
+
+ DataValueCollection values = response.Results;
+ DiagnosticInfoCollection diagnosticInfos = response.DiagnosticInfos;
+ ResponseHeader responseHeader = response.ResponseHeader;
+
+ ValidateResponse(values, nodesToRead);
+ ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);
+
+ UpdateNamespaceTable(values, diagnosticInfos, responseHeader);
+ }
+ #endregion
+
+ #region FetchTypeTree Async Methods
+ ///
+ public async Task FetchTypeTreeAsync(ExpandedNodeId typeId, CancellationToken ct = default)
+ {
+ Node node = await NodeCache.FindAsync(typeId, ct).ConfigureAwait(false) as Node;
+
+ if (node != null)
+ {
+ var subTypes = new ExpandedNodeIdCollection();
+ foreach (IReference reference in node.Find(ReferenceTypeIds.HasSubtype, false))
+ {
+ subTypes.Add(reference.TargetId);
+ }
+ if (subTypes.Count > 0)
+ {
+ await FetchTypeTreeAsync(subTypes, ct).ConfigureAwait(false);
+ }
+ }
+ }
+
+ ///
+ public async Task FetchTypeTreeAsync(ExpandedNodeIdCollection typeIds, CancellationToken ct = default)
+ {
+ var referenceTypeIds = new NodeIdCollection() { ReferenceTypeIds.HasSubtype };
+ IList nodes = await NodeCache.FindReferencesAsync(typeIds, referenceTypeIds, false, false, ct).ConfigureAwait(false);
+ var subTypes = new ExpandedNodeIdCollection();
+ foreach (INode inode in nodes)
+ {
+ if (inode is Node node)
+ {
+ foreach (IReference reference in node.Find(ReferenceTypeIds.HasSubtype, false))
+ {
+ if (!typeIds.Contains(reference.TargetId))
+ {
+ subTypes.Add(reference.TargetId);
+ }
+ }
+ }
+ }
+ if (subTypes.Count > 0)
+ {
+ await FetchTypeTreeAsync(subTypes, ct).ConfigureAwait(false);
+ }
+ }
+ #endregion
+
+ #region FetchOperationLimits Async Methods
+ ///
+ /// Fetch the operation limits of the server.
+ ///
+ public async Task FetchOperationLimitsAsync(CancellationToken ct)
+ {
+ try
+ {
+ var operationLimitsProperties = typeof(OperationLimits)
+ .GetProperties().Select(p => p.Name).ToList();
+
+ var nodeIds = new NodeIdCollection(
+ operationLimitsProperties.Select(name => (NodeId)typeof(VariableIds)
+ .GetField("Server_ServerCapabilities_OperationLimits_" + name, BindingFlags.Public | BindingFlags.Static)
+ .GetValue(null))
+ );
+
+ (DataValueCollection values, IList errors) = await ReadValuesAsync(nodeIds, ct).ConfigureAwait(false);
+
+ OperationLimits configOperationLimits = m_configuration?.ClientConfiguration?.OperationLimits ?? new OperationLimits();
+ var operationLimits = new OperationLimits();
+
+ for (int ii = 0; ii < nodeIds.Count; ii++)
+ {
+ PropertyInfo property = typeof(OperationLimits).GetProperty(operationLimitsProperties[ii]);
+ uint value = (uint)property.GetValue(configOperationLimits);
+ if (values[ii] != null &&
+ ServiceResult.IsNotBad(errors[ii]))
+ {
+ if (values[ii].Value is uint serverValue)
+ {
+ if (serverValue > 0 &&
+ (value == 0 || serverValue < value))
+ {
+ value = serverValue;
+ }
+ }
+ }
+ property.SetValue(operationLimits, value);
+ }
+
+ OperationLimits = operationLimits;
+ }
+ catch (Exception ex)
+ {
+ Utils.LogError(ex, "Failed to read operation limits from server. Using configuration defaults.");
+ OperationLimits operationLimits = m_configuration?.ClientConfiguration?.OperationLimits;
+ if (operationLimits != null)
+ {
+ OperationLimits = operationLimits;
+ }
+ }
+ }
+ #endregion
+
#region ReadNode Async Methods
///
public async Task<(IList, IList)> ReadNodesAsync(
@@ -417,7 +820,7 @@ public async Task ReadNodeAsync(
CancellationToken ct = default)
{
// build list of attributes.
- var attributes = CreateAttributes(nodeClass, optionalAttributes);
+ IDictionary attributes = CreateAttributes(nodeClass, optionalAttributes);
// build list of values to read.
ReadValueIdCollection itemsToRead = new ReadValueIdCollection();
@@ -517,7 +920,7 @@ public async Task ReadValueAsync(
ClientBase.ValidateResponse(values, itemsToRead);
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, itemsToRead);
- foreach (var value in values)
+ foreach (DataValue value in values)
{
ServiceResult result = ServiceResult.Good;
if (StatusCode.IsBad(value.StatusCode))
@@ -531,6 +934,128 @@ public async Task ReadValueAsync(
}
#endregion
+ #region Browse Methods
+ ///
+ public async Task<(
+ ResponseHeader responseHeader,
+ ByteStringCollection continuationPoints,
+ IList referencesList,
+ IList errors
+ )> BrowseAsync(
+ RequestHeader requestHeader,
+ ViewDescription view,
+ IList nodesToBrowse,
+ uint maxResultsToReturn,
+ BrowseDirection browseDirection,
+ NodeId referenceTypeId,
+ bool includeSubtypes,
+ uint nodeClassMask,
+ CancellationToken ct = default)
+ {
+
+ BrowseDescriptionCollection browseDescription = new BrowseDescriptionCollection();
+ foreach (NodeId nodeToBrowse in nodesToBrowse)
+ {
+ BrowseDescription description = new BrowseDescription {
+ NodeId = nodeToBrowse,
+ BrowseDirection = browseDirection,
+ ReferenceTypeId = referenceTypeId,
+ IncludeSubtypes = includeSubtypes,
+ NodeClassMask = nodeClassMask,
+ ResultMask = (uint)BrowseResultMask.All
+ };
+
+ browseDescription.Add(description);
+ }
+
+ BrowseResponse browseResponse = await BrowseAsync(
+ requestHeader,
+ view,
+ maxResultsToReturn,
+ browseDescription,
+ ct).ConfigureAwait(false);
+
+ ClientBase.ValidateResponse(browseResponse.ResponseHeader);
+ BrowseResultCollection results = browseResponse.Results;
+ DiagnosticInfoCollection diagnosticInfos = browseResponse.DiagnosticInfos;
+
+ ClientBase.ValidateResponse(results, browseDescription);
+ ClientBase.ValidateDiagnosticInfos(diagnosticInfos, browseDescription);
+
+ int ii = 0;
+ var errors = new List();
+ var continuationPoints = new ByteStringCollection();
+ var referencesList = new List();
+ foreach (BrowseResult result in results)
+ {
+ if (StatusCode.IsBad(result.StatusCode))
+ {
+ errors.Add(new ServiceResult(result.StatusCode, ii, diagnosticInfos, browseResponse.ResponseHeader.StringTable));
+ }
+ else
+ {
+ errors.Add(ServiceResult.Good);
+ }
+ continuationPoints.Add(result.ContinuationPoint);
+ referencesList.Add(result.References);
+ ii++;
+ }
+
+ return (browseResponse.ResponseHeader, continuationPoints, referencesList, errors);
+ }
+ #endregion
+
+ #region BrowseNext Methods
+
+ ///
+ public async Task<(
+ ResponseHeader responseHeader,
+ ByteStringCollection revisedContinuationPoints,
+ IList referencesList,
+ List errors
+ )> BrowseNextAsync(
+ RequestHeader requestHeader,
+ ByteStringCollection continuationPoints,
+ bool releaseContinuationPoint,
+ CancellationToken ct = default)
+ {
+ BrowseNextResponse response = await base.BrowseNextAsync(
+ requestHeader,
+ releaseContinuationPoint,
+ continuationPoints,
+ ct).ConfigureAwait(false);
+
+ ClientBase.ValidateResponse(response.ResponseHeader);
+
+ BrowseResultCollection results = response.Results;
+ DiagnosticInfoCollection diagnosticInfos = response.DiagnosticInfos;
+
+ ClientBase.ValidateResponse(results, continuationPoints);
+ ClientBase.ValidateDiagnosticInfos(diagnosticInfos, continuationPoints);
+
+ int ii = 0;
+ var errors = new List();
+ var revisedContinuationPoints = new ByteStringCollection();
+ var referencesList = new List();
+ foreach (BrowseResult result in results)
+ {
+ if (StatusCode.IsBad(result.StatusCode))
+ {
+ errors.Add(new ServiceResult(result.StatusCode, ii, diagnosticInfos, response.ResponseHeader.StringTable));
+ }
+ else
+ {
+ errors.Add(ServiceResult.Good);
+ }
+ revisedContinuationPoints.Add(result.ContinuationPoint);
+ referencesList.Add(result.References);
+ ii++;
+ }
+
+ return (response.ResponseHeader, revisedContinuationPoints, referencesList, errors);
+ }
+ #endregion
+
#region Call Methods
///
public async Task> CallAsync(NodeId objectId, NodeId methodId, CancellationToken ct = default, params object[] args)
@@ -581,9 +1106,273 @@ public async Task> CallAsync(NodeId objectId, NodeId methodId, Can
}
#endregion
+ #region FetchReferences Async Methods
+ ///
+ public async Task FetchReferencesAsync(
+ NodeId nodeId,
+ CancellationToken ct = default)
+ {
+ // browse for all references.
+
+ ReferenceDescriptionCollection results = new ReferenceDescriptionCollection();
+ (
+ _,
+ ByteStringCollection continuationPoint,
+ IList descriptions,
+ _
+ ) = await BrowseAsync(
+ null,
+ null,
+ new[] { nodeId },
+ 0,
+ BrowseDirection.Both,
+ null,
+ true,
+ 0,
+ ct).ConfigureAwait(false);
+
+ if (descriptions.Count > 0)
+ {
+ results.AddRange(descriptions[0]);
+
+ // process any continuation point.
+ while (continuationPoint != null && continuationPoint.Count > 0 & continuationPoint[0] != null)
+ {
+ (
+ _,
+ ByteStringCollection revisedContinuationPoint,
+ IList additionalDescriptions,
+ _
+ ) = await BrowseNextAsync(
+ null,
+ continuationPoint,
+ false,
+ ct).ConfigureAwait(false);
+
+ continuationPoint = revisedContinuationPoint;
+
+ if (additionalDescriptions.Count > 0)
+ results.AddRange(additionalDescriptions[0]);
+ }
+ }
+ return results;
+ }
+
+ ///
+ public async Task<(IList, IList)> FetchReferencesAsync(
+ IList nodeIds,
+ CancellationToken ct = default)
+ {
+ var result = new List();
+
+ // browse for all references.
+ (
+ _,
+ ByteStringCollection continuationPoints,
+ IList descriptions,
+ IList errors
+ ) = await BrowseAsync(
+ null,
+ null,
+ nodeIds,
+ 0,
+ BrowseDirection.Both,
+ null,
+ true,
+ 0,
+ ct).ConfigureAwait(false);
+
+ result.AddRange(descriptions);
+
+ // process any continuation point.
+ List previousResult = result;
+ IList previousErrors = errors;
+ while (HasAnyContinuationPoint(continuationPoints))
+ {
+ var nextContinuationPoints = new ByteStringCollection();
+ var nextResult = new List();
+ var nextErrors = new List();
+
+ for (int ii = 0; ii < continuationPoints.Count; ii++)
+ {
+ byte[] cp = continuationPoints[ii];
+ if (cp != null)
+ {
+ nextContinuationPoints.Add(cp);
+ nextResult.Add(previousResult[ii]);
+ nextErrors.Add(previousErrors[ii]);
+ }
+ }
+
+ (
+ _,
+ ByteStringCollection revisedContinuationPoints,
+ IList nextDescriptions,
+ IList browseNextErrors
+ ) = await BrowseNextAsync(
+ null,
+ nextContinuationPoints,
+ false,
+ ct).ConfigureAwait(false);
+
+ continuationPoints = revisedContinuationPoints;
+ previousResult = nextResult;
+ previousErrors = nextErrors;
+
+ for (int ii = 0; ii < nextDescriptions.Count; ii++)
+ {
+ nextResult[ii].AddRange(nextDescriptions[ii]);
+ if (StatusCode.IsBad(browseNextErrors[ii].StatusCode))
+ {
+ nextErrors[ii] = browseNextErrors[ii];
+ }
+ }
+ }
+
+ return (result, errors);
+ }
+ #endregion
+
+ #region Recreate Async Methods
+ ///
+ /// Recreates a session based on a specified template.
+ ///
+ /// The Session object to use as template
+ ///
+ /// The new session object.
+ public static async Task RecreateAsync(Session sessionTemplate, CancellationToken ct = default)
+ {
+ ServiceMessageContext messageContext = sessionTemplate.m_configuration.CreateMessageContext();
+ messageContext.Factory = sessionTemplate.Factory;
+
+ // create the channel object used to connect to the server.
+ ITransportChannel channel = SessionChannel.Create(
+ sessionTemplate.m_configuration,
+ sessionTemplate.ConfiguredEndpoint.Description,
+ sessionTemplate.ConfiguredEndpoint.Configuration,
+ sessionTemplate.m_instanceCertificate,
+ sessionTemplate.m_configuration.SecurityConfiguration.SendCertificateChain ?
+ sessionTemplate.m_instanceCertificateChain : null,
+ messageContext);
+
+ // create the session object.
+ Session session = sessionTemplate.CloneSession(channel, true);
+
+ try
+ {
+ // open the session.
+ await session.OpenAsync(
+ sessionTemplate.SessionName,
+ (uint)sessionTemplate.SessionTimeout,
+ sessionTemplate.Identity,
+ sessionTemplate.PreferredLocales,
+ sessionTemplate.m_checkDomain,
+ ct).ConfigureAwait(false);
+
+ await session.RecreateSubscriptionsAsync(sessionTemplate.Subscriptions, ct).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ session.Dispose();
+ throw ServiceResultException.Create(StatusCodes.BadCommunicationError, e, "Could not recreate session. {0}", sessionTemplate.SessionName);
+ }
+
+ return session;
+ }
+
+ ///
+ /// Recreates a session based on a specified template.
+ ///
+ /// The Session object to use as template
+ /// The waiting reverse connection.
+ ///
+ /// The new session object.
+ public static async Task RecreateAsync(Session sessionTemplate, ITransportWaitingConnection connection, CancellationToken ct = default)
+ {
+ ServiceMessageContext messageContext = sessionTemplate.m_configuration.CreateMessageContext();
+ messageContext.Factory = sessionTemplate.Factory;
+
+ // create the channel object used to connect to the server.
+ ITransportChannel channel = SessionChannel.Create(
+ sessionTemplate.m_configuration,
+ connection,
+ sessionTemplate.m_endpoint.Description,
+ sessionTemplate.m_endpoint.Configuration,
+ sessionTemplate.m_instanceCertificate,
+ sessionTemplate.m_configuration.SecurityConfiguration.SendCertificateChain ?
+ sessionTemplate.m_instanceCertificateChain : null,
+ messageContext);
+
+ // create the session object.
+ Session session = sessionTemplate.CloneSession(channel, true);
+
+ try
+ {
+ // open the session.
+ await session.OpenAsync(
+ sessionTemplate.m_sessionName,
+ (uint)sessionTemplate.m_sessionTimeout,
+ sessionTemplate.m_identity,
+ sessionTemplate.m_preferredLocales,
+ sessionTemplate.m_checkDomain,
+ ct).ConfigureAwait(false);
+
+ await session.RecreateSubscriptionsAsync(sessionTemplate.Subscriptions, ct).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ session.Dispose();
+ throw ServiceResultException.Create(StatusCodes.BadCommunicationError, e, "Could not recreate session. {0}", sessionTemplate.m_sessionName);
+ }
+
+ return session;
+ }
+
+ ///
+ /// Recreates a session based on a specified template using the provided channel.
+ ///
+ /// The Session object to use as template
+ /// The waiting reverse connection.
+ ///
+ /// The new session object.
+ public static async Task RecreateAsync(Session sessionTemplate, ITransportChannel transportChannel, CancellationToken ct = default)
+ {
+ ServiceMessageContext messageContext = sessionTemplate.m_configuration.CreateMessageContext();
+ messageContext.Factory = sessionTemplate.Factory;
+
+ // create the session object.
+ Session session = sessionTemplate.CloneSession(transportChannel, true);
+
+ try
+ {
+ // open the session.
+ await session.OpenAsync(
+ sessionTemplate.m_sessionName,
+ (uint)sessionTemplate.m_sessionTimeout,
+ sessionTemplate.m_identity,
+ sessionTemplate.m_preferredLocales,
+ sessionTemplate.m_checkDomain,
+ ct).ConfigureAwait(false);
+
+ // create the subscriptions.
+ foreach (Subscription subscription in session.Subscriptions)
+ {
+ await subscription.CreateAsync(ct).ConfigureAwait(false);
+ }
+ }
+ catch (Exception e)
+ {
+ session.Dispose();
+ throw ServiceResultException.Create(StatusCodes.BadCommunicationError, e, "Could not recreate session. {0}", sessionTemplate.m_sessionName);
+ }
+
+ return session;
+ }
+ #endregion
+
#region Close Async Methods
///
- public Task CloseAsync(CancellationToken ct = default)
+ public override Task CloseAsync(CancellationToken ct = default)
{
return CloseAsync(m_keepAliveInterval, true, ct);
}
@@ -641,7 +1430,7 @@ public virtual async Task CloseAsync(int timeout, bool closeChannel,
{
// close the session and delete all subscriptions if specified.
this.OperationTimeout = timeout;
- var response = await base.CloseSessionAsync(null, m_deleteSubscriptionsOnClose, ct).ConfigureAwait(false);
+ CloseSessionResponse response = await base.CloseSessionAsync(null, m_deleteSubscriptionsOnClose, ct).ConfigureAwait(false);
this.OperationTimeout = existingTimeout;
if (closeChannel)
@@ -682,6 +1471,194 @@ public virtual async Task CloseAsync(int timeout, bool closeChannel,
return result;
}
#endregion
+
+ #region Reconnect Async Methods
+ ///
+ public Task ReconnectAsync(CancellationToken ct)
+ => ReconnectAsync(null, null, ct);
+
+ ///
+ public Task ReconnectAsync(ITransportWaitingConnection connection, CancellationToken ct)
+ => ReconnectAsync(connection, null, ct);
+
+ ///
+ public Task ReconnectAsync(ITransportChannel channel, CancellationToken ct)
+ => ReconnectAsync(null, channel, ct);
+
+ ///
+ /// Reconnects to the server after a network failure using a waiting connection.
+ ///
+ private async Task ReconnectAsync(ITransportWaitingConnection connection, ITransportChannel transportChannel, CancellationToken ct)
+ {
+ bool resetReconnect = false;
+ await m_reconnectLock.WaitAsync(ct).ConfigureAwait(false);
+ try
+ {
+ bool reconnecting = m_reconnecting;
+ m_reconnecting = true;
+ resetReconnect = true;
+ m_reconnectLock.Release();
+
+ // check if already connecting.
+ if (reconnecting)
+ {
+ Utils.LogWarning("Session is already attempting to reconnect.");
+
+ throw ServiceResultException.Create(
+ StatusCodes.BadInvalidState,
+ "Session is already attempting to reconnect.");
+ }
+
+ IAsyncResult result = PrepareReconnectBeginActivate(
+ connection,
+ transportChannel);
+
+ if (!(result is ChannelAsyncOperation operation)) throw new ArgumentNullException(nameof(result));
+
+ try
+ {
+ _ = await operation.EndAsync(kReconnectTimeout / 2, true, ct).ConfigureAwait(false);
+ }
+ catch (ServiceResultException)
+ {
+ Utils.LogWarning("WARNING: ACTIVATE SESSION {0} timed out. {1}/{2}", SessionId, GoodPublishRequestCount, OutstandingRequestCount);
+ }
+
+ // reactivate session.
+ byte[] serverNonce = null;
+ StatusCodeCollection certificateResults = null;
+ DiagnosticInfoCollection certificateDiagnosticInfos = null;
+
+ EndActivateSession(
+ result,
+ out serverNonce,
+ out certificateResults,
+ out certificateDiagnosticInfos);
+
+ int publishCount = 0;
+
+ Utils.LogInfo("Session RECONNECT {0} completed successfully.", SessionId);
+
+ lock (SyncRoot)
+ {
+ m_previousServerNonce = m_serverNonce;
+ m_serverNonce = serverNonce;
+ publishCount = GetMinPublishRequestCount(true);
+ }
+
+ await m_reconnectLock.WaitAsync(ct).ConfigureAwait(false);
+ m_reconnecting = false;
+ resetReconnect = false;
+ m_reconnectLock.Release();
+
+ // refill pipeline.
+ for (int ii = 0; ii < publishCount; ii++)
+ {
+ BeginPublish(OperationTimeout);
+ }
+
+ StartKeepAliveTimer();
+
+ IndicateSessionConfigurationChanged();
+ }
+ finally
+ {
+ if (resetReconnect)
+ {
+ await m_reconnectLock.WaitAsync(ct).ConfigureAwait(false);
+ m_reconnecting = false;
+ m_reconnectLock.Release();
+ }
+ }
+ }
+
+ ///
+ public async Task RepublishAsync(uint subscriptionId, uint sequenceNumber, CancellationToken ct)
+ {
+ // send republish request.
+ RequestHeader requestHeader = new RequestHeader {
+ TimeoutHint = (uint)OperationTimeout,
+ ReturnDiagnostics = (uint)(int)ReturnDiagnostics,
+ RequestHandle = Utils.IncrementIdentifier(ref m_publishCounter)
+ };
+
+ try
+ {
+ Utils.LogInfo("Requesting RepublishAsync for {0}-{1}", subscriptionId, sequenceNumber);
+
+ // request republish.
+ RepublishResponse response = await RepublishAsync(
+ requestHeader,
+ subscriptionId,
+ sequenceNumber,
+ ct).ConfigureAwait(false);
+ ResponseHeader responseHeader = response.ResponseHeader;
+ NotificationMessage notificationMessage = response.NotificationMessage;
+
+ Utils.LogInfo("Received RepublishAsync for {0}-{1}-{2}", subscriptionId, sequenceNumber, responseHeader.ServiceResult);
+
+ // process response.
+ ProcessPublishResponse(
+ responseHeader,
+ subscriptionId,
+ null,
+ false,
+ notificationMessage);
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ return ProcessRepublishResponseError(e, subscriptionId, sequenceNumber);
+ }
+ }
+
+ ///
+ /// Recreate the subscriptions in a reconnected session.
+ /// Uses Transfer service if is set to true.
+ ///
+ /// The template for the subscriptions.
+ ///
+ private async Task RecreateSubscriptionsAsync(IEnumerable subscriptionsTemplate, CancellationToken ct)
+ {
+ bool transferred = false;
+ if (TransferSubscriptionsOnReconnect)
+ {
+ try
+ {
+ transferred = await TransferSubscriptionsAsync(new SubscriptionCollection(subscriptionsTemplate), false, ct).ConfigureAwait(false);
+ }
+ catch (ServiceResultException sre)
+ {
+ if (sre.StatusCode == StatusCodes.BadServiceUnsupported)
+ {
+ TransferSubscriptionsOnReconnect = false;
+ Utils.LogWarning("Transfer subscription unsupported, TransferSubscriptionsOnReconnect set to false.");
+ }
+ else
+ {
+ Utils.LogError(sre, "Transfer subscriptions failed.");
+ }
+ }
+ catch (Exception ex)
+ {
+ Utils.LogError(ex, "Unexpected Transfer subscriptions error.");
+ }
+ }
+
+ if (!transferred)
+ {
+ // Create the subscriptions which were not transferred.
+ foreach (Subscription subscription in Subscriptions)
+ {
+ if (!subscription.Created)
+ {
+ await subscription.CreateAsync(ct).ConfigureAwait(false);
+ }
+ }
+ }
+ }
+ #endregion
}
}
#endif
diff --git a/Libraries/Opc.Ua.Client/SessionConfiguration.cs b/Libraries/Opc.Ua.Client/SessionConfiguration.cs
index 3d67b80a7..b337e06a0 100644
--- a/Libraries/Opc.Ua.Client/SessionConfiguration.cs
+++ b/Libraries/Opc.Ua.Client/SessionConfiguration.cs
@@ -27,6 +27,7 @@
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/
+using System;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
@@ -38,6 +39,11 @@ namespace Opc.Ua.Client
/// needed to reconnect a session with a new secure channel.
///
[DataContract(Namespace = Namespaces.OpcUaXsd)]
+ [KnownType(typeof(UserIdentityToken))]
+ [KnownType(typeof(AnonymousIdentityToken))]
+ [KnownType(typeof(X509IdentityToken))]
+ [KnownType(typeof(IssuedIdentityToken))]
+ [KnownType(typeof(UserIdentity))]
public class SessionConfiguration
{
///
@@ -45,6 +51,7 @@ public class SessionConfiguration
///
internal SessionConfiguration(ISession session, byte[] serverNonce, NodeId authenthicationToken)
{
+ Timestamp = DateTime.UtcNow;
SessionName = session.SessionName;
SessionId = session.SessionId;
AuthenticationToken = authenthicationToken;
@@ -63,54 +70,58 @@ public static SessionConfiguration Create(Stream stream)
XmlReaderSettings settings = Utils.DefaultXmlReaderSettings();
using (XmlReader reader = XmlReader.Create(stream, settings))
{
- DataContractSerializer serializer = new DataContractSerializer(typeof(SessionConfiguration),
- new [] { typeof(UserIdentityToken), typeof(AnonymousIdentityToken), typeof(X509IdentityToken),
- typeof(IssuedIdentityToken), typeof(UserIdentity) });
+ DataContractSerializer serializer = new DataContractSerializer(typeof(SessionConfiguration));
SessionConfiguration sessionConfiguration = (SessionConfiguration)serializer.ReadObject(reader);
return sessionConfiguration;
}
}
+ ///
+ /// When the session configuration was created.
+ ///
+ [DataMember(IsRequired = true, Order = 10)]
+ public DateTime Timestamp { get; set; }
+
///
/// The session name used by the client.
///
- [DataMember(IsRequired=true, Order = 10)]
+ [DataMember(IsRequired = true, Order = 20)]
public string SessionName { get; set; }
///
/// The session id assigned by the server.
///
- [DataMember(IsRequired = true, Order = 20)]
+ [DataMember(IsRequired = true, Order = 30)]
public NodeId SessionId { get; set; }
///
/// The authentication token used by the server to identify the session.
///
- [DataMember(IsRequired = true, Order = 30)]
+ [DataMember(IsRequired = true, Order = 40)]
public NodeId AuthenticationToken { get; set; }
///
/// The identity used to create the session.
///
- [DataMember(IsRequired = true, Order = 40)]
+ [DataMember(IsRequired = true, Order = 50)]
public IUserIdentity Identity { get; set; }
///
/// The configured endpoint for the secure channel.
///
- [DataMember(IsRequired = true, Order = 50)]
+ [DataMember(IsRequired = true, Order = 60)]
public ConfiguredEndpoint ConfiguredEndpoint { get; set; }
///
/// If the client is configured to check the certificate domain.
///
- [DataMember(IsRequired = false, Order = 60)]
+ [DataMember(IsRequired = false, Order = 70)]
public bool CheckDomain { get; set; }
///
/// The last server nonce received.
///
- [DataMember(IsRequired = true, Order = 70)]
+ [DataMember(IsRequired = true, Order = 80)]
public byte[] ServerNonce { get; set; }
}
}
diff --git a/Libraries/Opc.Ua.Client/SessionObsolete.cs b/Libraries/Opc.Ua.Client/SessionObsolete.cs
index 12c75a9f5..b4c35d727 100644
--- a/Libraries/Opc.Ua.Client/SessionObsolete.cs
+++ b/Libraries/Opc.Ua.Client/SessionObsolete.cs
@@ -40,7 +40,7 @@ namespace Opc.Ua.Client
///
/// Obsolete warnings for service calls which should not be used when using the Session API.
///
- public partial class Session : SessionClientBatched, ISession, IDisposable
+ public partial class Session : SessionClientBatched, ISession
{
///
[Obsolete("Call Create instead. Service Call doesn't create Session.")]
diff --git a/Libraries/Opc.Ua.Client/SessionReconnectHandler.cs b/Libraries/Opc.Ua.Client/SessionReconnectHandler.cs
index d4485934e..e66204940 100644
--- a/Libraries/Opc.Ua.Client/SessionReconnectHandler.cs
+++ b/Libraries/Opc.Ua.Client/SessionReconnectHandler.cs
@@ -95,7 +95,7 @@ public enum ReconnectState
public SessionReconnectHandler(bool reconnectAbort = false, int maxReconnectPeriod = -1)
{
m_reconnectAbort = reconnectAbort;
- m_reconnectTimer = new Timer(OnReconnect, this, Timeout.Infinite, Timeout.Infinite);
+ m_reconnectTimer = new Timer(OnReconnectAsync, this, Timeout.Infinite, Timeout.Infinite);
m_state = ReconnectState.Ready;
m_cancelReconnect = false;
m_updateFromServer = false;
@@ -285,7 +285,7 @@ public virtual int CheckedReconnectPeriod(int reconnectPeriod, bool exponentialB
///
/// Called when the reconnect timer expires.
///
- private async void OnReconnect(object state)
+ private async void OnReconnectAsync(object state)
{
DateTime reconnectStart = DateTime.UtcNow;
try
@@ -320,7 +320,7 @@ private async void OnReconnect(object state)
// do the reconnect.
if (keepaliveRecovered ||
- await DoReconnect().ConfigureAwait(false))
+ await DoReconnectAsync().ConfigureAwait(false))
{
lock (m_lock)
{
@@ -365,7 +365,7 @@ await DoReconnect().ConfigureAwait(false))
///
/// Reconnects to the server.
///
- private async Task DoReconnect()
+ private async Task DoReconnectAsync()
{
// helper to override operation timeout
int operationTimeout = m_session.OperationTimeout;
@@ -384,11 +384,11 @@ private async Task DoReconnect()
m_session.Endpoint.Server.ApplicationUri
).ConfigureAwait(false);
- m_session.Reconnect(connection);
+ await m_session.ReconnectAsync(connection).ConfigureAwait(false);
}
else
{
- m_session.Reconnect();
+ await m_session.ReconnectAsync().ConfigureAwait(false);
}
// monitored items should start updating on their own.
@@ -418,12 +418,15 @@ private async Task DoReconnect()
}
// check if the security configuration may have changed
- if (sre.StatusCode == StatusCodes.BadSecurityChecksFailed)
+ if (sre.StatusCode == StatusCodes.BadSecurityChecksFailed ||
+ sre.StatusCode == StatusCodes.BadCertificateInvalid)
{
m_updateFromServer = true;
Utils.LogInfo("Reconnect failed due to security check. Request endpoint update from server. {0}", sre.Message);
}
- else
+ // wait for next scheduled reconnect if connection failed,
+ // otherwise recreate session immediately
+ else if (sre.StatusCode != StatusCodes.BadSessionIdInvalid)
{
// next attempt is to recreate session
m_reconnectFailed = true;
@@ -486,13 +489,15 @@ await endpoint.UpdateFromServerAsync(
session = await m_session.SessionFactory.RecreateAsync(m_session).ConfigureAwait(false);
}
- m_session.Close();
+ // note: the template session is not connected at this point
+ // and must be disposed by the owner
m_session = session;
return true;
}
catch (ServiceResultException sre)
{
- if (sre.InnerResult?.StatusCode == StatusCodes.BadSecurityChecksFailed)
+ if (sre.InnerResult?.StatusCode == StatusCodes.BadSecurityChecksFailed ||
+ sre.InnerResult?.StatusCode == StatusCodes.BadCertificateInvalid)
{
// schedule endpoint update and retry
m_updateFromServer = true;
@@ -533,7 +538,7 @@ private void EnterReadyState()
#endregion
#region Private Fields
- private object m_lock = new object();
+ private readonly object m_lock = new object();
private ISession m_session;
private ReconnectState m_state;
private Random m_random;
diff --git a/Libraries/Opc.Ua.Client/Subscription.cs b/Libraries/Opc.Ua.Client/Subscription.cs
index 2787245bf..a8a3dde8c 100644
--- a/Libraries/Opc.Ua.Client/Subscription.cs
+++ b/Libraries/Opc.Ua.Client/Subscription.cs
@@ -28,7 +28,6 @@
* ======================================================================*/
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
@@ -122,7 +121,7 @@ public Subscription(Subscription template, bool copyEventHandlers)
// copy the list of monitored items.
foreach (MonitoredItem monitoredItem in template.MonitoredItems)
{
- MonitoredItem clone = new MonitoredItem(monitoredItem, copyEventHandlers, true);
+ MonitoredItem clone = monitoredItem.CloneMonitoredItem(copyEventHandlers, true);
clone.DisplayName = monitoredItem.DisplayName;
AddItem(clone);
}
@@ -146,7 +145,7 @@ private void ResetPublishTimerAndWorkerState()
/// Called by the .NET framework during deserialization.
///
[OnDeserializing]
- private void Initialize(StreamingContext context)
+ protected void Initialize(StreamingContext context)
{
m_cache = new object();
Initialize();
@@ -219,8 +218,16 @@ public virtual object Clone()
///
public new object MemberwiseClone()
{
- var clone = new Subscription(this);
- return clone;
+ return new Subscription(this);
+ }
+
+ ///
+ /// Clones a subscription or a subclass with an option to copy event handlers.
+ ///
+ /// A cloned instance of the subscription or its subclass.
+ public virtual Subscription CloneSubscription(bool copyEventHandlers)
+ {
+ return new Subscription(this, copyEventHandlers);
}
#endregion
@@ -797,9 +804,10 @@ public bool PublishingStopped
{
lock (m_cache)
{
- int keepAliveInterval = (int)(Math.Min(m_currentPublishingInterval * m_currentKeepAliveCount, Int32.MaxValue - 500));
+ int keepAliveInterval = (int)(Math.Min(m_currentPublishingInterval * (m_currentKeepAliveCount + 1), Int32.MaxValue - 500));
+ TimeSpan timeSinceLastNotification = DateTime.UtcNow - m_lastNotificationTime;
- if (m_lastNotificationTime.AddMilliseconds(keepAliveInterval + 500) < DateTime.UtcNow)
+ if (timeSinceLastNotification.TotalMilliseconds > keepAliveInterval + 500)
{
return true;
}
@@ -1822,7 +1830,7 @@ private void StartKeepAliveTimer()
if (m_messageWorkerTask == null || m_messageWorkerTask.IsCompleted)
{
m_messageWorkerShutdownEvent.Reset();
- m_messageWorkerTask = Task.Run(() => PublishResponseMessageWorker());
+ m_messageWorkerTask = Task.Run(() => PublishResponseMessageWorkerAsync());
}
}
@@ -1869,9 +1877,9 @@ private void OnKeepAlive(object state)
}
///
- /// Periodically checks if the sessions have timed out.
+ /// Publish response worker task for the subscriptions.
///
- private async Task PublishResponseMessageWorker()
+ private async Task PublishResponseMessageWorkerAsync()
{
try
{
@@ -1886,7 +1894,8 @@ private async Task PublishResponseMessageWorker()
Utils.LogTrace("SubscriptionId {0} - Publish Thread {1:X8} Exited Normally.", m_id, Environment.CurrentManagedThreadId);
break;
}
- OnMessageReceived();
+
+ await OnMessageReceivedAsync(CancellationToken.None).ConfigureAwait(false);
}
while (true);
}
@@ -2084,7 +2093,7 @@ private void AdjustCounts(ref uint keepAliveCount, ref uint lifetimeCount)
///
/// Processes the incoming messages.
///
- private void OnMessageReceived()
+ private async Task OnMessageReceivedAsync(CancellationToken ct)
{
try
{
@@ -2256,6 +2265,9 @@ private void OnMessageReceived()
if (statusChanged != null)
{
+ statusChanged.PublishTime = message.PublishTime;
+ statusChanged.SequenceNumber = message.SequenceNumber;
+
Utils.LogWarning("StatusChangeNotification received with Status = {0} for SubscriptionId={1}.",
statusChanged.Status.ToString(), Id);
@@ -2300,7 +2312,7 @@ private void OnMessageReceived()
{
for (int ii = 0; ii < messagesToRepublish.Count; ii++)
{
- if (!session.Republish(subscriptionId, messagesToRepublish[ii].SequenceNumber))
+ if (!await session.RepublishAsync(subscriptionId, messagesToRepublish[ii].SequenceNumber, ct).ConfigureAwait(false))
{
messagesToRepublish[ii].Republished = false;
}
@@ -2951,6 +2963,17 @@ public virtual object Clone()
clone.AddRange(this.Select(item => (Subscription)item.Clone()));
return clone;
}
+
+ ///
+ /// Helper to clone a SubscriptionCollection with event handlers using the
+ /// method.
+ ///
+ public virtual SubscriptionCollection CloneSubscriptions(bool copyEventhandlers)
+ {
+ SubscriptionCollection clone = new SubscriptionCollection();
+ clone.AddRange(this.Select(item => (Subscription)item.CloneSubscription(copyEventhandlers)));
+ return clone;
+ }
#endregion
}
}
diff --git a/Libraries/Opc.Ua.Client/SubscriptionAsync.cs b/Libraries/Opc.Ua.Client/SubscriptionAsync.cs
index 4f40ca547..dfae46627 100644
--- a/Libraries/Opc.Ua.Client/SubscriptionAsync.cs
+++ b/Libraries/Opc.Ua.Client/SubscriptionAsync.cs
@@ -452,7 +452,7 @@ public async Task> SetMonitoringModeAsync(
///
/// Tells the server to refresh all conditions being monitored by the subscription.
///
- public async Task ConditionRefreshAsync(CancellationToken ct = default(CancellationToken))
+ public async Task ConditionRefreshAsync(CancellationToken ct = default)
{
VerifySubscriptionState(true);
diff --git a/Libraries/Opc.Ua.Client/TraceableSession.cs b/Libraries/Opc.Ua.Client/TraceableSession.cs
index 5b9c5a782..9c42f568c 100644
--- a/Libraries/Opc.Ua.Client/TraceableSession.cs
+++ b/Libraries/Opc.Ua.Client/TraceableSession.cs
@@ -2,7 +2,7 @@
* Copyright (c) 2005-2023 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
- *
+ *
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
@@ -11,7 +11,7 @@
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
- *
+ *
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
@@ -31,6 +31,9 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -65,7 +68,7 @@ public TraceableSession(ISession session)
///
/// The ISession which is being traced.
///
- private ISession m_session;
+ private readonly ISession m_session;
///
public ISession Session => m_session;
@@ -272,10 +275,26 @@ public int OperationTimeout
///
public bool CheckDomain => m_session.CheckDomain;
+ ///
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(this, obj)) return true;
+ // Presume that the wrapper is being compared to the
+ // wrapped object, e.g. in a keep alive callback.
+ if (ReferenceEquals(m_session, obj)) return true;
+ return m_session?.Equals(obj) ?? false;
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return m_session?.GetHashCode() ?? base.GetHashCode();
+ }
+
///
public void Reconnect()
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Reconnect)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.Reconnect();
}
@@ -284,7 +303,7 @@ public void Reconnect()
///
public void Reconnect(ITransportWaitingConnection connection)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Reconnect)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.Reconnect(connection);
}
@@ -293,61 +312,88 @@ public void Reconnect(ITransportWaitingConnection connection)
///
public void Reconnect(ITransportChannel channel)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Reconnect)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.Reconnect(channel);
}
}
///
- public void Save(string filePath)
+ public async Task ReconnectAsync(CancellationToken ct = default)
+ {
+ using (Activity activity = ActivitySource.StartActivity())
+ {
+ await m_session.ReconnectAsync(ct).ConfigureAwait(false);
+ }
+ }
+
+ ///
+ public async Task ReconnectAsync(ITransportWaitingConnection connection, CancellationToken ct = default)
+ {
+ using (Activity activity = ActivitySource.StartActivity())
+ {
+ await m_session.ReconnectAsync(connection, ct).ConfigureAwait(false);
+ }
+ }
+
+ ///
+ public async Task ReconnectAsync(ITransportChannel channel, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Save)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- m_session.Save(filePath);
+ await m_session.ReconnectAsync(channel, ct).ConfigureAwait(false);
}
}
///
- public void Save(Stream stream, IEnumerable subscriptions)
+ public void Save(string filePath, IEnumerable knownTypes = null)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Save)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- m_session.Save(stream, subscriptions);
+ m_session.Save(filePath, knownTypes);
}
}
///
- public void Save(string filePath, IEnumerable subscriptions)
+ public void Save(Stream stream, IEnumerable subscriptions, IEnumerable knownTypes = null)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Save)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- m_session.Save(filePath, subscriptions);
+ m_session.Save(stream, subscriptions, knownTypes);
}
}
///
- public IEnumerable Load(Stream stream, bool transferSubscriptions = false)
+ public void Save(string filePath, IEnumerable subscriptions, IEnumerable knownTypes = null)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Load)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.Load(stream, transferSubscriptions);
+ m_session.Save(filePath, subscriptions, knownTypes);
}
}
///
- public IEnumerable Load(string filePath, bool transferSubscriptions = false)
+ public IEnumerable Load(Stream stream, bool transferSubscriptions = false, IEnumerable knownTypes = null)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Load)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.Load(filePath, transferSubscriptions);
+ return m_session.Load(stream, transferSubscriptions, knownTypes);
+ }
+ }
+
+ ///
+ public IEnumerable Load(string filePath, bool transferSubscriptions = false, IEnumerable knownTypes = null)
+ {
+ using (Activity activity = ActivitySource.StartActivity())
+ {
+ return m_session.Load(filePath, transferSubscriptions, knownTypes);
}
}
///
public void FetchNamespaceTables()
{
- using (Activity activity = ActivitySource.StartActivity(nameof(FetchNamespaceTables)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.FetchNamespaceTables();
}
@@ -356,7 +402,7 @@ public void FetchNamespaceTables()
///
public void FetchTypeTree(ExpandedNodeId typeId)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(FetchTypeTree)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.FetchTypeTree(typeId);
}
@@ -365,16 +411,34 @@ public void FetchTypeTree(ExpandedNodeId typeId)
///
public void FetchTypeTree(ExpandedNodeIdCollection typeIds)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(FetchTypeTree)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.FetchTypeTree(typeIds);
}
}
+ ///
+ public async Task FetchTypeTreeAsync(ExpandedNodeId typeId, CancellationToken ct = default)
+ {
+ using (Activity activity = ActivitySource.StartActivity())
+ {
+ await m_session.FetchTypeTreeAsync(typeId, ct).ConfigureAwait(false);
+ }
+ }
+
+ ///
+ public async Task FetchTypeTreeAsync(ExpandedNodeIdCollection typeIds, CancellationToken ct = default)
+ {
+ using (Activity activity = ActivitySource.StartActivity())
+ {
+ await m_session.FetchTypeTreeAsync(typeIds, ct).ConfigureAwait(false);
+ }
+ }
+
///
public ReferenceDescriptionCollection ReadAvailableEncodings(NodeId variableId)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadAvailableEncodings)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.ReadAvailableEncodings(variableId);
}
@@ -383,43 +447,43 @@ public ReferenceDescriptionCollection ReadAvailableEncodings(NodeId variableId)
///
public ReferenceDescription FindDataDescription(NodeId encodingId)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(FindDataDescription)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.FindDataDescription(encodingId);
}
}
///
- public Task FindDataDictionary(NodeId descriptionId)
+ public async Task FindDataDictionary(NodeId descriptionId, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(FindDataDictionary)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.FindDataDictionary(descriptionId);
+ return await m_session.FindDataDictionary(descriptionId, ct).ConfigureAwait(false);
}
}
///
- public async Task LoadDataDictionary(ReferenceDescription dictionaryNode, bool forceReload = false)
+ public DataDictionary LoadDataDictionary(ReferenceDescription dictionaryNode, bool forceReload = false)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(LoadDataDictionary)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return await m_session.LoadDataDictionary(dictionaryNode, forceReload).ConfigureAwait(false);
+ return m_session.LoadDataDictionary(dictionaryNode, forceReload);
}
}
///
- public async Task> LoadDataTypeSystem(NodeId dataTypeSystem = null)
+ public async Task> LoadDataTypeSystem(NodeId dataTypeSystem = null, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(LoadDataTypeSystem)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return await m_session.LoadDataTypeSystem(dataTypeSystem).ConfigureAwait(false);
+ return await m_session.LoadDataTypeSystem(dataTypeSystem, ct).ConfigureAwait(false);
}
}
///
public Node ReadNode(NodeId nodeId)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadNode)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.ReadNode(nodeId);
}
@@ -428,7 +492,7 @@ public Node ReadNode(NodeId nodeId)
///
public Node ReadNode(NodeId nodeId, NodeClass nodeClass, bool optionalAttributes = true)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadNode)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.ReadNode(nodeId, nodeClass, optionalAttributes);
}
@@ -437,7 +501,7 @@ public Node ReadNode(NodeId nodeId, NodeClass nodeClass, bool optionalAttributes
///
public void ReadNodes(IList nodeIds, out IList nodeCollection, out IList errors, bool optionalAttributes = false)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadNodes)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.ReadNodes(nodeIds, out nodeCollection, out errors, optionalAttributes);
}
@@ -446,7 +510,7 @@ public void ReadNodes(IList nodeIds, out IList nodeCollection, out
///
public void ReadNodes(IList nodeIds, NodeClass nodeClass, out IList nodeCollection, out IList errors, bool optionalAttributes = false)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadNodes)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.ReadNodes(nodeIds, nodeClass, out nodeCollection, out errors, optionalAttributes);
}
@@ -455,7 +519,7 @@ public void ReadNodes(IList nodeIds, NodeClass nodeClass, out IList
public DataValue ReadValue(NodeId nodeId)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadValue)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.ReadValue(nodeId);
}
@@ -464,7 +528,7 @@ public DataValue ReadValue(NodeId nodeId)
///
public object ReadValue(NodeId nodeId, Type expectedType)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadValue)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.ReadValue(nodeId, expectedType);
}
@@ -473,7 +537,7 @@ public object ReadValue(NodeId nodeId, Type expectedType)
///
public void ReadValues(IList nodeIds, out DataValueCollection values, out IList errors)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadValues)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.ReadValues(nodeIds, out values, out errors);
}
@@ -482,7 +546,7 @@ public void ReadValues(IList nodeIds, out DataValueCollection values, ou
///
public ReferenceDescriptionCollection FetchReferences(NodeId nodeId)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(FetchReferences)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.FetchReferences(nodeId);
}
@@ -491,16 +555,34 @@ public ReferenceDescriptionCollection FetchReferences(NodeId nodeId)
///
public void FetchReferences(IList nodeIds, out IList referenceDescriptions, out IList errors)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(FetchReferences)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.FetchReferences(nodeIds, out referenceDescriptions, out errors);
}
}
+ ///
+ public async Task FetchReferencesAsync(NodeId nodeId, CancellationToken ct)
+ {
+ using (Activity activity = ActivitySource.StartActivity())
+ {
+ return await m_session.FetchReferencesAsync(nodeId, ct).ConfigureAwait(false);
+ }
+ }
+
+ ///
+ public async Task<(IList, IList)> FetchReferencesAsync(IList nodeIds, CancellationToken ct)
+ {
+ using (Activity activity = ActivitySource.StartActivity())
+ {
+ return await m_session.FetchReferencesAsync(nodeIds, ct).ConfigureAwait(false);
+ }
+ }
+
///
public void Open(string sessionName, IUserIdentity identity)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Open)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.Open(sessionName, identity);
}
@@ -509,7 +591,7 @@ public void Open(string sessionName, IUserIdentity identity)
///
public void Open(string sessionName, uint sessionTimeout, IUserIdentity identity, IList preferredLocales)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Open)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.Open(sessionName, sessionTimeout, identity, preferredLocales);
}
@@ -518,7 +600,7 @@ public void Open(string sessionName, uint sessionTimeout, IUserIdentity identity
///
public void Open(string sessionName, uint sessionTimeout, IUserIdentity identity, IList preferredLocales, bool checkDomain)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Open)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.Open(sessionName, sessionTimeout, identity, preferredLocales, checkDomain);
}
@@ -527,7 +609,7 @@ public void Open(string sessionName, uint sessionTimeout, IUserIdentity identity
///
public void ChangePreferredLocales(StringCollection preferredLocales)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ChangePreferredLocales)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.ChangePreferredLocales(preferredLocales);
}
@@ -536,7 +618,7 @@ public void ChangePreferredLocales(StringCollection preferredLocales)
///
public void UpdateSession(IUserIdentity identity, StringCollection preferredLocales)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(UpdateSession)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.UpdateSession(identity, preferredLocales);
}
@@ -545,7 +627,7 @@ public void UpdateSession(IUserIdentity identity, StringCollection preferredLoca
///
public void FindComponentIds(NodeId instanceId, IList componentPaths, out NodeIdCollection componentIds, out List errors)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(FindComponentIds)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.FindComponentIds(instanceId, componentPaths, out componentIds, out errors);
}
@@ -554,7 +636,7 @@ public void FindComponentIds(NodeId instanceId, IList componentPaths, ou
///
public void ReadValues(IList variableIds, IList expectedTypes, out List values, out List errors)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadValues)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.ReadValues(variableIds, expectedTypes, out values, out errors);
}
@@ -563,15 +645,53 @@ public void ReadValues(IList variableIds, IList expectedTypes, out
///
public void ReadDisplayName(IList nodeIds, out IList displayNames, out IList errors)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadDisplayName)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.ReadDisplayName(nodeIds, out displayNames, out errors);
}
}
+
+ ///
+ public async Task OpenAsync(string sessionName, IUserIdentity identity, CancellationToken ct)
+ {
+ using (Activity activity = ActivitySource.StartActivity())
+ {
+ await m_session.OpenAsync(sessionName, identity, ct).ConfigureAwait(false);
+ }
+ }
+
+ ///
+ public async Task OpenAsync(string sessionName, uint sessionTimeout, IUserIdentity identity, IList preferredLocales, CancellationToken ct)
+ {
+ using (Activity activity = ActivitySource.StartActivity())
+ {
+ await m_session.OpenAsync(sessionName, sessionTimeout, identity, preferredLocales, ct).ConfigureAwait(false);
+ }
+ }
+
+ ///
+ public async Task OpenAsync(string sessionName, uint sessionTimeout, IUserIdentity identity, IList preferredLocales, bool checkDomain, CancellationToken ct)
+ {
+ using (Activity activity = ActivitySource.StartActivity())
+ {
+ await m_session.OpenAsync(sessionName, sessionTimeout, identity, preferredLocales, checkDomain, ct).ConfigureAwait(false);
+ }
+ }
+
+
+ ///
+ public async Task FetchNamespaceTablesAsync(CancellationToken ct = default)
+ {
+ using (Activity activity = ActivitySource.StartActivity())
+ {
+ await m_session.FetchNamespaceTablesAsync(ct).ConfigureAwait(false);
+ }
+ }
+
///
public async Task<(IList, IList)> ReadNodesAsync(IList nodeIds, NodeClass nodeClass, bool optionalAttributes = false, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadNodesAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.ReadNodesAsync(nodeIds, nodeClass, optionalAttributes, ct).ConfigureAwait(false);
}
@@ -580,7 +700,7 @@ public void ReadDisplayName(IList nodeIds, out IList displayName
///
public async Task ReadValueAsync(NodeId nodeId, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadValueAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.ReadValueAsync(nodeId, ct).ConfigureAwait(false);
}
@@ -589,7 +709,7 @@ public async Task ReadValueAsync(NodeId nodeId, CancellationToken ct
///
public async Task ReadNodeAsync(NodeId nodeId, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadNodeAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.ReadNodeAsync(nodeId, ct).ConfigureAwait(false);
}
@@ -598,7 +718,7 @@ public async Task ReadNodeAsync(NodeId nodeId, CancellationToken ct = defa
///
public async Task ReadNodeAsync(NodeId nodeId, NodeClass nodeClass, bool optionalAttributes = true, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadNodeAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.ReadNodeAsync(nodeId, nodeClass, optionalAttributes, ct).ConfigureAwait(false);
}
@@ -607,7 +727,7 @@ public async Task ReadNodeAsync(NodeId nodeId, NodeClass nodeClass, bool o
///
public async Task<(IList, IList)> ReadNodesAsync(IList nodeIds, bool optionalAttributes = false, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadNodesAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.ReadNodesAsync(nodeIds, optionalAttributes, ct).ConfigureAwait(false);
}
@@ -616,7 +736,7 @@ public async Task ReadNodeAsync(NodeId nodeId, NodeClass nodeClass, bool o
///
public async Task<(DataValueCollection, IList)> ReadValuesAsync(IList nodeIds, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadValuesAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.ReadValuesAsync(nodeIds, ct).ConfigureAwait(false);
}
@@ -625,7 +745,7 @@ public async Task ReadNodeAsync(NodeId nodeId, NodeClass nodeClass, bool o
///
public StatusCode Close(int timeout)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Close)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Close(timeout);
}
@@ -634,7 +754,7 @@ public StatusCode Close(int timeout)
///
public StatusCode Close(bool closeChannel)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Close)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Close(closeChannel);
}
@@ -643,7 +763,7 @@ public StatusCode Close(bool closeChannel)
///
public StatusCode Close(int timeout, bool closeChannel)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Close)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Close(timeout, closeChannel);
}
@@ -652,7 +772,7 @@ public StatusCode Close(int timeout, bool closeChannel)
///
public async Task CloseAsync(CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CloseAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.CloseAsync(ct).ConfigureAwait(false);
}
@@ -661,7 +781,7 @@ public async Task CloseAsync(CancellationToken ct = default)
///
public async Task CloseAsync(bool closeChannel, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CloseAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.CloseAsync(closeChannel, ct).ConfigureAwait(false);
}
@@ -670,7 +790,7 @@ public async Task CloseAsync(bool closeChannel, CancellationToken ct
///
public async Task CloseAsync(int timeout, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CloseAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.CloseAsync(timeout, ct).ConfigureAwait(false);
}
@@ -679,7 +799,7 @@ public async Task CloseAsync(int timeout, CancellationToken ct = def
///
public async Task CloseAsync(int timeout, bool closeChannel, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CloseAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.CloseAsync(timeout, closeChannel, ct).ConfigureAwait(false);
}
@@ -688,7 +808,7 @@ public async Task CloseAsync(int timeout, bool closeChannel, Cancell
///
public bool AddSubscription(Subscription subscription)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(AddSubscription)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.AddSubscription(subscription);
}
@@ -697,7 +817,7 @@ public bool AddSubscription(Subscription subscription)
///
public bool RemoveSubscription(Subscription subscription)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(RemoveSubscription)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.RemoveSubscription(subscription);
}
@@ -706,7 +826,7 @@ public bool RemoveSubscription(Subscription subscription)
///
public bool RemoveSubscriptions(IEnumerable subscriptions)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(RemoveSubscriptions)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.RemoveSubscriptions(subscriptions);
}
@@ -715,7 +835,7 @@ public bool RemoveSubscriptions(IEnumerable subscriptions)
///
public bool TransferSubscriptions(SubscriptionCollection subscriptions, bool sendInitialValues)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(TransferSubscriptions)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.TransferSubscriptions(subscriptions, sendInitialValues);
}
@@ -724,7 +844,7 @@ public bool TransferSubscriptions(SubscriptionCollection subscriptions, bool sen
///
public bool RemoveTransferredSubscription(Subscription subscription)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(RemoveTransferredSubscription)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.RemoveTransferredSubscription(subscription);
}
@@ -733,7 +853,7 @@ public bool RemoveTransferredSubscription(Subscription subscription)
///
public async Task RemoveSubscriptionAsync(Subscription subscription)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(RemoveSubscriptionAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.RemoveSubscriptionAsync(subscription).ConfigureAwait(false);
}
@@ -742,7 +862,7 @@ public async Task RemoveSubscriptionAsync(Subscription subscription)
///
public async Task RemoveSubscriptionsAsync(IEnumerable subscriptions)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(RemoveSubscriptionsAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.RemoveSubscriptionsAsync(subscriptions).ConfigureAwait(false);
}
@@ -751,7 +871,7 @@ public async Task RemoveSubscriptionsAsync(IEnumerable subsc
///
public ResponseHeader Browse(RequestHeader requestHeader, ViewDescription view, NodeId nodeToBrowse, uint maxResultsToReturn, BrowseDirection browseDirection, NodeId referenceTypeId, bool includeSubtypes, uint nodeClassMask, out byte[] continuationPoint, out ReferenceDescriptionCollection references)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Browse)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Browse(requestHeader, view, nodeToBrowse, maxResultsToReturn, browseDirection, referenceTypeId, includeSubtypes, nodeClassMask, out continuationPoint, out references);
}
@@ -772,7 +892,7 @@ public ResponseHeader EndBrowse(IAsyncResult result, out byte[] continuationPoin
///
public ResponseHeader BrowseNext(RequestHeader requestHeader, bool releaseContinuationPoint, byte[] continuationPoint, out byte[] revisedContinuationPoint, out ReferenceDescriptionCollection references)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(BrowseNext)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.BrowseNext(requestHeader, releaseContinuationPoint, continuationPoint, out revisedContinuationPoint, out references);
}
@@ -793,7 +913,7 @@ public ResponseHeader EndBrowseNext(IAsyncResult result, out byte[] revisedConti
///
public IList Call(NodeId objectId, NodeId methodId, params object[] args)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Call)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Call(objectId, methodId, args);
}
@@ -808,16 +928,25 @@ public IAsyncResult BeginPublish(int timeout)
///
public bool Republish(uint subscriptionId, uint sequenceNumber)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Republish)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Republish(subscriptionId, sequenceNumber);
}
}
+ ///
+ public async Task RepublishAsync(uint subscriptionId, uint sequenceNumber, CancellationToken ct = default)
+ {
+ using (Activity activity = ActivitySource.StartActivity())
+ {
+ return await m_session.RepublishAsync(subscriptionId, sequenceNumber, ct).ConfigureAwait(false);
+ }
+ }
+
///
public ResponseHeader CreateSession(RequestHeader requestHeader, ApplicationDescription clientDescription, string serverUri, string endpointUrl, string sessionName, byte[] clientNonce, byte[] clientCertificate, double requestedSessionTimeout, uint maxResponseMessageSize, out NodeId sessionId, out NodeId authenticationToken, out double revisedSessionTimeout, out byte[] serverNonce, out byte[] serverCertificate, out EndpointDescriptionCollection serverEndpoints, out SignedSoftwareCertificateCollection serverSoftwareCertificates, out SignatureData serverSignature, out uint maxRequestMessageSize)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CreateSession)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.CreateSession(requestHeader, clientDescription, serverUri, endpointUrl, sessionName, clientNonce, clientCertificate, requestedSessionTimeout, maxResponseMessageSize, out sessionId, out authenticationToken, out revisedSessionTimeout, out serverNonce, out serverCertificate, out serverEndpoints, out serverSoftwareCertificates, out serverSignature, out maxRequestMessageSize);
}
@@ -838,7 +967,7 @@ public ResponseHeader EndCreateSession(IAsyncResult result, out NodeId sessionId
///
public async Task CreateSessionAsync(RequestHeader requestHeader, ApplicationDescription clientDescription, string serverUri, string endpointUrl, string sessionName, byte[] clientNonce, byte[] clientCertificate, double requestedSessionTimeout, uint maxResponseMessageSize, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CreateSessionAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.CreateSessionAsync(requestHeader, clientDescription, serverUri, endpointUrl, sessionName, clientNonce, clientCertificate, requestedSessionTimeout, maxResponseMessageSize, ct).ConfigureAwait(false);
}
@@ -847,7 +976,7 @@ public async Task CreateSessionAsync(RequestHeader reques
///
public ResponseHeader ActivateSession(RequestHeader requestHeader, SignatureData clientSignature, SignedSoftwareCertificateCollection clientSoftwareCertificates, StringCollection localeIds, ExtensionObject userIdentityToken, SignatureData userTokenSignature, out byte[] serverNonce, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ActivateSession)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.ActivateSession(requestHeader, clientSignature, clientSoftwareCertificates, localeIds, userIdentityToken, userTokenSignature, out serverNonce, out results, out diagnosticInfos);
}
@@ -868,7 +997,7 @@ public ResponseHeader EndActivateSession(IAsyncResult result, out byte[] serverN
///
public async Task ActivateSessionAsync(RequestHeader requestHeader, SignatureData clientSignature, SignedSoftwareCertificateCollection clientSoftwareCertificates, StringCollection localeIds, ExtensionObject userIdentityToken, SignatureData userTokenSignature, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ActivateSessionAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.ActivateSessionAsync(requestHeader, clientSignature, clientSoftwareCertificates, localeIds, userIdentityToken, userTokenSignature, ct).ConfigureAwait(false);
}
@@ -877,7 +1006,7 @@ public async Task ActivateSessionAsync(RequestHeader re
///
public ResponseHeader CloseSession(RequestHeader requestHeader, bool deleteSubscriptions)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CloseSession)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.CloseSession(requestHeader, deleteSubscriptions);
}
@@ -898,7 +1027,7 @@ public ResponseHeader EndCloseSession(IAsyncResult result)
///
public async Task CloseSessionAsync(RequestHeader requestHeader, bool deleteSubscriptions, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CloseSessionAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return await m_session.CloseSessionAsync(requestHeader, deleteSubscriptions, ct).ConfigureAwait(false);
}
@@ -907,7 +1036,7 @@ public async Task CloseSessionAsync(RequestHeader requestH
///
public ResponseHeader Cancel(RequestHeader requestHeader, uint requestHandle, out uint cancelCount)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Cancel)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Cancel(requestHeader, requestHandle, out cancelCount);
}
@@ -926,18 +1055,18 @@ public ResponseHeader EndCancel(IAsyncResult result, out uint cancelCount)
}
///
- public Task CancelAsync(RequestHeader requestHeader, uint requestHandle, CancellationToken ct)
+ public async Task CancelAsync(RequestHeader requestHeader, uint requestHandle, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CancelAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.CancelAsync(requestHeader, requestHandle, ct);
+ return await m_session.CancelAsync(requestHeader, requestHandle, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader AddNodes(RequestHeader requestHeader, AddNodesItemCollection nodesToAdd, out AddNodesResultCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(AddNodes)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.AddNodes(requestHeader, nodesToAdd, out results, out diagnosticInfos);
}
@@ -956,18 +1085,18 @@ public ResponseHeader EndAddNodes(IAsyncResult result, out AddNodesResultCollect
}
///
- public Task AddNodesAsync(RequestHeader requestHeader, AddNodesItemCollection nodesToAdd, CancellationToken ct)
+ public async Task AddNodesAsync(RequestHeader requestHeader, AddNodesItemCollection nodesToAdd, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(AddNodesAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.AddNodesAsync(requestHeader, nodesToAdd, ct);
+ return await m_session.AddNodesAsync(requestHeader, nodesToAdd, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader AddReferences(RequestHeader requestHeader, AddReferencesItemCollection referencesToAdd, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(AddReferences)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.AddReferences(requestHeader, referencesToAdd, out results, out diagnosticInfos);
}
@@ -986,18 +1115,18 @@ public ResponseHeader EndAddReferences(IAsyncResult result, out StatusCodeCollec
}
///
- public Task AddReferencesAsync(RequestHeader requestHeader, AddReferencesItemCollection referencesToAdd, CancellationToken ct)
+ public async Task AddReferencesAsync(RequestHeader requestHeader, AddReferencesItemCollection referencesToAdd, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(AddReferencesAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.AddReferencesAsync(requestHeader, referencesToAdd, ct);
+ return await m_session.AddReferencesAsync(requestHeader, referencesToAdd, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader DeleteNodes(RequestHeader requestHeader, DeleteNodesItemCollection nodesToDelete, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(DeleteNodes)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.DeleteNodes(requestHeader, nodesToDelete, out results, out diagnosticInfos);
}
@@ -1016,18 +1145,18 @@ public ResponseHeader EndDeleteNodes(IAsyncResult result, out StatusCodeCollecti
}
///
- public Task DeleteNodesAsync(RequestHeader requestHeader, DeleteNodesItemCollection nodesToDelete, CancellationToken ct)
+ public async Task DeleteNodesAsync(RequestHeader requestHeader, DeleteNodesItemCollection nodesToDelete, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(DeleteNodesAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.DeleteNodesAsync(requestHeader, nodesToDelete, ct);
+ return await m_session.DeleteNodesAsync(requestHeader, nodesToDelete, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader DeleteReferences(RequestHeader requestHeader, DeleteReferencesItemCollection referencesToDelete, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(DeleteReferences)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.DeleteReferences(requestHeader, referencesToDelete, out results, out diagnosticInfos);
}
@@ -1046,18 +1175,18 @@ public ResponseHeader EndDeleteReferences(IAsyncResult result, out StatusCodeCol
}
///
- public Task DeleteReferencesAsync(RequestHeader requestHeader, DeleteReferencesItemCollection referencesToDelete, CancellationToken ct)
+ public async Task DeleteReferencesAsync(RequestHeader requestHeader, DeleteReferencesItemCollection referencesToDelete, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(DeleteReferencesAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.DeleteReferencesAsync(requestHeader, referencesToDelete, ct);
+ return await m_session.DeleteReferencesAsync(requestHeader, referencesToDelete, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader Browse(RequestHeader requestHeader, ViewDescription view, uint requestedMaxReferencesPerNode, BrowseDescriptionCollection nodesToBrowse, out BrowseResultCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Browse)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Browse(requestHeader, view, requestedMaxReferencesPerNode, nodesToBrowse, out results, out diagnosticInfos);
}
@@ -1076,18 +1205,18 @@ public ResponseHeader EndBrowse(IAsyncResult result, out BrowseResultCollection
}
///
- public Task BrowseAsync(RequestHeader requestHeader, ViewDescription view, uint requestedMaxReferencesPerNode, BrowseDescriptionCollection nodesToBrowse, CancellationToken ct)
+ public async Task BrowseAsync(RequestHeader requestHeader, ViewDescription view, uint requestedMaxReferencesPerNode, BrowseDescriptionCollection nodesToBrowse, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(BrowseAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.BrowseAsync(requestHeader, view, requestedMaxReferencesPerNode, nodesToBrowse, ct);
+ return await m_session.BrowseAsync(requestHeader, view, requestedMaxReferencesPerNode, nodesToBrowse, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader BrowseNext(RequestHeader requestHeader, bool releaseContinuationPoints, ByteStringCollection continuationPoints, out BrowseResultCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(BrowseNext)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.BrowseNext(requestHeader, releaseContinuationPoints, continuationPoints, out results, out diagnosticInfos);
}
@@ -1106,18 +1235,18 @@ public ResponseHeader EndBrowseNext(IAsyncResult result, out BrowseResultCollect
}
///
- public Task BrowseNextAsync(RequestHeader requestHeader, bool releaseContinuationPoints, ByteStringCollection continuationPoints, CancellationToken ct)
+ public async Task BrowseNextAsync(RequestHeader requestHeader, bool releaseContinuationPoints, ByteStringCollection continuationPoints, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(BrowseNextAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.BrowseNextAsync(requestHeader, releaseContinuationPoints, continuationPoints, ct);
+ return await m_session.BrowseNextAsync(requestHeader, releaseContinuationPoints, continuationPoints, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader TranslateBrowsePathsToNodeIds(RequestHeader requestHeader, BrowsePathCollection browsePaths, out BrowsePathResultCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(TranslateBrowsePathsToNodeIds)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.TranslateBrowsePathsToNodeIds(requestHeader, browsePaths, out results, out diagnosticInfos);
}
@@ -1136,18 +1265,18 @@ public ResponseHeader EndTranslateBrowsePathsToNodeIds(IAsyncResult result, out
}
///
- public Task TranslateBrowsePathsToNodeIdsAsync(RequestHeader requestHeader, BrowsePathCollection browsePaths, CancellationToken ct)
+ public async Task TranslateBrowsePathsToNodeIdsAsync(RequestHeader requestHeader, BrowsePathCollection browsePaths, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(TranslateBrowsePathsToNodeIdsAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.TranslateBrowsePathsToNodeIdsAsync(requestHeader, browsePaths, ct);
+ return await m_session.TranslateBrowsePathsToNodeIdsAsync(requestHeader, browsePaths, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader RegisterNodes(RequestHeader requestHeader, NodeIdCollection nodesToRegister, out NodeIdCollection registeredNodeIds)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(RegisterNodes)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.RegisterNodes(requestHeader, nodesToRegister, out registeredNodeIds);
}
@@ -1166,18 +1295,18 @@ public ResponseHeader EndRegisterNodes(IAsyncResult result, out NodeIdCollection
}
///
- public Task RegisterNodesAsync(RequestHeader requestHeader, NodeIdCollection nodesToRegister, CancellationToken ct)
+ public async Task RegisterNodesAsync(RequestHeader requestHeader, NodeIdCollection nodesToRegister, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(RegisterNodesAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.RegisterNodesAsync(requestHeader, nodesToRegister, ct);
+ return await m_session.RegisterNodesAsync(requestHeader, nodesToRegister, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader UnregisterNodes(RequestHeader requestHeader, NodeIdCollection nodesToUnregister)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(UnregisterNodes)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.UnregisterNodes(requestHeader, nodesToUnregister);
}
@@ -1196,18 +1325,18 @@ public ResponseHeader EndUnregisterNodes(IAsyncResult result)
}
///
- public Task UnregisterNodesAsync(RequestHeader requestHeader, NodeIdCollection nodesToUnregister, CancellationToken ct)
+ public async Task UnregisterNodesAsync(RequestHeader requestHeader, NodeIdCollection nodesToUnregister, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(UnregisterNodesAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.UnregisterNodesAsync(requestHeader, nodesToUnregister, ct);
+ return await m_session.UnregisterNodesAsync(requestHeader, nodesToUnregister, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader QueryFirst(RequestHeader requestHeader, ViewDescription view, NodeTypeDescriptionCollection nodeTypes, ContentFilter filter, uint maxDataSetsToReturn, uint maxReferencesToReturn, out QueryDataSetCollection queryDataSets, out byte[] continuationPoint, out ParsingResultCollection parsingResults, out DiagnosticInfoCollection diagnosticInfos, out ContentFilterResult filterResult)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(QueryFirst)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.QueryFirst(requestHeader, view, nodeTypes, filter, maxDataSetsToReturn, maxReferencesToReturn, out queryDataSets, out continuationPoint, out parsingResults, out diagnosticInfos, out filterResult);
}
@@ -1226,18 +1355,18 @@ public ResponseHeader EndQueryFirst(IAsyncResult result, out QueryDataSetCollect
}
///
- public Task QueryFirstAsync(RequestHeader requestHeader, ViewDescription view, NodeTypeDescriptionCollection nodeTypes, ContentFilter filter, uint maxDataSetsToReturn, uint maxReferencesToReturn, CancellationToken ct)
+ public async Task QueryFirstAsync(RequestHeader requestHeader, ViewDescription view, NodeTypeDescriptionCollection nodeTypes, ContentFilter filter, uint maxDataSetsToReturn, uint maxReferencesToReturn, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(QueryFirstAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.QueryFirstAsync(requestHeader, view, nodeTypes, filter, maxDataSetsToReturn, maxReferencesToReturn, ct);
+ return await m_session.QueryFirstAsync(requestHeader, view, nodeTypes, filter, maxDataSetsToReturn, maxReferencesToReturn, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader QueryNext(RequestHeader requestHeader, bool releaseContinuationPoint, byte[] continuationPoint, out QueryDataSetCollection queryDataSets, out byte[] revisedContinuationPoint)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(QueryNext)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.QueryNext(requestHeader, releaseContinuationPoint, continuationPoint, out queryDataSets, out revisedContinuationPoint);
}
@@ -1256,18 +1385,18 @@ public ResponseHeader EndQueryNext(IAsyncResult result, out QueryDataSetCollecti
}
///
- public Task QueryNextAsync(RequestHeader requestHeader, bool releaseContinuationPoint, byte[] continuationPoint, CancellationToken ct)
+ public async Task QueryNextAsync(RequestHeader requestHeader, bool releaseContinuationPoint, byte[] continuationPoint, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(QueryNextAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.QueryNextAsync(requestHeader, releaseContinuationPoint, continuationPoint, ct);
+ return await m_session.QueryNextAsync(requestHeader, releaseContinuationPoint, continuationPoint, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader Read(RequestHeader requestHeader, double maxAge, TimestampsToReturn timestampsToReturn, ReadValueIdCollection nodesToRead, out DataValueCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Read)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Read(requestHeader, maxAge, timestampsToReturn, nodesToRead, out results, out diagnosticInfos);
}
@@ -1286,18 +1415,18 @@ public ResponseHeader EndRead(IAsyncResult result, out DataValueCollection resul
}
///
- public Task ReadAsync(RequestHeader requestHeader, double maxAge, TimestampsToReturn timestampsToReturn, ReadValueIdCollection nodesToRead, CancellationToken ct)
+ public async Task ReadAsync(RequestHeader requestHeader, double maxAge, TimestampsToReturn timestampsToReturn, ReadValueIdCollection nodesToRead, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReadAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.ReadAsync(requestHeader, maxAge, timestampsToReturn, nodesToRead, ct);
+ return await m_session.ReadAsync(requestHeader, maxAge, timestampsToReturn, nodesToRead, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader HistoryRead(RequestHeader requestHeader, ExtensionObject historyReadDetails, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, HistoryReadValueIdCollection nodesToRead, out HistoryReadResultCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(HistoryRead)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.HistoryRead(requestHeader, historyReadDetails, timestampsToReturn, releaseContinuationPoints, nodesToRead, out results, out diagnosticInfos);
}
@@ -1316,18 +1445,18 @@ public ResponseHeader EndHistoryRead(IAsyncResult result, out HistoryReadResultC
}
///
- public Task HistoryReadAsync(RequestHeader requestHeader, ExtensionObject historyReadDetails, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, HistoryReadValueIdCollection nodesToRead, CancellationToken ct)
+ public async Task HistoryReadAsync(RequestHeader requestHeader, ExtensionObject historyReadDetails, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, HistoryReadValueIdCollection nodesToRead, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(HistoryReadAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.HistoryReadAsync(requestHeader, historyReadDetails, timestampsToReturn, releaseContinuationPoints, nodesToRead, ct);
+ return await m_session.HistoryReadAsync(requestHeader, historyReadDetails, timestampsToReturn, releaseContinuationPoints, nodesToRead, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader Write(RequestHeader requestHeader, WriteValueCollection nodesToWrite, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Write)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Write(requestHeader, nodesToWrite, out results, out diagnosticInfos);
}
@@ -1346,18 +1475,18 @@ public ResponseHeader EndWrite(IAsyncResult result, out StatusCodeCollection res
}
///
- public Task WriteAsync(RequestHeader requestHeader, WriteValueCollection nodesToWrite, CancellationToken ct)
+ public async Task WriteAsync(RequestHeader requestHeader, WriteValueCollection nodesToWrite, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(WriteAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.WriteAsync(requestHeader, nodesToWrite, ct);
+ return await m_session.WriteAsync(requestHeader, nodesToWrite, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader HistoryUpdate(RequestHeader requestHeader, ExtensionObjectCollection historyUpdateDetails, out HistoryUpdateResultCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(HistoryUpdate)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.HistoryUpdate(requestHeader, historyUpdateDetails, out results, out diagnosticInfos);
}
@@ -1376,18 +1505,18 @@ public ResponseHeader EndHistoryUpdate(IAsyncResult result, out HistoryUpdateRes
}
///
- public Task HistoryUpdateAsync(RequestHeader requestHeader, ExtensionObjectCollection historyUpdateDetails, CancellationToken ct)
+ public async Task HistoryUpdateAsync(RequestHeader requestHeader, ExtensionObjectCollection historyUpdateDetails, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(HistoryUpdateAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.HistoryUpdateAsync(requestHeader, historyUpdateDetails, ct);
+ return await m_session.HistoryUpdateAsync(requestHeader, historyUpdateDetails, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader Call(RequestHeader requestHeader, CallMethodRequestCollection methodsToCall, out CallMethodResultCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Call)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Call(requestHeader, methodsToCall, out results, out diagnosticInfos);
}
@@ -1406,18 +1535,18 @@ public ResponseHeader EndCall(IAsyncResult result, out CallMethodResultCollectio
}
///
- public Task CallAsync(RequestHeader requestHeader, CallMethodRequestCollection methodsToCall, CancellationToken ct)
+ public async Task CallAsync(RequestHeader requestHeader, CallMethodRequestCollection methodsToCall, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CallAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.CallAsync(requestHeader, methodsToCall, ct);
+ return await m_session.CallAsync(requestHeader, methodsToCall, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader CreateMonitoredItems(RequestHeader requestHeader, uint subscriptionId, TimestampsToReturn timestampsToReturn, MonitoredItemCreateRequestCollection itemsToCreate, out MonitoredItemCreateResultCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CreateMonitoredItems)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.CreateMonitoredItems(requestHeader, subscriptionId, timestampsToReturn, itemsToCreate, out results, out diagnosticInfos);
}
@@ -1436,18 +1565,18 @@ public ResponseHeader EndCreateMonitoredItems(IAsyncResult result, out Monitored
}
///
- public Task CreateMonitoredItemsAsync(RequestHeader requestHeader, uint subscriptionId, TimestampsToReturn timestampsToReturn, MonitoredItemCreateRequestCollection itemsToCreate, CancellationToken ct)
+ public async Task CreateMonitoredItemsAsync(RequestHeader requestHeader, uint subscriptionId, TimestampsToReturn timestampsToReturn, MonitoredItemCreateRequestCollection itemsToCreate, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CreateMonitoredItemsAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.CreateMonitoredItemsAsync(requestHeader, subscriptionId, timestampsToReturn, itemsToCreate, ct);
+ return await m_session.CreateMonitoredItemsAsync(requestHeader, subscriptionId, timestampsToReturn, itemsToCreate, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader ModifyMonitoredItems(RequestHeader requestHeader, uint subscriptionId, TimestampsToReturn timestampsToReturn, MonitoredItemModifyRequestCollection itemsToModify, out MonitoredItemModifyResultCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ModifyMonitoredItems)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.ModifyMonitoredItems(requestHeader, subscriptionId, timestampsToReturn, itemsToModify, out results, out diagnosticInfos);
}
@@ -1466,18 +1595,18 @@ public ResponseHeader EndModifyMonitoredItems(IAsyncResult result, out Monitored
}
///
- public Task ModifyMonitoredItemsAsync(RequestHeader requestHeader, uint subscriptionId, TimestampsToReturn timestampsToReturn, MonitoredItemModifyRequestCollection itemsToModify, CancellationToken ct)
+ public async Task ModifyMonitoredItemsAsync(RequestHeader requestHeader, uint subscriptionId, TimestampsToReturn timestampsToReturn, MonitoredItemModifyRequestCollection itemsToModify, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ModifyMonitoredItemsAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.ModifyMonitoredItemsAsync(requestHeader, subscriptionId, timestampsToReturn, itemsToModify, ct);
+ return await m_session.ModifyMonitoredItemsAsync(requestHeader, subscriptionId, timestampsToReturn, itemsToModify, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader SetMonitoringMode(RequestHeader requestHeader, uint subscriptionId, MonitoringMode monitoringMode, UInt32Collection monitoredItemIds, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(SetMonitoringMode)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.SetMonitoringMode(requestHeader, subscriptionId, monitoringMode, monitoredItemIds, out results, out diagnosticInfos);
}
@@ -1496,18 +1625,18 @@ public ResponseHeader EndSetMonitoringMode(IAsyncResult result, out StatusCodeCo
}
///
- public Task SetMonitoringModeAsync(RequestHeader requestHeader, uint subscriptionId, MonitoringMode monitoringMode, UInt32Collection monitoredItemIds, CancellationToken ct)
+ public async Task SetMonitoringModeAsync(RequestHeader requestHeader, uint subscriptionId, MonitoringMode monitoringMode, UInt32Collection monitoredItemIds, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(SetMonitoringModeAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.SetMonitoringModeAsync(requestHeader, subscriptionId, monitoringMode, monitoredItemIds, ct);
+ return await m_session.SetMonitoringModeAsync(requestHeader, subscriptionId, monitoringMode, monitoredItemIds, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader SetTriggering(RequestHeader requestHeader, uint subscriptionId, uint triggeringItemId, UInt32Collection linksToAdd, UInt32Collection linksToRemove, out StatusCodeCollection addResults, out DiagnosticInfoCollection addDiagnosticInfos, out StatusCodeCollection removeResults, out DiagnosticInfoCollection removeDiagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(SetTriggering)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.SetTriggering(requestHeader, subscriptionId, triggeringItemId, linksToAdd, linksToRemove, out addResults, out addDiagnosticInfos, out removeResults, out removeDiagnosticInfos);
}
@@ -1526,18 +1655,18 @@ public ResponseHeader EndSetTriggering(IAsyncResult result, out StatusCodeCollec
}
///
- public Task SetTriggeringAsync(RequestHeader requestHeader, uint subscriptionId, uint triggeringItemId, UInt32Collection linksToAdd, UInt32Collection linksToRemove, CancellationToken ct)
+ public async Task SetTriggeringAsync(RequestHeader requestHeader, uint subscriptionId, uint triggeringItemId, UInt32Collection linksToAdd, UInt32Collection linksToRemove, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(SetTriggeringAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.SetTriggeringAsync(requestHeader, subscriptionId, triggeringItemId, linksToAdd, linksToRemove, ct);
+ return await m_session.SetTriggeringAsync(requestHeader, subscriptionId, triggeringItemId, linksToAdd, linksToRemove, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader DeleteMonitoredItems(RequestHeader requestHeader, uint subscriptionId, UInt32Collection monitoredItemIds, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(DeleteMonitoredItems)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.DeleteMonitoredItems(requestHeader, subscriptionId, monitoredItemIds, out results, out diagnosticInfos);
}
@@ -1556,18 +1685,18 @@ public ResponseHeader EndDeleteMonitoredItems(IAsyncResult result, out StatusCod
}
///
- public Task DeleteMonitoredItemsAsync(RequestHeader requestHeader, uint subscriptionId, UInt32Collection monitoredItemIds, CancellationToken ct)
+ public async Task DeleteMonitoredItemsAsync(RequestHeader requestHeader, uint subscriptionId, UInt32Collection monitoredItemIds, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(DeleteMonitoredItemsAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.DeleteMonitoredItemsAsync(requestHeader, subscriptionId, monitoredItemIds, ct);
+ return await m_session.DeleteMonitoredItemsAsync(requestHeader, subscriptionId, monitoredItemIds, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader CreateSubscription(RequestHeader requestHeader, double requestedPublishingInterval, uint requestedLifetimeCount, uint requestedMaxKeepAliveCount, uint maxNotificationsPerPublish, bool publishingEnabled, byte priority, out uint subscriptionId, out double revisedPublishingInterval, out uint revisedLifetimeCount, out uint revisedMaxKeepAliveCount)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CreateSubscription)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.CreateSubscription(requestHeader, requestedPublishingInterval, requestedLifetimeCount, requestedMaxKeepAliveCount, maxNotificationsPerPublish, publishingEnabled, priority, out subscriptionId, out revisedPublishingInterval, out revisedLifetimeCount, out revisedMaxKeepAliveCount);
}
@@ -1586,18 +1715,18 @@ public ResponseHeader EndCreateSubscription(IAsyncResult result, out uint subscr
}
///
- public Task CreateSubscriptionAsync(RequestHeader requestHeader, double requestedPublishingInterval, uint requestedLifetimeCount, uint requestedMaxKeepAliveCount, uint maxNotificationsPerPublish, bool publishingEnabled, byte priority, CancellationToken ct)
+ public async Task CreateSubscriptionAsync(RequestHeader requestHeader, double requestedPublishingInterval, uint requestedLifetimeCount, uint requestedMaxKeepAliveCount, uint maxNotificationsPerPublish, bool publishingEnabled, byte priority, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(CreateSubscriptionAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.CreateSubscriptionAsync(requestHeader, requestedPublishingInterval, requestedLifetimeCount, requestedMaxKeepAliveCount, maxNotificationsPerPublish, publishingEnabled, priority, ct);
+ return await m_session.CreateSubscriptionAsync(requestHeader, requestedPublishingInterval, requestedLifetimeCount, requestedMaxKeepAliveCount, maxNotificationsPerPublish, publishingEnabled, priority, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader ModifySubscription(RequestHeader requestHeader, uint subscriptionId, double requestedPublishingInterval, uint requestedLifetimeCount, uint requestedMaxKeepAliveCount, uint maxNotificationsPerPublish, byte priority, out double revisedPublishingInterval, out uint revisedLifetimeCount, out uint revisedMaxKeepAliveCount)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ModifySubscription)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.ModifySubscription(requestHeader, subscriptionId, requestedPublishingInterval, requestedLifetimeCount, requestedMaxKeepAliveCount, maxNotificationsPerPublish, priority, out revisedPublishingInterval, out revisedLifetimeCount, out revisedMaxKeepAliveCount);
}
@@ -1616,18 +1745,18 @@ public ResponseHeader EndModifySubscription(IAsyncResult result, out double revi
}
///
- public Task ModifySubscriptionAsync(RequestHeader requestHeader, uint subscriptionId, double requestedPublishingInterval, uint requestedLifetimeCount, uint requestedMaxKeepAliveCount, uint maxNotificationsPerPublish, byte priority, CancellationToken ct)
+ public async Task ModifySubscriptionAsync(RequestHeader requestHeader, uint subscriptionId, double requestedPublishingInterval, uint requestedLifetimeCount, uint requestedMaxKeepAliveCount, uint maxNotificationsPerPublish, byte priority, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ModifySubscriptionAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.ModifySubscriptionAsync(requestHeader, subscriptionId, requestedPublishingInterval, requestedLifetimeCount, requestedMaxKeepAliveCount, maxNotificationsPerPublish, priority, ct);
+ return await m_session.ModifySubscriptionAsync(requestHeader, subscriptionId, requestedPublishingInterval, requestedLifetimeCount, requestedMaxKeepAliveCount, maxNotificationsPerPublish, priority, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader SetPublishingMode(RequestHeader requestHeader, bool publishingEnabled, UInt32Collection subscriptionIds, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(SetPublishingMode)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.SetPublishingMode(requestHeader, publishingEnabled, subscriptionIds, out results, out diagnosticInfos);
}
@@ -1646,18 +1775,18 @@ public ResponseHeader EndSetPublishingMode(IAsyncResult result, out StatusCodeCo
}
///
- public Task SetPublishingModeAsync(RequestHeader requestHeader, bool publishingEnabled, UInt32Collection subscriptionIds, CancellationToken ct)
+ public async Task SetPublishingModeAsync(RequestHeader requestHeader, bool publishingEnabled, UInt32Collection subscriptionIds, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(SetPublishingModeAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.SetPublishingModeAsync(requestHeader, publishingEnabled, subscriptionIds, ct);
+ return await m_session.SetPublishingModeAsync(requestHeader, publishingEnabled, subscriptionIds, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader Publish(RequestHeader requestHeader, SubscriptionAcknowledgementCollection subscriptionAcknowledgements, out uint subscriptionId, out UInt32Collection availableSequenceNumbers, out bool moreNotifications, out NotificationMessage notificationMessage, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Publish)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Publish(requestHeader, subscriptionAcknowledgements, out subscriptionId, out availableSequenceNumbers, out moreNotifications, out notificationMessage, out results, out diagnosticInfos);
}
@@ -1676,18 +1805,18 @@ public ResponseHeader EndPublish(IAsyncResult result, out uint subscriptionId, o
}
///
- public Task PublishAsync(RequestHeader requestHeader, SubscriptionAcknowledgementCollection subscriptionAcknowledgements, CancellationToken ct)
+ public async Task PublishAsync(RequestHeader requestHeader, SubscriptionAcknowledgementCollection subscriptionAcknowledgements, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(PublishAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.PublishAsync(requestHeader, subscriptionAcknowledgements, ct);
+ return await m_session.PublishAsync(requestHeader, subscriptionAcknowledgements, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader Republish(RequestHeader requestHeader, uint subscriptionId, uint retransmitSequenceNumber, out NotificationMessage notificationMessage)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Republish)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Republish(requestHeader, subscriptionId, retransmitSequenceNumber, out notificationMessage);
}
@@ -1706,18 +1835,18 @@ public ResponseHeader EndRepublish(IAsyncResult result, out NotificationMessage
}
///
- public Task RepublishAsync(RequestHeader requestHeader, uint subscriptionId, uint retransmitSequenceNumber, CancellationToken ct)
+ public async Task RepublishAsync(RequestHeader requestHeader, uint subscriptionId, uint retransmitSequenceNumber, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(RepublishAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.RepublishAsync(requestHeader, subscriptionId, retransmitSequenceNumber, ct);
+ return await m_session.RepublishAsync(requestHeader, subscriptionId, retransmitSequenceNumber, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader TransferSubscriptions(RequestHeader requestHeader, UInt32Collection subscriptionIds, bool sendInitialValues, out TransferResultCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(TransferSubscriptions)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.TransferSubscriptions(requestHeader, subscriptionIds, sendInitialValues, out results, out diagnosticInfos);
}
@@ -1736,18 +1865,18 @@ public ResponseHeader EndTransferSubscriptions(IAsyncResult result, out Transfer
}
///
- public Task TransferSubscriptionsAsync(RequestHeader requestHeader, UInt32Collection subscriptionIds, bool sendInitialValues, CancellationToken ct)
+ public async Task TransferSubscriptionsAsync(RequestHeader requestHeader, UInt32Collection subscriptionIds, bool sendInitialValues, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(TransferSubscriptionsAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.TransferSubscriptionsAsync(requestHeader, subscriptionIds, sendInitialValues, ct);
+ return await m_session.TransferSubscriptionsAsync(requestHeader, subscriptionIds, sendInitialValues, ct).ConfigureAwait(false);
}
}
///
public ResponseHeader DeleteSubscriptions(RequestHeader requestHeader, UInt32Collection subscriptionIds, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(DeleteSubscriptions)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.DeleteSubscriptions(requestHeader, subscriptionIds, out results, out diagnosticInfos);
}
@@ -1766,18 +1895,18 @@ public ResponseHeader EndDeleteSubscriptions(IAsyncResult result, out StatusCode
}
///
- public Task DeleteSubscriptionsAsync(RequestHeader requestHeader, UInt32Collection subscriptionIds, CancellationToken ct)
+ public async Task DeleteSubscriptionsAsync(RequestHeader requestHeader, UInt32Collection subscriptionIds, CancellationToken ct)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(DeleteSubscriptionsAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.DeleteSubscriptionsAsync(requestHeader, subscriptionIds, ct);
+ return await m_session.DeleteSubscriptionsAsync(requestHeader, subscriptionIds, ct).ConfigureAwait(false);
}
}
///
public void AttachChannel(ITransportChannel channel)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(AttachChannel)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.AttachChannel(channel);
}
@@ -1786,7 +1915,7 @@ public void AttachChannel(ITransportChannel channel)
///
public void DetachChannel()
{
- using (Activity activity = ActivitySource.StartActivity(nameof(DetachChannel)))
+ using (Activity activity = ActivitySource.StartActivity())
{
m_session.DetachChannel();
}
@@ -1795,7 +1924,7 @@ public void DetachChannel()
///
public StatusCode Close()
{
- using (Activity activity = ActivitySource.StartActivity(nameof(Close)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.Close();
}
@@ -1831,7 +1960,7 @@ public void Dispose()
///
public SessionConfiguration SaveSessionConfiguration(Stream stream = null)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(SaveSessionConfiguration)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.SaveSessionConfiguration(stream);
}
@@ -1840,7 +1969,7 @@ public SessionConfiguration SaveSessionConfiguration(Stream stream = null)
///
public bool ApplySessionConfiguration(SessionConfiguration sessionConfiguration)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ApplySessionConfiguration)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.ApplySessionConfiguration(sessionConfiguration);
}
@@ -1849,72 +1978,72 @@ public bool ApplySessionConfiguration(SessionConfiguration sessionConfiguration)
///
public bool ReactivateSubscriptions(SubscriptionCollection subscriptions, bool sendInitialValues)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(ReactivateSubscriptions)))
+ using (Activity activity = ActivitySource.StartActivity())
{
return m_session.ReactivateSubscriptions(subscriptions, sendInitialValues);
}
}
///
- public Task RemoveSubscriptionAsync(Subscription subscription, CancellationToken ct = default)
+ public async Task RemoveSubscriptionAsync(Subscription subscription, CancellationToken ct = default)
{
- using (Activity activity = ActivitySource.StartActivity(nameof(RemoveSubscriptionAsync)))
+ using (Activity activity = ActivitySource.StartActivity())
{
- return m_session.RemoveSubscriptionAsync(subscription, ct);
+ return await m_session.RemoveSubscriptionAsync(subscription, ct).ConfigureAwait(false);
}
}
///
- public Task RemoveSubscriptionsAsync(IEnumerable