From 6daf0f7bb8f8919d087c64734393a28e2487e5e4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 4 Jul 2024 15:23:02 +0200 Subject: [PATCH] Remove all newtonsoft references and transform into system.text.json (#305) * update newtonsoft to system.text.json * add more verifications * add transformer and tests * remove unused using * fix smaller issues with AdminShellConverters and apply necessary nullable for AssetAdministrationShell parameter assetInformation * remove unused parameters * Transform usings to System.Text.Json * Fix system.text.json usage * remove not references AdminShellCollections.cs * fix test setup in AdminShellCollectionTests.cs * add tests * Add tests * Fix method modifiers * Add Tests for AdaptiveFilterContractResolver * remove newtonsoft references in favor to System.Text.Json * update newtonsoft to system.text.json * Transform to System.Text.Json in Startup.cs * Transform to System.Text.Json in ServerConfiguration.cs * Transform to System.Text.Json * Transform AasxPluginOptionSerialization.cs to System.Text.Json * Transform AasxRestClient.cs to System.Text.Json and Delete EnergyModel_SourceSystem_Azure.cs * transform first chunk of Program.cs to System.Text.Json WARNING: Work in progress * Transform Program.cs to use System.Text.Json * Transform SecurityClient.cs to System.Text.Json * transform TimeSeries.cs to System.Text.Json * Transform TimeSeriesPlotting.cs to use System.Text.Json * Transform to System.text.Json * Transform ToJson Method to System.Text.Json * Transfrom simple values to System.Text.Json * update formatter to system.text.json in Startup.cs * Transform Registry Lib to System.Text.Json * fix spelling issue 'retrived' to 'retrieved' * Remove remaining newtonsoft references * Remove Newtonsoft references * update CHANGELOG.md * Revert * fix modifiers * revert nullable * fix merge issues * update remarks * fix merge issues * Fix swagger initialisation * fix MessageType serialization and remove hungarian notation * fix hungarian notation * re-add missing nullchecks * fix missing null check * fix nullable errors in AASXFileServerAPIApi.cs * fix nulltype errors in AssetAdministrationShellRepositoryAPIApi.cs * fix null types * update null fixes in SerializationAPIApi.cs * fix nullables * fix nullables and error handling in SubmodelRepositoryAPIApi.cs * reformat AssetAdministrationShellRegistryAPIApi.cs * Fix API nullables and error handling * refactor ServiceDescription.cs and Description.cs * Make ServiceDescription.cs testable and create tests * add tests DescriptionAPIApiControllerTests.cs * apply resharper suggestions * add tests for GenerateSerializationService.cs * update documentation for Logging interfaces and classes * Fix MessageTypeEnum not displayed as text in HTTP result * Fix DateTime handling in ExceptionMiddleware.cs * fix nullability issue * refactor namings in RegistryInitializerService.cs * Refactor RegistryInitializerService.cs and fix nullable bugs * fix merging issues * fix merging issues --- CHANGELOG.md | 1 + src/AasCore.Aas3_0/AasCore.Aas3_0.csproj | 1 - src/AasCore.Aas3_0/jsonization.cs | 252 +-- src/AasCore.Aas3_0/types.cs | 71 +- src/AasCore.Aas3_0/verification.cs | 6 +- src/AasCore.Aas3_0/visitation.cs | 20 +- src/AasCore.Aas3_0/xmlization.cs | 12 +- .../AdaptiveFilterContractResolverTests.cs | 29 + .../V20/AdminShellConvertersTests.cs | 165 ++ .../AasxCsharpLibrary.Tests.csproj | 40 + .../AdaptiveFilterContractResolverTests.cs | 141 ++ src/AasxCsharpLibrary.Tests/GlobalUsings.cs | 5 + .../JsonAasxConverterTests.cs | 209 +++ .../AasxCompatibilityModels/V20/AdminShell.cs | 809 +++++---- .../V20/AdminShellConverters.cs | 190 +-- .../AasxCsharpLibrary.csproj | 1 - .../AdminShellCollections.cs | 62 - src/AasxCsharpLibrary/AdminShellConverters.cs | 282 ++-- src/AasxCsharpLibrary/AdminShellPackageEnv.cs | 70 +- .../ExtendAnnotatedRelationshipElement.cs | 10 +- .../ExtendAssetAdministrationShell.cs | 4 +- .../Extensions/ExtendAssetInformation.cs | 4 +- .../Extensions/ExtendBlob.cs | 4 +- .../Extensions/ExtendConceptDescription.cs | 2 +- .../ExtendDataSpecificationIEC61360.cs | 2 +- .../ExtendEmbeddedDataSpecification.cs | 2 +- .../Extensions/ExtendEntity.cs | 8 +- .../Extensions/ExtendEnvironment.cs | 72 +- .../Extensions/ExtendFile.cs | 4 +- .../ExtendIDataSpecificationContent.cs | 4 +- .../Extensions/ExtendIIdentifiable.cs | 2 +- .../Extensions/ExtendIReferable.cs | 16 +- .../Extensions/ExtendISubmodelElement.cs | 46 +- .../Extensions/ExtendMultiLanguageProperty.cs | 2 +- .../Extensions/ExtendOperation.cs | 2 +- .../Extensions/ExtendProperty.cs | 4 +- .../Extensions/ExtendRange.cs | 4 +- .../Extensions/ExtendReference.cs | 4 +- .../Extensions/ExtendRelationshipElement.cs | 2 +- .../Extensions/ExtendSubmodel.cs | 22 +- .../ExtendSubmodelElementCollection.cs | 14 +- .../Extensions/ExtendSubmodelElementList.cs | 2 +- .../Extensions/ExtensionsUtil.cs | 8 +- .../Extensions/LocatedReference.cs | 4 +- src/AasxServer.sln | 20 + .../AasxServerAspNetCore.csproj | 1 - src/AasxServerAspNetCore/Startup.cs | 179 +- src/AasxServerBlazor/AasxServerBlazor.csproj | 3 - .../Configuration/DependencyRegistry.cs | 3 + .../Configuration/ServerConfiguration.cs | 220 ++- .../AasEventMsgEnvelope.cs | 3 +- .../AasPayloadUpdateValue.cs | 3 +- .../AasxHttpContextHelper.cs | 1455 ++++++++-------- .../AasxHttpHandleStore.cs | 20 +- .../AasxPluginOptionSerialization.cs | 97 +- src/AasxServerStandardBib/AasxRestClient.cs | 7 +- src/AasxServerStandardBib/AasxRestServer.cs | 61 +- .../AasxServerStandardBib.csproj | 1 - .../IAssetAdministrationShellService.cs | 4 +- .../Logging/ApplicationLogging.cs | 58 +- .../Logging/IAppLogger.cs | 42 +- .../Logging/LogMessages.cs | 70 + .../Logging/LoggerAdapter.cs | 65 +- src/AasxServerStandardBib/MqttClient.cs | 4 +- src/AasxServerStandardBib/Program.cs | 665 ++++---- src/AasxServerStandardBib/SecurityClient.cs | 1196 +++++++------- .../AssetAdministrationShellService.cs | 4 +- src/AasxServerStandardBib/TimeSeries.cs | 318 ++-- .../TimeSeriesPlotting.cs | 298 ++-- .../DescriptionAPIApiControllerTests.cs | 84 + .../Models/MessageTests.cs | 172 ++ .../Models/ServiceDescriptionTests.cs | 180 ++ .../GenerateSerializationServiceTests.cs | 125 ++ .../Controllers/AASXFileServerAPIApi.cs | 451 ++--- ...ssetAdministrationShellRepositoryAPIApi.cs | 623 +++++-- .../ConceptDescriptionRepositoryAPIApi.cs | 8 +- .../Controllers/DescriptionAPIApi.cs | 27 +- .../Controllers/SerializationAPIApi.cs | 16 +- .../Controllers/SubmodelRepositoryAPIApi.cs | 587 +++++-- .../Formatters/AasRequestFormatter.cs | 282 ++-- .../Formatters/AasResponseFormatter.cs | 6 +- .../IO.Swagger.Lib.V3.csproj | 1 - .../IGenerateSerializationService.cs | 18 +- .../Interfaces/ILevelExtentModifierService.cs | 2 +- .../Interfaces/IPathModifierService.cs | 2 +- .../Interfaces/IReferenceModifierService.cs | 2 +- .../Middleware/ExceptionMiddleware.cs | 55 +- .../Models/BaseOperationResult.cs | 25 +- src/IO.Swagger.Lib.V3/Models/Description.cs | 260 ++- .../Models/ExecutionState.cs | 83 +- .../Models/GetPathItemsResult.cs | 8 +- .../Models/GetReferencesResult.cs | 7 +- .../Models/GetSubmodelElementsResult.cs | 7 +- .../Models/IServiceDescription.cs | 46 + src/IO.Swagger.Lib.V3/Models/Message.cs | 353 ++-- .../Models/OperationRequest.cs | 11 +- .../Models/OperationResult.cs | 11 +- src/IO.Swagger.Lib.V3/Models/Result.cs | 22 +- .../Models/ServerDescriptionProfiles.cs | 108 ++ .../Models/ServiceDescription.cs | 246 +-- .../Models/ServiceProfiles.cs | 120 ++ .../Mappers/IMappingService.cs | 4 +- .../Mappers/MappingService.cs | 4 +- .../MetadataMappers/RequestMetadataMapper.cs | 2 +- .../MetadataMappers/ResponseMetadataMapper.cs | 2 +- .../ResponseMetadataTransformer.cs | 16 +- .../ValueMappers/ResponseValueMapper.cs | 2 +- .../ValueMappers/ResponseValueTransformer.cs | 2 +- .../ValueMappers/ValueOnlyJsonDeserializer.cs | 106 +- .../PathModifier/PathTransformer.cs | 425 +++-- .../Services/AasRepositoryApiHelperService.cs | 2 +- .../Services/GenerateSerializationService.cs | 83 +- .../Services/LevelExtentModifierService.cs | 9 +- .../Services/PaginationService.cs | 150 +- .../Services/PathModifierService.cs | 58 +- .../Services/ReferenceModifierService.cs | 2 +- src/IO.Swagger.Lib.V3/Startup.cs | 110 +- .../ReferenceElementExtensionsTests.cs | 100 ++ .../AasDescriptorPaginationServiceTests.cs | 4 +- .../SubmodelPropertyExtractionServiceTests.cs | 134 ++ .../AssetAdministrationShellRegistryAPIApi.cs | 960 ++++++----- .../Extensions/ReferenceElementExtensions.cs | 20 + .../IO.Swagger.Registry.Lib.V3.csproj | 1 - .../Interfaces/IRegistryInitializerService.cs | 6 +- .../AssetAdministrationShellDescriptor.cs | 14 +- .../Models/Descriptor.cs | 10 +- .../Models/Endpoint.cs | 10 +- .../Models/Message.cs | 45 +- .../Models/ProtocolInformation.cs | 52 +- .../ProtocolInformationSecurityAttributes.cs | 44 +- .../Models/Result.cs | 10 +- .../Models/SubmodelDescriptor.cs | 10 +- .../DescriptorDeserializeImplementation.cs | 2 +- .../AasDescriptorPaginationService.cs | 2 +- .../Services/AasDescriptorWritingService.cs | 195 +++ .../Services/IAasDescriptorWritingService.cs | 49 + .../ISubmodelPropertyExtractionService.cs | 52 + .../Services/RegistryInitializerService.cs | 1456 +++++++---------- .../SubmodelPropertyExtractionService.cs | 62 + src/IO.Swagger.Registry.Lib.V3/Startup.cs | 67 +- 140 files changed, 9098 insertions(+), 6543 deletions(-) create mode 100644 src/AasxCsharpLibrary.Tests/AasxCompatibilityModels/V20/AdaptiveFilterContractResolverTests.cs create mode 100644 src/AasxCsharpLibrary.Tests/AasxCompatibilityModels/V20/AdminShellConvertersTests.cs create mode 100644 src/AasxCsharpLibrary.Tests/AasxCsharpLibrary.Tests.csproj create mode 100644 src/AasxCsharpLibrary.Tests/AdaptiveFilterContractResolverTests.cs create mode 100644 src/AasxCsharpLibrary.Tests/GlobalUsings.cs create mode 100644 src/AasxCsharpLibrary.Tests/JsonAasxConverterTests.cs delete mode 100644 src/AasxCsharpLibrary/AdminShellCollections.cs create mode 100644 src/AasxServerStandardBib/Logging/LogMessages.cs create mode 100644 src/IO.Swagger.Lib.V3.Tests/Controllers/DescriptionAPIApiControllerTests.cs create mode 100644 src/IO.Swagger.Lib.V3.Tests/Models/MessageTests.cs create mode 100644 src/IO.Swagger.Lib.V3.Tests/Models/ServiceDescriptionTests.cs create mode 100644 src/IO.Swagger.Lib.V3.Tests/Services/GenerateSerializationServiceTests.cs create mode 100644 src/IO.Swagger.Lib.V3/Models/IServiceDescription.cs create mode 100644 src/IO.Swagger.Lib.V3/Models/ServerDescriptionProfiles.cs create mode 100644 src/IO.Swagger.Lib.V3/Models/ServiceProfiles.cs create mode 100644 src/IO.Swagger.Registry.Lib.V3.Tests/Extensions/ReferenceElementExtensionsTests.cs create mode 100644 src/IO.Swagger.Registry.Lib.V3.Tests/Services/SubmodelPropertyExtractionServiceTests.cs create mode 100644 src/IO.Swagger.Registry.Lib.V3/Extensions/ReferenceElementExtensions.cs create mode 100644 src/IO.Swagger.Registry.Lib.V3/Services/AasDescriptorWritingService.cs create mode 100644 src/IO.Swagger.Registry.Lib.V3/Services/IAasDescriptorWritingService.cs create mode 100644 src/IO.Swagger.Registry.Lib.V3/Services/ISubmodelPropertyExtractionService.cs create mode 100644 src/IO.Swagger.Registry.Lib.V3/Services/SubmodelPropertyExtractionService.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dd4d2443..88436d40e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed - I40Languages.cs and I40Messages.cs removed (@Freezor) +- References and usings of Newtonsoft in favor of a complete usage of System.Text.Json in the whole project. (@Freezor) ### Updated diff --git a/src/AasCore.Aas3_0/AasCore.Aas3_0.csproj b/src/AasCore.Aas3_0/AasCore.Aas3_0.csproj index 4ef7c7509..9603e6eed 100644 --- a/src/AasCore.Aas3_0/AasCore.Aas3_0.csproj +++ b/src/AasCore.Aas3_0/AasCore.Aas3_0.csproj @@ -21,6 +21,5 @@ false - diff --git a/src/AasCore.Aas3_0/jsonization.cs b/src/AasCore.Aas3_0/jsonization.cs index e6c576358..e738aee1c 100644 --- a/src/AasCore.Aas3_0/jsonization.cs +++ b/src/AasCore.Aas3_0/jsonization.cs @@ -15740,7 +15740,7 @@ public static Aas.LangStringTextType LangStringTextTypeFrom( /// Thrown when is not a valid JSON /// representation of Environment. /// - public static Aas.Environment EnvironmentFrom( + public static Environment EnvironmentFrom( Nodes.JsonNode node) { Aas.Environment? result = DeserializeImplementation.EnvironmentFrom( @@ -16047,7 +16047,7 @@ Aas.IExtension that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -16077,7 +16077,7 @@ Aas.IExtension that if (that.RefersTo != null) { var arrayRefersTo = new Nodes.JsonArray(); - foreach (IReference item in that.RefersTo) + foreach (IReference? item in that.RefersTo) { arrayRefersTo.Add( Transform( @@ -16098,7 +16098,7 @@ Aas.IAdministrativeInformation that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -16149,7 +16149,7 @@ Aas.IQualifier that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -16197,7 +16197,7 @@ Aas.IAssetAdministrationShell that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -16221,7 +16221,7 @@ Aas.IAssetAdministrationShell that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -16233,7 +16233,7 @@ Aas.IAssetAdministrationShell that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -16254,7 +16254,7 @@ Aas.IAssetAdministrationShell that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -16275,7 +16275,7 @@ Aas.IAssetAdministrationShell that if (that.Submodels != null) { var arraySubmodels = new Nodes.JsonArray(); - foreach (IReference item in that.Submodels) + foreach (IReference? item in that.Submodels) { arraySubmodels.Add( Transform( @@ -16307,7 +16307,7 @@ Aas.IAssetInformation that if (that.SpecificAssetIds != null) { var arraySpecificAssetIds = new Nodes.JsonArray(); - foreach (ISpecificAssetId item in that.SpecificAssetIds) + foreach (ISpecificAssetId? item in that.SpecificAssetIds) { arraySpecificAssetIds.Add( Transform( @@ -16364,7 +16364,7 @@ Aas.ISpecificAssetId that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -16397,7 +16397,7 @@ Aas.ISubmodel that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -16421,7 +16421,7 @@ Aas.ISubmodel that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -16433,7 +16433,7 @@ Aas.ISubmodel that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -16469,7 +16469,7 @@ Aas.ISubmodel that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -16481,7 +16481,7 @@ Aas.ISubmodel that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -16493,7 +16493,7 @@ Aas.ISubmodel that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -16505,7 +16505,7 @@ Aas.ISubmodel that if (that.SubmodelElements != null) { var arraySubmodelElements = new Nodes.JsonArray(); - foreach (ISubmodelElement item in that.SubmodelElements) + foreach (ISubmodelElement? item in that.SubmodelElements) { arraySubmodelElements.Add( Transform( @@ -16528,7 +16528,7 @@ Aas.IRelationshipElement that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -16552,7 +16552,7 @@ Aas.IRelationshipElement that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -16564,7 +16564,7 @@ Aas.IRelationshipElement that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -16582,7 +16582,7 @@ Aas.IRelationshipElement that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -16594,7 +16594,7 @@ Aas.IRelationshipElement that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -16606,7 +16606,7 @@ Aas.IRelationshipElement that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -16635,7 +16635,7 @@ Aas.ISubmodelElementList that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -16659,7 +16659,7 @@ Aas.ISubmodelElementList that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -16671,7 +16671,7 @@ Aas.ISubmodelElementList that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -16689,7 +16689,7 @@ Aas.ISubmodelElementList that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -16701,7 +16701,7 @@ Aas.ISubmodelElementList that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -16713,7 +16713,7 @@ Aas.ISubmodelElementList that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -16749,7 +16749,7 @@ Aas.ISubmodelElementList that if (that.Value != null) { var arrayValue = new Nodes.JsonArray(); - foreach (ISubmodelElement item in that.Value) + foreach (ISubmodelElement? item in that.Value) { arrayValue.Add( Transform( @@ -16772,7 +16772,7 @@ Aas.ISubmodelElementCollection that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -16796,7 +16796,7 @@ Aas.ISubmodelElementCollection that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -16808,7 +16808,7 @@ Aas.ISubmodelElementCollection that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -16826,7 +16826,7 @@ Aas.ISubmodelElementCollection that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -16838,7 +16838,7 @@ Aas.ISubmodelElementCollection that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -16850,7 +16850,7 @@ Aas.ISubmodelElementCollection that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -16862,7 +16862,7 @@ Aas.ISubmodelElementCollection that if (that.Value != null) { var arrayValue = new Nodes.JsonArray(); - foreach (ISubmodelElement item in that.Value) + foreach (ISubmodelElement? item in that.Value) { arrayValue.Add( Transform( @@ -16885,7 +16885,7 @@ Aas.IProperty that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -16909,7 +16909,7 @@ Aas.IProperty that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -16921,7 +16921,7 @@ Aas.IProperty that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -16939,7 +16939,7 @@ Aas.IProperty that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -16951,7 +16951,7 @@ Aas.IProperty that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -16963,7 +16963,7 @@ Aas.IProperty that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -17001,7 +17001,7 @@ Aas.IMultiLanguageProperty that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -17025,7 +17025,7 @@ Aas.IMultiLanguageProperty that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -17037,7 +17037,7 @@ Aas.IMultiLanguageProperty that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -17055,7 +17055,7 @@ Aas.IMultiLanguageProperty that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -17067,7 +17067,7 @@ Aas.IMultiLanguageProperty that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -17079,7 +17079,7 @@ Aas.IMultiLanguageProperty that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -17091,7 +17091,7 @@ Aas.IMultiLanguageProperty that if (that.Value != null) { var arrayValue = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Value) + foreach (ILangStringTextType? item in that.Value) { arrayValue.Add( Transform( @@ -17120,7 +17120,7 @@ Aas.IRange that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -17144,7 +17144,7 @@ Aas.IRange that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -17156,7 +17156,7 @@ Aas.IRange that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -17174,7 +17174,7 @@ Aas.IRange that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -17186,7 +17186,7 @@ Aas.IRange that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -17198,7 +17198,7 @@ Aas.IRange that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -17236,7 +17236,7 @@ Aas.IReferenceElement that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -17260,7 +17260,7 @@ Aas.IReferenceElement that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -17272,7 +17272,7 @@ Aas.IReferenceElement that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -17290,7 +17290,7 @@ Aas.IReferenceElement that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -17302,7 +17302,7 @@ Aas.IReferenceElement that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -17314,7 +17314,7 @@ Aas.IReferenceElement that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -17343,7 +17343,7 @@ Aas.IBlob that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -17367,7 +17367,7 @@ Aas.IBlob that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -17379,7 +17379,7 @@ Aas.IBlob that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -17397,7 +17397,7 @@ Aas.IBlob that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -17409,7 +17409,7 @@ Aas.IBlob that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -17421,7 +17421,7 @@ Aas.IBlob that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -17454,7 +17454,7 @@ Aas.IFile that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -17478,7 +17478,7 @@ Aas.IFile that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -17490,7 +17490,7 @@ Aas.IFile that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -17508,7 +17508,7 @@ Aas.IFile that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -17520,7 +17520,7 @@ Aas.IFile that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -17532,7 +17532,7 @@ Aas.IFile that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -17564,7 +17564,7 @@ Aas.IAnnotatedRelationshipElement that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -17588,7 +17588,7 @@ Aas.IAnnotatedRelationshipElement that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -17600,7 +17600,7 @@ Aas.IAnnotatedRelationshipElement that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -17618,7 +17618,7 @@ Aas.IAnnotatedRelationshipElement that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -17630,7 +17630,7 @@ Aas.IAnnotatedRelationshipElement that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -17642,7 +17642,7 @@ Aas.IAnnotatedRelationshipElement that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -17660,7 +17660,7 @@ Aas.IAnnotatedRelationshipElement that if (that.Annotations != null) { var arrayAnnotations = new Nodes.JsonArray(); - foreach (IDataElement item in that.Annotations) + foreach (IDataElement? item in that.Annotations) { arrayAnnotations.Add( Transform( @@ -17683,7 +17683,7 @@ Aas.IEntity that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -17707,7 +17707,7 @@ Aas.IEntity that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -17719,7 +17719,7 @@ Aas.IEntity that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -17737,7 +17737,7 @@ Aas.IEntity that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -17749,7 +17749,7 @@ Aas.IEntity that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -17761,7 +17761,7 @@ Aas.IEntity that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -17773,7 +17773,7 @@ Aas.IEntity that if (that.Statements != null) { var arrayStatements = new Nodes.JsonArray(); - foreach (ISubmodelElement item in that.Statements) + foreach (ISubmodelElement? item in that.Statements) { arrayStatements.Add( Transform( @@ -17794,7 +17794,7 @@ Aas.IEntity that if (that.SpecificAssetIds != null) { var arraySpecificAssetIds = new Nodes.JsonArray(); - foreach (ISpecificAssetId item in that.SpecificAssetIds) + foreach (ISpecificAssetId? item in that.SpecificAssetIds) { arraySpecificAssetIds.Add( Transform( @@ -17866,7 +17866,7 @@ Aas.IBasicEventElement that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -17890,7 +17890,7 @@ Aas.IBasicEventElement that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -17902,7 +17902,7 @@ Aas.IBasicEventElement that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -17920,7 +17920,7 @@ Aas.IBasicEventElement that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -17932,7 +17932,7 @@ Aas.IBasicEventElement that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -17944,7 +17944,7 @@ Aas.IBasicEventElement that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -18006,7 +18006,7 @@ Aas.IOperation that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -18030,7 +18030,7 @@ Aas.IOperation that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -18042,7 +18042,7 @@ Aas.IOperation that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -18060,7 +18060,7 @@ Aas.IOperation that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -18072,7 +18072,7 @@ Aas.IOperation that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -18084,7 +18084,7 @@ Aas.IOperation that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -18096,7 +18096,7 @@ Aas.IOperation that if (that.InputVariables != null) { var arrayInputVariables = new Nodes.JsonArray(); - foreach (IOperationVariable item in that.InputVariables) + foreach (IOperationVariable? item in that.InputVariables) { arrayInputVariables.Add( Transform( @@ -18108,7 +18108,7 @@ Aas.IOperation that if (that.OutputVariables != null) { var arrayOutputVariables = new Nodes.JsonArray(); - foreach (IOperationVariable item in that.OutputVariables) + foreach (IOperationVariable? item in that.OutputVariables) { arrayOutputVariables.Add( Transform( @@ -18120,7 +18120,7 @@ Aas.IOperation that if (that.InoutputVariables != null) { var arrayInoutputVariables = new Nodes.JsonArray(); - foreach (IOperationVariable item in that.InoutputVariables) + foreach (IOperationVariable? item in that.InoutputVariables) { arrayInoutputVariables.Add( Transform( @@ -18155,7 +18155,7 @@ Aas.ICapability that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -18179,7 +18179,7 @@ Aas.ICapability that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -18191,7 +18191,7 @@ Aas.ICapability that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -18209,7 +18209,7 @@ Aas.ICapability that if (that.SupplementalSemanticIds != null) { var arraySupplementalSemanticIds = new Nodes.JsonArray(); - foreach (IReference item in that.SupplementalSemanticIds) + foreach (IReference? item in that.SupplementalSemanticIds) { arraySupplementalSemanticIds.Add( Transform( @@ -18221,7 +18221,7 @@ Aas.ICapability that if (that.Qualifiers != null) { var arrayQualifiers = new Nodes.JsonArray(); - foreach (IQualifier item in that.Qualifiers) + foreach (IQualifier? item in that.Qualifiers) { arrayQualifiers.Add( Transform( @@ -18233,7 +18233,7 @@ Aas.ICapability that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -18256,7 +18256,7 @@ Aas.IConceptDescription that if (that.Extensions != null) { var arrayExtensions = new Nodes.JsonArray(); - foreach (IExtension item in that.Extensions) + foreach (IExtension? item in that.Extensions) { arrayExtensions.Add( Transform( @@ -18280,7 +18280,7 @@ Aas.IConceptDescription that if (that.DisplayName != null) { var arrayDisplayName = new Nodes.JsonArray(); - foreach (ILangStringNameType item in that.DisplayName) + foreach (ILangStringNameType? item in that.DisplayName) { arrayDisplayName.Add( Transform( @@ -18292,7 +18292,7 @@ Aas.IConceptDescription that if (that.Description != null) { var arrayDescription = new Nodes.JsonArray(); - foreach (ILangStringTextType item in that.Description) + foreach (ILangStringTextType? item in that.Description) { arrayDescription.Add( Transform( @@ -18313,7 +18313,7 @@ Aas.IConceptDescription that if (that.EmbeddedDataSpecifications != null) { var arrayEmbeddedDataSpecifications = new Nodes.JsonArray(); - foreach (IEmbeddedDataSpecification item in that.EmbeddedDataSpecifications) + foreach (IEmbeddedDataSpecification? item in that.EmbeddedDataSpecifications) { arrayEmbeddedDataSpecifications.Add( Transform( @@ -18325,7 +18325,7 @@ Aas.IConceptDescription that if (that.IsCaseOf != null) { var arrayIsCaseOf = new Nodes.JsonArray(); - foreach (IReference item in that.IsCaseOf) + foreach (IReference? item in that.IsCaseOf) { arrayIsCaseOf.Add( Transform( @@ -18355,7 +18355,7 @@ Aas.IReference that } var arrayKeys = new Nodes.JsonArray(); - foreach (IKey item in that.Keys) + foreach (IKey? item in that.Keys) { arrayKeys.Add( Transform( @@ -18420,7 +18420,7 @@ Aas.IEnvironment that if (that.AssetAdministrationShells != null) { var arrayAssetAdministrationShells = new Nodes.JsonArray(); - foreach (IAssetAdministrationShell item in that.AssetAdministrationShells) + foreach (IAssetAdministrationShell? item in that.AssetAdministrationShells) { arrayAssetAdministrationShells.Add( Transform( @@ -18432,7 +18432,7 @@ Aas.IEnvironment that if (that.Submodels != null) { var arraySubmodels = new Nodes.JsonArray(); - foreach (ISubmodel item in that.Submodels) + foreach (ISubmodel? item in that.Submodels) { arraySubmodels.Add( Transform( @@ -18444,7 +18444,7 @@ Aas.IEnvironment that if (that.ConceptDescriptions != null) { var arrayConceptDescriptions = new Nodes.JsonArray(); - foreach (IConceptDescription item in that.ConceptDescriptions) + foreach (IConceptDescription? item in that.ConceptDescriptions) { arrayConceptDescriptions.Add( Transform( @@ -18514,7 +18514,7 @@ Aas.IValueList that var result = new Nodes.JsonObject(); var arrayValueReferencePairs = new Nodes.JsonArray(); - foreach (IValueReferencePair item in that.ValueReferencePairs) + foreach (IValueReferencePair? item in that.ValueReferencePairs) { arrayValueReferencePairs.Add( Transform( @@ -18577,7 +18577,7 @@ Aas.IDataSpecificationIec61360 that var result = new Nodes.JsonObject(); var arrayPreferredName = new Nodes.JsonArray(); - foreach (ILangStringPreferredNameTypeIec61360 item in that.PreferredName) + foreach (ILangStringPreferredNameTypeIec61360? item in that.PreferredName) { arrayPreferredName.Add( Transform( @@ -18588,7 +18588,7 @@ Aas.IDataSpecificationIec61360 that if (that.ShortName != null) { var arrayShortName = new Nodes.JsonArray(); - foreach (ILangStringShortNameTypeIec61360 item in that.ShortName) + foreach (ILangStringShortNameTypeIec61360? item in that.ShortName) { arrayShortName.Add( Transform( @@ -18633,7 +18633,7 @@ Aas.IDataSpecificationIec61360 that if (that.Definition != null) { var arrayDefinition = new Nodes.JsonArray(); - foreach (ILangStringDefinitionTypeIec61360 item in that.Definition) + foreach (ILangStringDefinitionTypeIec61360? item in that.Definition) { arrayDefinition.Add( Transform( @@ -18693,7 +18693,7 @@ public static class Serialize /// /// Serialize an instance of the meta-model into a JSON object. /// - public static Nodes.JsonObject ToJsonObject(Aas.IClass that) + public static Nodes.JsonObject ToJsonObject(IClass? that) { return Serialize.Transformer.Transform(that); } diff --git a/src/AasCore.Aas3_0/types.cs b/src/AasCore.Aas3_0/types.cs index 9da0115a8..c440835d6 100644 --- a/src/AasCore.Aas3_0/types.cs +++ b/src/AasCore.Aas3_0/types.cs @@ -3,7 +3,6 @@ * Do NOT edit or append. */ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; // can't alias @@ -12,6 +11,8 @@ namespace AasCore.Aas3_0 { + using System.Text.Json.Serialization; + /// /// Represent a general class of an AAS model. /// @@ -1233,7 +1234,7 @@ public interface IAssetAdministrationShell : /// /// Meta-information about the asset the AAS is representing. /// - public IAssetInformation AssetInformation { get; set; } + public IAssetInformation? AssetInformation { get; set; } /// /// References to submodels of the AAS. @@ -1345,7 +1346,7 @@ public class AssetAdministrationShell : IAssetAdministrationShell /// /// Meta-information about the asset the AAS is representing. /// - public IAssetInformation AssetInformation { get; set; } + public IAssetInformation? AssetInformation { get; set; } /// /// References to submodels of the AAS. @@ -1629,7 +1630,7 @@ public T Transform( public AssetAdministrationShell( string? id, - IAssetInformation assetInformation, + IAssetInformation? assetInformation, List? extensions = null, string? category = null, string? idShort = null, @@ -2893,12 +2894,12 @@ public interface IRelationshipElement : ISubmodelElement /// /// Reference to the first element in the relationship taking the role of the subject. /// - public IReference First { get; set; } + public IReference? First { get; set; } /// /// Reference to the second element in the relationship taking the role of the object. /// - public IReference Second { get; set; } + public IReference? Second { get; set; } } /// @@ -3006,12 +3007,12 @@ public class RelationshipElement : IRelationshipElement /// /// Reference to the first element in the relationship taking the role of the subject. /// - public IReference First { get; set; } + public IReference? First { get; set; } /// /// Reference to the second element in the relationship taking the role of the object. /// - public IReference Second { get; set; } + public IReference? Second { get; set; } #region Parent @@ -3303,8 +3304,8 @@ public T Transform( } public RelationshipElement( - IReference first, - IReference second, + IReference? first, + IReference? second, List? extensions = null, string? category = null, string? idShort = null, @@ -7499,12 +7500,12 @@ public class AnnotatedRelationshipElement : IAnnotatedRelationshipElement /// /// Reference to the first element in the relationship taking the role of the subject. /// - public IReference First { get; set; } + public IReference? First { get; set; } /// /// Reference to the second element in the relationship taking the role of the object. /// - public IReference Second { get; set; } + public IReference? Second { get; set; } /// /// A data element that represents an annotation that holds for the relationship @@ -7833,8 +7834,8 @@ public T Transform( } public AnnotatedRelationshipElement( - IReference first, - IReference second, + IReference? first, + IReference? second, List? extensions = null, string? category = null, string? idShort = null, @@ -8494,7 +8495,7 @@ public interface IEventPayload : IClass /// , , /// 's. /// - public IReference Source { get; set; } + public IReference? Source { get; set; } /// /// of the source event element, if available @@ -8511,7 +8512,7 @@ public interface IEventPayload : IClass /// Can be , or /// . /// - public IReference ObservableReference { get; set; } + public IReference? ObservableReference { get; set; } /// /// of the referable which defines the scope of @@ -8561,7 +8562,7 @@ public class EventPayload : IEventPayload /// , , /// 's. /// - public IReference Source { get; set; } + public IReference? Source { get; set; } /// /// of the source event element, if available @@ -8578,7 +8579,7 @@ public class EventPayload : IEventPayload /// Can be , or /// . /// - public IReference ObservableReference { get; set; } + public IReference? ObservableReference { get; set; } /// /// of the referable which defines the scope of @@ -8735,8 +8736,8 @@ public T Transform( } public EventPayload( - IReference source, - IReference observableReference, + IReference? source, + IReference? observableReference, string? timeStamp, IReference? sourceSemanticId = null, IReference? observableSemanticId = null, @@ -8785,7 +8786,7 @@ public interface IBasicEventElement : IEventElement /// Reference to a referable, e.g., a data element or /// a submodel, that is being observed. /// - public IReference Observed { get; set; } + public IReference? Observed { get; set; } /// /// Direction of event. @@ -8973,7 +8974,7 @@ public class BasicEventElement : IBasicEventElement /// Reference to a referable, e.g., a data element or /// a submodel, that is being observed. /// - public IReference Observed { get; set; } + public IReference? Observed { get; set; } /// /// Direction of event. @@ -9342,7 +9343,7 @@ public T Transform( } public BasicEventElement( - IReference observed, + IReference? observed, Direction direction, StateOfEvent state, List? extensions = null, @@ -9960,7 +9961,7 @@ public interface IOperationVariable : IClass /// /// Describes an argument or result of an operation via a submodel element /// - public ISubmodelElement Value { get; set; } + public ISubmodelElement? Value { get; set; } } /// @@ -9972,7 +9973,7 @@ public class OperationVariable : IOperationVariable /// /// Describes an argument or result of an operation via a submodel element /// - public ISubmodelElement Value { get; set; } + public ISubmodelElement? Value { get; set; } /// /// Iterate over all the class instances referenced from this instance @@ -10037,7 +10038,7 @@ public T Transform( return transformer.TransformOperationVariable(this, context); } - public OperationVariable(ISubmodelElement value) + public OperationVariable(ISubmodelElement? value) { Value = value; } @@ -12097,12 +12098,12 @@ public interface IEmbeddedDataSpecification : IClass /// /// Reference to the data specification /// - public IReference DataSpecification { get; set; } + public IReference? DataSpecification { get; set; } /// /// Actual content of the data specification /// - public IDataSpecificationContent DataSpecificationContent { get; set; } + public IDataSpecificationContent? DataSpecificationContent { get; set; } } /// @@ -12113,12 +12114,12 @@ public class EmbeddedDataSpecification : IEmbeddedDataSpecification /// /// Reference to the data specification /// - public IReference DataSpecification { get; set; } + public IReference? DataSpecification { get; set; } /// /// Actual content of the data specification /// - public IDataSpecificationContent DataSpecificationContent { get; set; } + public IDataSpecificationContent? DataSpecificationContent { get; set; } /// /// Iterate over all the class instances referenced from this instance @@ -12194,8 +12195,8 @@ public T Transform( } public EmbeddedDataSpecification( - IReference dataSpecification, - IDataSpecificationContent dataSpecificationContent) + IReference? dataSpecification, + IDataSpecificationContent? dataSpecificationContent) { DataSpecification = dataSpecification; DataSpecificationContent = dataSpecificationContent; @@ -12591,7 +12592,7 @@ public interface IValueReferencePair : IClass /// /// It is recommended to use a global reference. /// - public IReference ValueId { get; set; } + public IReference? ValueId { get; set; } } /// @@ -12611,7 +12612,7 @@ public class ValueReferencePair : IValueReferencePair /// /// It is recommended to use a global reference. /// - public IReference ValueId { get; set; } + public IReference? ValueId { get; set; } /// /// Iterate over all the class instances referenced from this instance @@ -12678,7 +12679,7 @@ public T Transform( public ValueReferencePair( string? value, - IReference valueId) + IReference? valueId) { Value = value; ValueId = valueId; diff --git a/src/AasCore.Aas3_0/verification.cs b/src/AasCore.Aas3_0/verification.cs index 86ef278ae..328516df5 100644 --- a/src/AasCore.Aas3_0/verification.cs +++ b/src/AasCore.Aas3_0/verification.cs @@ -1960,7 +1960,7 @@ Aas.DataTypeDefXsd valueType /// Check that the target of the model reference matches the . /// public static bool IsModelReferenceTo( - IReference reference, + IReference? reference, KeyTypes expectedType ) { @@ -1973,7 +1973,7 @@ KeyTypes expectedType /// Check that the target of the reference matches a . /// public static bool IsModelReferenceToReferable( - IReference reference + IReference? reference ) { return reference.Type == ReferenceTypes.ModelReference @@ -9615,7 +9615,7 @@ var error in Verification.VerifyNonEmptyXmlSerializableString( /// /// The instance of the meta-model to be verified /// - public static IEnumerable Verify(Aas.IClass that) + public static IEnumerable Verify(IClass? that) { foreach (var error in _transformer.Transform(that)) { diff --git a/src/AasCore.Aas3_0/visitation.cs b/src/AasCore.Aas3_0/visitation.cs index 552c5eb7a..83719ed32 100644 --- a/src/AasCore.Aas3_0/visitation.cs +++ b/src/AasCore.Aas3_0/visitation.cs @@ -705,7 +705,7 @@ IDataSpecificationIec61360 that /// Context type public interface IVisitorWithContext { - public void Visit(IClass that, TContext context); + public void Visit(IClass? that, TContext context); public void VisitExtension( IExtension that, TContext context @@ -723,7 +723,7 @@ public void VisitAssetAdministrationShell( TContext context ); public void VisitAssetInformation( - IAssetInformation that, + IAssetInformation? that, TContext context ); public void VisitResource( @@ -807,7 +807,7 @@ public void VisitConceptDescription( TContext context ); public void VisitReference( - IReference that, + IReference? that, TContext context ); public void VisitKey( @@ -868,7 +868,7 @@ TContext context public abstract class AbstractVisitorWithContext : IVisitorWithContext { - public void Visit(IClass that, TContext context) + public void Visit(IClass? that, TContext context) { that.Accept(this, context); } @@ -889,7 +889,7 @@ public abstract void VisitAssetAdministrationShell( TContext context ); public abstract void VisitAssetInformation( - IAssetInformation that, + IAssetInformation? that, TContext context ); public abstract void VisitResource( @@ -973,7 +973,7 @@ public abstract void VisitConceptDescription( TContext context ); public abstract void VisitReference( - IReference that, + IReference? that, TContext context ); public abstract void VisitKey( @@ -1038,7 +1038,7 @@ TContext context /// The type of the transformation result public interface ITransformer { - public T Transform(IClass that); + public T Transform(IClass? that); public T TransformExtension( IExtension that ); @@ -1162,7 +1162,7 @@ IDataSpecificationIec61360 that /// The type of the transformation result public abstract class AbstractTransformer : ITransformer { - public T Transform(IClass that) + public T Transform(IClass? that) { return that.Transform(this); } @@ -1333,7 +1333,7 @@ IDataSpecificationIec61360 that /// The type of the transformation result public interface ITransformerWithContext { - public T Transform(IClass that, TContext context); + public T Transform(IClass? that, TContext context); public T TransformExtension( IExtension that, TContext context @@ -1502,7 +1502,7 @@ TContext context public abstract class AbstractTransformerWithContext : ITransformerWithContext { - public T Transform(IClass that, TContext context) + public T Transform(IClass? that, TContext context) { return that.Transform(this, context); } diff --git a/src/AasCore.Aas3_0/xmlization.cs b/src/AasCore.Aas3_0/xmlization.cs index c16b7360f..fd29dae7c 100644 --- a/src/AasCore.Aas3_0/xmlization.cs +++ b/src/AasCore.Aas3_0/xmlization.cs @@ -20606,7 +20606,7 @@ public static Aas.LangStringTextType LangStringTextTypeFrom( /// Thrown when the element is not a valid XML /// representation of Environment. /// - public static Aas.Environment EnvironmentFrom( + public static Environment EnvironmentFrom( Xml.XmlReader reader) { Aas.Environment? result = ( @@ -21330,7 +21330,7 @@ public override void VisitAssetAdministrationShell( } private void AssetInformationToSequence( - Aas.IAssetInformation that, + IAssetInformation? that, Xml.XmlWriter writer) { writer.WriteStartElement( @@ -21402,7 +21402,7 @@ private void AssetInformationToSequence( } // private void AssetInformationToSequence public override void VisitAssetInformation( - Aas.IAssetInformation that, + IAssetInformation? that, Xml.XmlWriter writer) { writer.WriteStartElement( @@ -24648,7 +24648,7 @@ public override void VisitConceptDescription( } private void ReferenceToSequence( - Aas.IReference that, + IReference? that, Xml.XmlWriter writer) { if (that == null) @@ -24700,7 +24700,7 @@ private void ReferenceToSequence( } // private void ReferenceToSequence public override void VisitReference( - Aas.IReference that, + IReference? that, Xml.XmlWriter writer) { writer.WriteStartElement( @@ -25377,7 +25377,7 @@ public static class Serialize /// Serialize an instance of the meta-model to XML. /// public static void To( - Aas.IClass that, + IClass? that, Xml.XmlWriter writer) { Serialize._visitorWithWriter.Visit( diff --git a/src/AasxCsharpLibrary.Tests/AasxCompatibilityModels/V20/AdaptiveFilterContractResolverTests.cs b/src/AasxCsharpLibrary.Tests/AasxCompatibilityModels/V20/AdaptiveFilterContractResolverTests.cs new file mode 100644 index 000000000..de461c273 --- /dev/null +++ b/src/AasxCsharpLibrary.Tests/AasxCompatibilityModels/V20/AdaptiveFilterContractResolverTests.cs @@ -0,0 +1,29 @@ +namespace AasxCsharpLibary.Tests.AasxCompatibilityModels.V20; + +using System.Text.Json; +using global::AasxCompatibilityModels; + +public class AdaptiveFilterContractResolverTests +{ + private readonly Fixture _fixture; + + public AdaptiveFilterContractResolverTests() + { + _fixture = new Fixture(); + _fixture.Customize(new AutoMoqCustomization()); + } + + [Fact] + public void AdaptiveFilterContractResolver_CanConvert_Should_Return_True_For_AdministrationShell() + { + // Arrange + var resolver = new AdminShell_V20.AdminShellConverters.AdaptiveFilterContractResolver(); + var typeToConvert = typeof(AdminShellV20.AdministrationShell); + + // Act + var result = resolver.CanConvert(typeToConvert); + + // Assert + result.Should().BeTrue(); + } +} \ No newline at end of file diff --git a/src/AasxCsharpLibrary.Tests/AasxCompatibilityModels/V20/AdminShellConvertersTests.cs b/src/AasxCsharpLibrary.Tests/AasxCompatibilityModels/V20/AdminShellConvertersTests.cs new file mode 100644 index 000000000..52a6dcb90 --- /dev/null +++ b/src/AasxCsharpLibrary.Tests/AasxCompatibilityModels/V20/AdminShellConvertersTests.cs @@ -0,0 +1,165 @@ +namespace AasxCsharpLibary.Tests.AasxCompatibilityModels.V20; + +using System.Text; +using System.Text.Json; +using AdminShell_V20; +using global::AasxCompatibilityModels; + +public class AdminShellConvertersTests +{ + private readonly Fixture _fixture; + + public AdminShellConvertersTests() + { + _fixture = new Fixture(); + _fixture.Customize(new AutoMoqCustomization()); + } + + [Fact] + public void JsonAasxConverter_CanConvert_Should_Return_True_For_Referable() + { + // Arrange + var converter = new AdminShell_V20.AdminShellConverters.JsonAasxConverter(); + var typeToConvert = typeof(AdminShellV20.Referable); + + // Act + var result = converter.CanConvert(typeToConvert); + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void JsonAasxConverter_Read_Should_Populate_Target_Object() + { + // Arrange + var jsonString = "{\"modelType\": { \"name\": \"SubmodelElement\" }, \"otherProperty\": \"value\" }"; + var options = new JsonSerializerOptions(); // Use real JsonSerializerOptions + var bytes = System.Text.Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes, new JsonReaderOptions {AllowTrailingCommas = true}); + + var converter = new AdminShell_V20.AdminShellConverters.JsonAasxConverter(); + + // Act + var result = converter.Read(ref reader, typeof(AdminShellV20.Referable), options); + + // Assert + result.Should().BeOfType(); // Adjust type as needed based on the actual return type + + result.Should().NotBeNull(); + result.category.Should().BeNull(); + result.description.Should().BeNull(); + result.idShort.Should().Be(string.Empty); + result.parent.Should().BeNull(); + result.DiaryData.Should().NotBeNull(); + result.DiaryData.Entries.Should().BeNull(); + result.DiaryData.TimeStamp.Should().NotBeNull(); + result.JsonDescription.Should().BeNull(); + } + + [Fact] + public void JsonAasxConverter_Read_Should_Handle_JsonDescription() + { + // Arrange + const string jsonString = @" + { + ""idShort"": ""123asd"", + ""category"": ""test"", + ""description"": { + ""langString"": [ + { + ""lang"": ""en"", + ""str"": ""Description text"" + } + ] + } + }"; + + var options = new JsonSerializerOptions(); // Use real JsonSerializerOptions + var bytes = Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes, new JsonReaderOptions { AllowTrailingCommas = true }); + + var converter = new AdminShellConverters.JsonAasxConverter(); + + // Act + var result = converter.Read(ref reader, typeof(AdminShellV20.Referable), options) as AdminShellV20.Referable; + + // Assert + result.Should().NotBeNull(); + result.JsonDescription.Should().NotBeNull(); + result.JsonDescription.Count.Should().Be(1); + + var firstLangStr = result.JsonDescription.FirstOrDefault(); + firstLangStr.Should().NotBeNull(); + firstLangStr.lang.Should().Be("en"); + firstLangStr.str.Should().Be("Description text"); + } + + [Fact] + public void Referable_Validate_Should_Add_Error_For_Missing_IdShort() + { + // Arrange + var referable = _fixture.Create(); + referable.idShort = null; // Simulate missing idShort + + var validationRecords = new AasValidationRecordList(); + + // Act + referable.Validate(validationRecords); + + // Assert + validationRecords.Should().ContainSingle(record => + record.Severity == AasValidationSeverity.SpecViolation && + record.Message == "Referable: missing idShort"); + } + + [Fact] + public void Referable_ComputeHashcode_Should_Return_Correct_Hash() + { + // Arrange + var referable = new AdminShellV20.Referable("testId"); + + // Act + var hashcode = referable.ComputeHashcode(); + + // Assert + hashcode.Should().NotBeNullOrEmpty(); + hashcode.Length.Should().Be(64); // SHA256 hash length + } + + [Fact] + public void Referable_CollectIdShortByParent_Should_Return_Correct_Path() + { + // Arrange + var parent = _fixture.Create(); + parent.idShort = "parent"; + + var child = _fixture.Create(); + child.idShort = "child"; + child.parent = parent; + + // Act + var fullPath = child.CollectIdShortByParent(); + + // Assert + fullPath.Should().Be("parent/child"); + } + + + [Fact] + public void JsonAasxConverter_Write_Should_ThrowNotImplementedException() + { + // Arrange + var originalReferable = _fixture.Create(); + var converter = new AdminShell_V20.AdminShellConverters.JsonAasxConverter(); + var options = new JsonSerializerOptions {WriteIndented = true}; + var buffer = new MemoryStream(); + var writer = new Utf8JsonWriter(buffer); + + // Act + Action act = () => converter.Write(writer, originalReferable, options); + + // Assert + act.Should().ThrowExactly("we did not implement that yet and it is not needed yet"); + } +} \ No newline at end of file diff --git a/src/AasxCsharpLibrary.Tests/AasxCsharpLibrary.Tests.csproj b/src/AasxCsharpLibrary.Tests/AasxCsharpLibrary.Tests.csproj new file mode 100644 index 000000000..4f31cc34f --- /dev/null +++ b/src/AasxCsharpLibrary.Tests/AasxCsharpLibrary.Tests.csproj @@ -0,0 +1,40 @@ + + + + net8.0 + enable + enable + + false + true + false + AasxCsharpLibary.Tests + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/src/AasxCsharpLibrary.Tests/AdaptiveFilterContractResolverTests.cs b/src/AasxCsharpLibrary.Tests/AdaptiveFilterContractResolverTests.cs new file mode 100644 index 000000000..844ae0946 --- /dev/null +++ b/src/AasxCsharpLibrary.Tests/AdaptiveFilterContractResolverTests.cs @@ -0,0 +1,141 @@ +using System.Text.Json; + +namespace AasxCsharpLibary.Tests; + +using AdminShellNS; + +public class AdaptiveFilterContractResolverTests +{ + private readonly Fixture _fixture; + private readonly JsonSerializerOptions _jsonOptions; + + public AdaptiveFilterContractResolverTests() + { + _fixture = new Fixture(); + _fixture.Customize(new AutoMoqCustomization()); + _jsonOptions = new JsonSerializerOptions(); + } + + [Fact] + public void Read_Should_Return_JsonElement_For_Valid_Json() + { + // Arrange + const string jsonString = """{ "key": "value" }"""; + var bytes = System.Text.Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes); + + var resolver = new AdminShellConverters.AdaptiveFilterContractResolver(); + + // Act + var result = resolver.Read(ref reader, typeof(JsonElement), _jsonOptions); + + // Assert + result.Should().NotBeNull(); + result.GetProperty("key").GetString().Should().Be("value"); + } + + [Fact] + public void Read_Should_Handle_Invalid_Json() + { + // Arrange + const string jsonString = """{ "key": "value" """; + var bytes = System.Text.Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes); + + var resolver = new AdminShellConverters.AdaptiveFilterContractResolver(); + + // Act + try + { + resolver.Read(ref reader, typeof(JsonElement), _jsonOptions); + } + catch (JsonException e) + { + // Assert + e.Message.Should().Contain("Error while reading JSON"); + } + } + + [Fact] + public void Write_Should_Throw_NotImplementedException() + { + // Arrange + var resolver = new AdminShellConverters.AdaptiveFilterContractResolver(); + var writer = new Utf8JsonWriter(Stream.Null); + var jsonElement = JsonDocument.Parse("{}").RootElement; + + // Act & Assert + Assert.Throws(() => resolver.Write(writer, jsonElement, _jsonOptions)); + } + + [Fact] + public void AdaptiveFilterContractResolver_Should_Set_Properties_Correctly() + { + // Arrange + var resolver = new AdminShellConverters.AdaptiveFilterContractResolver(false, false, false, false, false); + + // Act & Assert + resolver.AasHasViews.Should().BeFalse(); + resolver.BlobHasValue.Should().BeFalse(); + resolver.SubmodelHasElements.Should().BeFalse(); + resolver.SmcHasValue.Should().BeFalse(); + resolver.OpHasVariables.Should().BeFalse(); + } + + [Fact] + public void Read_Should_Return_JsonElement_For_Empty_Json() + { + // Arrange + const string jsonString = "{}"; + var bytes = System.Text.Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes); + + var resolver = new AdminShellConverters.AdaptiveFilterContractResolver(); + + // Act + var result = resolver.Read(ref reader, typeof(JsonElement), _jsonOptions); + + // Assert + result.Should().NotBeNull(); + result.ValueKind.Should().Be(JsonValueKind.Object); + } + + [Fact] + public void Read_Should_Return_JsonElement_For_Nested_Json() + { + // Arrange + const string jsonString = """{ "key1": { "key2": "value" } }"""; + var bytes = System.Text.Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes); + + var resolver = new AdminShellConverters.AdaptiveFilterContractResolver(); + + // Act + var result = resolver.Read(ref reader, typeof(JsonElement), _jsonOptions); + + // Assert + result.Should().NotBeNull(); + result.GetProperty("key1").GetProperty("key2").GetString().Should().Be("value"); + } + + [Fact] + public void Read_Should_Return_JsonElement_For_Array_Json() + { + // Arrange + const string jsonString = """{ "key": [ "value1", "value2" ] }"""; + var bytes = System.Text.Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes); + + var resolver = new AdminShellConverters.AdaptiveFilterContractResolver(); + + // Act + var result = resolver.Read(ref reader, typeof(JsonElement), _jsonOptions); + + // Assert + result.Should().NotBeNull(); + var array = result.GetProperty("key").EnumerateArray().ToArray(); + array.Should().HaveCount(2); + array[0].GetString().Should().Be("value1"); + array[1].GetString().Should().Be("value2"); + } +} \ No newline at end of file diff --git a/src/AasxCsharpLibrary.Tests/GlobalUsings.cs b/src/AasxCsharpLibrary.Tests/GlobalUsings.cs new file mode 100644 index 000000000..f04fa059b --- /dev/null +++ b/src/AasxCsharpLibrary.Tests/GlobalUsings.cs @@ -0,0 +1,5 @@ +global using Xunit; +global using FluentAssertions; +global using Moq; +global using AutoFixture; +global using AutoFixture.AutoMoq; \ No newline at end of file diff --git a/src/AasxCsharpLibrary.Tests/JsonAasxConverterTests.cs b/src/AasxCsharpLibrary.Tests/JsonAasxConverterTests.cs new file mode 100644 index 000000000..68ddcd590 --- /dev/null +++ b/src/AasxCsharpLibrary.Tests/JsonAasxConverterTests.cs @@ -0,0 +1,209 @@ +using System.Text.Json; +using AdminShellNS; + +namespace AasxCsharpLibary.Tests; + +using AasCore.Aas3_0; + +public class JsonAasxConverterTests +{ + private readonly Fixture _fixture; + private readonly JsonSerializerOptions _jsonOptions; + + public JsonAasxConverterTests() + { + _fixture = new Fixture(); + _fixture.Customize(new AutoMoqCustomization()); + _jsonOptions = new JsonSerializerOptions(); + } + + [Fact] + public void Read_Should_Deserialize_JsonWithCategoryAndIdShort() + { + // Arrange + const string jsonString = @" + { + ""upperClassProperty"": { + ""lowerClassProperty"": ""Submodel"" + }, + ""category"": ""test"", + ""idShort"": ""123abc"" + }"; + + var bytes = System.Text.Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes); + + var converter = new AdminShellConverters.JsonAasxConverter("upperClassProperty", "lowerClassProperty"); + + // Act + var result = converter.Read(ref reader, typeof(IReferable), _jsonOptions); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + result.Category.Should().Be("test"); + result.IdShort.Should().Be("123abc"); + } + + [Fact] + public void Read_Should_Return_Null_For_Missing_UpperClassProperty() + { + // Arrange + const string jsonString = @" + { + ""category"": ""test"", + ""idShort"": ""123abc"" + }"; + + var bytes = System.Text.Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes); + + var converter = new AdminShellConverters.JsonAasxConverter("upperClassProperty", "lowerClassProperty"); + + // Act + var result = converter.Read(ref reader, typeof(IReferable), _jsonOptions); + + // Assert + result.Should().BeNull(); + } + + + [Fact] + public void Read_Should_Return_Null_For_Invalid_Json() + { + // Arrange + const string jsonString = @"{ ""invalidJson"": ""test"" }"; + + var bytes = System.Text.Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes); + + var converter = new AdminShellConverters.JsonAasxConverter("upperClassProperty", "lowerClassProperty"); + + // Act + var result = converter.Read(ref reader, typeof(IReferable), _jsonOptions); + + // Assert + result.Should().BeNull(); + } + + [Fact] + public void Read_Should_Deserialize_JsonWithDisplayName() + { + // Arrange + const string jsonString = @" + { + ""upperClassProperty"": { + ""lowerClassProperty"": ""Submodel"" + }, + ""displayName"": [ + { ""lang"": ""en"", ""value"": ""Test DisplayName"" } + ] + }"; + + var bytes = System.Text.Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes); + + var converter = new AdminShellConverters.JsonAasxConverter("upperClassProperty", "lowerClassProperty"); + + // Act + var result = converter.Read(ref reader, typeof(IReferable), _jsonOptions) as Submodel; + + // Assert + result.Should().NotBeNull(); + result.DisplayName.Should().ContainSingle() + .Which.Should().BeEquivalentTo(new LangStringNameType("en", "Test DisplayName")); + } + + [Fact] + public void Read_Should_Deserialize_JsonWithDescription() + { + // Arrange + const string jsonString = @" + { + ""upperClassProperty"": { + ""lowerClassProperty"": ""Submodel"" + }, + ""description"": [ + { ""lang"": ""en"", ""value"": ""Test Description"" } + ] + }"; + + var bytes = System.Text.Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes); + + var converter = new AdminShellConverters.JsonAasxConverter("upperClassProperty", "lowerClassProperty"); + + // Act + var result = converter.Read(ref reader, typeof(IReferable), _jsonOptions) as Submodel; + + // Assert + result.Should().NotBeNull(); + result.Description.Should().ContainSingle() + .Which.Should().BeEquivalentTo(new LangStringTextType("en", "Test Description")); + } + + [Fact] + public void Read_Should_Handle_Missing_OptionalProperties() + { + // Arrange + const string jsonString = @" + { + ""upperClassProperty"": { + ""lowerClassProperty"": ""Submodel"" + } + }"; + + var bytes = System.Text.Encoding.UTF8.GetBytes(jsonString); + var reader = new Utf8JsonReader(bytes); + + var converter = new AdminShellConverters.JsonAasxConverter("upperClassProperty", "lowerClassProperty"); + + // Act + var result = converter.Read(ref reader, typeof(IReferable), _jsonOptions) as Submodel; + + // Assert + result.Should().NotBeNull(); + result.Category.Should().BeNull(); + result.IdShort.Should().BeNull(); + result.DisplayName.Should().BeNull(); + result.Description.Should().BeNull(); + } + + [Fact] + public void Write_Should_Throw_NotImplementedException() + { + // Arrange + var converter = new AdminShellConverters.JsonAasxConverter("upperClassProperty", "lowerClassProperty"); + var writer = new Utf8JsonWriter(Stream.Null); + var referable = new Mock().Object; + + // Act & Assert + Assert.Throws(() => converter.Write(writer, referable, _jsonOptions)); + } + + [Fact] + public void CanConvert_Should_Return_True_For_IReferable() + { + // Arrange + var converter = new AdminShellConverters.JsonAasxConverter("upperClassProperty", "lowerClassProperty"); + + // Act + var canConvert = converter.CanConvert(typeof(IReferable)); + + // Assert + canConvert.Should().BeTrue(); + } + + [Fact] + public void CanConvert_Should_Return_False_For_Non_IReferable() + { + // Arrange + var converter = new AdminShellConverters.JsonAasxConverter("upperClassProperty", "lowerClassProperty"); + + // Act + var canConvert = converter.CanConvert(typeof(string)); + + // Assert + canConvert.Should().BeFalse(); + } +} \ No newline at end of file diff --git a/src/AasxCsharpLibrary/AasxCompatibilityModels/V20/AdminShell.cs b/src/AasxCsharpLibrary/AasxCompatibilityModels/V20/AdminShell.cs index 7c390a1ce..0e5bf2958 100644 --- a/src/AasxCsharpLibrary/AasxCompatibilityModels/V20/AdminShell.cs +++ b/src/AasxCsharpLibrary/AasxCompatibilityModels/V20/AdminShell.cs @@ -8,7 +8,6 @@ This source code may use other Open Source software components (see LICENSE.txt) */ using AdminShell_V20; -using Newtonsoft.Json; using System; using System.Collections; using System.Collections.Generic; @@ -22,6 +21,9 @@ This source code may use other Open Source software components (see LICENSE.txt) namespace AasxCompatibilityModels { + using System.Text.Json; + using System.Text.Json.Serialization; + /// /// This empty class derives always from the current version of the Administration Shell class hierarchy. /// @@ -40,9 +42,9 @@ public class Identification { // members - [ XmlAttribute ] [ CountForHash ] public string? idType = ""; + [XmlAttribute] [CountForHash] public string? idType = ""; - [ XmlText ] [ CountForHash ] public string? id = ""; + [XmlText] [CountForHash] public string? id = ""; // some constants @@ -125,10 +127,10 @@ public class Administration { // members - [ MetaModelName("Administration.version") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("Administration.version")] [TextSearchable] [CountForHash] public string version = ""; - [ MetaModelName("Administration.revision") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("Administration.revision")] [TextSearchable] [CountForHash] public string revision = ""; // constructors @@ -169,16 +171,16 @@ public enum MatchMode { Strict, Relaxed, Identification }; // Members - [ MetaModelName("Key.type") ] [ TextSearchable ] [ XmlAttribute ] [ CountForHash ] + [MetaModelName("Key.type")] [TextSearchable] [XmlAttribute] [CountForHash] public string? type = ""; - [ XmlAttribute ] [ CountForHash ] public bool local = false; + [XmlAttribute] [CountForHash] public bool local = false; - [ MetaModelName("Key.idType") ] [ TextSearchable ] [ XmlAttribute ] [ JsonIgnore ] [ CountForHash ] + [MetaModelName("Key.idType")] [TextSearchable] [XmlAttribute] [JsonIgnore] [CountForHash] public string? idType = ""; - [ XmlIgnore ] - [ JsonProperty(PropertyName = "idType") ] + [XmlIgnore] + [JsonPropertyName("idType")] public string? JsonIdType { // adapt idShort <-> IdShort @@ -186,10 +188,10 @@ public string? JsonIdType set => idType = (value == "idShort") ? "IdShort" : value; } - [ MetaModelName("Key.value") ] [ TextSearchable ] [ XmlText ] [ CountForHash ] + [MetaModelName("Key.value")] [TextSearchable] [XmlText] [CountForHash] public string? value = ""; - [ XmlIgnore ] [ JsonProperty(PropertyName = "index") ] [ CountForHash ] + [XmlIgnore] [JsonPropertyName("index")] [CountForHash] public int index = 0; public Key() @@ -236,7 +238,7 @@ public static Key GetFromRef(Reference r) { if (r == null || r.Count != 1) return null; - return r[ 0 ]; + return r[0]; } public Identification ToId() @@ -279,8 +281,8 @@ public static Key Parse(string cell, string? typeIfNotSet = null, if (m.Success) { return new AdminShell.Key( - m.Groups[ 1 ].ToString(), m.Groups[ 2 ].ToString() == "local", - m.Groups[ 3 ].ToString(), m.Groups[ 5 ].ToString()); + m.Groups[1].ToString(), m.Groups[2].ToString() == "local", + m.Groups[3].ToString(), m.Groups[5].ToString()); } } @@ -292,7 +294,7 @@ m.Groups[ 1 ].ToString(), m.Groups[ 2 ].ToString() == "local", { return new AdminShell.Key( typeIfNotSet, true, - m.Groups[ 1 ].ToString(), m.Groups[ 3 ].ToString()); + m.Groups[1].ToString(), m.Groups[3].ToString()); } } @@ -303,8 +305,8 @@ m.Groups[ 1 ].ToString(), m.Groups[ 2 ].ToString() == "local", if (m.Success) { return new AdminShell.Key( - m.Groups[ 1 ].ToString(), !m.Groups[ 3 ].ToString().Contains("not"), - m.Groups[ 5 ].ToString(), m.Groups[ 7 ].ToString()); + m.Groups[1].ToString(), !m.Groups[3].ToString().Contains("not"), + m.Groups[5].ToString(), m.Groups[7].ToString()); } } @@ -318,7 +320,7 @@ public static string KeyListToString(List keys) return ""; // normally, exactly one key if (keys.Count == 1) - return keys[ 0 ].ToString(); + return keys[0].ToString(); // multiple! var s = "[ "; foreach (var k in keys) @@ -379,7 +381,7 @@ public enum IdentifierType { IdShort = 0, FragmentId, Custom, IRDI, IRI }; public static string? GetIdentifierTypeName(IdentifierType t) { - return IdentifierTypeNames[ (int) t ]; + return IdentifierTypeNames[(int)t]; } public static string? IdShort = "IdShort"; @@ -534,7 +536,7 @@ public class KeyList : List { // getters / setters - [ XmlIgnore ] public bool IsEmpty { get { return this.Count < 1; } } + [XmlIgnore] public bool IsEmpty { get { return this.Count < 1; } } // constructors / creators @@ -581,7 +583,7 @@ public bool Matches(KeyList other, Key.MatchMode matchMode = Key.MatchMode.Stric var same = true; for (int i = 0; i < this.Count; i++) - same = same && this[ i ].Matches(other[ i ], matchMode); + same = same && this[i].Matches(other[i], matchMode); return same; } @@ -591,7 +593,7 @@ public bool Matches(KeyList other, Key.MatchMode matchMode = Key.MatchMode.Stric public void NumberIndices() { for (int i = 0; i < this.Count; i++) - this[ i ].index = i; + this[i].index = i; } public string? ToString(int format = 0, string delimiter = ",") @@ -624,10 +626,10 @@ public static KeyList Parse(string input) { if (this.Count < 1) return "-"; - var i = this.Count - 1; - var res = this[ i ].value; - if (this[ i ].IsIdType(new[] {Key.FragmentId}) && i > 0) - res += this[ i - 1 ].value; + var i = this.Count - 1; + var res = this[i].value; + if (this[i].IsIdType(new[] {Key.FragmentId}) && i > 0) + res += this[i - 1].value; return res; } @@ -644,7 +646,7 @@ public static void Validate(AasValidationRecordList results, KeyList kl, var idx = 0; while (idx < kl.Count) { - var act = Key.Validate(results, kl[ idx ], container); + var act = Key.Validate(results, kl[idx], container); if (act == AasValidationAction.ToBeDeleted) { kl.RemoveAt(idx); @@ -671,7 +673,7 @@ public bool StartsWith(KeyList head, bool emptyIsTrue = false, if (i >= this.Count) return false; - if (!head[ i ].Matches(this[ i ], matchMode)) + if (!head[i].Matches(this[i], matchMode)) return false; } @@ -706,7 +708,7 @@ public KeyList SubList(int startPos, int count = int.MaxValue) for (int i = startPos; i < this.Count && nr < count; i++) { nr++; - res.Add(this[ i ]); + res.Add(this[i]); } return res; @@ -734,16 +736,16 @@ public KeyList ReplaceLastKey(KeyList newKeys) { if (startPos >= this.Count) return ""; - int nr = 0; + int nr = 0; var res = ""; for (int i = startPos; i < this.Count && nr < count; i++) { nr++; - if (this[ i ].idType.Trim().ToLower() == Key.IdShort.Trim().ToLower()) + if (this[i].idType.Trim().ToLower() == Key.IdShort.Trim().ToLower()) { if (res != "") res += "/"; - res += this[ i ].value; + res += this[i].value; } } @@ -781,24 +783,24 @@ public interface IAasElement string? GetElementName(); } - [ XmlType(TypeName = "reference") ] + [XmlType(TypeName = "reference")] public class Reference : IAasElement { // members - [ XmlIgnore ] // anyway, as it is private - [ JsonIgnore ] + [XmlIgnore] // anyway, as it is private + [JsonIgnore] private KeyList keys = new KeyList(); // getters / setters - [ XmlArray("keys") ] - [ XmlArrayItem("key") ] - [ JsonIgnore ] + [XmlArray("keys")] + [XmlArrayItem("key")] + [JsonIgnore] public KeyList Keys { get { return keys; } } - [ XmlIgnore ] - [ JsonProperty(PropertyName = "keys") ] + [XmlIgnore] + [JsonPropertyName("keys")] public KeyList JsonKeys { get @@ -808,10 +810,10 @@ public KeyList JsonKeys } } - [ XmlIgnore ] [ JsonIgnore ] public bool IsEmpty { get { return keys == null || keys.Count < 1; } } + [XmlIgnore] [JsonIgnore] public bool IsEmpty { get { return keys == null || keys.Count < 1; } } - [ XmlIgnore ] - [ JsonIgnore ] + [XmlIgnore] + [JsonIgnore] public int Count { get @@ -821,11 +823,11 @@ public int Count } } - [ XmlIgnore ] [ JsonIgnore ] public Key this[int index] { get { return keys[ index ]; } } + [XmlIgnore] [JsonIgnore] public Key this[int index] { get { return keys[index]; } } - [ XmlIgnore ] [ JsonIgnore ] public Key First { get { return this.Count < 1 ? null : this.keys[ 0 ]; } } + [XmlIgnore] [JsonIgnore] public Key First { get { return this.Count < 1 ? null : this.keys[0]; } } - [ XmlIgnore ] [ JsonIgnore ] public Key Last { get { return this.Count < 1 ? null : this.keys[ this.keys.Count - 1 ]; } } + [XmlIgnore] [JsonIgnore] public Key Last { get { return this.Count < 1 ? null : this.keys[this.keys.Count - 1]; } } // constructors / creators @@ -928,7 +930,7 @@ public Key GetAsExactlyOneKey() { if (keys == null || keys.Count != 1) return null; - var k = keys[ 0 ]; + var k = keys[0]; return new Key(k.type, k.local, k.idType, k.value); } @@ -937,7 +939,7 @@ public bool MatchesExactlyOneKey( { if (keys == null || keys.Count != 1) return false; - var k = keys[ 0 ]; + var k = keys[0]; return k.Matches(type, local, idType, id, matchMode); } @@ -953,7 +955,7 @@ public bool Matches( { if (this.Count == 1) { - var k = keys[ 0 ]; + var k = keys[0]; return k.Matches(type, local, idType, id, matchMode); } @@ -964,7 +966,7 @@ public bool Matches(Key key, Key.MatchMode matchMode = Key.MatchMode.Strict) { if (this.Count == 1) { - var k = keys[ 0 ]; + var k = keys[0]; return k.Matches(key, matchMode); } @@ -977,7 +979,7 @@ public bool Matches(Identification other) return false; if (this.Count == 1) { - var k = keys[ 0 ]; + var k = keys[0]; return k.Matches(Key.GlobalReference, false, other.idType, other.id, Key.MatchMode.Identification); } @@ -991,7 +993,7 @@ public bool Matches(Reference other, Key.MatchMode matchMode = Key.MatchMode.Str var same = true; for (int i = 0; i < this.Count; i++) - same = same && this.keys[ i ].Matches(other.keys[ i ], matchMode); + same = same && this.keys[i].Matches(other.keys[i], matchMode); return same; } @@ -1044,7 +1046,7 @@ public virtual AasElementSelfDescription GetSelfDescription() } } - [ XmlType(TypeName = "derivedFrom") ] + [XmlType(TypeName = "derivedFrom")] public class AssetAdministrationShellRef : Reference { // constructors @@ -1067,7 +1069,7 @@ public override AasElementSelfDescription GetSelfDescription() } } - [ XmlType(TypeName = "assetRef") ] + [XmlType(TypeName = "assetRef")] public class AssetRef : Reference { // constructors @@ -1093,7 +1095,7 @@ public override AasElementSelfDescription GetSelfDescription() } } - [ XmlType(TypeName = "submodelRef") ] + [XmlType(TypeName = "submodelRef")] public class SubmodelRef : Reference { // constructors @@ -1132,7 +1134,7 @@ public override AasElementSelfDescription GetSelfDescription() } } - [ XmlType(TypeName = "conceptDescriptionRef") ] + [XmlType(TypeName = "conceptDescriptionRef")] public class ConceptDescriptionRef : Reference { // constructors @@ -1163,7 +1165,7 @@ public override AasElementSelfDescription GetSelfDescription() } } - [ XmlType(TypeName = "dataSpecificationRef") ] + [XmlType(TypeName = "dataSpecificationRef")] public class DataSpecificationRef : Reference { // constructors @@ -1198,10 +1200,10 @@ public override AasElementSelfDescription GetSelfDescription() } } - [ XmlType(TypeName = "conceptDescriptions") ] + [XmlType(TypeName = "conceptDescriptions")] public class ConceptDescriptionRefs { - [ XmlElement(ElementName = "conceptDescriptionRef") ] + [XmlElement(ElementName = "conceptDescriptionRef")] public List conceptDescriptions = new List(); // constructors @@ -1225,7 +1227,7 @@ public ConceptDescriptionRefs(AasxCompatibilityModels.AdminShellV10.ConceptDescr #endif } - [ XmlType(TypeName = "containedElementRef") ] + [XmlType(TypeName = "containedElementRef")] public class ContainedElementRef : Reference { // constructors @@ -1283,7 +1285,7 @@ public HasDataSpecification(AasxCompatibilityModels.AdminShellV10.HasDataSpecifi // Iv 2.0.1, theoretically each entity with HasDataSpecification could also conatin a // EmbeddedDataSpecification. - [ XmlType(TypeName = "hasDataSpecification") ] + [XmlType(TypeName = "hasDataSpecification")] public class HasDataSpecification : List { public HasDataSpecification() { } @@ -1310,8 +1312,8 @@ public HasDataSpecification(AasxCompatibilityModels.AdminShellV10.HasDataSpecifi // make some explicit and easy to use getter, setters - [ XmlIgnore ] - [ JsonIgnore ] + [XmlIgnore] + [JsonIgnore] public EmbeddedDataSpecification IEC61360 { get @@ -1342,8 +1344,8 @@ public EmbeddedDataSpecification IEC61360 } } - [ XmlIgnore ] - [ JsonIgnore ] + [XmlIgnore] + [JsonIgnore] public DataSpecificationIEC61360 IEC61360Content { get @@ -1370,12 +1372,12 @@ public DataSpecificationIEC61360 IEC61360Content } #endif - [ XmlType(TypeName = "ContainedElements") ] + [XmlType(TypeName = "ContainedElements")] public class ContainedElements { // members - [ XmlElement(ElementName = "containedElementRef") ] // make "reference" go away by magic?! + [XmlElement(ElementName = "containedElementRef")] // make "reference" go away by magic?! public List reference = new List(); // getter / setter @@ -1391,7 +1393,7 @@ public int Count } } - public ContainedElementRef this[int index] { get { return reference[ index ]; } } + public ContainedElementRef this[int index] { get { return reference[index]; } } // Creators @@ -1429,7 +1431,7 @@ public static ContainedElements CreateOrSetInner(ContainedElements outer, Contai } } - [ XmlType(TypeName = "langString", Namespace = "http://www.admin-shell.io/2/0") ] + [XmlType(TypeName = "langString", Namespace = "http://www.admin-shell.io/2/0")] public class LangStr { // constants @@ -1437,14 +1439,10 @@ public class LangStr // members - [ MetaModelName("LangStr.lang") ] - [ TextSearchable ] - [ XmlAttribute(Namespace = "http://www.admin-shell.io/2/0") ] - [ JsonProperty(PropertyName = "language") ] - [ CountForHash ] + [MetaModelName("LangStr.lang")] [TextSearchable] [XmlAttribute(Namespace = "http://www.admin-shell.io/2/0")] [JsonPropertyName("language")] [CountForHash] public string? lang = ""; - [ MetaModelName("LangStr.str") ] [ TextSearchable ] [ XmlText ] [ JsonProperty(PropertyName = "text") ] [ CountForHash ] + [MetaModelName("LangStr.str")] [TextSearchable] [XmlText] [JsonPropertyName("text")] [CountForHash] public string? str = ""; // constructors @@ -1477,7 +1475,7 @@ public static ListOfLangStr CreateManyFromStringArray(string?[] s) var i = 0; while ((i + 1) < s.Length) { - r.Add(new LangStr(s[ i ], s[ i + 1 ])); + r.Add(new LangStr(s[i], s[i + 1])); i += 2; } @@ -1539,7 +1537,7 @@ public string? this[string? lang] if (ls.lang.Trim().ToLower() == defaultLang) res = ls.str; if (res == null && this.Count > 0) - res = this[ 0 ].str; + res = this[0].str; // found? return res; @@ -1572,7 +1570,7 @@ public bool AllLangSameString() return true; for (int i = 1; i < this.Count; i++) - if (this[ 0 ]?.str != null && this[ 0 ]?.str?.Trim() != this[ i ]?.str?.Trim()) + if (this[0]?.str != null && this[0]?.str?.Trim() != this[i]?.str?.Trim()) return false; return true; @@ -1611,7 +1609,7 @@ public static ListOfLangStr Parse(string? cell) } // use the match and shorten cell .. - res.Add(new LangStr(m.Groups[ 2 ].ToString(), m.Groups[ 1 ].ToString().Trim())); + res.Add(new LangStr(m.Groups[2].ToString(), m.Groups[1].ToString().Trim())); cell = cell.Substring(m.Index + m.Length); } @@ -1623,7 +1621,7 @@ public class Description { // members - [ XmlElement(ElementName = "langString") ] + [XmlElement(ElementName = "langString")] public ListOfLangStr langString = new ListOfLangStr(); // constructors @@ -1666,14 +1664,14 @@ public class AssetKind public static string Type = "Type"; public static string Instance = "Instance"; - [ MetaModelName("AssetKind.kind") ] [ TextSearchable ] [ XmlText ] [ CountForHash ] + [MetaModelName("AssetKind.kind")] [TextSearchable] [XmlText] [CountForHash] public string kind = "Instance"; // getters / setters - [ XmlIgnore ] [ JsonIgnore ] public bool IsInstance { get { return kind == null || kind.Trim().ToLower() == "instance"; } } + [XmlIgnore] [JsonIgnore] public bool IsInstance { get { return kind == null || kind.Trim().ToLower() == "instance"; } } - [ XmlIgnore ] [ JsonIgnore ] public bool IsType { get { return kind != null && kind.Trim().ToLower() == "type"; } } + [XmlIgnore] [JsonIgnore] public bool IsType { get { return kind != null && kind.Trim().ToLower() == "type"; } } // constructors / creators @@ -1715,14 +1713,14 @@ public class ModelingKind public static string Template = "Template"; public static string Instance = "Instance"; - [ MetaModelName("ModelingKind.kind") ] [ TextSearchable ] [ XmlText ] [ CountForHash ] + [MetaModelName("ModelingKind.kind")] [TextSearchable] [XmlText] [CountForHash] public string kind = Instance; // getters / setters - [ XmlIgnore ] [ JsonIgnore ] public bool IsInstance { get { return kind == null || kind.Trim().ToLower() == Instance.ToLower(); } } + [XmlIgnore] [JsonIgnore] public bool IsInstance { get { return kind == null || kind.Trim().ToLower() == Instance.ToLower(); } } - [ XmlIgnore ] [ JsonIgnore ] public bool IsTemplate { get { return kind != null && kind.Trim().ToLower() == Template.ToLower(); } } + [XmlIgnore] [JsonIgnore] public bool IsTemplate { get { return kind != null && kind.Trim().ToLower() == Template.ToLower(); } } // constructors / creators @@ -1853,7 +1851,7 @@ public static SemanticId CreateFromKeys(List keys) public new static SemanticId Parse(string input) { - return (SemanticId) CreateNew(KeyList.Parse(input)); + return (SemanticId)CreateNew(KeyList.Parse(input)); } } @@ -1879,7 +1877,7 @@ public interface IValidateEntity /// /// This attribute indicates, that it should e.g. serialized in JSON. /// - [ System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = true) ] + [System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = true)] public class CountForHash : System.Attribute { } @@ -1887,7 +1885,7 @@ public class CountForHash : System.Attribute /// /// This attribute indicates, that evaluation shall not count following field or not dive into references. /// - [ System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = true) ] + [System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = true)] public class SkipForHash : System.Attribute { } @@ -1895,7 +1893,7 @@ public class SkipForHash : System.Attribute /// /// This attribute indicates, that the field / property is searchable /// - [ System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = true) ] + [System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = true)] public class MetaModelName : System.Attribute { public string name; @@ -1910,7 +1908,7 @@ public MetaModelName(string name) /// This attribute indicates, that the field / property shall be skipped for reflection /// in order to avoid cycles /// - [ System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = true) ] + [System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = true)] public class SkipForReflection : System.Attribute { } @@ -1919,7 +1917,7 @@ public class SkipForReflection : System.Attribute /// This attribute indicates, that the field / property shall be skipped for searching, because it is not /// directly displayed in Package Explorer /// - [ System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = true) ] + [System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = true)] public class SkipForSearch : System.Attribute { } @@ -1927,7 +1925,7 @@ public class SkipForSearch : System.Attribute /// /// This attribute indicates, that the field / property is searchable /// - [ System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = true) ] + [System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = true)] public class TextSearchable : System.Attribute { } @@ -1963,9 +1961,9 @@ public class DiaryDataDef { public enum TimeStampKind { Create, Update } - [ XmlIgnore ] [ JsonIgnore ] private DateTime[] _timeStamp = new DateTime[2]; + [XmlIgnore] [JsonIgnore] private DateTime[] _timeStamp = new DateTime[2]; - [ XmlIgnore ] [ JsonIgnore ] public DateTime[] TimeStamp { get { return _timeStamp; } } + [XmlIgnore] [JsonIgnore] public DateTime[] TimeStamp { get { return _timeStamp; } } /// /// List of entries, timewise one after each other (entries are timestamped). @@ -1997,7 +1995,7 @@ public static void AddAndSetTimestamps(Referable element, IAasDiaryEntry de, boo while (el?.DiaryData != null) { // itself - el.DiaryData.TimeStamp[ (int) tsk ] = DateTime.UtcNow; + el.DiaryData.TimeStamp[(int)tsk] = DateTime.UtcNow; // go up el = (el as Referable)?.parent as IDiaryData; @@ -2039,27 +2037,27 @@ public class Referable : IValidateEntity, IAasElement, IDiaryData, IGetReference { // diary - [ XmlIgnore ] [ JsonIgnore ] [ SkipForHash ] [ SkipForReflection ] + [XmlIgnore] [JsonIgnore] [SkipForHash] [SkipForReflection] private DiaryDataDef _diaryData = new DiaryDataDef(); - [ XmlIgnore ] - [ JsonIgnore ] - [ SkipForReflection ] + [XmlIgnore] + [JsonIgnore] + [SkipForReflection] public DiaryDataDef DiaryData { get { return _diaryData; } } // members - [ MetaModelName("Referable.IdShort") ] [ TextSearchable ] [ CountForHash ] - public string? idShort = ""; + [MetaModelName("Referable.IdShort")] [TextSearchable] [CountForHash] + public string? idShort = string.Empty; - [ MetaModelName("Referable.category") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("Referable.category")] [TextSearchable] [CountForHash] public string category = null; - [ XmlElement(ElementName = "description") ] [ JsonIgnore ] [ CountForHash ] + [XmlElement(ElementName = "description")] [JsonIgnore] [CountForHash] public Description description = null; - [ XmlIgnore ] - [ JsonProperty(PropertyName = "descriptions") ] + [XmlIgnore] + [JsonPropertyName("descriptions")] public ListOfLangStr JsonDescription { get @@ -2080,10 +2078,10 @@ public ListOfLangStr JsonDescription } } - [ XmlIgnore ] - [ JsonIgnore ] - [ SkipForHash ] // important to skip, as recursion elsewise will go in cycles! - [ SkipForReflection ] + [XmlIgnore] + [JsonIgnore] + [SkipForHash] // important to skip, as recursion elsewise will go in cycles! + [SkipForReflection] // important to skip, as recursion elsewise will go in cycles! public IAasElement parent = null; @@ -2313,27 +2311,27 @@ public byte[] ComputeByteArray() // optimize for probabilities if (o is string) - bs = System.Text.Encoding.UTF8.GetBytes((string) o); + bs = System.Text.Encoding.UTF8.GetBytes((string)o); else if (o is char[]) - bs = System.Text.Encoding.UTF8.GetBytes((char[]) o); + bs = System.Text.Encoding.UTF8.GetBytes((char[])o); else if (o is double) - bs = BitConverter.GetBytes((double) o); + bs = BitConverter.GetBytes((double)o); else if (o is float) - bs = BitConverter.GetBytes((float) o); + bs = BitConverter.GetBytes((float)o); else if (o is char) - bs = BitConverter.GetBytes((char) o); + bs = BitConverter.GetBytes((char)o); else if (o is int) - bs = BitConverter.GetBytes((int) o); + bs = BitConverter.GetBytes((int)o); else if (o is long) - bs = BitConverter.GetBytes((long) o); + bs = BitConverter.GetBytes((long)o); else if (o is short) - bs = BitConverter.GetBytes((short) o); + bs = BitConverter.GetBytes((short)o); else if (o is uint) - bs = BitConverter.GetBytes((uint) o); + bs = BitConverter.GetBytes((uint)o); else if (o is ulong) - bs = BitConverter.GetBytes((ulong) o); + bs = BitConverter.GetBytes((ulong)o); else if (o is ushort) - bs = BitConverter.GetBytes((ushort) o); + bs = BitConverter.GetBytes((ushort)o); if (bs != null) mems.Write(bs, 0, bs.Length); @@ -2389,8 +2387,8 @@ public int Compare(Referable a, Referable b) if (!cb) return -1; - var ia = Index[ a ]; - var ib = Index[ b ]; + var ia = Index[a]; + var ib = Index[b]; if (ia == ib) return 0; @@ -2576,34 +2574,33 @@ public interface IGetSemanticId public class AdministrationShell : Identifiable, IFindAllReferences { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } } // from hasDataSpecification: - [ XmlElement(ElementName = "hasDataSpecification") ] + [XmlElement(ElementName = "hasDataSpecification")] public HasDataSpecification hasDataSpecification = null; // from this very class public AssetAdministrationShellRef derivedFrom = null; - [ JsonProperty(PropertyName = "asset") ] - public AssetRef assetRef = new AssetRef(); + [JsonPropertyName("asset")] public AssetRef assetRef = new AssetRef(); - [ JsonProperty(PropertyName = "submodels") ] [ SkipForSearch ] + [JsonPropertyName("submodels")] [SkipForSearch] public List submodelRefs = new List(); - [ JsonIgnore ] public Views views = null; + [JsonIgnore] public Views views = null; - [ XmlIgnore ] - [ JsonProperty(PropertyName = "views") ] + [XmlIgnore] + [JsonPropertyName("views")] public View[] JsonViews { get { return views?.views.ToArray(); } set { views = Views.CreateOrSetInnerViews(views, value); } } - [ JsonProperty(PropertyName = "conceptDictionaries") ] + [JsonPropertyName("conceptDictionaries")] public List conceptDictionaries = null; // constructors @@ -2799,27 +2796,27 @@ public AasElementSelfDescription GetSelfDescription() public class Asset : Identifiable { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } } // from hasDataSpecification: - [ XmlElement(ElementName = "hasDataSpecification") ] + [XmlElement(ElementName = "hasDataSpecification")] public HasDataSpecification hasDataSpecification = null; // from this very class - [ XmlElement(ElementName = "assetIdentificationModelRef") ] + [XmlElement(ElementName = "assetIdentificationModelRef")] public SubmodelRef assetIdentificationModelRef = null; - [ XmlElement(ElementName = "billOfMaterialRef") ] + [XmlElement(ElementName = "billOfMaterialRef")] public SubmodelRef billOfMaterialRef = null; // from HasKind - [ XmlElement(ElementName = "kind") ] [ JsonIgnore ] + [XmlElement(ElementName = "kind")] [JsonIgnore] public AssetKind kind = new AssetKind(); - [ XmlIgnore ] - [ JsonProperty(PropertyName = "kind") ] + [XmlIgnore] + [JsonPropertyName("kind")] public string JsonKind { get @@ -2933,26 +2930,26 @@ public AasElementSelfDescription GetSelfDescription() public class View : Referable { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } } // members // from hasSemanticId: - [ XmlElement(ElementName = "semanticId") ] + [XmlElement(ElementName = "semanticId")] public SemanticId semanticId = null; // from hasDataSpecification - [ XmlElement(ElementName = "hasDataSpecification") ] + [XmlElement(ElementName = "hasDataSpecification")] public HasDataSpecification hasDataSpecification = null; // from this very class - [ JsonIgnore ] [ SkipForSearch ] public ContainedElements containedElements = null; + [JsonIgnore] [SkipForSearch] public ContainedElements containedElements = null; - [ XmlIgnore ] - [ SkipForSearch ] - [ JsonProperty(PropertyName = "containedElements") ] + [XmlIgnore] + [SkipForSearch] + [JsonPropertyName("containedElements")] public ContainedElementRef[] JsonContainedElements { get { return containedElements?.reference.ToArray(); } @@ -2961,10 +2958,10 @@ public ContainedElementRef[] JsonContainedElements // getter / setter - [ XmlIgnore ] [ JsonIgnore ] public bool IsEmpty { get { return containedElements == null || containedElements.Count < 1; } } + [XmlIgnore] [JsonIgnore] public bool IsEmpty { get { return containedElements == null || containedElements.Count < 1; } } - [ XmlIgnore ] - [ JsonIgnore ] + [XmlIgnore] + [JsonIgnore] public int Count { get @@ -2979,7 +2976,7 @@ public ContainedElementRef this[int index] get { if (containedElements == null) return null; - return containedElements[ index ]; + return containedElements[index]; } } @@ -3099,7 +3096,7 @@ public override void Validate(AasValidationRecordList results) public class Views { - [ XmlElement(ElementName = "view") ] [ JsonIgnore ] + [XmlElement(ElementName = "view")] [JsonIgnore] public List views = new List(); // constructors @@ -3145,15 +3142,15 @@ public class LangStringSet { // members - [ XmlElement(ElementName = "langString", Namespace = "http://www.admin-shell.io/aas/2/0") ] + [XmlElement(ElementName = "langString", Namespace = "http://www.admin-shell.io/aas/2/0")] public ListOfLangStr langString = new ListOfLangStr(); // getters / setters - [ XmlIgnore ] [ JsonIgnore ] public bool IsEmpty { get { return langString == null || langString.Count < 1; } } + [XmlIgnore] [JsonIgnore] public bool IsEmpty { get { return langString == null || langString.Count < 1; } } - [ XmlIgnore ] - [ JsonIgnore ] + [XmlIgnore] + [JsonIgnore] public int Count { get @@ -3163,7 +3160,7 @@ public int Count } } - [ XmlIgnore ] [ JsonIgnore ] public LangStr this[int index] { get { return langString[ index ]; } } + [XmlIgnore] [JsonIgnore] public LangStr this[int index] { get { return langString[index]; } } // constructors @@ -3233,7 +3230,7 @@ public class LangStringSetIEC61360 : ListOfLangStr { // getters / setters - [ XmlIgnore ] [ JsonIgnore ] public bool IsEmpty { get { return this.Count < 1; } } + [XmlIgnore] [JsonIgnore] public bool IsEmpty { get { return this.Count < 1; } } // constructors @@ -3278,17 +3275,17 @@ public class UnitId { // members - [ XmlIgnore ] [ JsonIgnore ] public KeyList keys = new KeyList(); + [XmlIgnore] [JsonIgnore] public KeyList keys = new KeyList(); // getter / setters - [ XmlArray("keys") ] - [ XmlArrayItem("key") ] - [ JsonIgnore ] + [XmlArray("keys")] + [XmlArrayItem("key")] + [JsonIgnore] public KeyList Keys { get { return keys; } } - [ XmlIgnore ] - [ JsonProperty(PropertyName = "keys") ] + [XmlIgnore] + [JsonPropertyName("keys")] public KeyList JsonKeys { get @@ -3298,10 +3295,10 @@ public KeyList JsonKeys } } - [ XmlIgnore ] [ JsonIgnore ] public bool IsEmpty { get { return keys == null || keys.IsEmpty; } } + [XmlIgnore] [JsonIgnore] public bool IsEmpty { get { return keys == null || keys.IsEmpty; } } - [ XmlIgnore ] - [ JsonIgnore ] + [XmlIgnore] + [JsonIgnore] public int Count { get @@ -3311,7 +3308,7 @@ public int Count } } - [ XmlIgnore ] [ JsonIgnore ] public Key this[int index] { get { return keys[ index ]; } } + [XmlIgnore] [JsonIgnore] public Key this[int index] { get { return keys[index]; } } // constructors / creators @@ -3352,11 +3349,11 @@ public static UnitId CreateNew(Reference src) } } - [ XmlRoot(Namespace = "http://www.admin-shell.io/IEC61360/2/0") ] + [XmlRoot(Namespace = "http://www.admin-shell.io/IEC61360/2/0")] public class DataSpecificationIEC61360 { // static member - [ XmlIgnore ] [ JsonIgnore ] public static string[] DataTypeNames = + [XmlIgnore] [JsonIgnore] public static string[] DataTypeNames = { "STRING", "STRING_TRANSLATABLE", "REAL_MEASURE", "REAL_COUNT", "REAL_CURRENCY", "INTEGER_MEASURE", "INTEGER_COUNT", "INTEGER_CURRENCY", "BOOLEAN", "URL", "RATIONAL", "RATIONAL_MEASURE", "TIME", "TIMESTAMP", "DATE" @@ -3371,21 +3368,21 @@ public class DataSpecificationIEC61360 // these cardinalities are NOT MAINTAINED in ANY WAY by the system public LangStringSetIEC61360 shortName = null; - [ MetaModelName("DataSpecificationIEC61360.unit") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("DataSpecificationIEC61360.unit")] [TextSearchable] [CountForHash] public string unit = ""; public UnitId unitId = null; - [ MetaModelName("DataSpecificationIEC61360.valueFormat") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("DataSpecificationIEC61360.valueFormat")] [TextSearchable] [CountForHash] public string valueFormat = null; - [ MetaModelName("DataSpecificationIEC61360.sourceOfDefinition") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("DataSpecificationIEC61360.sourceOfDefinition")] [TextSearchable] [CountForHash] public string? sourceOfDefinition = null; - [ MetaModelName("DataSpecificationIEC61360.symbol") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("DataSpecificationIEC61360.symbol")] [TextSearchable] [CountForHash] public string symbol = null; - [ MetaModelName("DataSpecificationIEC61360.dataType") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("DataSpecificationIEC61360.dataType")] [TextSearchable] [CountForHash] public string? dataType = ""; // TODO (MIHO, 2020-08-27): According to spec, cardinality is [0..1][1..n] @@ -3425,7 +3422,7 @@ public DataSpecificationIEC61360(AasxCompatibilityModels.AdminShellV10.DataSpeci this.unitId = new UnitId(src.unitId); this.valueFormat = src.valueFormat; if (src.sourceOfDefinition != null && src.sourceOfDefinition.Count > 0) - this.sourceOfDefinition = src.sourceOfDefinition[ 0 ].str; + this.sourceOfDefinition = src.sourceOfDefinition[0].str; this.symbol = src.symbol; this.dataType = src.dataType; if (src.definition != null) @@ -3570,10 +3567,10 @@ public class EmbeddedDataSpecification { // members - [ JsonIgnore ] public DataSpecificationContent dataSpecificationContent = null; + [JsonIgnore] public DataSpecificationContent dataSpecificationContent = null; - [ XmlIgnore ] - [ JsonProperty("dataSpecificationContent") ] + [XmlIgnore] + [JsonPropertyName("dataSpecificationContent")] public DataSpecificationIEC61360 JsonWrongDataSpec61360 { get { return dataSpecificationContent?.dataSpecificationIEC61360; } @@ -3650,8 +3647,8 @@ public DataSpecificationIEC61360 GetIEC61360() public class ConceptDescription : Identifiable, System.IDisposable { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } } // members @@ -3669,12 +3666,12 @@ public void GetData() { } // According to Spec V2.0.1, a ConceptDescription might feature alos multiple data specifications /* TODO (MIHO, 2020-08-30): align wording of the member ("embeddedDataSpecification") with the * wording of the other entities ("hasDataSpecification") */ - [ XmlElement(ElementName = "embeddedDataSpecification") ] [ JsonIgnore ] + [XmlElement(ElementName = "embeddedDataSpecification")] [JsonIgnore] public HasDataSpecification embeddedDataSpecification = null; #endif - [ XmlIgnore ] - [ JsonProperty(PropertyName = "embeddedDataSpecifications") ] + [XmlIgnore] + [JsonPropertyName("embeddedDataSpecifications")] public EmbeddedDataSpecification[] JsonEmbeddedDataSpecifications { get @@ -3690,12 +3687,12 @@ public EmbeddedDataSpecification[] JsonEmbeddedDataSpecifications // old // this class - [ XmlIgnore ] private List isCaseOf = null; + [XmlIgnore] private List isCaseOf = null; // getter / setter - [ XmlElement(ElementName = "isCaseOf") ] - [ JsonProperty(PropertyName = "isCaseOf") ] + [XmlElement(ElementName = "isCaseOf")] + [JsonPropertyName("isCaseOf")] public List IsCaseOf { get { return isCaseOf; } @@ -3807,8 +3804,8 @@ public DataSpecificationIEC61360 GetIEC61360() // as experimental approach, forward the IEC getter/sett of hasDataSpec directly - [ XmlIgnore ] - [ JsonIgnore ] + [XmlIgnore] + [JsonIgnore] public EmbeddedDataSpecification IEC61360DataSpec { get @@ -3824,8 +3821,8 @@ public EmbeddedDataSpecification IEC61360DataSpec } } - [ XmlIgnore ] - [ JsonIgnore ] + [XmlIgnore] + [JsonIgnore] public DataSpecificationIEC61360 IEC61360Content { get @@ -4000,7 +3997,7 @@ public ConceptDescription Find(List keys) if (keys.Count != 1) return null; // and we're picky - var key = keys[ 0 ]; + var key = keys[0]; if (!key.local || key.type.ToLower().Trim() != "conceptdescription") return null; // brute force @@ -4044,7 +4041,7 @@ public AasElementSelfDescription GetSelfDescription() public class ConceptDictionary : Referable { - [ XmlElement(ElementName = "conceptDescriptions") ] + [XmlElement(ElementName = "conceptDescriptions")] public ConceptDescriptionRefs conceptDescriptionsRefs = null; // constructors @@ -4077,7 +4074,7 @@ public static ConceptDictionary CreateNew(string? idShort = null) public void AddReference(Reference r) { - var cdr = (ConceptDescriptionRef) (ConceptDescriptionRef.CreateNew(r.Keys)); + var cdr = (ConceptDescriptionRef)(ConceptDescriptionRef.CreateNew(r.Keys)); if (conceptDescriptionsRefs == null) conceptDescriptionsRefs = new ConceptDescriptionRefs(); conceptDescriptionsRefs.conceptDescriptions.Add(cdr); @@ -4107,69 +4104,69 @@ public LocatedReference(Identifiable identifiable, Reference reference) } } - [ XmlRoot(ElementName = "aasenv", Namespace = "http://www.admin-shell.io/aas/2/0") ] + [XmlRoot(ElementName = "aasenv", Namespace = "http://www.admin-shell.io/aas/2/0")] public class AdministrationShellEnv : IFindAllReferences, IAasElement, IDiaryData, IRecurseOnReferables { // diary (as e.g. deleted AASes need to be listed somewhere) - [ XmlIgnore ] [ JsonIgnore ] [ SkipForHash ] [ SkipForReflection ] + [XmlIgnore] [JsonIgnore] [SkipForHash] [SkipForReflection] private DiaryDataDef _diaryData = new DiaryDataDef(); - [ XmlIgnore ] - [ JsonIgnore ] - [ SkipForReflection ] + [XmlIgnore] + [JsonIgnore] + [SkipForReflection] public DiaryDataDef DiaryData { get { return _diaryData; } } // members - [ XmlAttribute(Namespace = System.Xml.Schema.XmlSchema.InstanceNamespace) ] [ JsonIgnore ] + [XmlAttribute(Namespace = System.Xml.Schema.XmlSchema.InstanceNamespace)] [JsonIgnore] public string schemaLocation = "http://www.admin-shell.io/aas/2/0 AAS.xsd http://www.admin-shell.io/IEC61360/2/0 IEC61360.xsd"; - [ XmlIgnore ] // will be ignored, anyway + [XmlIgnore] // will be ignored, anyway private ListOfAdministrationShells administrationShells = new ListOfAdministrationShells(); - [ XmlIgnore ] // will be ignored, anyway + [XmlIgnore] // will be ignored, anyway private ListOfAssets assets = new ListOfAssets(); - [ XmlIgnore ] // will be ignored, anyway + [XmlIgnore] // will be ignored, anyway private ListOfSubmodels submodels = new ListOfSubmodels(); - [ XmlIgnore ] // will be ignored, anyway + [XmlIgnore] // will be ignored, anyway private ListOfConceptDescriptions conceptDescriptions = new ListOfConceptDescriptions(); // getter / setters - [ XmlArray("assetAdministrationShells") ] - [ XmlArrayItem("assetAdministrationShell") ] - [ JsonProperty(PropertyName = "assetAdministrationShells") ] + [XmlArray("assetAdministrationShells")] + [XmlArrayItem("assetAdministrationShell")] + [JsonPropertyName("assetAdministrationShells")] public ListOfAdministrationShells AdministrationShells { get { return administrationShells; } set { administrationShells = value; } } - [ XmlArray("assets") ] - [ XmlArrayItem("asset") ] - [ JsonProperty(PropertyName = "assets") ] + [XmlArray("assets")] + [XmlArrayItem("asset")] + [JsonPropertyName("assets")] public ListOfAssets Assets { get { return assets; } set { assets = value; } } - [ XmlArray("submodels") ] - [ XmlArrayItem("submodel") ] - [ JsonProperty(PropertyName = "submodels") ] + [XmlArray("submodels")] + [XmlArrayItem("submodel")] + [JsonPropertyName("submodels")] public ListOfSubmodels Submodels { get { return submodels; } set { submodels = value; } } - [ XmlArray("conceptDescriptions") ] - [ XmlArrayItem("conceptDescription") ] - [ JsonProperty(PropertyName = "conceptDescriptions") ] + [XmlArray("conceptDescriptions")] + [XmlArrayItem("conceptDescription")] + [JsonPropertyName("conceptDescriptions")] public ListOfConceptDescriptions ConceptDescriptions { get { return conceptDescriptions; } @@ -4310,7 +4307,7 @@ public Asset FindAsset(AssetRef aref) if (aref.Count != 1) return null; // and we're picky - var key = aref[ 0 ]; + var key = aref[0]; if (!key.local || key.type.ToLower().Trim() != "asset") return null; // brute force @@ -4341,7 +4338,7 @@ public Submodel FindSubmodel(SubmodelRef smref) if (smref.Count != 1) return null; // and we're picky - var key = smref.Keys[ 0 ]; + var key = smref.Keys[0]; if (!key.local || key.type.ToLower().Trim() != "submodel") return null; // brute force @@ -4456,8 +4453,8 @@ public Referable FindReferableByReference(KeyList kl, int keyIndex = 0, bool exa return null; // which type? - var firstType = kl[ keyIndex ].type.Trim().ToLower(); - var firstIdentification = new Identification(kl[ keyIndex ].idType, kl[ keyIndex ].value); + var firstType = kl[keyIndex].type.Trim().ToLower(); + var firstIdentification = new Identification(kl[keyIndex].idType, kl[keyIndex].value); AdministrationShell aasToFollow = null; if (firstType == Key.AAS.Trim().ToLower()) @@ -4512,11 +4509,11 @@ public Referable FindReferableByReference(KeyList kl, int keyIndex = 0, bool exa if (aasToFollow != null) { // search different entities - if (kl[ keyIndex + 1 ].type.Trim().ToLower() == Key.Submodel.ToLower() - || kl[ keyIndex + 1 ].type.Trim().ToLower() == Key.SubmodelRef.ToLower()) + if (kl[keyIndex + 1].type.Trim().ToLower() == Key.Submodel.ToLower() + || kl[keyIndex + 1].type.Trim().ToLower() == Key.SubmodelRef.ToLower()) { // ok, search SubmodelRef - var smref = aasToFollow.FindSubmodelRef(kl[ keyIndex + 1 ].ToId()); + var smref = aasToFollow.FindSubmodelRef(kl[keyIndex + 1].ToId()); if (smref == null) return exactMatch ? null : aasToFollow; @@ -4548,7 +4545,7 @@ public Referable FindReferableByReference(KeyList kl, int keyIndex = 0, bool exa if (firstType == Key.Submodel.Trim().ToLower()) { // ok, search Submodel - var sm = this.FindSubmodel(new Identification(kl[ keyIndex ].idType, kl[ keyIndex ].value)); + var sm = this.FindSubmodel(new Identification(kl[keyIndex].idType, kl[keyIndex].value)); if (sm == null) return null; @@ -4625,7 +4622,7 @@ public ConceptDescription FindConceptDescription(List keys) if (keys.Count != 1) return null; // and we're picky - var key = keys[ 0 ]; + var key = keys[0]; if (!key.local || key.type.ToLower().Trim() != "conceptdescription") return null; // brute force @@ -4822,8 +4819,8 @@ public List RenameIdentifiable(Identification oldId, Identificatio return (s != null && s.semanticId != null && s.semanticId.Matches(oldId)); })) { - sme.semanticId[ 0 ].idType = newId.idType; - sme.semanticId[ 0 ].value = newId.id; + sme.semanticId[0].idType = newId.idType; + sme.semanticId[0].value = newId.id; res.Add(sme); } @@ -4844,11 +4841,11 @@ public List RenameIdentifiable(Identification oldId, Identificatio var r = lr?.Reference; if (r != null) for (int i = 0; i < r.Count; i++) - if (r[ i ].Matches(Key.Submodel, false, oldId.idType, oldId.id, Key.MatchMode.Relaxed)) + if (r[i].Matches(Key.Submodel, false, oldId.idType, oldId.id, Key.MatchMode.Relaxed)) { // directly replace - r[ i ].idType = newId.idType; - r[ i ].value = newId.id; + r[i].idType = newId.idType; + r[i].value = newId.id; if (res.Contains(lr.Identifiable)) res.Add(lr.Identifiable); } @@ -4874,11 +4871,11 @@ public List RenameIdentifiable(Identification oldId, Identificatio var r = lr?.Reference; if (r != null) for (int i = 0; i < r.Count; i++) - if (r[ i ].Matches(Key.Asset, false, oldId.idType, oldId.id, Key.MatchMode.Relaxed)) + if (r[i].Matches(Key.Asset, false, oldId.idType, oldId.id, Key.MatchMode.Relaxed)) { // directly replace - r[ i ].idType = newId.idType; - r[ i ].value = newId.id; + r[i].idType = newId.idType; + r[i].value = newId.id; if (res.Contains(lr.Identifiable)) res.Add(lr.Identifiable); } @@ -4907,23 +4904,23 @@ public void SerializeXmlToStream(StreamWriter s) serializer.Serialize(s, this, nss); } - public JsonWriter SerialiazeJsonToStream(StreamWriter sw, bool leaveJsonWriterOpen = false) - { - sw.AutoFlush = true; + private static readonly JsonSerializerOptions _serializerOptions = new() {DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, WriteIndented = true}; - JsonSerializer serializer = new JsonSerializer() - { - NullValueHandling = NullValueHandling.Ignore, - ReferenceLoopHandling = ReferenceLoopHandling.Serialize, - Formatting = Newtonsoft.Json.Formatting.Indented - }; + public void SerializeJsonToStream(Stream stream, bool leaveStreamOpen = false) + { + using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions {Indented = true})) + { + System.Text.Json.JsonSerializer.Serialize(writer, this, _serializerOptions); + } - JsonWriter writer = new JsonTextWriter(sw); - serializer.Serialize(writer, this); - if (leaveJsonWriterOpen) - return writer; - writer.Close(); - return null; + if (leaveStreamOpen) + { + stream.Flush(); + } + else + { + stream.Close(); + } } public AdministrationShellEnv DeserializeFromXmlStream(TextReader reader) @@ -4934,14 +4931,17 @@ public AdministrationShellEnv DeserializeFromXmlStream(TextReader reader) return res; } + private JsonSerializerOptions options = new(); + public AdministrationShellEnv DeserializeFromJsonStream(TextReader reader) { - JsonSerializer serializer = new JsonSerializer(); - serializer.Converters.Add(new AdminShellConverters.JsonAasxConverter("modelType", "name")); - var res = (AdministrationShellEnv) serializer.Deserialize(reader, typeof(AdministrationShellEnv)); - return res; + options.Converters.Add(new AdminShellConverters.JsonAasxConverter()); + + using var jsonDocument = JsonDocument.Parse(reader.ReadToEnd()); + return JsonSerializer.Deserialize(jsonDocument.RootElement.GetRawText(), options); } + // special functions private static void CreateFromExistingEnvRecurseForCDs( @@ -4972,7 +4972,7 @@ private static void CreateFromExistingEnvRecurseForCDs( if (w.submodelElement is Operation op) for (int i = 0; i < 2; i++) { - var w2s = Operation.GetWrappers(op[ i ]); + var w2s = Operation.GetWrappers(op[i]); CreateFromExistingEnvRecurseForCDs(src, w2s, ref filterForCD); } @@ -5085,7 +5085,7 @@ public Referable.ComparerIndexed CreateIndexedComparerCdsForSmUsage() continue; if (cmp.Index.ContainsKey(cd)) continue; - cmp.Index[ cd ] = nr++; + cmp.Index[cd] = nr++; } return cmp; @@ -5170,27 +5170,27 @@ public interface IGetQualifiers public class Qualifier : IAasElement { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } } // member // from hasSemantics: - [ XmlElement(ElementName = "semanticId") ] + [XmlElement(ElementName = "semanticId")] public SemanticId semanticId = null; // this class // TODO (Michael Hoffmeister, 2020-08-01): check, if Json has Qualifiers or not - [ MetaModelName("Qualifier.type") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("Qualifier.type")] [TextSearchable] [CountForHash] public string? type = ""; - [ MetaModelName("Qualifier.valueType") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("Qualifier.valueType")] [TextSearchable] [CountForHash] public string valueType = ""; - [ CountForHash ] public Reference valueId = null; + [CountForHash] public Reference valueId = null; - [ MetaModelName("Qualifier.value") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("Qualifier.value")] [TextSearchable] [CountForHash] public string value = null; // dead-csharp off @@ -5274,10 +5274,10 @@ public static Qualifier Parse(string input) return new Qualifier() { - type = m.Groups[ 1 ].ToString().Trim(), - semanticId = SemanticId.Parse(m.Groups[ 1 ].ToString().Trim()), - value = m.Groups[ 3 ].ToString().Trim(), - valueId = Reference.Parse(m.Groups[ 1 ].ToString().Trim()) + type = m.Groups[1].ToString().Trim(), + semanticId = SemanticId.Parse(m.Groups[1].ToString().Trim()), + value = m.Groups[3].ToString().Trim(), + valueId = Reference.Parse(m.Groups[1].ToString().Trim()) }; } } @@ -5430,8 +5430,8 @@ public class SubmodelElement : Referable, System.IDisposable, IGetReference, IGe public static Type[] PROP_MLP = new Type[] {typeof(AdminShell.MultiLanguageProperty), typeof(AdminShell.Property)}; // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } } // members @@ -5441,11 +5441,11 @@ void System.IDisposable.Dispose() { } public void GetData() { } // from HasKind - [ XmlElement(ElementName = "kind") ] [ JsonIgnore ] + [XmlElement(ElementName = "kind")] [JsonIgnore] public ModelingKind kind = new ModelingKind(); - [ XmlIgnore ] - [ JsonProperty(PropertyName = "kind") ] + [XmlIgnore] + [JsonPropertyName("kind")] public string JsonKind { get @@ -5463,19 +5463,19 @@ public string JsonKind } // from hasSemanticId: - [ XmlElement(ElementName = "semanticId") ] + [XmlElement(ElementName = "semanticId")] public SemanticId semanticId = new SemanticId(); public SemanticId GetSemanticId() { return semanticId; } // from Qualifiable: - [ XmlArray("qualifier") ] [ XmlArrayItem("qualifier") ] [ JsonProperty(PropertyName = "constraints") ] + [XmlArray("qualifier")] [XmlArrayItem("qualifier")] [JsonPropertyName("constraints")] public QualifierCollection qualifiers = null; public QualifierCollection GetQualifiers() => qualifiers; // from hasDataSpecification: - [ XmlElement(ElementName = "embeddedDataSpecification") ] + [XmlElement(ElementName = "embeddedDataSpecification")] public HasDataSpecification hasDataSpecification = null; // getter / setter @@ -5702,24 +5702,24 @@ public override void Validate(AasValidationRecordList results) } } - [ XmlType(TypeName = "submodelElement") ] + [XmlType(TypeName = "submodelElement")] public class SubmodelElementWrapper { // members - [ XmlElement(ElementName = "property", Type = typeof(Property)) ] - [ XmlElement(ElementName = "multiLanguageProperty", Type = typeof(MultiLanguageProperty)) ] - [ XmlElement(ElementName = "range", Type = typeof(Range)) ] - [ XmlElement(ElementName = "file", Type = typeof(File)) ] - [ XmlElement(ElementName = "blob", Type = typeof(Blob)) ] - [ XmlElement(ElementName = "referenceElement", Type = typeof(ReferenceElement)) ] - [ XmlElement(ElementName = "relationshipElement", Type = typeof(RelationshipElement)) ] - [ XmlElement(ElementName = "annotatedRelationshipElement", Type = typeof(AnnotatedRelationshipElement)) ] - [ XmlElement(ElementName = "capability", Type = typeof(Capability)) ] - [ XmlElement(ElementName = "submodelElementCollection", Type = typeof(SubmodelElementCollection)) ] - [ XmlElement(ElementName = "operation", Type = typeof(Operation)) ] - [ XmlElement(ElementName = "basicEvent", Type = typeof(BasicEvent)) ] - [ XmlElement(ElementName = "entity", Type = typeof(Entity)) ] + [XmlElement(ElementName = "property", Type = typeof(Property))] + [XmlElement(ElementName = "multiLanguageProperty", Type = typeof(MultiLanguageProperty))] + [XmlElement(ElementName = "range", Type = typeof(Range))] + [XmlElement(ElementName = "file", Type = typeof(File))] + [XmlElement(ElementName = "blob", Type = typeof(Blob))] + [XmlElement(ElementName = "referenceElement", Type = typeof(ReferenceElement))] + [XmlElement(ElementName = "relationshipElement", Type = typeof(RelationshipElement))] + [XmlElement(ElementName = "annotatedRelationshipElement", Type = typeof(AnnotatedRelationshipElement))] + [XmlElement(ElementName = "capability", Type = typeof(Capability))] + [XmlElement(ElementName = "submodelElementCollection", Type = typeof(SubmodelElementCollection))] + [XmlElement(ElementName = "operation", Type = typeof(Operation))] + [XmlElement(ElementName = "basicEvent", Type = typeof(BasicEvent))] + [XmlElement(ElementName = "entity", Type = typeof(Entity))] public SubmodelElement submodelElement; // element names @@ -5811,7 +5811,7 @@ public SubmodelElementWrapper( public static string GetAdequateName(AdequateElementEnum ae) { - return AdequateElementNames[ (int) ae ]; + return AdequateElementNames[(int)ae]; } /// @@ -5822,7 +5822,7 @@ public static AdequateElementEnum GetAdequateEnum(string? adequateName) if (adequateName == null) return AdequateElementEnum.Unknown; - foreach (var en in (AdequateElementEnum[]) Enum.GetValues(typeof(AdequateElementEnum))) + foreach (var en in (AdequateElementEnum[])Enum.GetValues(typeof(AdequateElementEnum))) if (Enum.GetName(typeof(AdequateElementEnum), en)?.Trim().ToLower() == adequateName.Trim().ToLower()) return en; @@ -5838,13 +5838,13 @@ public static AdequateElementEnum GetAdequateEnum2(string adequateName, bool use if (adequateName == null) return AdequateElementEnum.Unknown; - foreach (var en in (AdequateElementEnum[]) Enum.GetValues(typeof(AdequateElementEnum))) - if (((int) en < AdequateElementNames.Length - && AdequateElementNames[ (int) en ].Trim().ToLower() == adequateName.Trim().ToLower()) + foreach (var en in (AdequateElementEnum[])Enum.GetValues(typeof(AdequateElementEnum))) + if (((int)en < AdequateElementNames.Length + && AdequateElementNames[(int)en].Trim().ToLower() == adequateName.Trim().ToLower()) || (useShortName - && (int) en < AdequateElementShortName.Length - && AdequateElementShortName[ (int) en ] != null - && AdequateElementShortName[ (int) en ].Trim().ToLower() == adequateName.Trim().ToLower())) + && (int)en < AdequateElementShortName.Length + && AdequateElementShortName[(int)en] != null + && AdequateElementShortName[(int)en].Trim().ToLower() == adequateName.Trim().ToLower())) return en; return AdequateElementEnum.Unknown; @@ -5860,7 +5860,7 @@ public static IEnumerable GetAdequateEnums( } else { - foreach (var en in (AdequateElementEnum[]) Enum.GetValues(typeof(AdequateElementEnum))) + foreach (var en in (AdequateElementEnum[])Enum.GetValues(typeof(AdequateElementEnum))) { if (en == AdequateElementEnum.Unknown) continue; @@ -5947,10 +5947,10 @@ public static string GetElementNameByAdequateType(SubmodelElement sme) // get the names string res = null; - if ((int) en < AdequateElementNames.Length) - res = AdequateElementNames[ (int) en ].Trim(); - if ((int) en < AdequateElementShortName.Length && AdequateElementShortName[ (int) en ] != null) - res = AdequateElementShortName[ (int) en ].Trim(); + if ((int)en < AdequateElementNames.Length) + res = AdequateElementNames[(int)en].Trim(); + if ((int)en < AdequateElementShortName.Length && AdequateElementShortName[(int)en] != null) + res = AdequateElementShortName[(int)en].Trim(); return res; } @@ -5985,14 +5985,14 @@ public static Referable FindReferableByReference( return null; // as SubmodelElements are not Identifiables, the actual key shall be IdShort - if (rf[ keyIndex ].idType.Trim().ToLower() != Key.GetIdentifierTypeName( - Key.IdentifierType.IdShort).Trim().ToLower()) + if (rf[keyIndex].idType.Trim().ToLower() != Key.GetIdentifierTypeName( + Key.IdentifierType.IdShort).Trim().ToLower()) return null; // over all wrappers foreach (var smw in wrappers) if (smw.submodelElement != null && - smw.submodelElement.idShort.Trim().ToLower() == rf[ keyIndex ].value.Trim().ToLower()) + smw.submodelElement.idShort.Trim().ToLower() == rf[keyIndex].value.Trim().ToLower()) { // match on this level. Did we find a leaf element? if ((keyIndex + 1) >= rf.Count) @@ -6131,8 +6131,8 @@ public IEnumerable FindDeep(Predicate match = null) where T : SubmodelE if (current is Operation op) for (int i = 0; i < 2; i++) - if (Operation.GetWrappers(op[ i ]) != null) - foreach (var x in Operation.GetWrappers(op[ i ]).FindDeep(match)) + if (Operation.GetWrappers(op[i]) != null) + foreach (var x in Operation.GetWrappers(op[i]).FindDeep(match)) yield return x; } } @@ -6359,7 +6359,7 @@ public void RecurseOnReferables( if (current is Operation op) for (int i = 0; i < 2; i++) - Operation.GetWrappers(op[ i ])?.RecurseOnReferables(state, parents, lambda); + Operation.GetWrappers(op[i])?.RecurseOnReferables(state, parents, lambda); if (current is AnnotatedRelationshipElement arel) arel.annotations?.RecurseOnReferables(state, parents, lambda); @@ -6708,8 +6708,8 @@ public class Submodel : Identifiable, IManageSubmodelElements, IGetSemanticId, IGetQualifiers { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } } // members @@ -6719,11 +6719,11 @@ void System.IDisposable.Dispose() { } public void GetData() { } // from HasKind - [ XmlElement(ElementName = "kind") ] [ JsonIgnore ] + [XmlElement(ElementName = "kind")] [JsonIgnore] public ModelingKind kind = new ModelingKind(); - [ XmlIgnore ] - [ JsonProperty(PropertyName = "kind") ] + [XmlIgnore] + [JsonPropertyName("kind")] public string JsonKind { get @@ -6741,25 +6741,25 @@ public string JsonKind } // from hasSemanticId: - [ XmlElement(ElementName = "semanticId") ] + [XmlElement(ElementName = "semanticId")] public SemanticId semanticId = new SemanticId(); public SemanticId GetSemanticId() { return semanticId; } // from Qualifiable: - [ XmlArray("qualifier") ] [ XmlArrayItem("qualifier") ] + [XmlArray("qualifier")] [XmlArrayItem("qualifier")] public QualifierCollection qualifiers = null; public QualifierCollection GetQualifiers() => qualifiers; // from hasDataSpecification: - [ XmlElement(ElementName = "embeddedDataSpecification") ] + [XmlElement(ElementName = "embeddedDataSpecification")] public HasDataSpecification hasDataSpecification = null; // from this very class - [ XmlIgnore ] [ JsonIgnore ] private SubmodelElementWrapperCollection _submodelElements = null; + [XmlIgnore] [JsonIgnore] private SubmodelElementWrapperCollection _submodelElements = null; - [ JsonIgnore ] + [JsonIgnore] public SubmodelElementWrapperCollection submodelElements { get { return _submodelElements; } @@ -6770,8 +6770,8 @@ public SubmodelElementWrapperCollection submodelElements } } - [ XmlIgnore ] - [ JsonProperty(PropertyName = "submodelElements") ] + [XmlIgnore] + [JsonPropertyName("submodelElements")] public SubmodelElement[] JsonSubmodelElements { get @@ -6858,8 +6858,8 @@ public static Submodel CreateNew(string? idType, string? id, string version = nu return (s); } - [ JsonIgnore ] - [ XmlIgnore ] + [JsonIgnore] + [XmlIgnore] public SubmodelElementWrapperCollection SmeForWrite { get @@ -7208,12 +7208,10 @@ public class JsonValueTypeCast { public class JsonDataObjectType { - [ JsonProperty(PropertyName = "name") ] - public string name = ""; + [JsonPropertyName("name")] public string name = ""; } - [ JsonProperty(PropertyName = "dataObjectType") ] - public JsonDataObjectType dataObjectType = new JsonDataObjectType(); + [JsonPropertyName("dataObjectType")] public JsonDataObjectType dataObjectType = new JsonDataObjectType(); public JsonValueTypeCast(string name) { @@ -7224,8 +7222,8 @@ public JsonValueTypeCast(string name) public class Property : DataElement { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public new JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } @@ -7233,11 +7231,11 @@ [ JsonProperty(PropertyName = "modelType") ] // members - [ MetaModelName("Property.valueType") ] [ TextSearchable ] [ JsonIgnore ] + [MetaModelName("Property.valueType")] [TextSearchable] [JsonIgnore] public string valueType = ""; - [ XmlIgnore ] - [ JsonProperty(PropertyName = "valueType") ] + [XmlIgnore] + [JsonPropertyName("valueType")] public JsonValueTypeCast JsonValueType { get { return new JsonValueTypeCast(this.valueType); } @@ -7245,7 +7243,7 @@ public JsonValueTypeCast JsonValueType } - [ MetaModelName("Property.value") ] [ TextSearchable ] + [MetaModelName("Property.value")] [TextSearchable] public string? value = ""; public Reference valueId = null; @@ -7357,8 +7355,8 @@ public bool IsTrue() public class MultiLanguageProperty : DataElement { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public new JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } @@ -7420,7 +7418,7 @@ public MultiLanguageProperty Set(LangStr ls) return this; if (this.value?.langString == null) this.value = new LangStringSet(); - this.value.langString[ ls.lang ] = ls.str; + this.value.langString[ls.lang] = ls.str; return this; } @@ -7443,8 +7441,8 @@ public override void ValueFromText(string? text, string? defaultLang = null) public class Range : DataElement { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public new JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } @@ -7452,21 +7450,21 @@ [ JsonProperty(PropertyName = "modelType") ] // members - [ MetaModelName("Range.valueType") ] [ TextSearchable ] [ JsonIgnore ] [ CountForHash ] + [MetaModelName("Range.valueType")] [TextSearchable] [JsonIgnore] [CountForHash] public string valueType = ""; - [ XmlIgnore ] - [ JsonProperty(PropertyName = "valueType") ] + [XmlIgnore] + [JsonPropertyName("valueType")] public JsonValueTypeCast JsonValueType { get { return new JsonValueTypeCast(this.valueType); } set { this.valueType = value?.dataObjectType?.name; } } - [ MetaModelName("Range.min") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("Range.min")] [TextSearchable] [CountForHash] public string min = ""; - [ MetaModelName("Range.max") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("Range.max")] [TextSearchable] [CountForHash] public string max = ""; // constructors @@ -7510,8 +7508,8 @@ public override string ValueAsText(string? defaultLang = null) public class Blob : DataElement { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public new JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } @@ -7519,10 +7517,10 @@ [ JsonProperty(PropertyName = "modelType") ] // members - [ MetaModelName("Blob.mimeType") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("Blob.mimeType")] [TextSearchable] [CountForHash] public string? mimeType = ""; - [ MetaModelName("Blob.value") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("Blob.value")] [TextSearchable] [CountForHash] public string value = ""; // constructors @@ -7574,8 +7572,8 @@ public override AasElementSelfDescription GetSelfDescription() public class File : DataElement { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public new JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } @@ -7583,10 +7581,10 @@ [ JsonProperty(PropertyName = "modelType") ] // members - [ MetaModelName("File.mimeType") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("File.mimeType")] [TextSearchable] [CountForHash] public string? mimeType = ""; - [ MetaModelName("File.value") ] [ TextSearchable ] [ CountForHash ] + [MetaModelName("File.value")] [TextSearchable] [CountForHash] public string value = ""; // constructors @@ -7654,8 +7652,8 @@ public override string ValueAsText(string? defaultLang = null) public class ReferenceElement : DataElement { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public new JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } @@ -7714,8 +7712,8 @@ public override AasElementSelfDescription GetSelfDescription() public class RelationshipElement : DataElement { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public new JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } @@ -7783,8 +7781,8 @@ public override AasElementSelfDescription GetSelfDescription() public class AnnotatedRelationshipElement : RelationshipElement, IManageSubmodelElements, IEnumerateChildren { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public new JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } @@ -7794,14 +7792,14 @@ [ JsonProperty(PropertyName = "modelType") ] // from this very class - [ JsonIgnore ] - [ SkipForHash ] // do NOT count children! - [ XmlArray("annotations") ] - [ XmlArrayItem("dataElement") ] + [JsonIgnore] + [SkipForHash] // do NOT count children! + [XmlArray("annotations")] + [XmlArrayItem("dataElement")] public DataElementWrapperCollection annotations = null; - [ XmlIgnore ] - [ JsonProperty(PropertyName = "annotations") ] + [XmlIgnore] + [JsonPropertyName("annotations")] public DataElement[] JsonAnotations { get @@ -7944,18 +7942,18 @@ public override AasElementSelfDescription GetSelfDescription() public class SubmodelElementCollection : SubmodelElement, IManageSubmodelElements, IEnumerateChildren { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public new JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } } // values == SMEs - [ XmlIgnore ] [ JsonIgnore ] [ SkipForHash ] // do NOT count children! + [XmlIgnore] [JsonIgnore] [SkipForHash] // do NOT count children! private SubmodelElementWrapperCollection _value = null; - [ JsonIgnore ] + [JsonIgnore] public SubmodelElementWrapperCollection value { get { return _value; } @@ -7966,8 +7964,8 @@ public SubmodelElementWrapperCollection value } } - [ XmlIgnore ] - [ JsonProperty(PropertyName = "value") ] + [XmlIgnore] + [JsonPropertyName("value")] public SubmodelElement[] JsonValue { get @@ -8186,8 +8184,8 @@ public enum Direction { In, Out, InOut }; // only the SME attributes of "value" are counting // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } } // members @@ -8232,34 +8230,34 @@ public AasElementSelfDescription GetSelfDescription() public class Operation : SubmodelElement, IEnumerateChildren { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public new JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } } // members - [ JsonIgnore ] [ XmlElement(ElementName = "inputVariable") ] [ SkipForHash ] // do NOT count children! + [JsonIgnore] [XmlElement(ElementName = "inputVariable")] [SkipForHash] // do NOT count children! public List inputVariable = new List(); - [ JsonIgnore ] [ XmlElement(ElementName = "outputVariable") ] [ SkipForHash ] // do NOT count children! + [JsonIgnore] [XmlElement(ElementName = "outputVariable")] [SkipForHash] // do NOT count children! public List outputVariable = new List(); - [ JsonIgnore ] [ XmlElement(ElementName = "inoutputVariable") ] [ SkipForHash ] // do NOT count children! + [JsonIgnore] [XmlElement(ElementName = "inoutputVariable")] [SkipForHash] // do NOT count children! public List inoutputVariable = new List(); - [ XmlIgnore ] + [XmlIgnore] // MICHA 190504: enabled JSON operation variables! - [ JsonProperty(PropertyName = "inputVariable") ] + [JsonPropertyName("inputVariable")] public OperationVariable[] JsonInputVariable { get { return inputVariable?.ToArray(); } set { inputVariable = (value != null) ? new List(value) : null; } } - [ XmlIgnore ] - [ JsonProperty(PropertyName = "outputVariable") ] + [XmlIgnore] + [JsonPropertyName("outputVariable")] // MICHA 190504: enabled JSON operation variables! public OperationVariable[] JsonOutputVariable { @@ -8267,8 +8265,8 @@ public OperationVariable[] JsonOutputVariable set { outputVariable = (value != null) ? new List(value) : null; } } - [ XmlIgnore ] - [ JsonProperty(PropertyName = "inoutputVariable") ] + [XmlIgnore] + [JsonPropertyName("inoutputVariable")] // MICHA 190504: enabled JSON operation variables! public OperationVariable[] JsonInOutputVariable { @@ -8439,12 +8437,12 @@ public Operation(SubmodelElement src) return; for (int i = 0; i < 2; i++) - if (op[ i ] != null) + if (op[i] != null) { - if (this[ i ] == null) - this[ i ] = new List(); - foreach (var ov in op[ i ]) - this[ i ].Add(new OperationVariable(ov)); + if (this[i] == null) + this[i] = new List(); + foreach (var ov in op[i]) + this[i].Add(new OperationVariable(ov)); } } @@ -8453,12 +8451,12 @@ public Operation(AasxCompatibilityModels.AdminShellV10.Operation src) : base(src) { for (int i = 0; i < 2; i++) - if (src[ i ] != null) + if (src[i] != null) { - if (this[ i ] == null) - this[ i ] = new List(); - foreach (var ov in src[ i ]) - this[ i ].Add(new OperationVariable(ov)); + if (this[i] == null) + this[i] = new List(); + foreach (var ov in src[i]) + this[i].Add(new OperationVariable(ov)); } } #endif @@ -8478,18 +8476,18 @@ public enum EntityTypeEnum { CoManagedEntity = 0, SelfManagedEntity = 1, Undef = // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public new JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } } // from this very class - [ XmlIgnore ] [ JsonIgnore ] [ SkipForHash ] // do NOT count children! + [XmlIgnore] [JsonIgnore] [SkipForHash] // do NOT count children! private SubmodelElementWrapperCollection _statements = null; - [ JsonIgnore ] + [JsonIgnore] public SubmodelElementWrapperCollection statements { get { return _statements; } @@ -8500,8 +8498,8 @@ public SubmodelElementWrapperCollection statements } } - [ XmlIgnore ] - [ JsonProperty(PropertyName = "statements") ] + [XmlIgnore] + [JsonPropertyName("statements")] public SubmodelElement[] JsonStatements { get @@ -8528,10 +8526,9 @@ public SubmodelElement[] JsonStatements // further members - [ CountForHash ] public string? entityType = ""; + [CountForHash] public string? entityType = ""; - [ JsonProperty(PropertyName = "asset") ] - public AssetRef assetRef = null; + [JsonPropertyName("asset")] public AssetRef assetRef = null; // enumerates its children @@ -8586,7 +8583,7 @@ public Entity(EntityTypeEnum entityType, string? idShort = null, AssetRef assetR { CreateNewLogic(idShort, null, semanticIdKey); - this.entityType = EntityTypeNames[ (int) entityType ]; + this.entityType = EntityTypeNames[(int)entityType]; this.assetRef = assetRef; } @@ -8664,9 +8661,9 @@ public T CreateSMEForIdShort(string idShort, string category = null, public EntityTypeEnum GetEntityType() { EntityTypeEnum res = EntityTypeEnum.Undef; - if (this.entityType != null && this.entityType.Trim().ToLower() == EntityTypeNames[ 0 ].ToLower()) + if (this.entityType != null && this.entityType.Trim().ToLower() == EntityTypeNames[0].ToLower()) res = EntityTypeEnum.CoManagedEntity; - if (this.entityType != null && this.entityType.Trim().ToLower() == EntityTypeNames[ 1 ].ToLower()) + if (this.entityType != null && this.entityType.Trim().ToLower() == EntityTypeNames[1].ToLower()) res = EntityTypeEnum.SelfManagedEntity; return res; } @@ -8683,8 +8680,8 @@ public override AasElementSelfDescription GetSelfDescription() public class BasicEvent : SubmodelElement { // for JSON only - [ XmlIgnore ] - [ JsonProperty(PropertyName = "modelType") ] + [XmlIgnore] + [JsonPropertyName("modelType")] public new JsonModelTypeWrapper JsonModelType { get { return new JsonModelTypeWrapper(GetElementName()); } diff --git a/src/AasxCsharpLibrary/AasxCompatibilityModels/V20/AdminShellConverters.cs b/src/AasxCsharpLibrary/AasxCompatibilityModels/V20/AdminShellConverters.cs index 1fc738e87..7e34dc248 100644 --- a/src/AasxCsharpLibrary/AasxCompatibilityModels/V20/AdminShellConverters.cs +++ b/src/AasxCsharpLibrary/AasxCompatibilityModels/V20/AdminShellConverters.cs @@ -8,163 +8,99 @@ This source code may use other Open Source software components (see LICENSE.txt) */ using System; -using System.Reflection; using AasxCompatibilityModels; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Serialization; -//namespace AdminShellNS -namespace AdminShell_V20 +namespace AdminShell_V20; + +using System.Text.Json; +using System.Text.Json.Serialization; + +public static class AdminShellConverters { - public static class AdminShellConverters + /// + /// This converter is used for reading JSON files; it claims to be responsible for + /// "Referable" (the base class) + /// and decides, which subclass of the base class shall be populated. + /// If the object is SubmodelElement, the decision, which special subclass to create is done in a factory + /// AdminShell.SubmodelElementWrapper.CreateAdequateType(), + /// in order to have all subclass specific decisions in one place (SubmodelElementWrapper) + /// Remark: There is a NuGet package JsonSubTypes, which could have done the job, except the fact of having + /// "modelType" being a class property with a contained property "name". + /// + public class JsonAasxConverter : JsonConverter { - /// - /// This converter is used for reading JSON files; it claims to be responsible for - /// "Referable" (the base class) - /// and decides, which sub-class of the base class shall be populated. - /// If the object is SubmodelElement, the decision, shich special sub-class to create is done in a factory - /// AdminShell.SubmodelElementWrapper.CreateAdequateType(), - /// in order to have all sub-class specific decisions in one place (SubmodelElementWrapper) - /// Remark: There is a NuGet package JsonSubTypes, which could have done the job, except the fact of having - /// "modelType" being a class property with a contained property "name". - /// - public class JsonAasxConverter : JsonConverter + public override AdminShellV20.Referable Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - private string UpperClassProperty = "modelType"; - private string LowerClassProperty = "name"; - - public JsonAasxConverter() : base() - { - } + using var doc = JsonDocument.ParseValue(ref reader); + var root = doc.RootElement; - public JsonAasxConverter(string UpperClassProperty, string LowerClassProperty) : base() - { - this.UpperClassProperty = UpperClassProperty; - this.LowerClassProperty = LowerClassProperty; - } + var target = new AdminShellV20.Referable(); - public override bool CanConvert(Type objectType) + // Check if the root element has the necessary properties + if (root.TryGetProperty("idShort", out JsonElement idShortElement)) { - // Info MIHO 21 APR 2020: changed this from SubmodelElement to Referable - if (typeof(AdminShell.Referable).IsAssignableFrom(objectType)) - return true; - return false; + target.idShort = idShortElement.GetString(); } - public override bool CanWrite + if (root.TryGetProperty("category", out JsonElement categoryElement)) { - get { return false; } + target.category = categoryElement.GetString(); } - public override object ReadJson(JsonReader reader, - Type objectType, - object existingValue, - JsonSerializer serializer) + if (!root.TryGetProperty("description", out JsonElement descriptionElement)) { - // Load JObject from stream - JObject jObject = JObject.Load(reader); - - // Create target object based on JObject - object target = new AdminShell.Referable(); - - if (jObject.ContainsKey(UpperClassProperty)) - { - var j2 = jObject[UpperClassProperty]; - if (j2 != null) - foreach (var c in j2.Children()) - { - var cprop = c as Newtonsoft.Json.Linq.JProperty; - if (cprop == null) - continue; - if (cprop.Name == LowerClassProperty && cprop.Value.Type.ToString() == "String") - { - var cpval = cprop.Value.ToObject(); - if (cpval == null) - continue; - // Info MIHO 21 APR 2020: use Referable.CreateAdequateType instead of SMW... - var o = AdminShell.Referable.CreateAdequateType(cpval); - if (o != null) - target = o; - } - } - } - - // Populate the object properties - serializer.Populate(jObject.CreateReader(), target); - return target; } - /// - /// Introduced for JSON serialization, can create Referables based on a string name - /// - /// string name (standard PascalCased) - + var langStringArray = descriptionElement.GetProperty("langString").EnumerateArray(); - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + foreach (var langString in langStringArray) { - throw new NotImplementedException(); + var lang = langString.GetProperty("lang").GetString(); + var str = langString.GetProperty("str").GetString(); + target.AddDescription(lang, str); } + + return target; } + + public override void Write(Utf8JsonWriter writer, AdminShellV20.Referable value, JsonSerializerOptions options) => throw new NotImplementedException(); - /// - /// This converter / contract resolver for Json.NET adaptively filters different levels of depth - /// of nested AASX structures. - /// - public class AdaptiveFilterContractResolver : DefaultContractResolver - { - public bool AasHasViews = true; - public bool BlobHasValue = true; - public bool SubmodelHasElements = true; - public bool SmcHasValue = true; - public bool OpHasVariables = true; + public override bool CanConvert(Type typeToConvert) => typeof(AdminShellV20.Referable).IsAssignableFrom(typeToConvert); + } - public AdaptiveFilterContractResolver() { } + public class AdaptiveFilterContractResolver : JsonConverter + { + public bool AasHasViews = true; + public bool BlobHasValue = true; + public bool SubmodelHasElements = true; + public bool SmcHasValue = true; + public bool OpHasVariables = true; - public AdaptiveFilterContractResolver(bool deep = true, bool complete = true) - { - if (!deep) - { - this.SubmodelHasElements = false; - this.SmcHasValue = false; - this.OpHasVariables = false; - } - if (!complete) - { - this.AasHasViews = false; - this.BlobHasValue = false; - } + public AdaptiveFilterContractResolver() { } + public AdaptiveFilterContractResolver(bool deep = true, bool complete = true) + { + if (!deep) + { + SubmodelHasElements = false; + SmcHasValue = false; + OpHasVariables = false; } - protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + if (complete) { - JsonProperty property = base.CreateProperty(member, memberSerialization); - - if (!BlobHasValue && property.DeclaringType == typeof(AdminShell.Blob) && - property.PropertyName == "value") - property.ShouldSerialize = instance => { return false; }; - - if (!SubmodelHasElements && property.DeclaringType == typeof(AdminShell.Submodel) && - property.PropertyName == "submodelElements") - property.ShouldSerialize = instance => { return false; }; - - if (!SmcHasValue && property.DeclaringType == typeof(AdminShell.SubmodelElementCollection) && - property.PropertyName == "value") - property.ShouldSerialize = instance => { return false; }; + return; + } - if (!OpHasVariables && property.DeclaringType == typeof(AdminShell.Operation) && - (property.PropertyName == "in" || property.PropertyName == "out")) - property.ShouldSerialize = instance => { return false; }; + AasHasViews = false; + BlobHasValue = false; + } - if (!AasHasViews && property.DeclaringType == typeof(AdminShell.AdministrationShell) && - property.PropertyName == "views") - property.ShouldSerialize = instance => { return false; }; + public override AdminShellV20.AdministrationShell Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException(); - return property; - } - } + public override void Write(Utf8JsonWriter writer, AdminShellV20.AdministrationShell value, JsonSerializerOptions options) => throw new NotImplementedException(); + public override bool CanConvert(Type typeToConvert) => typeof(AdminShellV20.AdministrationShell).IsAssignableFrom(typeToConvert); } -} +} \ No newline at end of file diff --git a/src/AasxCsharpLibrary/AasxCsharpLibrary.csproj b/src/AasxCsharpLibrary/AasxCsharpLibrary.csproj index e7a6ba6b7..f342abea1 100644 --- a/src/AasxCsharpLibrary/AasxCsharpLibrary.csproj +++ b/src/AasxCsharpLibrary/AasxCsharpLibrary.csproj @@ -44,7 +44,6 @@ - diff --git a/src/AasxCsharpLibrary/AdminShellCollections.cs b/src/AasxCsharpLibrary/AdminShellCollections.cs deleted file mode 100644 index 11e53c0f9..000000000 --- a/src/AasxCsharpLibrary/AdminShellCollections.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* -Copyright (c) 2018-2021 Festo AG & Co. KG -Author: Michael Hoffmeister - -This source code is licensed under the Apache License 2.0 (see LICENSE.txt). - -This source code may use other Open Source software components (see LICENSE.txt). -*/ - -using System.Collections.Generic; - -namespace AdminShellNS -{ - public class MultiValueDictionary - { - private Dictionary> dict = new Dictionary>(); - public void Add(K key, V value) - { - if (dict.TryGetValue(key, out var list)) - list.Add(value); - else - dict.Add(key, new List { value }); - } - - public bool ContainsKey(K key) => dict.ContainsKey(key); - - public List this[K key] => dict[key]; - - public IEnumerable> Keys - { - get - { - return dict.Values; - } - } - } - - public class DoubleSidedDict - { - private Dictionary _forward = new Dictionary(); - private Dictionary _backward = new Dictionary(); - - public void AddPair(T1 item1, T2 item2) - { - _forward.Add(item1, item2); - _backward.Add(item2, item1); - } - - public bool Contains1(T1 key1) => _forward.ContainsKey(key1); - public bool Contains2(T2 key2) => _backward.ContainsKey(key2); - - public T2 Get2(T1 key1) => _forward[key1]; - public T1 Get1(T2 key2) => _backward[key2]; - - public T2 Get2OrDefault(T1 key1) - => (key1 != null && _forward.ContainsKey(key1)) ? _forward[key1] : default(T2); - public T1 Get1OrDefault(T2 key2) - => (key2 != null && _backward.ContainsKey(key2)) ? _backward[key2] : default(T1); - - public void Clear() { _forward.Clear(); _backward.Clear(); } - } -} diff --git a/src/AasxCsharpLibrary/AdminShellConverters.cs b/src/AasxCsharpLibrary/AdminShellConverters.cs index 6bc421373..eb02510a6 100644 --- a/src/AasxCsharpLibrary/AdminShellConverters.cs +++ b/src/AasxCsharpLibrary/AdminShellConverters.cs @@ -1,186 +1,198 @@ -/* -Copyright (c) 2018-2021 Festo AG & Co. KG -Author: Michael Hoffmeister +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; -This source code is licensed under the Apache License 2.0 (see LICENSE.txt). +namespace AdminShellNS; -This source code may use other Open Source software components (see LICENSE.txt). -*/ +using System.Linq; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Serialization; -using System; -using System.Reflection; - -namespace AdminShellNS +public static class AdminShellConverters { - public static class AdminShellConverters + public class JsonAasxConverter : JsonConverter { - /// - /// This converter is used for reading JSON files; it claims to be responsible for - /// "Referable" (the base class) - /// and decides, which sub-class of the base class shall be populated. - /// If the object is SubmodelElement, the decision, shich special sub-class to create is done in a factory - /// SubmodelElementWrapper.CreateAdequateType(), - /// in order to have all sub-class specific decisions in one place (SubmodelElementWrapper) - /// Remark: There is a NuGet package JsonSubTypes, which could have done the job, except the fact of having - /// "modelType" being a class property with a contained property "name". - /// - public class JsonAasxConverter : JsonConverter + private string UpperClassProperty { get; } + private string LowerClassProperty { get; } + + public JsonAasxConverter(string upperClassProperty, string lowerClassProperty) { - private string UpperClassProperty = "modelType"; - private string LowerClassProperty = "name"; + UpperClassProperty = upperClassProperty ?? throw new ArgumentNullException(nameof(upperClassProperty)); + LowerClassProperty = lowerClassProperty ?? throw new ArgumentNullException(nameof(lowerClassProperty)); + } - public JsonAasxConverter() : base() - { - } + public override bool CanConvert(Type typeToConvert) => typeof(IReferable).IsAssignableFrom(typeToConvert); - public JsonAasxConverter(string UpperClassProperty, string LowerClassProperty) : base() - { - this.UpperClassProperty = UpperClassProperty; - this.LowerClassProperty = LowerClassProperty; - } + public override IReferable? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + using var doc = JsonDocument.ParseValue(ref reader); + var root = doc.RootElement; - public override bool CanConvert(Type objectType) - { - // Info MIHO 21 APR 2020: changed this from SubmodelElement to Referable - if (typeof(IReferable).IsAssignableFrom(objectType)) - return true; - return false; - } + IReferable? target = null; - public override bool CanWrite + if (root.TryGetProperty(UpperClassProperty, out var upperClassProperty)) { - get { return false; } + target = CreateReferableInstance(upperClassProperty); } - public override object ReadJson(JsonReader reader, - Type objectType, - object existingValue, - JsonSerializer serializer) + if (target != null) { - // Load JObject from stream - JObject jObject = JObject.Load(reader); + DeserializeReferableProperties(root, target); + } - // Create target object based on JObject - IReferable target = null; + return target; + } - if (jObject.ContainsKey(UpperClassProperty)) - { - var j2 = jObject[UpperClassProperty]; - if (j2 != null) - foreach (var c in j2.Children()) - { - var cprop = c as Newtonsoft.Json.Linq.JProperty; - if (cprop == null) - continue; - if (cprop.Name == LowerClassProperty && cprop.Value.Type.ToString() == "String") - { - var cpval = cprop.Value.ToObject(); - if (cpval == null) - continue; - // Info MIHO 21 APR 2020: use Referable.CreateAdequateType instead of SMW... - var o = CreateAdequateType(cpval); - if (o != null) - target = o; - } - } - } + private IReferable? CreateReferableInstance(JsonElement upperClassProperty) => upperClassProperty.EnumerateObject() + .Where(lowerClassPropertyValue => + lowerClassPropertyValue.Name == LowerClassProperty && + lowerClassPropertyValue.Value.ValueKind == JsonValueKind.String) + .Select(lowerClassPropertyValue => + CreateAdequateType(lowerClassPropertyValue.Value.GetString())) + .FirstOrDefault(); - // Populate the object properties - serializer.Populate(jObject.CreateReader(), target); + private void DeserializeReferableProperties(JsonElement root, IReferable target) + { + DeserializeProperty(root, "category", JsonValueKind.String, value => target.Category = value.GetString()); + DeserializeArrayProperty(root, "idShort", JsonValueKind.String, value => target.IdShort = value.GetString()); + DeserializeLangStringArrayProperty(root, "displayName", value => target.DisplayName = value); + DeserializeLangStringArrayProperty(root, "description", value => target.Description = value); + } - return target; + private static void DeserializeProperty(JsonElement root, string propertyName, JsonValueKind expectedKind, Action assignAction) + { + if (root.TryGetProperty(propertyName, out var property) && property.ValueKind == expectedKind) + { + assignAction(property); } + } - public static IReferable CreateAdequateType(string elementName) + public static void DeserializeArrayProperty(JsonElement root, string propertyName, JsonValueKind expectedKind, Action assignAction) + { + if (root.TryGetProperty(propertyName, out var property) && property.ValueKind == expectedKind) { - if (elementName == KeyTypes.AssetAdministrationShell.ToString()) - return new AssetAdministrationShell("", null); - //if (elementName == "Asset") - // return new AssetInformation(AssetKind.Instance); - if (elementName == KeyTypes.ConceptDescription.ToString()) - return new ConceptDescription(""); - if (elementName == KeyTypes.Submodel.ToString()) - return new Submodel(""); - //if (elementName == KeyTypes.View) - // return new View(); - return CreateSubmodelElementIstance(elementName); + assignAction(property); } + } - private static ISubmodelElement CreateSubmodelElementIstance(string typeName) + private static void DeserializeLangStringArrayProperty(JsonElement root, string propertyName, Action> assignAction) + { + if (!root.TryGetProperty(propertyName, out var property) || property.ValueKind != JsonValueKind.Array) { - Type type = Type.GetType(typeName); - if (type == null || !type.IsSubclassOf(typeof(ISubmodelElement))) - return null; - var sme = Activator.CreateInstance(type) as ISubmodelElement; - return sme; + return; } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + var list = new List(); + foreach (var item in property.EnumerateArray()) { - throw new NotImplementedException(); + if (item.TryGetProperty("lang", out var langElement) && item.TryGetProperty("value", out var valueElement) && + langElement.ValueKind == JsonValueKind.String && valueElement.ValueKind == JsonValueKind.String) + { + list.Add(new LangStringNameType(langElement.GetString(), valueElement.GetString())); + } } + + assignAction(list); } - /// - /// This converter / contract resolver for Json.NET adaptively filters different levels of depth - /// of nested AASX structures. - /// - public class AdaptiveFilterContractResolver : DefaultContractResolver + private void DeserializeLangStringArrayProperty(JsonElement root, string propertyName, Action> assignAction) { - public bool AasHasViews = true; - public bool BlobHasValue = true; - public bool SubmodelHasElements = true; - public bool SmcHasValue = true; - public bool OpHasVariables = true; - - public AdaptiveFilterContractResolver() { } + if (!root.TryGetProperty(propertyName, out var property) || property.ValueKind != JsonValueKind.Array) + { + return; + } - public AdaptiveFilterContractResolver(bool deep = true, bool complete = true) + var list = new List(); + foreach (var item in property.EnumerateArray()) { - if (!deep) + if (!item.TryGetProperty("lang", out var langElement) || !item.TryGetProperty("value", out var valueElement) || + langElement.ValueKind != JsonValueKind.String || valueElement.ValueKind != JsonValueKind.String) { - this.SubmodelHasElements = false; - this.SmcHasValue = false; - this.OpHasVariables = false; + continue; } - if (!complete) + + // Convert ILangStringNameType to ILangStringTextType if possible + var convertedItem = ConvertToLangStringTextType(new LangStringNameType(langElement.GetString(), valueElement.GetString())); + if (convertedItem != null) { - this.AasHasViews = false; - this.BlobHasValue = false; + list.Add(convertedItem); } + } + + assignAction(list); + } + + private static ILangStringTextType ConvertToLangStringTextType(ILangStringNameType nameType) => new LangStringTextType(nameType.Language, nameType.Text); + + public override void Write(Utf8JsonWriter writer, IReferable value, JsonSerializerOptions options) => throw new NotImplementedException(); + private static IReferable? CreateAdequateType(string elementName) + { + var administrationShellType = Enum.GetName(typeof(KeyTypes), KeyTypes.AssetAdministrationShell); + var conceptDescriptionType = Enum.GetName(typeof(KeyTypes), KeyTypes.ConceptDescription); + var submodelType = Enum.GetName(typeof(KeyTypes), KeyTypes.Submodel); + + if (elementName == administrationShellType) + { + return new AssetAdministrationShell(string.Empty, null); } - protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + if (elementName == conceptDescriptionType) { - JsonProperty property = base.CreateProperty(member, memberSerialization); + return new ConceptDescription(string.Empty, null); + } - if (!BlobHasValue && property.DeclaringType == typeof(Blob) && - property.PropertyName == "value") - property.ShouldSerialize = instance => { return false; }; + if (elementName == submodelType) + { + return new Submodel(string.Empty, null); + } - if (!SubmodelHasElements && property.DeclaringType == typeof(Submodel) && - property.PropertyName == "submodelElements") - property.ShouldSerialize = instance => { return false; }; + return CreateSubmodelElementInstance(elementName); + } - if (!SmcHasValue && property.DeclaringType == typeof(SubmodelElementCollection) && - property.PropertyName == "value") - property.ShouldSerialize = instance => { return false; }; + private static ISubmodelElement? CreateSubmodelElementInstance(string typeName) + { + var type = Type.GetType(typeName); + if (type != null && typeof(ISubmodelElement).IsAssignableFrom(type)) + { + return Activator.CreateInstance(type) as ISubmodelElement; + } - if (!OpHasVariables && property.DeclaringType == typeof(Operation) && - (property.PropertyName == "in" || property.PropertyName == "out")) - property.ShouldSerialize = instance => { return false; }; + return null; + } + } - if (!AasHasViews && property.DeclaringType == typeof(AssetAdministrationShell) && - property.PropertyName == "views") - property.ShouldSerialize = instance => { return false; }; + public class AdaptiveFilterContractResolver : JsonConverter + { + // Properties to configure the behavior of the converter + public bool AasHasViews { get; } + public bool BlobHasValue { get; } + public bool SubmodelHasElements { get; } + public bool SmcHasValue { get; } + public bool OpHasVariables { get; } + + public AdaptiveFilterContractResolver(bool aasHasViews = true, bool blobHasValue = true, bool submodelHasElements = true, bool smcHasValue = true, + bool opHasVariables = true) + { + AasHasViews = aasHasViews; + BlobHasValue = blobHasValue; + SubmodelHasElements = submodelHasElements; + SmcHasValue = smcHasValue; + OpHasVariables = opHasVariables; + } - return property; + public override JsonElement Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + try + { + using var doc = JsonDocument.ParseValue(ref reader); + return doc.RootElement.Clone(); + } + catch (JsonException ex) + { + throw new JsonException("Error while reading JSON.", ex); } } + public override void Write(Utf8JsonWriter writer, JsonElement value, JsonSerializerOptions options) => throw new NotImplementedException(); } -} +} \ No newline at end of file diff --git a/src/AasxCsharpLibrary/AdminShellPackageEnv.cs b/src/AasxCsharpLibrary/AdminShellPackageEnv.cs index 22ee3a04e..0a6f3fad4 100644 --- a/src/AasxCsharpLibrary/AdminShellPackageEnv.cs +++ b/src/AasxCsharpLibrary/AdminShellPackageEnv.cs @@ -10,8 +10,6 @@ This source code may use other Open Source software components (see LICENSE.txt) using Extensions; -using Newtonsoft.Json; -// using ScottPlot.Drawing.Colormaps; using System; using System.Collections.Generic; using System.IO; @@ -26,6 +24,9 @@ This source code may use other Open Source software components (see LICENSE.txt) namespace AdminShellNS { + using System.Text.Json; + using Environment = AasCore.Aas3_0.Environment; + /// /// This class lets an outer functionality keep track on the supplementary files, which are in or /// are pending to be added or deleted to an Package. @@ -142,10 +143,10 @@ public static void XmlSkipHeader(XmlReader xmlReader) /// /// Open for read stream /// - public static AasCore.Aas3_0.Environment DeserializeXmlFromStreamWithCompat(Stream s) + public static Environment? DeserializeXmlFromStreamWithCompat(Stream s) { // not sure - AasCore.Aas3_0.Environment res = null; + Environment? res = null; // try get first element var nsuri = TryReadXmlFirstElementNamespaceURI(s); @@ -260,7 +261,7 @@ public class AdminShellPackageEnv : IDisposable private string _tempFn = null; - private AasCore.Aas3_0.Environment _aasEnv = new AasCore.Aas3_0.Environment(new List(), new List(), new List()); + private Environment? _aasEnv = new AasCore.Aas3_0.Environment(new List(), new List(), new List()); private Package _openPackage = null; private string _envXml = null; private readonly ListOfAasSupplementaryFile _pendingFilesToAdd = new ListOfAasSupplementaryFile(); @@ -285,7 +286,7 @@ public string getEnvXml() return _envXml; } - public AdminShellPackageEnv(AasCore.Aas3_0.Environment env) + public AdminShellPackageEnv(Environment? env) { if (env != null) _aasEnv = env; @@ -318,7 +319,7 @@ public string Filename } } - public AasCore.Aas3_0.Environment AasEnv + public Environment? AasEnv { get { @@ -326,7 +327,7 @@ public AasCore.Aas3_0.Environment AasEnv } } - private static AasCore.Aas3_0.Environment LoadXml(string fn) + private static Environment? LoadXml(string fn) { try { @@ -348,7 +349,7 @@ private static AasCore.Aas3_0.Environment LoadXml(string fn) } } - private static AasCore.Aas3_0.Environment LoadJson(string fn) + private static Environment? LoadJson(string fn) { try { @@ -363,7 +364,7 @@ private static AasCore.Aas3_0.Environment LoadJson(string fn) //var aasEnv = (AasCore.Aas3_0_RC02.Environment)serializer.Deserialize( // file, typeof(AasCore.Aas3_0_RC02.Environment)); - var node = System.Text.Json.Nodes.JsonNode.Parse(file); + var node = System.Text.Json.Nodes.JsonNode.Parse(file); var aasEnv = Jsonization.Deserialize.EnvironmentFrom(node); return aasEnv; @@ -379,7 +380,7 @@ private static AasCore.Aas3_0.Environment LoadJson(string fn) /// is unequal if indirectLoadSave is used. private static (AasCore.Aas3_0.Environment, Package, String) LoadPackageAasx(string fn, string fnToLoad, bool loadXml = false) { - AasCore.Aas3_0.Environment aasEnv; + Environment? aasEnv; Package openPackage = null; string envXml = null; @@ -642,6 +643,13 @@ public void SetTempFn(string fn) } } + private JsonSerializerOptions _jsonSerializerOptions = new() + { + WriteIndented = true, + DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull, + ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve + }; + public void LoadFromAasEnvString(string content) { try @@ -739,28 +747,6 @@ public bool SaveAs(string fn, bool writeFreshly = false, SerializationFormat pre try { - //// TODO (Michael Hoffmeister, 2020-08-01): use a unified function to create a serializer - //JsonSerializer serializer = new JsonSerializer() - //{ - // NullValueHandling = NullValueHandling.Ignore, - // ReferenceLoopHandling = ReferenceLoopHandling.Serialize, - // Formatting = Newtonsoft.Json.Formatting.Indented - //}; - - //var sw = new StreamWriter(s); - //var writer = new JsonTextWriter(sw); - - //serializer.Serialize(writer, _aasEnv); - //writer.Flush(); - //sw.Flush(); - //s.Flush(); - - //if (useMemoryStream == null) - //{ - // writer.Close(); - // sw.Close(); - //} - using (var wr = new System.Text.Json.Utf8JsonWriter(s)) { Jsonization.Serialize.ToJsonObject(_aasEnv).WriteTo(wr, @@ -973,20 +959,10 @@ public bool SaveAs(string fn, bool writeFreshly = false, SerializationFormat pre // now, specPart shall be != null! if (specPart.Uri.ToString().ToLower().Trim().EndsWith("json")) { - using (var s = specPart.GetStream(FileMode.Create)) - { - JsonSerializer serializer = new JsonSerializer(); - serializer.NullValueHandling = NullValueHandling.Ignore; - serializer.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; - serializer.Formatting = Newtonsoft.Json.Formatting.Indented; - using (var sw = new StreamWriter(s)) - { - using (JsonWriter writer = new JsonTextWriter(sw)) - { - serializer.Serialize(writer, _aasEnv); - } - } - } + using var s = specPart.GetStream(FileMode.Create); + using var sw = new StreamWriter(s); + var jsonString = JsonSerializer.Serialize(_aasEnv, _jsonSerializerOptions); + sw.Write(jsonString); } else { diff --git a/src/AasxCsharpLibrary/Extensions/ExtendAnnotatedRelationshipElement.cs b/src/AasxCsharpLibrary/Extensions/ExtendAnnotatedRelationshipElement.cs index 9a5194ba3..924a7990f 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendAnnotatedRelationshipElement.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendAnnotatedRelationshipElement.cs @@ -33,7 +33,7 @@ public static void Remove(this AnnotatedRelationshipElement annotatedRelationshi } } - public static object AddChild(this AnnotatedRelationshipElement annotatedRelationshipElement, ISubmodelElement childSubmodelElement, EnumerationPlacmentBase placement = null) + public static object? AddChild(this AnnotatedRelationshipElement annotatedRelationshipElement, ISubmodelElement? childSubmodelElement, EnumerationPlacmentBase placement = null) { if (childSubmodelElement == null || childSubmodelElement is not IDataElement) return null; @@ -48,7 +48,7 @@ public static object AddChild(this AnnotatedRelationshipElement annotatedRelatio } #endregion - public static AnnotatedRelationshipElement ConvertAnnotationsFromV20(this AnnotatedRelationshipElement annotatedRelationshipElement, AasxCompatibilityModels.AdminShellV20.AnnotatedRelationshipElement sourceAnnotedRelElement) + public static AnnotatedRelationshipElement? ConvertAnnotationsFromV20(this AnnotatedRelationshipElement? annotatedRelationshipElement, AasxCompatibilityModels.AdminShellV20.AnnotatedRelationshipElement sourceAnnotedRelElement) { if (sourceAnnotedRelElement == null) { @@ -60,8 +60,8 @@ public static AnnotatedRelationshipElement ConvertAnnotationsFromV20(this Annota annotatedRelationshipElement.Annotations ??= new List(); foreach (var submodelElementWrapper in sourceAnnotedRelElement.annotations) { - var sourceSubmodelElement = submodelElementWrapper.submodelElement; - ISubmodelElement outputSubmodelElement = null; + var sourceSubmodelElement = submodelElementWrapper.submodelElement; + ISubmodelElement? outputSubmodelElement = null; if (sourceSubmodelElement != null) { outputSubmodelElement = outputSubmodelElement.ConvertFromV20(sourceSubmodelElement); @@ -91,7 +91,7 @@ public static T FindFirstIdShortAs(this IAnnotatedRelationshipElement annoted } public static AnnotatedRelationshipElement Set(this AnnotatedRelationshipElement elem, - Reference first, Reference second) + Reference? first, Reference? second) { elem.First = first; elem.Second = second; diff --git a/src/AasxCsharpLibrary/Extensions/ExtendAssetAdministrationShell.cs b/src/AasxCsharpLibrary/Extensions/ExtendAssetAdministrationShell.cs index 3ce9c2a50..1b0858286 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendAssetAdministrationShell.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendAssetAdministrationShell.cs @@ -51,7 +51,7 @@ public static bool EqualsAas(this IAssetAdministrationShell source, IAssetAdmini } - public static bool HasSubmodelReference(this IAssetAdministrationShell assetAdministrationShell, Reference submodelReference) + public static bool HasSubmodelReference(this IAssetAdministrationShell assetAdministrationShell, Reference? submodelReference) { if (submodelReference == null) { @@ -69,7 +69,7 @@ public static bool HasSubmodelReference(this IAssetAdministrationShell assetAdmi return false; } - public static void AddSubmodelReference(this IAssetAdministrationShell assetAdministrationShell, Reference newSubmodelReference) + public static void AddSubmodelReference(this IAssetAdministrationShell assetAdministrationShell, Reference? newSubmodelReference) { if (assetAdministrationShell.Submodels == null) { diff --git a/src/AasxCsharpLibrary/Extensions/ExtendAssetInformation.cs b/src/AasxCsharpLibrary/Extensions/ExtendAssetInformation.cs index 58a3bb164..5171c648c 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendAssetInformation.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendAssetInformation.cs @@ -16,7 +16,7 @@ public static Tuple ToCaptionInfo(this AssetInformation assetInf } #endregion - public static AssetInformation ConvertFromV10(this AssetInformation assetInformation, AasxCompatibilityModels.AdminShellV10.Asset sourceAsset) + public static AssetInformation? ConvertFromV10(this AssetInformation? assetInformation, AasxCompatibilityModels.AdminShellV10.Asset sourceAsset) { //Determine AssetKind var assetKind = AssetKind.Instance; @@ -34,7 +34,7 @@ public static AssetInformation ConvertFromV10(this AssetInformation assetInforma return assetInformation; } - public static AssetInformation ConvertFromV20(this AssetInformation assetInformation, AasxCompatibilityModels.AdminShellV20.Asset sourceAsset) + public static AssetInformation? ConvertFromV20(this AssetInformation? assetInformation, AasxCompatibilityModels.AdminShellV20.Asset sourceAsset) { //Determine AssetKind var assetKind = AssetKind.Instance; diff --git a/src/AasxCsharpLibrary/Extensions/ExtendBlob.cs b/src/AasxCsharpLibrary/Extensions/ExtendBlob.cs index 94b5f6649..0b804c3df 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendBlob.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendBlob.cs @@ -11,14 +11,14 @@ public static void Set(this Blob blob, blob.Value = value; } - public static Blob ConvertFromV10(this Blob blob, AasxCompatibilityModels.AdminShellV10.Blob sourceBlob) + public static Blob? ConvertFromV10(this Blob? blob, AasxCompatibilityModels.AdminShellV10.Blob sourceBlob) { blob.ContentType = sourceBlob.mimeType; blob.Value = Encoding.ASCII.GetBytes(sourceBlob.value); return blob; } - public static Blob ConvertFromV20(this Blob blob, AasxCompatibilityModels.AdminShellV20.Blob sourceBlob) + public static Blob? ConvertFromV20(this Blob? blob, AasxCompatibilityModels.AdminShellV20.Blob sourceBlob) { blob.ContentType = sourceBlob.mimeType; blob.Value = Encoding.ASCII.GetBytes(sourceBlob.value); diff --git a/src/AasxCsharpLibrary/Extensions/ExtendConceptDescription.cs b/src/AasxCsharpLibrary/Extensions/ExtendConceptDescription.cs index fa5570f6f..c9615b2ff 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendConceptDescription.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendConceptDescription.cs @@ -92,7 +92,7 @@ public static DataSpecificationIec61360 GetIEC61360(this ConceptDescription conc // return conceptDescription.EmbeddedDataSpecifications?.GetPhysicalUnitContent(); //} - public static IEnumerable FindAllReferences(this IConceptDescription conceptDescription) + public static IEnumerable FindAllReferences(this IConceptDescription conceptDescription) { yield break; } diff --git a/src/AasxCsharpLibrary/Extensions/ExtendDataSpecificationIEC61360.cs b/src/AasxCsharpLibrary/Extensions/ExtendDataSpecificationIEC61360.cs index 08af968bd..15e14367d 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendDataSpecificationIEC61360.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendDataSpecificationIEC61360.cs @@ -4,7 +4,7 @@ namespace Extensions { public static class ExtendDataSpecificationIEC61360 { - public static DataSpecificationIec61360 ConvertFromV20(this DataSpecificationIec61360 ds61360, AasxCompatibilityModels.AdminShellV20.DataSpecificationIEC61360 src616360) + public static DataSpecificationIec61360? ConvertFromV20(this DataSpecificationIec61360? ds61360, AasxCompatibilityModels.AdminShellV20.DataSpecificationIEC61360 src616360) { if (src616360.preferredName != null) ds61360.PreferredName = new List().ConvertFromV20(src616360.preferredName); diff --git a/src/AasxCsharpLibrary/Extensions/ExtendEmbeddedDataSpecification.cs b/src/AasxCsharpLibrary/Extensions/ExtendEmbeddedDataSpecification.cs index 231e45238..e89e3a45e 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendEmbeddedDataSpecification.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendEmbeddedDataSpecification.cs @@ -74,7 +74,7 @@ public static EmbeddedDataSpecification ConvertFromV20(this EmbeddedDataSpecific return embeddedDataSpecification; } - public static EmbeddedDataSpecification CreateIec61360WithContent(DataSpecificationIec61360 content = null) + public static EmbeddedDataSpecification CreateIec61360WithContent(DataSpecificationIec61360? content = null) { if (content == null) content = new DataSpecificationIec61360(null); diff --git a/src/AasxCsharpLibrary/Extensions/ExtendEntity.cs b/src/AasxCsharpLibrary/Extensions/ExtendEntity.cs index 7404cd28a..0ac1cf34c 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendEntity.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendEntity.cs @@ -33,7 +33,7 @@ public static void Remove(this Entity entity, ISubmodelElement submodelElement) } } - public static object AddChild(this Entity entity, ISubmodelElement childSubmodelElement, EnumerationPlacmentBase placement = null) + public static object? AddChild(this Entity entity, ISubmodelElement? childSubmodelElement, EnumerationPlacmentBase placement = null) { if (childSubmodelElement == null) return null; @@ -47,7 +47,7 @@ public static object AddChild(this Entity entity, ISubmodelElement childSubmodel #endregion - public static Entity ConvertFromV20(this Entity entity, AasxCompatibilityModels.AdminShellV20.Entity sourceEntity) + public static Entity? ConvertFromV20(this Entity? entity, AasxCompatibilityModels.AdminShellV20.Entity sourceEntity) { if (sourceEntity == null) { @@ -59,8 +59,8 @@ public static Entity ConvertFromV20(this Entity entity, AasxCompatibilityModels. entity.Statements ??= new List(); foreach (var submodelElementWrapper in sourceEntity.statements) { - var sourceSubmodelElement = submodelElementWrapper.submodelElement; - ISubmodelElement outputSubmodelElement = null; + var sourceSubmodelElement = submodelElementWrapper.submodelElement; + ISubmodelElement? outputSubmodelElement = null; if (sourceSubmodelElement != null) { outputSubmodelElement = outputSubmodelElement.ConvertFromV20(sourceSubmodelElement); diff --git a/src/AasxCsharpLibrary/Extensions/ExtendEnvironment.cs b/src/AasxCsharpLibrary/Extensions/ExtendEnvironment.cs index 07ee1d084..fba32429b 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendEnvironment.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendEnvironment.cs @@ -1,6 +1,5 @@ using AdminShellNS; using AdminShellNS.Extensions; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; @@ -8,6 +7,10 @@ namespace Extensions { + using System.Text.Json; + using System.Text.Json.Serialization; + using Environment = AasCore.Aas3_0.Environment; + public static class ExtendEnvironment { #region Environment @@ -112,7 +115,7 @@ public static IEnumerable FindAllReferable(this AasCore.Aas3_0.Envir #if !DoNotUseAasxCompatibilityModels - public static AasCore.Aas3_0.Environment ConvertFromV10(this AasCore.Aas3_0.Environment environment, AasxCompatibilityModels.AdminShellV10.AdministrationShellEnv sourceEnvironement) + public static Environment? ConvertFromV10(this Environment? environment, AasxCompatibilityModels.AdminShellV10.AdministrationShellEnv sourceEnvironement) { //Convert Administration Shells if (!sourceEnvironement.AdministrationShells.IsNullOrEmpty()) @@ -171,7 +174,7 @@ public static AasCore.Aas3_0.Environment ConvertFromV10(this AasCore.Aas3_0.Envi } - public static AasCore.Aas3_0.Environment ConvertFromV20(this AasCore.Aas3_0.Environment environment, AasxCompatibilityModels.AdminShellV20.AdministrationShellEnv sourceEnvironement) + public static Environment? ConvertFromV20(this Environment? environment, AasxCompatibilityModels.AdminShellV20.AdministrationShellEnv sourceEnvironement) { //Convert Administration Shells if (!sourceEnvironement.AdministrationShells.IsNullOrEmpty()) @@ -232,7 +235,7 @@ public static AasCore.Aas3_0.Environment ConvertFromV20(this AasCore.Aas3_0.Envi #endif - public static AasCore.Aas3_0.Environment CreateFromExistingEnvironment(this AasCore.Aas3_0.Environment environment, AasCore.Aas3_0.Environment sourceEnvironment, List filterForAas = null, List filterForAssets = null, List filterForSubmodel = null, List filterForConceptDescriptions = null) + public static AasCore.Aas3_0.Environment CreateFromExistingEnvironment(this AasCore.Aas3_0.Environment environment, Environment? sourceEnvironment, List filterForAas = null, List filterForAssets = null, List filterForSubmodel = null, List filterForConceptDescriptions = null) { if (filterForAas == null) { @@ -311,7 +314,7 @@ public static AasCore.Aas3_0.Environment CreateFromExistingEnvironment(this AasC } - public static void CreateFromExistingEnvRecurseForCDs(this AasCore.Aas3_0.Environment environment, AasCore.Aas3_0.Environment sourceEnvironment, List submodelElements, ref List filterForConceptDescription) + public static void CreateFromExistingEnvRecurseForCDs(this AasCore.Aas3_0.Environment environment, Environment? sourceEnvironment, List submodelElements, ref List filterForConceptDescription) { if (submodelElements.IsNullOrEmpty() || filterForConceptDescription.IsNullOrEmpty()) { @@ -351,7 +354,7 @@ public static void CreateFromExistingEnvRecurseForCDs(this AasCore.Aas3_0.Enviro if (submodelElement is AnnotatedRelationshipElement annotatedRelationshipElement) { - var annotedELements = new List(); + var annotedELements = new List(); foreach (var annotation in annotatedRelationshipElement.Annotations) { annotedELements.Add(annotation); @@ -361,7 +364,7 @@ public static void CreateFromExistingEnvRecurseForCDs(this AasCore.Aas3_0.Enviro if (submodelElement is Operation operation) { - var operationELements = new List(); + var operationELements = new List(); foreach (var inputVariable in operation.InputVariables) { operationELements.Add(inputVariable.Value); @@ -413,25 +416,36 @@ public static AssetAdministrationShell Add(this AasCore.Aas3_0.Environment env, return aas; } - public static JsonWriter SerialiazeJsonToStream(this AasCore.Aas3_0.Environment environment, StreamWriter streamWriter, bool leaveJsonWriterOpen = false) + private static JsonSerializerOptions JsonSerializerOptions = new() + { + WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + ReferenceHandler = ReferenceHandler.Preserve + }; + + public static Utf8JsonWriter SerializeJsonToStream(this AasCore.Aas3_0.Environment environment, StreamWriter streamWriter, bool leaveJsonWriterOpen = false) { streamWriter.AutoFlush = true; - JsonSerializer serializer = new JsonSerializer() - { - NullValueHandling = NullValueHandling.Ignore, - ReferenceLoopHandling = ReferenceLoopHandling.Serialize, - Formatting = Newtonsoft.Json.Formatting.Indented - }; + var utf8JsonWriter = new Utf8JsonWriter(streamWriter.BaseStream, new JsonWriterOptions + { + Indented = true + }); + + JsonSerializer.Serialize(utf8JsonWriter, environment, JsonSerializerOptions); - JsonWriter writer = new JsonTextWriter(streamWriter); - serializer.Serialize(writer, environment); if (leaveJsonWriterOpen) - return writer; - writer.Close(); - return null; + { + utf8JsonWriter.Flush(); + return utf8JsonWriter; + } + else + { + utf8JsonWriter.Dispose(); + return null; + } } - + #endregion #region Submodel Queries @@ -452,7 +466,7 @@ public static IEnumerable FindAllSubmodelGroupedByAAS(this AasCore.Aa } } } - public static ISubmodel FindSubmodel(this AasCore.Aas3_0.Environment environment, IReference submodelReference) + public static ISubmodel FindSubmodel(this Environment? environment, IReference submodelReference) { if (submodelReference == null) { @@ -479,7 +493,7 @@ public static ISubmodel FindSubmodel(this AasCore.Aas3_0.Environment environment return null; } - public static ISubmodel FindSubmodelById(this AasCore.Aas3_0.Environment environment, string? submodelId) + public static ISubmodel FindSubmodelById(this Environment? environment, string? submodelId) { if (string.IsNullOrEmpty(submodelId)) { @@ -525,7 +539,7 @@ public static IEnumerable FindAllSubmodelBySemanticId(this AasCore.Aa #endregion #region AssetAdministrationShell Queries - public static IAssetAdministrationShell FindAasWithSubmodelId(this AasCore.Aas3_0.Environment environment, string? submodelId) + public static IAssetAdministrationShell FindAasWithSubmodelId(this Environment? environment, string? submodelId) { if (submodelId == null) { @@ -537,7 +551,7 @@ public static IAssetAdministrationShell FindAasWithSubmodelId(this AasCore.Aas3_ return aas; } - public static IAssetAdministrationShell FindAasById(this AasCore.Aas3_0.Environment environment, string? aasId) + public static IAssetAdministrationShell FindAasById(this Environment? environment, string? aasId) { if (string.IsNullOrEmpty(aasId)) { @@ -554,7 +568,7 @@ public static IAssetAdministrationShell FindAasById(this AasCore.Aas3_0.Environm #region ConceptDescription Queries public static IConceptDescription FindConceptDescriptionById( - this AasCore.Aas3_0.Environment env, string? cdId) + this Environment? env, string? cdId) { if (string.IsNullOrEmpty(cdId)) return null; @@ -564,7 +578,7 @@ public static IConceptDescription FindConceptDescriptionById( } public static IConceptDescription FindConceptDescriptionByReference( - this AasCore.Aas3_0.Environment env, IReference rf) + this Environment? env, IReference rf) { if (rf == null) return null; @@ -598,8 +612,8 @@ public bool IsValid } public static IReferable FindReferableByReference( - this AasCore.Aas3_0.Environment environment, - IReference reference, + this Environment? environment, + IReference? reference, int keyIndex = 0, List submodelElementList = null, ReferableRootInfo rootInfo = null) @@ -920,7 +934,7 @@ public static List RenameIdentifiable(this AasCore.Aas3_0.Environ return null; } - public static IAssetAdministrationShell FindAasWithAssetInformation(this AasCore.Aas3_0.Environment environment, string? globalAssetId) + public static IAssetAdministrationShell FindAasWithAssetInformation(this Environment? environment, string? globalAssetId) { if (string.IsNullOrEmpty(globalAssetId)) { diff --git a/src/AasxCsharpLibrary/Extensions/ExtendFile.cs b/src/AasxCsharpLibrary/Extensions/ExtendFile.cs index 9e1d8b117..76a6ad9d3 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendFile.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendFile.cs @@ -14,13 +14,13 @@ public static void Set(this File file, file.Value = value; } - public static File ConvertFromV10(this File file, AasxCompatibilityModels.AdminShellV10.File sourceFile) + public static File? ConvertFromV10(this File? file, AasxCompatibilityModels.AdminShellV10.File sourceFile) { file.ContentType = sourceFile.mimeType; file.Value = sourceFile.value; return file; } - public static File ConvertFromV20(this File file, AasxCompatibilityModels.AdminShellV20.File sourceFile) + public static File? ConvertFromV20(this File? file, AasxCompatibilityModels.AdminShellV20.File sourceFile) { file.ContentType = sourceFile.mimeType; file.Value = sourceFile.value; diff --git a/src/AasxCsharpLibrary/Extensions/ExtendIDataSpecificationContent.cs b/src/AasxCsharpLibrary/Extensions/ExtendIDataSpecificationContent.cs index e23d87eec..e442e5062 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendIDataSpecificationContent.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendIDataSpecificationContent.cs @@ -43,7 +43,7 @@ public static IDataSpecificationContent ContentFactoryFor(ContentTypes ct) return null; } - public static ContentTypes GuessContentTypeFor(IReference rf) + public static ContentTypes GuessContentTypeFor(IReference? rf) { foreach (var v in AdminShellUtil.GetEnumValues(new[] { ContentTypes.NoInfo })) if (rf?.MatchesExactlyOneKey(GetKeyFor(v)) == true) @@ -51,7 +51,7 @@ public static ContentTypes GuessContentTypeFor(IReference rf) return ContentTypes.NoInfo; } - public static ContentTypes GuessContentTypeFor(IDataSpecificationContent content) + public static ContentTypes GuessContentTypeFor(IDataSpecificationContent? content) { if (content is DataSpecificationIec61360) return ContentTypes.Iec61360; diff --git a/src/AasxCsharpLibrary/Extensions/ExtendIIdentifiable.cs b/src/AasxCsharpLibrary/Extensions/ExtendIIdentifiable.cs index 82b78da52..fe1673e5f 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendIIdentifiable.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendIIdentifiable.cs @@ -13,7 +13,7 @@ public static string ToStringExtended(this List identifiables, st } #endregion - public static Reference GetReference(this IIdentifiable identifiable) + public static Reference? GetReference(this IIdentifiable identifiable) { var key = new Key(ExtensionsUtil.GetKeyType(identifiable), identifiable.Id); // TODO (jtikekar, 2023-09-04): if model or Global reference? diff --git a/src/AasxCsharpLibrary/Extensions/ExtendIReferable.cs b/src/AasxCsharpLibrary/Extensions/ExtendIReferable.cs index b12f21cb4..c81561a7b 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendIReferable.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendIReferable.cs @@ -131,7 +131,7 @@ public static string ToIdShortString(this IReferable rf) return rf.IdShort.Trim(); } - public static Reference GetReference(this IReferable referable) + public static Reference? GetReference(this IReferable referable) { if (referable is IIdentifiable identifiable) { @@ -325,9 +325,9 @@ public static void CollectReferencesByParent(this IReferable referable, List 0); } - public static IEnumerable EnumerateChildren(this IReferable referable) + public static IEnumerable EnumerateChildren(this IReferable? referable) { if (referable is Submodel submodel && submodel.SubmodelElements != null) { @@ -426,7 +426,7 @@ public static IEnumerable EnumerateChildren(this IReferable re } - public static void SetAllParentsAndTimestamps(this IReferable referable, IReferable parent, DateTime timeStamp, DateTime timeStampCreate) + public static void SetAllParentsAndTimestamps(this IReferable? referable, IReferable? parent, DateTime timeStamp, DateTime timeStampCreate) { // if (parent == null) // return; @@ -498,7 +498,7 @@ public static Key ToKey(this IReferable rf) return new Key(sd.KeyType.Value, rf.IdShort); } - public static System.Text.Json.Nodes.JsonNode ToJsonObject(List classes) + public static System.Text.Json.Nodes.JsonNode ToJsonObject(List classes) { var jar = new System.Text.Json.Nodes.JsonArray(); if (classes != null) @@ -556,7 +556,7 @@ public static IExtension HasExtensionOfName(this IReferable rf, string extension return null; } - public static Extension Add(this IReferable rf, Extension ext) + public static Extension Add(this IReferable? rf, Extension ext) { if (rf.Extensions == null) rf.Extensions = new List(); @@ -564,7 +564,7 @@ public static Extension Add(this IReferable rf, Extension ext) return ext; } - public static void MigrateV20QualifiersToExtensions(this IReferable rf) + public static void MigrateV20QualifiersToExtensions(this IReferable? rf) { // access if (!(rf is IQualifiable iq) || iq.Qualifiers == null || !(rf is IHasExtensions ihe)) diff --git a/src/AasxCsharpLibrary/Extensions/ExtendISubmodelElement.cs b/src/AasxCsharpLibrary/Extensions/ExtendISubmodelElement.cs index fa9996722..08440f93d 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendISubmodelElement.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendISubmodelElement.cs @@ -27,7 +27,7 @@ public static List Copy(this List original) return res; } - public static object AddChild(this ISubmodelElement submodelElement, ISubmodelElement childSubmodelElement, EnumerationPlacmentBase placement = null) + public static object? AddChild(this ISubmodelElement submodelElement, ISubmodelElement? childSubmodelElement, EnumerationPlacmentBase placement = null) { if (submodelElement is AnnotatedRelationshipElement annotatedRelationshipElement) { @@ -119,7 +119,7 @@ public static IEnumerable FindAllParents(this ISubmodelElement submo } public static IEnumerable FindAllParentsWithSemanticId( - this ISubmodelElement submodelElement, Reference semId, + this ISubmodelElement submodelElement, Reference? semId, bool includeThis = false, bool includeSubmodel = false, bool passOverMiss = false) { return (FindAllParents(submodelElement, @@ -172,7 +172,7 @@ public static IQualifier FindQualifierOfType(this ISubmodelElement submodelEleme return null; } - public static Reference GetModelReference(this ISubmodelElement sme, bool includeParents = true) + public static Reference? GetModelReference(this ISubmodelElement sme, bool includeParents = true) { // this will be the tail of our chain var keyList = new List(); @@ -248,9 +248,9 @@ public static IEnumerable FindDeep(this ISubmodelElement submodelElement) //} } - public static ISubmodelElement ConvertFromV10(this ISubmodelElement submodelElement, AdminShellV10.SubmodelElement sourceSubmodelElement, bool shallowCopy = false) + public static ISubmodelElement? ConvertFromV10(this ISubmodelElement? submodelElement, AdminShellV10.SubmodelElement sourceSubmodelElement, bool shallowCopy = false) { - ISubmodelElement outputSubmodelElement = null; + ISubmodelElement? outputSubmodelElement = null; if (sourceSubmodelElement != null) { if (sourceSubmodelElement is AdminShellV10.SubmodelElementCollection collection) @@ -279,7 +279,7 @@ public static ISubmodelElement ConvertFromV10(this ISubmodelElement submodelElem } else if (sourceSubmodelElement is AdminShellV10.RelationshipElement sourceRelationshipElement) { - var newFirst = ExtensionsUtil.ConvertReferenceFromV10(sourceRelationshipElement.first, ReferenceTypes.ModelReference); + var newFirst = ExtensionsUtil.ConvertReferenceFromV10(sourceRelationshipElement.first, ReferenceTypes.ModelReference); var newSecond = ExtensionsUtil.ConvertReferenceFromV10(sourceRelationshipElement.second, ReferenceTypes.ModelReference); outputSubmodelElement = new RelationshipElement(newFirst, newSecond); } @@ -294,7 +294,7 @@ public static ISubmodelElement ConvertFromV10(this ISubmodelElement submodelElem { if (inputVariable.value.submodelElement != null) { - ISubmodelElement newSubmodelElement = null; + ISubmodelElement? newSubmodelElement = null; newSubmodelElement = newSubmodelElement.ConvertFromV10(inputVariable.value.submodelElement); var newOpVariable = new OperationVariable(newSubmodelElement); newInputVariables.Add(newOpVariable); @@ -308,7 +308,7 @@ public static ISubmodelElement ConvertFromV10(this ISubmodelElement submodelElem { if (outputVariable.value.submodelElement != null) { - ISubmodelElement newSubmodelElement = null; + ISubmodelElement? newSubmodelElement = null; newSubmodelElement = newSubmodelElement.ConvertFromV10(outputVariable.value.submodelElement); var newOpVariable = new OperationVariable(newSubmodelElement); newOutputVariables.Add(newOpVariable); @@ -326,7 +326,7 @@ public static ISubmodelElement ConvertFromV10(this ISubmodelElement submodelElem return outputSubmodelElement; } - private static void BasicConversionFromV10(this ISubmodelElement submodelElement, AdminShellV10.SubmodelElement sourceSubmodelElement) + private static void BasicConversionFromV10(this ISubmodelElement? submodelElement, AdminShellV10.SubmodelElement sourceSubmodelElement) { if (!string.IsNullOrEmpty(sourceSubmodelElement.idShort)) { @@ -398,9 +398,9 @@ private static void BasicConversionFromV10(this ISubmodelElement submodelElement } } - public static ISubmodelElement ConvertFromV20(this ISubmodelElement submodelElement, AdminShellV20.SubmodelElement sourceSubmodelElement, bool shallowCopy = false) + public static ISubmodelElement? ConvertFromV20(this ISubmodelElement? submodelElement, AdminShellV20.SubmodelElement sourceSubmodelElement, bool shallowCopy = false) { - ISubmodelElement outputSubmodelElement = null; + ISubmodelElement? outputSubmodelElement = null; if (sourceSubmodelElement != null) { if (sourceSubmodelElement is AdminShellV20.SubmodelElementCollection collection) @@ -440,14 +440,14 @@ public static ISubmodelElement ConvertFromV20(this ISubmodelElement submodelElem } else if (sourceSubmodelElement is AdminShellV20.AnnotatedRelationshipElement sourceAnnotedRelationshipElement) { - var newFirst = ExtensionsUtil.ConvertReferenceFromV20(sourceAnnotedRelationshipElement.first, ReferenceTypes.ModelReference); - var newSecond = ExtensionsUtil.ConvertReferenceFromV20(sourceAnnotedRelationshipElement.second, ReferenceTypes.ModelReference); - var newAnnotedRelElement = new AnnotatedRelationshipElement(newFirst, newSecond); + var newFirst = ExtensionsUtil.ConvertReferenceFromV20(sourceAnnotedRelationshipElement.first, ReferenceTypes.ModelReference); + var newSecond = ExtensionsUtil.ConvertReferenceFromV20(sourceAnnotedRelationshipElement.second, ReferenceTypes.ModelReference); + var newAnnotedRelElement = new AnnotatedRelationshipElement(newFirst, newSecond); outputSubmodelElement = newAnnotedRelElement.ConvertAnnotationsFromV20(sourceAnnotedRelationshipElement); } else if (sourceSubmodelElement is AdminShellV20.RelationshipElement sourceRelationshipElement) { - var newFirst = ExtensionsUtil.ConvertReferenceFromV20(sourceRelationshipElement.first, ReferenceTypes.ModelReference); + var newFirst = ExtensionsUtil.ConvertReferenceFromV20(sourceRelationshipElement.first, ReferenceTypes.ModelReference); var newSecond = ExtensionsUtil.ConvertReferenceFromV20(sourceRelationshipElement.second, ReferenceTypes.ModelReference); outputSubmodelElement = new RelationshipElement(newFirst, newSecond); } @@ -474,7 +474,7 @@ public static ISubmodelElement ConvertFromV20(this ISubmodelElement submodelElem { if (inputVariable.value.submodelElement != null) { - ISubmodelElement newSubmodelElement = null; + ISubmodelElement? newSubmodelElement = null; newSubmodelElement = newSubmodelElement.ConvertFromV20(inputVariable.value.submodelElement); var newOpVariable = new OperationVariable(newSubmodelElement); newInputVariables.Add(newOpVariable); @@ -488,7 +488,7 @@ public static ISubmodelElement ConvertFromV20(this ISubmodelElement submodelElem { if (outputVariable.value.submodelElement != null) { - ISubmodelElement newSubmodelElement = null; + ISubmodelElement? newSubmodelElement = null; newSubmodelElement = newSubmodelElement.ConvertFromV20(outputVariable.value.submodelElement); var newOpVariable = new OperationVariable(newSubmodelElement); newOutputVariables.Add(newOpVariable); @@ -502,7 +502,7 @@ public static ISubmodelElement ConvertFromV20(this ISubmodelElement submodelElem { if (inOutVariable.value.submodelElement != null) { - ISubmodelElement newSubmodelElement = null; + ISubmodelElement? newSubmodelElement = null; newSubmodelElement = newSubmodelElement.ConvertFromV20(inOutVariable.value.submodelElement); var newOpVariable = new OperationVariable(newSubmodelElement); newInOutVariables.Add(newOpVariable); @@ -526,7 +526,7 @@ public static ISubmodelElement ConvertFromV20(this ISubmodelElement submodelElem return outputSubmodelElement; } - private static void BasicConversionFromV20(this ISubmodelElement submodelElement, AdminShellV20.SubmodelElement sourceSubmodelElement) + private static void BasicConversionFromV20(this ISubmodelElement? submodelElement, AdminShellV20.SubmodelElement sourceSubmodelElement) { if (!string.IsNullOrEmpty(sourceSubmodelElement.idShort)) submodelElement.IdShort = sourceSubmodelElement.idShort; @@ -662,7 +662,7 @@ public static IReferable FindReferableByReference( return null; } - public static IEnumerable FindDeep(this List submodelElements, Predicate match = null) where T : ISubmodelElement + public static IEnumerable FindDeep(this List submodelElements, Predicate match = null) where T : ISubmodelElement { foreach (var smw in submodelElements) { @@ -694,7 +694,7 @@ public static IEnumerable FindDeep(this List submodelEle if (current is Operation op) { - var operationVariables = new List(); + var operationVariables = new List(); foreach (var opVariable in op.InputVariables) { operationVariables.Add(opVariable.Value); @@ -1013,7 +1013,7 @@ public static IEnumerable FindAllSemanticIdAs(this List } public static IEnumerable FindAllSemanticIdAs(this List submodelELements, - Reference semId, MatchMode matchMode = MatchMode.Strict) + Reference? semId, MatchMode matchMode = MatchMode.Strict) where T : ISubmodelElement { foreach (var submodelElement in submodelELements) @@ -1031,7 +1031,7 @@ public static T FindFirstSemanticIdAs(this List submodelEle } public static T FindFirstSemanticIdAs(this List submodelElements, - Reference semId, MatchMode matchMode = MatchMode.Strict) + Reference? semId, MatchMode matchMode = MatchMode.Strict) where T : ISubmodelElement { return submodelElements.FindAllSemanticIdAs(semId, matchMode).FirstOrDefault(); diff --git a/src/AasxCsharpLibrary/Extensions/ExtendMultiLanguageProperty.cs b/src/AasxCsharpLibrary/Extensions/ExtendMultiLanguageProperty.cs index 2c6a3ffbe..c6c246ab0 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendMultiLanguageProperty.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendMultiLanguageProperty.cs @@ -23,7 +23,7 @@ public static void ValueFromText(this MultiLanguageProperty multiLanguagePropert return "" + multiLanguageProperty.Value?.GetDefaultString(defaultLang); } - public static MultiLanguageProperty ConvertFromV20(this MultiLanguageProperty property, AasxCompatibilityModels.AdminShellV20.MultiLanguageProperty sourceProperty) + public static MultiLanguageProperty? ConvertFromV20(this MultiLanguageProperty? property, AasxCompatibilityModels.AdminShellV20.MultiLanguageProperty sourceProperty) { if (sourceProperty == null) { diff --git a/src/AasxCsharpLibrary/Extensions/ExtendOperation.cs b/src/AasxCsharpLibrary/Extensions/ExtendOperation.cs index 9e68c0f7f..e56a2b21c 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendOperation.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendOperation.cs @@ -8,7 +8,7 @@ public static class ExtendOperation { #region AasxPackageExplorer - public static object AddChild(this Operation operation, ISubmodelElement childSubmodelElement, EnumerationPlacmentBase placement = null) + public static object? AddChild(this Operation operation, ISubmodelElement? childSubmodelElement, EnumerationPlacmentBase placement = null) { // not enough information to select list of children? var pl = placement as EnumerationPlacmentOperationVariable; diff --git a/src/AasxCsharpLibrary/Extensions/ExtendProperty.cs b/src/AasxCsharpLibrary/Extensions/ExtendProperty.cs index fc59f3180..90b9599eb 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendProperty.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendProperty.cs @@ -50,7 +50,7 @@ public static bool IsValueTrue(this Property property) // no return null; } - public static Property ConvertFromV10(this Property property, AasxCompatibilityModels.AdminShellV10.Property sourceProperty) + public static Property? ConvertFromV10(this Property? property, AasxCompatibilityModels.AdminShellV10.Property sourceProperty) { if (sourceProperty == null) { @@ -87,7 +87,7 @@ public static Property ConvertFromV10(this Property property, AasxCompatibilityM return property; } - public static Property ConvertFromV20(this Property property, AasxCompatibilityModels.AdminShellV20.Property sourceProperty) + public static Property? ConvertFromV20(this Property? property, AasxCompatibilityModels.AdminShellV20.Property sourceProperty) { if (sourceProperty == null) { diff --git a/src/AasxCsharpLibrary/Extensions/ExtendRange.cs b/src/AasxCsharpLibrary/Extensions/ExtendRange.cs index 8f61a233f..8249927a7 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendRange.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendRange.cs @@ -10,14 +10,14 @@ public static class ExtendRange return "" + range.Min + " .. " + range.Max; } - public static AasCore.Aas3_0.Range ConvertFromV20(this AasCore.Aas3_0.Range range, AasxCompatibilityModels.AdminShellV20.Range sourceRange) + public static AAS.Range? ConvertFromV20(this AAS.Range? range, AasxCompatibilityModels.AdminShellV20.Range sourceRange) { if (sourceRange == null) { return null; } - var propertyType = AAS.Stringification.DataTypeDefXsdFromString("xs:" + sourceRange.valueType); + var propertyType = Stringification.DataTypeDefXsdFromString("xs:" + sourceRange.valueType); if (propertyType != null) { range.ValueType = (AAS.DataTypeDefXsd)propertyType; diff --git a/src/AasxCsharpLibrary/Extensions/ExtendReference.cs b/src/AasxCsharpLibrary/Extensions/ExtendReference.cs index b96d5d7ae..4e3b00a26 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendReference.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendReference.cs @@ -140,7 +140,7 @@ public static bool Matches(this IReference reference, string? id) return false; } - public static bool Matches(this IReference reference, IReference otherReference, MatchMode matchMode = MatchMode.Strict) + public static bool Matches(this IReference? reference, IReference? otherReference, MatchMode matchMode = MatchMode.Strict) { if (reference.Keys == null || reference.Keys.Count == 0 || otherReference?.Keys == null || otherReference.Keys.Count == 0) { @@ -196,7 +196,7 @@ public static bool MatchesExactlyOneKey(this IReference reference, Key key, Matc return output; } - public static Key GetAsExactlyOneKey(this IReference reference) + public static Key GetAsExactlyOneKey(this IReference? reference) { if (reference.Keys == null || reference.Keys.Count != 1) { diff --git a/src/AasxCsharpLibrary/Extensions/ExtendRelationshipElement.cs b/src/AasxCsharpLibrary/Extensions/ExtendRelationshipElement.cs index 3cface08f..580fa5cbc 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendRelationshipElement.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendRelationshipElement.cs @@ -5,7 +5,7 @@ namespace Extensions public static class ExtendRelationshipElement { public static AAS.RelationshipElement Set(this AAS.RelationshipElement elem, - AAS.Reference first, AAS.Reference second) + Reference? first, Reference? second) { elem.First = first; elem.Second = second; diff --git a/src/AasxCsharpLibrary/Extensions/ExtendSubmodel.cs b/src/AasxCsharpLibrary/Extensions/ExtendSubmodel.cs index 533a2cbb6..e2f0b1b9d 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendSubmodel.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendSubmodel.cs @@ -70,7 +70,7 @@ public static Tuple ToCaptionInfo(this Submodel submodel) public static IEnumerable FindAllReferences(this ISubmodel submodel) { // not nice: use temp list - var temp = new List(); + var temp = new List(); // recurse submodel.RecurseOnSubmodelElements(null, (state, parents, sme) => @@ -186,8 +186,8 @@ public static Submodel ConvertFromV10(this Submodel submodel, AasxCompatibilityM foreach (var submodelElementWrapper in sourceSubmodel.submodelElements) { - var sourceSubmodelELement = submodelElementWrapper.submodelElement; - ISubmodelElement outputSubmodelElement = null; + var sourceSubmodelELement = submodelElementWrapper.submodelElement; + ISubmodelElement? outputSubmodelElement = null; if (sourceSubmodelELement != null) { outputSubmodelElement = outputSubmodelElement.ConvertFromV10(sourceSubmodelELement, shallowCopy); @@ -275,8 +275,8 @@ public static Submodel ConvertFromV20(this Submodel sm, AasxCompatibilityModels. foreach (var submodelElementWrapper in srcSM.submodelElements) { - var sourceSubmodelELement = submodelElementWrapper.submodelElement; - ISubmodelElement outputSubmodelElement = null; + var sourceSubmodelELement = submodelElementWrapper.submodelElement; + ISubmodelElement? outputSubmodelElement = null; if (sourceSubmodelELement != null) { outputSubmodelElement = outputSubmodelElement.ConvertFromV20(sourceSubmodelELement, shallowCopy); @@ -373,14 +373,14 @@ public static ISubmodelElement FindSubmodelElementByIdShort(this ISubmodel submo } } - public static void SetAllParents(this ISubmodel submodel, DateTime timestamp) + public static void SetAllParents(this ISubmodel? submodel, DateTime timestamp) { if (submodel.SubmodelElements != null) foreach (var sme in submodel.SubmodelElements) SetParentsForSME(submodel, sme, timestamp); } - public static void SetParentsForSME(IReferable parent, ISubmodelElement submodelElement, DateTime timestamp) + public static void SetParentsForSME(IReferable? parent, ISubmodelElement? submodelElement, DateTime timestamp) { if (submodelElement == null) return; @@ -396,7 +396,7 @@ public static void SetParentsForSME(IReferable parent, ISubmodelElement submodel } } - public static void SetParentsForSME(IReferable parent, ISubmodelElement submodelElement) + public static void SetParentsForSME(IReferable? parent, ISubmodelElement? submodelElement) { if (submodelElement == null) return; @@ -409,18 +409,18 @@ public static void SetParentsForSME(IReferable parent, ISubmodelElement submodel } } - public static void SetAllParents(this ISubmodel submodel) + public static void SetAllParents(this ISubmodel? submodel) { if (submodel.SubmodelElements != null) foreach (var sme in submodel.SubmodelElements) SetParentsForSME(submodel, sme); } - public static void SetParentAndTimestamp(this ISubmodel submodel) + public static void SetParentAndTimestamp(this ISubmodel? submodel) { SetParentAndTimestamp(submodel, DateTime.UtcNow); } - public static void SetParentAndTimestamp(this ISubmodel submodel, DateTime timeStamp) + public static void SetParentAndTimestamp(this ISubmodel? submodel, DateTime timeStamp) { submodel.SetTimeStamp(timeStamp); diff --git a/src/AasxCsharpLibrary/Extensions/ExtendSubmodelElementCollection.cs b/src/AasxCsharpLibrary/Extensions/ExtendSubmodelElementCollection.cs index 223bef4fc..8059762c9 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendSubmodelElementCollection.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendSubmodelElementCollection.cs @@ -44,7 +44,7 @@ public static void Remove(this SubmodelElementCollection submodelElementCollecti } } - public static object AddChild(this SubmodelElementCollection submodelElementCollection, ISubmodelElement childSubmodelElement, EnumerationPlacmentBase placement = null) + public static object? AddChild(this SubmodelElementCollection submodelElementCollection, ISubmodelElement? childSubmodelElement, EnumerationPlacmentBase placement = null) { if (childSubmodelElement == null) return null; @@ -65,7 +65,7 @@ public static T FindFirstIdShortAs(this ISubmodelElementCollection submodelEl return (T)submodelElement; } - public static SubmodelElementCollection ConvertFromV10(this SubmodelElementCollection submodelElementCollection, AasxCompatibilityModels.AdminShellV10.SubmodelElementCollection sourceSmeCollection, bool shallowCopy = false) + public static SubmodelElementCollection? ConvertFromV10(this SubmodelElementCollection? submodelElementCollection, AasxCompatibilityModels.AdminShellV10.SubmodelElementCollection sourceSmeCollection, bool shallowCopy = false) { if (sourceSmeCollection == null) return null; @@ -81,8 +81,8 @@ public static SubmodelElementCollection ConvertFromV10(this SubmodelElementColle { foreach (var submodelElementWrapper in sourceSmeCollection.value) { - var sourceSubmodelElement = submodelElementWrapper.submodelElement; - ISubmodelElement outputSubmodelElement = null; + var sourceSubmodelElement = submodelElementWrapper.submodelElement; + ISubmodelElement? outputSubmodelElement = null; if (sourceSubmodelElement != null) { outputSubmodelElement = outputSubmodelElement.ConvertFromV10(sourceSubmodelElement, shallowCopy); @@ -96,7 +96,7 @@ public static SubmodelElementCollection ConvertFromV10(this SubmodelElementColle return submodelElementCollection; } - public static SubmodelElementCollection ConvertFromV20(this SubmodelElementCollection submodelElementCollection, AasxCompatibilityModels.AdminShellV20.SubmodelElementCollection sourceSmeCollection, bool shallowCopy = false) + public static SubmodelElementCollection? ConvertFromV20(this SubmodelElementCollection? submodelElementCollection, AasxCompatibilityModels.AdminShellV20.SubmodelElementCollection sourceSmeCollection, bool shallowCopy = false) { if (sourceSmeCollection == null) return null; @@ -112,8 +112,8 @@ public static SubmodelElementCollection ConvertFromV20(this SubmodelElementColle { foreach (var submodelElementWrapper in sourceSmeCollection.value) { - var sourceSubmodelElement = submodelElementWrapper.submodelElement; - ISubmodelElement outputSubmodelElement = null; + var sourceSubmodelElement = submodelElementWrapper.submodelElement; + ISubmodelElement? outputSubmodelElement = null; if (sourceSubmodelElement != null) { outputSubmodelElement = outputSubmodelElement.ConvertFromV20(sourceSubmodelElement, shallowCopy); diff --git a/src/AasxCsharpLibrary/Extensions/ExtendSubmodelElementList.cs b/src/AasxCsharpLibrary/Extensions/ExtendSubmodelElementList.cs index d8f6f97d9..a7b506315 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendSubmodelElementList.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendSubmodelElementList.cs @@ -55,7 +55,7 @@ public static void Remove(this SubmodelElementList submodelElementList, ISubmode } } - public static object AddChild(this SubmodelElementList submodelElementList, ISubmodelElement childSubmodelElement, EnumerationPlacmentBase placement = null) + public static object? AddChild(this SubmodelElementList submodelElementList, ISubmodelElement? childSubmodelElement, EnumerationPlacmentBase placement = null) { if (childSubmodelElement == null) return null; diff --git a/src/AasxCsharpLibrary/Extensions/ExtensionsUtil.cs b/src/AasxCsharpLibrary/Extensions/ExtensionsUtil.cs index 3a0a0b96a..44898111e 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtensionsUtil.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtensionsUtil.cs @@ -7,9 +7,9 @@ namespace Extensions; public static class ExtensionsUtil { - public static Reference ConvertReferenceFromV10(AdminShellV10.Reference sourceReference, ReferenceTypes referenceTypes) + public static Reference? ConvertReferenceFromV10(AdminShellV10.Reference sourceReference, ReferenceTypes referenceTypes) { - Reference outputReference = null; + Reference? outputReference = null; if (sourceReference != null && !sourceReference.IsEmpty) { var keyList = new List(); @@ -32,9 +32,9 @@ public static Reference ConvertReferenceFromV10(AdminShellV10.Reference sourceRe return outputReference; } - public static Reference ConvertReferenceFromV20(AdminShellV20.Reference sourceReference, ReferenceTypes referenceTypes) + public static Reference? ConvertReferenceFromV20(AdminShellV20.Reference sourceReference, ReferenceTypes referenceTypes) { - Reference outputReference = null; + Reference? outputReference = null; if (sourceReference != null && !sourceReference.IsEmpty) { var keyList = new List(); diff --git a/src/AasxCsharpLibrary/Extensions/LocatedReference.cs b/src/AasxCsharpLibrary/Extensions/LocatedReference.cs index a99558b3e..39955d98b 100644 --- a/src/AasxCsharpLibrary/Extensions/LocatedReference.cs +++ b/src/AasxCsharpLibrary/Extensions/LocatedReference.cs @@ -3,10 +3,10 @@ public class LocatedReference { public IIdentifiable Identifiable; - public IReference Reference; + public IReference? Reference; public LocatedReference() { } - public LocatedReference(IIdentifiable identifiable, IReference reference) + public LocatedReference(IIdentifiable identifiable, IReference? reference) { Identifiable = identifiable; Reference = reference; diff --git a/src/AasxServer.sln b/src/AasxServer.sln index d052c8a81..f1a5e4a4c 100644 --- a/src/AasxServer.sln +++ b/src/AasxServer.sln @@ -98,6 +98,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IO.Swagger.Registry.Lib.V3. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AasxServerBlazorTests", "AasxServerBlazorTests\AasxServerBlazorTests.csproj", "{731275DC-5730-49FB-A721-3A39EE3F516E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AasxCsharpLibrary.Tests", "AasxCsharpLibrary.Tests\AasxCsharpLibrary.Tests.csproj", "{B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -417,6 +419,24 @@ Global {731275DC-5730-49FB-A721-3A39EE3F516E}.Release|x64.Build.0 = Release|Any CPU {731275DC-5730-49FB-A721-3A39EE3F516E}.Release|x86.ActiveCfg = Release|Any CPU {731275DC-5730-49FB-A721-3A39EE3F516E}.Release|x86.Build.0 = Release|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.Debug|x64.ActiveCfg = Debug|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.Debug|x64.Build.0 = Debug|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.Debug|x86.ActiveCfg = Debug|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.Debug|x86.Build.0 = Debug|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.DebugSlow|Any CPU.ActiveCfg = Debug|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.DebugSlow|Any CPU.Build.0 = Debug|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.DebugSlow|x64.ActiveCfg = Debug|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.DebugSlow|x64.Build.0 = Debug|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.DebugSlow|x86.ActiveCfg = Debug|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.DebugSlow|x86.Build.0 = Debug|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.Release|Any CPU.Build.0 = Release|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.Release|x64.ActiveCfg = Release|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.Release|x64.Build.0 = Release|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.Release|x86.ActiveCfg = Release|Any CPU + {B9B7BFEC-AEBB-42DB-A1C5-DAB16029F850}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/AasxServerAspNetCore/AasxServerAspNetCore.csproj b/src/AasxServerAspNetCore/AasxServerAspNetCore.csproj index 255513546..d86b0f7e6 100644 --- a/src/AasxServerAspNetCore/AasxServerAspNetCore.csproj +++ b/src/AasxServerAspNetCore/AasxServerAspNetCore.csproj @@ -15,7 +15,6 @@ - diff --git a/src/AasxServerAspNetCore/Startup.cs b/src/AasxServerAspNetCore/Startup.cs index 2676d8b57..fdfc29254 100644 --- a/src/AasxServerAspNetCore/Startup.cs +++ b/src/AasxServerAspNetCore/Startup.cs @@ -1,12 +1,15 @@ //var builder = WebApplication.CreateBuilder(args); //var app = builder.Build(); +using System.Text.Json; +using System.Text.Json.Serialization; using AasSecurity; using AasxServerDB; using AasxServerStandardBib.Extensions; using AasxServerStandardBib.Interfaces; using AasxServerStandardBib.Logging; using AasxServerStandardBib.Services; +using AdminShellNS; using IO.Swagger.Controllers; using IO.Swagger.Lib.V3.Formatters; using IO.Swagger.Lib.V3.Interfaces; @@ -14,6 +17,7 @@ using IO.Swagger.Lib.V3.SerializationModifiers.Mappers; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; using IO.Swagger.Lib.V3.Services; +using IO.Swagger.Models; using IO.Swagger.Registry.Lib.V3.Formatters; using IO.Swagger.Registry.Lib.V3.Interfaces; using IO.Swagger.Registry.Lib.V3.Services; @@ -21,8 +25,6 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.OpenApi.Models; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Serialization; internal class Startup { @@ -42,28 +44,28 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(Configuration); services.Configure(options => - { - options.AllowSynchronousIO = true; - options.Limits.MaxRequestBodySize = int.MaxValue; - }); + { + options.AllowSynchronousIO = true; + options.Limits.MaxRequestBodySize = int.MaxValue; + }); services.Configure(x => - { - x.ValueLengthLimit = int.MaxValue; - x.MultipartBodyLengthLimit = int.MaxValue; - x.MultipartHeadersLengthLimit = int.MaxValue; - }); + { + x.ValueLengthLimit = int.MaxValue; + x.MultipartBodyLengthLimit = int.MaxValue; + x.MultipartHeadersLengthLimit = int.MaxValue; + }); services.AddCors(options => - { - options.AddPolicy(_corsPolicyName, - builder => - { - builder - .AllowAnyOrigin() // Pass "Allowed Hosts" from appsettings.json - .AllowAnyMethod() - .AllowAnyHeader(); - }); - }); + { + options.AddPolicy(_corsPolicyName, + builder => + { + builder + .AllowAnyOrigin() // Pass "Allowed Hosts" from appsettings.json + .AllowAnyMethod() + .AllowAnyHeader(); + }); + }); services.AddControllers(); services.AddLazyResolution(); @@ -89,6 +91,7 @@ public void ConfigureServices(IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -100,74 +103,76 @@ public void ConfigureServices(IServiceCollection services) // Add framework services. services .AddLogging(config => - { - config.AddConsole(); - }) + { + config.AddConsole(); + }) .AddMvc(options => - { - options.InputFormatters.RemoveType(); - options.OutputFormatters.RemoveType(); - options.InputFormatters.Add(new AasRequestFormatter()); - options.OutputFormatters.Add(new AasResponseFormatter()); - options.InputFormatters.Add(new AasDescriptorRequestFormatter()); - options.OutputFormatters.Add(new AasDescriptorResponseFormatter()); - - }) - .AddNewtonsoftJson(opts => - { - opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver() - { - NamingStrategy = new CamelCaseNamingStrategy() { - // Do not change dictionary keys casing - ProcessDictionaryKeys = false - } - }; - opts.SerializerSettings.Converters.Add(new StringEnumConverter(new CamelCaseNamingStrategy())); - opts.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore; - }); + // Remove the default System.Text.Json formatters + options.InputFormatters.RemoveType(); + options.OutputFormatters.RemoveType(); + + // Add your custom formatters + options.InputFormatters.Add(new AasRequestFormatter()); + options.OutputFormatters.Add(new AasResponseFormatter()); + options.InputFormatters.Add(new AasDescriptorRequestFormatter()); + options.OutputFormatters.Add(new AasDescriptorResponseFormatter()); + }) + .AddJsonOptions(opts => + { + opts.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + opts.JsonSerializerOptions.DictionaryKeyPolicy = null; // Preserve dictionary key casing + opts.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + + // Add custom converters if needed + opts.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)); + + // Add other custom converters if required + opts.JsonSerializerOptions.Converters.Add(new AdminShellConverters.JsonAasxConverter("modelType", "name")); + }); services - .AddSwaggerGen(c => - { - c.SwaggerDoc("Final-Draft", new OpenApiInfo - { - Version = "Final-Draft", - Title = "DotAAS Part 2 | HTTP/REST | Asset Administration Shell Repository", - Description = "DotAAS Part 2 | HTTP/REST | Asset Administration Shell Repository (ASP.NET Core 3.1)", - Contact = new OpenApiContact() - { - Name = "Michael Hoffmeister, Torben Miny, Andreas Orzelski, Manuel Sauer, Constantin Ziesche", - Url = new Uri("https://github.com/swagger-api/swagger-codegen"), - Email = "" - }, - TermsOfService = new Uri("https://github.com/admin-shell-io/aas-specs") - }); - - c.EnableAnnotations(); - c.CustomSchemaIds(type => type.FullName); - - //string swaggerCommentedAssembly = typeof(AssetAdministrationShellEnvironmentAPIController).Assembly.GetName().Name; - var swaggerCommentedAssembly = typeof(AssetAdministrationShellRepositoryAPIApiController).Assembly.GetName().Name; - c.IncludeXmlComments($"{AppContext.BaseDirectory}{System.IO.Path.DirectorySeparatorChar}{swaggerCommentedAssembly}.xml"); - - // Include DataAnnotation attributes on Controller Action parameters as Swagger validation rules (e.g required, pattern, ..) - // Use [ValidateModelState] on Actions to actually validate it in C# as well! - - c.OperationFilter(); - }); + .AddSwaggerGen(c => + { + c.SwaggerDoc("Final-Draft", + new OpenApiInfo + { + Version = "Final-Draft", + Title = "DotAAS Part 2 | HTTP/REST | Asset Administration Shell Repository", + Description = "DotAAS Part 2 | HTTP/REST | Asset Administration Shell Repository (ASP.NET Core 3.1)", + Contact = new OpenApiContact() + { + Name = "Michael Hoffmeister, Torben Miny, Andreas Orzelski, Manuel Sauer, Constantin Ziesche", + Url = new Uri("https://github.com/swagger-api/swagger-codegen"), + Email = "" + }, + TermsOfService = new Uri("https://github.com/admin-shell-io/aas-specs") + }); + + c.EnableAnnotations(); + c.CustomSchemaIds(type => type.FullName); + + //string swaggerCommentedAssembly = typeof(AssetAdministrationShellEnvironmentAPIController).Assembly.GetName().Name; + var swaggerCommentedAssembly = typeof(AssetAdministrationShellRepositoryAPIApiController).Assembly.GetName().Name; + c.IncludeXmlComments($"{AppContext.BaseDirectory}{System.IO.Path.DirectorySeparatorChar}{swaggerCommentedAssembly}.xml"); + + // Include DataAnnotation attributes on Controller Action parameters as Swagger validation rules (e.g required, pattern, ..) + // Use [ValidateModelState] on Actions to actually validate it in C# as well! + + c.OperationFilter(); + }); services.AddAuthentication("AasSecurityAuth") .AddScheme("AasSecurityAuth", null); services.AddAuthorization(c => - { - c.AddPolicy("SecurityPolicy", policy => - { - policy.AuthenticationSchemes.Add("AasSecurityAuth"); - policy.Requirements.Add(new SecurityRequirement()); - }); - }); + { + c.AddPolicy("SecurityPolicy", policy => + { + policy.AuthenticationSchemes.Add("AasSecurityAuth"); + policy.Requirements.Add(new SecurityRequirement()); + }); + }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) @@ -197,15 +202,13 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), // specifying the Swagger JSON endpoint. app.UseSwaggerUI(c => - { - c.SwaggerEndpoint("Final-Draft/swagger.json", "DotAAS Part 2 | HTTP/REST | Asset Administration Shell Repository"); - }); + { + c.SwaggerEndpoint("Final-Draft/swagger.json", "DotAAS Part 2 | HTTP/REST | Asset Administration Shell Repository"); + }); app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - }); - - + { + endpoints.MapControllers(); + }); } } \ No newline at end of file diff --git a/src/AasxServerBlazor/AasxServerBlazor.csproj b/src/AasxServerBlazor/AasxServerBlazor.csproj index 1233a16fa..777012908 100644 --- a/src/AasxServerBlazor/AasxServerBlazor.csproj +++ b/src/AasxServerBlazor/AasxServerBlazor.csproj @@ -32,7 +32,6 @@ - @@ -41,8 +40,6 @@ - - diff --git a/src/AasxServerBlazor/Configuration/DependencyRegistry.cs b/src/AasxServerBlazor/Configuration/DependencyRegistry.cs index 8ee4a4aaa..d6d0dd6fb 100644 --- a/src/AasxServerBlazor/Configuration/DependencyRegistry.cs +++ b/src/AasxServerBlazor/Configuration/DependencyRegistry.cs @@ -15,6 +15,8 @@ namespace AasxServerBlazor.Configuration; +using IO.Swagger.Models; + public static class DependencyRegistry { public static void Register(IServiceCollection services) @@ -47,6 +49,7 @@ public static void Register(IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); } diff --git a/src/AasxServerBlazor/Configuration/ServerConfiguration.cs b/src/AasxServerBlazor/Configuration/ServerConfiguration.cs index 9e7ee2ddc..b75d62cca 100644 --- a/src/AasxServerBlazor/Configuration/ServerConfiguration.cs +++ b/src/AasxServerBlazor/Configuration/ServerConfiguration.cs @@ -13,8 +13,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Serialization; using IO.Swagger.Controllers; using IO.Swagger.Lib.V3.Formatters; using IO.Swagger.Lib.V3.Middleware; @@ -24,6 +22,10 @@ namespace AasxServerBlazor.Configuration; +using System.Text.Json; +using System.Text.Json.Serialization; +using AdminShellNS; + public static class ServerConfiguration { private const string ActivatedKey = "activated"; @@ -66,7 +68,7 @@ public static void AddFrameworkServices(IServiceCollection services) AddSwaggerGen(services); services.AddAuthentication(AuthenticationScheme) - .AddScheme(AuthenticationScheme, null); + .AddScheme(AuthenticationScheme, null); AddAuthorization(services); } @@ -80,23 +82,17 @@ public static void ConfigureSwagger(IApplicationBuilder app, IConfiguration conf { app.UseSwagger(); app.UseSwaggerUI(swaggerUiOptions => - { - //TODO: Either use the SwaggerGen generated Swagger contract (generated from C# classes) or - //alternatively use the original Swagger contract that's included in the static files - swaggerUiOptions.SwaggerEndpoint(SwaggerJsonEndpoint, - HttpRestAssetAdministrationShellRepository); - swaggerUiOptions.RoutePrefix = SwaggerRoutePrefix; - swaggerUiOptions.ConfigObject.AdditionalItems[SyntaxHighLightLowercase] = new Dictionary - { - [ActivatedKey] = false - }; - - var syntaxHighlight = configuration[SyntaxHighlightUppercase]; - swaggerUiOptions.ConfigObject.AdditionalItems[SyntaxHighLightLowercase] = new Dictionary - { - [ActivatedKey] = syntaxHighlight - }; - }); + { + //TODO: Either use the SwaggerGen generated Swagger contract (generated from C# classes) or + //alternatively use the original Swagger contract that's included in the static files + swaggerUiOptions.SwaggerEndpoint(SwaggerJsonEndpoint, + HttpRestAssetAdministrationShellRepository); + swaggerUiOptions.RoutePrefix = SwaggerRoutePrefix; + swaggerUiOptions.ConfigObject.AdditionalItems[SyntaxHighLightLowercase] = new Dictionary {[ActivatedKey] = false}; + + var syntaxHighlight = configuration[SyntaxHighlightUppercase]; + swaggerUiOptions.ConfigObject.AdditionalItems[SyntaxHighLightLowercase] = new Dictionary {[ActivatedKey] = syntaxHighlight}; + }); } /// @@ -130,12 +126,12 @@ public static void ConfigureEnvironment(IApplicationBuilder app, IWebHostEnviron private static void ConfigureEndpoints(IEndpointRouteBuilder endpoints) { endpoints.MapBlazorHub(options => - { - // Do NOT use Websockets - options.Transports = - HttpTransportType.ServerSentEvents | - HttpTransportType.LongPolling; - }); + { + // Do NOT use Websockets + options.Transports = + HttpTransportType.ServerSentEvents | + HttpTransportType.LongPolling; + }); endpoints.MapFallbackToPage(FallbackHostPattern); endpoints.MapControllers(); endpoints.MapGraphQL(); @@ -145,37 +141,31 @@ private static void ConfigureEndpoints(IEndpointRouteBuilder endpoints) #region Server Configuration - private static void ConfigureCors(IServiceCollection services) - { + private static void ConfigureCors(IServiceCollection services) => services.AddCors(options => - { - options.AddPolicy(CorsPolicyName, builder => - { - builder.AllowAnyOrigin() - .AllowAnyMethod() - .AllowAnyHeader(); - }); - }); - } - - private static void ConfigureFormOptions(IServiceCollection services) - { + { + options.AddPolicy(CorsPolicyName, builder => + { + builder.AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader(); + }); + }); + + private static void ConfigureFormOptions(IServiceCollection services) => services.Configure(formOptions => - { - formOptions.ValueLengthLimit = int.MaxValue; - formOptions.MultipartBodyLengthLimit = int.MaxValue; - formOptions.MultipartHeadersLengthLimit = int.MaxValue; - }); - } + { + formOptions.ValueLengthLimit = int.MaxValue; + formOptions.MultipartBodyLengthLimit = int.MaxValue; + formOptions.MultipartHeadersLengthLimit = int.MaxValue; + }); - private static void ConfigureKestrel(IServiceCollection services) - { + private static void ConfigureKestrel(IServiceCollection services) => services.Configure(options => - { - options.AllowSynchronousIO = true; - options.Limits.MaxRequestBodySize = int.MaxValue; - }); - } + { + options.AllowSynchronousIO = true; + options.Limits.MaxRequestBodySize = int.MaxValue; + }); private static void ConfigureRazorPages(IServiceCollection services) { @@ -187,72 +177,70 @@ private static void ConfigureRazorPages(IServiceCollection services) #region Framework Services Configuration - private static void AddAuthorization(IServiceCollection services) - { - services.AddAuthorization(authorizationOptions => - { - authorizationOptions.AddPolicy("SecurityPolicy", policy => - { - policy.AuthenticationSchemes.Add(AuthenticationScheme); - policy.Requirements.Add(new SecurityRequirement()); - }); - }); - } + private static void AddAuthorization(IServiceCollection services) => + services.AddAuthorizationBuilder() + .AddPolicy("SecurityPolicy", policy => + { + policy.AuthenticationSchemes.Add(AuthenticationScheme); + policy.Requirements.Add(new SecurityRequirement()); + }); - private static void AddMvc(IServiceCollection services) - { + private static void AddMvc(IServiceCollection services) => services.AddMvc(options => - { - options.InputFormatters.RemoveType(); - options.OutputFormatters - .RemoveType(); - options.InputFormatters.Add(new AasRequestFormatter()); - options.OutputFormatters.Add(new AasResponseFormatter()); - options.InputFormatters.Add(new AasDescriptorRequestFormatter()); - options.OutputFormatters.Add(new AasDescriptorResponseFormatter()); - }).AddNewtonsoftJson(opts => - { - opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver() - { - NamingStrategy = new CamelCaseNamingStrategy() - { - ProcessDictionaryKeys = false - } - }; - opts.SerializerSettings.Converters.Add(new StringEnumConverter(new CamelCaseNamingStrategy())); - opts.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore; - }); - } - - private static void AddSwaggerGen(IServiceCollection services) - { + { + // Remove the default System.Text.Json formatters + options.InputFormatters.RemoveType(); + options.OutputFormatters.RemoveType(); + + // Add custom formatters + options.InputFormatters.Add(new AasRequestFormatter()); + options.OutputFormatters.Add(new AasResponseFormatter()); + options.InputFormatters.Add(new AasDescriptorRequestFormatter()); + options.OutputFormatters.Add(new AasDescriptorResponseFormatter()); + }) + .AddJsonOptions(opts => + { + // Configure JSON options to use camel case and ignore null values + opts.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + opts.JsonSerializerOptions.DictionaryKeyPolicy = null; // Preserve dictionary key casing + opts.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + + // Add a converter for enum types to be serialized as camel case strings + opts.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)); + + // Add other necessary custom converters + opts.JsonSerializerOptions.Converters.Add(new AdminShellConverters.JsonAasxConverter("modelType", "name")); + }); + + + private static void AddSwaggerGen(IServiceCollection services) => services.AddSwaggerGen(swaggerGenOptions => - { - swaggerGenOptions.SwaggerDoc("Final-Draft", new OpenApiInfo - { - Version = "Final-Draft", - Title = HttpRestAssetAdministrationShellRepository, - Description = - "DotAAS Part 2 | HTTP/REST | Asset Administration Shell Repository (ASP.NET Core 3.1)", - Contact = new OpenApiContact() - { - Name = "Michael Hoffmeister, Torben Miny, Andreas Orzelski, Manuel Sauer, Constantin Ziesche", - Url = new Uri("https://github.com/swagger-api/swagger-codegen"), - Email = "" - }, - TermsOfService = new Uri("https://github.com/admin-shell-io/aas-specs") - }); - - swaggerGenOptions.EnableAnnotations(); - swaggerGenOptions.CustomSchemaIds(type => type.FullName); - - var swaggerCommentedAssembly = - typeof(AssetAdministrationShellRepositoryAPIApiController).Assembly.GetName().Name; - swaggerGenOptions.IncludeXmlComments( - $"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{swaggerCommentedAssembly}.xml"); - swaggerGenOptions.OperationFilter(); - }); - } + { + swaggerGenOptions.SwaggerDoc("Final-Draft", new OpenApiInfo + { + Version = "Final-Draft", + Title = HttpRestAssetAdministrationShellRepository, + Description = + "DotAAS Part 2 | HTTP/REST | Asset Administration Shell Repository (ASP.NET Core 3.1)", + Contact = new OpenApiContact() + { + Name + = "Michael Hoffmeister, Torben Miny, Andreas Orzelski, Manuel Sauer, Constantin Ziesche", + Url = new Uri("https://github.com/swagger-api/swagger-codegen"), + Email = "" + }, + TermsOfService = new Uri("https://github.com/admin-shell-io/aas-specs") + }); + + swaggerGenOptions.EnableAnnotations(); + swaggerGenOptions.CustomSchemaIds(type => type.FullName); + + var swaggerCommentedAssembly = + typeof(AssetAdministrationShellRepositoryAPIApiController).Assembly.GetName().Name; + swaggerGenOptions.IncludeXmlComments( + $"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{swaggerCommentedAssembly}.xml"); + swaggerGenOptions.OperationFilter(); + }); #endregion } \ No newline at end of file diff --git a/src/AasxServerStandardBib/AasEventMsgEnvelope.cs b/src/AasxServerStandardBib/AasEventMsgEnvelope.cs index 63af220ba..ce21e1e4f 100644 --- a/src/AasxServerStandardBib/AasEventMsgEnvelope.cs +++ b/src/AasxServerStandardBib/AasEventMsgEnvelope.cs @@ -13,13 +13,14 @@ This source code may use other Open Source software components (see LICENSE.txt) using AasxIntegrationBase; using Extensions; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Globalization; namespace AdminShellEvents { + using System.Text.Json.Serialization; + /// /// Outer class for any AAS event. AAS events shall interoperably exchage asynchronous information between /// different execution environments "operating" AASes. This basic event class is described in AASiD Part 1. diff --git a/src/AasxServerStandardBib/AasPayloadUpdateValue.cs b/src/AasxServerStandardBib/AasPayloadUpdateValue.cs index 7628f2619..43f758528 100644 --- a/src/AasxServerStandardBib/AasPayloadUpdateValue.cs +++ b/src/AasxServerStandardBib/AasPayloadUpdateValue.cs @@ -11,12 +11,13 @@ This source code may use other Open Source software components (see LICENSE.txt) // #define UseMarkup using AasxIntegrationBase; -using Newtonsoft.Json; using System.Collections.Generic; using System.Xml.Serialization; namespace AdminShellEvents { + using System.Text.Json.Serialization; + /// /// Single item of a update value payload. /// The element denoted by Path is changed in its value and shall not be devided into further diff --git a/src/AasxServerStandardBib/AasxHttpContextHelper.cs b/src/AasxServerStandardBib/AasxHttpContextHelper.cs index 20e82c93e..4578f0087 100644 --- a/src/AasxServerStandardBib/AasxHttpContextHelper.cs +++ b/src/AasxServerStandardBib/AasxHttpContextHelper.cs @@ -5,15 +5,10 @@ using Grapevine.Server; using Grapevine.Server.Attributes; using Grapevine.Shared; -using IdentityModel; using Jose; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.Collections.Specialized; -using System.Data; using System.Dynamic; using System.Globalization; using System.IO; @@ -21,7 +16,6 @@ using System.Net; using System.Net.Http; using System.Reflection; -using System.Runtime.ConstrainedExecution; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; @@ -42,6 +36,10 @@ specification Details of the Administration Shell. The hereby stated approach is namespace AasxRestServerLibrary { + using System.Text.Json; + using JsonConverter = System.Text.Json.Serialization.JsonConverter; + using JsonSerializer = System.Text.Json.JsonSerializer; + public class AasxHttpContextHelper { public static String SwitchToAASX = ""; @@ -92,15 +90,15 @@ public List CreateHandlesFromQueryString(System.Co try { var k = kr.Trim().ToLower(); - var v = queryStrings[ k ]; + var v = queryStrings[k]; if (k.StartsWith("q") && k.Length > 1 && v.Contains(',')) { var vl = v.Split(','); if (vl.Length == 2) { //var id = new IIdentifiable(vl[1]); - var id = vl[ 1 ]; - var h = new AasxHttpHandleIdentification(id, "@" + k); + var id = vl[1]; + var h = new AasxHttpHandleIdentification(id, "@" + k); res.Add(h); } } @@ -132,19 +130,19 @@ public List CreateHandlesFromRawUrl(string rawUrl) // try make a Regex wonder, again var m = Regex.Match(query, @"(\s*([^&]+)(&|))+"); - if (m.Success && m.Groups.Count >= 3 && m.Groups[ 2 ].Captures != null) - foreach (var cp in m.Groups[ 2 ].Captures) + if (m.Success && m.Groups.Count >= 3 && m.Groups[2].Captures != null) + foreach (var cp in m.Groups[2].Captures) { var m2 = Regex.Match(cp.ToString(), @"\s*(\w+)\s*=\s*([^,]+),(.+)$"); if (m2.Success && m2.Groups.Count >= 4) { - var k = m2.Groups[ 1 ].ToString(); - var idt = m2.Groups[ 2 ].ToString(); - var ids = m2.Groups[ 3 ].ToString(); + var k = m2.Groups[1].ToString(); + var idt = m2.Groups[2].ToString(); + var ids = m2.Groups[3].ToString(); //var id = new IIdentifiable(ids); var id = ids; - var h = new AasxHttpHandleIdentification(id, "@" + k); + var h = new AasxHttpHandleIdentification(id, "@" + k); res.Add(h); } } @@ -172,11 +170,11 @@ public FindAasReturn FindAAS(string aasid, System.Collections.Specialized.NameVa if (i > Packages.Length) return null; - if (Packages[ i ] == null || Packages[ i ].AasEnv == null || Packages[ i ].AasEnv.AssetAdministrationShells == null - || Packages[ i ].AasEnv.AssetAdministrationShells.Count < 1) + if (Packages[i] == null || Packages[i].AasEnv == null || Packages[i].AasEnv.AssetAdministrationShells == null + || Packages[i].AasEnv.AssetAdministrationShells.Count < 1) return null; - findAasReturn.aas = Packages[ i ].AasEnv.AssetAdministrationShells[ 0 ]; + findAasReturn.aas = Packages[i].AasEnv.AssetAdministrationShells[0]; findAasReturn.iPackage = i; } else @@ -184,18 +182,18 @@ public FindAasReturn FindAAS(string aasid, System.Collections.Specialized.NameVa // Name if (aasid == "id") { - findAasReturn.aas = Packages[ 0 ].AasEnv.AssetAdministrationShells[ 0 ]; + findAasReturn.aas = Packages[0].AasEnv.AssetAdministrationShells[0]; findAasReturn.iPackage = 0; } else { for (int i = 0; i < Packages.Length; i++) { - if (Packages[ i ] != null) + if (Packages[i] != null) { - if (Packages[ i ].AasEnv.AssetAdministrationShells[ 0 ].IdShort == aasid) + if (Packages[i].AasEnv.AssetAdministrationShells[0].IdShort == aasid) { - findAasReturn.aas = Packages[ i ].AasEnv.AssetAdministrationShells[ 0 ]; + findAasReturn.aas = Packages[i].AasEnv.AssetAdministrationShells[0]; findAasReturn.iPackage = i; break; } @@ -228,15 +226,15 @@ public FindAasReturn FindAAS(string aasid, System.Collections.Specialized.NameVa } public IReference FindSubmodelRefWithinAas(FindAasReturn findAasReturn, string smid, System.Collections.Specialized.NameValueCollection queryStrings = null, - string rawUrl = null) + string rawUrl = null) { // trivial - if (Packages[ findAasReturn.iPackage ] == null || Packages[ findAasReturn.iPackage ].AasEnv == null || findAasReturn.aas == null || smid == null || smid.Trim() == "") + if (Packages[findAasReturn.iPackage] == null || Packages[findAasReturn.iPackage].AasEnv == null || findAasReturn.aas == null || smid == null || smid.Trim() == "") return null; // via handle var specialHandles = this.CreateHandlesFromRawUrl(rawUrl); - var handleId = IdRefHandleStore.ResolveSpecific(smid, specialHandles); + var handleId = IdRefHandleStore.ResolveSpecific(smid, specialHandles); // no, iterate & find foreach (var smref in findAasReturn.aas.Submodels) @@ -248,7 +246,7 @@ public IReference FindSubmodelRefWithinAas(FindAasReturn findAasReturn, string s } else { - var sm = this.Packages[ findAasReturn.iPackage ].AasEnv.FindSubmodel(smref); + var sm = this.Packages[findAasReturn.iPackage].AasEnv.FindSubmodel(smref); if (sm != null && sm.IdShort != null && sm.IdShort.Trim().ToLower() == smid.Trim().ToLower()) return smref; } @@ -259,23 +257,23 @@ public IReference FindSubmodelRefWithinAas(FindAasReturn findAasReturn, string s } public ISubmodel FindSubmodelWithinAas(FindAasReturn findAasReturn, string smid, System.Collections.Specialized.NameValueCollection queryStrings = null, - string rawUrl = null) + string rawUrl = null) { // trivial - if (Packages[ findAasReturn.iPackage ] == null || Packages[ findAasReturn.iPackage ].AasEnv == null || findAasReturn.aas == null || smid == null || smid.Trim() == "") + if (Packages[findAasReturn.iPackage] == null || Packages[findAasReturn.iPackage].AasEnv == null || findAasReturn.aas == null || smid == null || smid.Trim() == "") return null; // via handle var specialHandles = this.CreateHandlesFromRawUrl(rawUrl); - var handleId = IdRefHandleStore.ResolveSpecific(smid, specialHandles); + var handleId = IdRefHandleStore.ResolveSpecific(smid, specialHandles); if (handleId != null && handleId.identification != null) - return Packages[ findAasReturn.iPackage ].AasEnv.FindSubmodelById(handleId.identification); + return Packages[findAasReturn.iPackage].AasEnv.FindSubmodelById(handleId.identification); // no, iterate & find foreach (var smref in findAasReturn.aas.Submodels) { - var sm = this.Packages[ findAasReturn.iPackage ].AasEnv.FindSubmodel(smref); + var sm = this.Packages[findAasReturn.iPackage].AasEnv.FindSubmodel(smref); if (sm != null && sm.IdShort != null && sm.IdShort.Trim().ToLower() == smid.Trim().ToLower()) return sm; } @@ -287,8 +285,8 @@ public ISubmodel FindSubmodelWithinAas(FindAasReturn findAasReturn, string smid, public ISubmodel FindSubmodelWithinAas(string aasid, string smid, System.Collections.Specialized.NameValueCollection queryStrings = null, string rawUrl = null) { - IAssetAdministrationShell aas = null; - int iPackage = -1; + IAssetAdministrationShell aas = null; + int iPackage = -1; if (Packages == null) return null; @@ -301,11 +299,11 @@ public ISubmodel FindSubmodelWithinAas(string aasid, string smid, System.Collect if (i > Packages.Length) return null; - if (Packages[ i ] == null || Packages[ i ].AasEnv == null || Packages[ i ].AasEnv.AssetAdministrationShells == null - || Packages[ i ].AasEnv.AssetAdministrationShells.Count < 1) + if (Packages[i] == null || Packages[i].AasEnv == null || Packages[i].AasEnv.AssetAdministrationShells == null + || Packages[i].AasEnv.AssetAdministrationShells.Count < 1) return null; - aas = Packages[ i ].AasEnv.AssetAdministrationShells[ 0 ]; + aas = Packages[i].AasEnv.AssetAdministrationShells[0]; iPackage = i; } else @@ -313,18 +311,18 @@ public ISubmodel FindSubmodelWithinAas(string aasid, string smid, System.Collect // Name if (aasid == "id") { - aas = Packages[ 0 ].AasEnv.AssetAdministrationShells[ 0 ]; + aas = Packages[0].AasEnv.AssetAdministrationShells[0]; iPackage = 0; } else { for (int i = 0; i < Packages.Length; i++) { - if (Packages[ i ] != null) + if (Packages[i] != null) { - if (Packages[ i ].AasEnv.AssetAdministrationShells[ 0 ].IdShort == aasid) + if (Packages[i].AasEnv.AssetAdministrationShells[0].IdShort == aasid) { - aas = Packages[ i ].AasEnv.AssetAdministrationShells[ 0 ]; + aas = Packages[i].AasEnv.AssetAdministrationShells[0]; iPackage = i; break; } @@ -340,7 +338,7 @@ public ISubmodel FindSubmodelWithinAas(string aasid, string smid, System.Collect foreach (var smref in aas.Submodels) { - var sm = this.Packages[ iPackage ].AasEnv.FindSubmodel(smref); + var sm = this.Packages[iPackage].AasEnv.FindSubmodel(smref); if (sm != null && sm.IdShort != null && sm.IdShort.Trim().ToLower() == smid.Trim().ToLower()) return sm; } @@ -353,17 +351,17 @@ public ISubmodel FindSubmodelWithinAas(string aasid, string smid, System.Collect public ISubmodel FindSubmodelWithoutAas(string smid, System.Collections.Specialized.NameValueCollection queryStrings = null, string rawUrl = null) { // trivial - if (Packages[ 0 ] == null || Packages[ 0 ].AasEnv == null || smid == null || smid.Trim() == "") + if (Packages[0] == null || Packages[0].AasEnv == null || smid == null || smid.Trim() == "") return null; // via handle var specialHandles = this.CreateHandlesFromRawUrl(rawUrl); - var handleId = IdRefHandleStore.ResolveSpecific(smid, specialHandles); + var handleId = IdRefHandleStore.ResolveSpecific(smid, specialHandles); if (handleId != null && handleId.identification != null) - return Packages[ 0 ].AasEnv.FindSubmodelById(handleId.identification); + return Packages[0].AasEnv.FindSubmodelById(handleId.identification); // no, iterate & find - foreach (var sm in this.Packages[ 0 ].AasEnv.Submodels) + foreach (var sm in this.Packages[0].AasEnv.Submodels) { if (sm != null && sm.IdShort != null && sm.IdShort.Trim().ToLower() == smid.Trim().ToLower()) return sm; @@ -374,20 +372,20 @@ public ISubmodel FindSubmodelWithoutAas(string smid, System.Collections.Speciali } public IConceptDescription FindCdWithoutAas(FindAasReturn findAasReturn, string cdid, System.Collections.Specialized.NameValueCollection queryStrings = null, - string rawUrl = null) + string rawUrl = null) { // trivial - if (Packages[ findAasReturn.iPackage ] == null || Packages[ findAasReturn.iPackage ].AasEnv == null || findAasReturn.aas == null || cdid == null || cdid.Trim() == "") + if (Packages[findAasReturn.iPackage] == null || Packages[findAasReturn.iPackage].AasEnv == null || findAasReturn.aas == null || cdid == null || cdid.Trim() == "") return null; // via handle var specialHandles = this.CreateHandlesFromRawUrl(rawUrl); - var handleId = IdRefHandleStore.ResolveSpecific(cdid, specialHandles); + var handleId = IdRefHandleStore.ResolveSpecific(cdid, specialHandles); if (handleId != null && handleId.identification != null) - return Packages[ findAasReturn.iPackage ].AasEnv.FindConceptDescriptionById(handleId.identification); + return Packages[findAasReturn.iPackage].AasEnv.FindConceptDescriptionById(handleId.identification); // no, iterate & find - foreach (var cd in Packages[ findAasReturn.iPackage ].AasEnv.ConceptDescriptions) + foreach (var cd in Packages[findAasReturn.iPackage].AasEnv.ConceptDescriptions) { if (cd.IdShort != null && cd.IdShort.Trim().ToLower() == cdid.Trim().ToLower()) return cd; @@ -406,9 +404,9 @@ public class FindSubmodelElementResult public FindSubmodelElementResult(IReferable elem = null, ISubmodelElement wrapper = null, IReferable parent = null) { - this.elem = elem; + this.elem = elem; this.submodelElement = wrapper; - this.parent = parent; + this.parent = parent; } } @@ -423,7 +421,7 @@ public FindSubmodelElementResult FindSubmodelElement(IReferable parent, List { return false; }; - - if (!SubmodelHasElements && property.DeclaringType == typeof(Submodel) && property.PropertyName == "submodelElements") - property.ShouldSerialize = instance => { return false; }; - - if (!SmcHasValue && property.DeclaringType == typeof(SubmodelElementCollection) && property.PropertyName == "value") - property.ShouldSerialize = instance => { return false; }; - - if (!OpHasVariables && property.DeclaringType == typeof(Operation) && (property.PropertyName == "in" || property.PropertyName == "out")) - property.ShouldSerialize = instance => { return false; }; - - //TODO (jtikekar, 2022-07-08): AssetAdministrationShell.Views not supported anymore - if (!AasHasViews && property.DeclaringType == typeof(AssetAdministrationShell) && property.PropertyName == "views") - property.ShouldSerialize = instance => { return false; }; - - return property; - } - } - public static string makeJsonLD(string json, int count) { - int total = json.Length; - string header = ""; - string jsonld = ""; - string name = ""; - int state = 0; - int identification = 0; - string id = "idNotFound"; + int total = json.Length; + string header = ""; + string jsonld = ""; + string name = ""; + int state = 0; + int identification = 0; + string id = "idNotFound"; for (int i = 0; i < total; i++) { - var c = json[ i ]; + var c = json[i]; switch (state) { case 0: @@ -576,22 +522,22 @@ public static string makeJsonLD(string json, int count) case 2: if (c == ':') { - bool skip = false; + bool skip = false; string pattern = ": null"; if (i + pattern.Length < total) { if (json.Substring(i, pattern.Length) == pattern) { - skip = true; - i += pattern.Length; + skip = true; + i += pattern.Length; // remove last "," in jsonld if character after null is not "," int j = jsonld.Length - 1; - while (Char.IsWhiteSpace(jsonld[ j ])) + while (Char.IsWhiteSpace(jsonld[j])) { j--; } - if (jsonld[ j ] == ',' && json[ i ] != ',') + if (jsonld[j] == ',' && json[i] != ',') { jsonld = jsonld.Substring(0, j) + "\r\n"; } @@ -600,7 +546,7 @@ public static string makeJsonLD(string json, int count) jsonld = jsonld.Substring(0, j + 1) + "\r\n"; } - while (json[ i ] != '\n') + while (json[i] != '\n') i++; } } @@ -613,15 +559,15 @@ public static string makeJsonLD(string json, int count) { id = ""; int j = i; - while (j < json.Length && json[ j ] != '"') + while (j < json.Length && json[j] != '"') { j++; } j++; - while (j < json.Length && json[ j ] != '"') + while (j < json.Length && json[j] != '"') { - id += json[ j ]; + id += json[j]; j++; } } @@ -640,7 +586,7 @@ public static string makeJsonLD(string json, int count) } state = 0; - name = ""; + name = ""; break; } } @@ -648,47 +594,51 @@ public static string makeJsonLD(string json, int count) string prefix = " \"aio\": \"https://admin-shell-io.com/ns#\",\r\n"; prefix += " \"I40GenericCredential\": \"aio:I40GenericCredential\",\r\n"; prefix += " \"__AAS\": \"aio:__AAS\",\r\n"; - header = prefix + header; - header = "\"context\": {\r\n" + header + "\r\n},\r\n"; + header = prefix + header; + header = "\"context\": {\r\n" + header + "\r\n},\r\n"; int k = jsonld.Length - 2; - while (k >= 0 && jsonld[ k ] != '}' && jsonld[ k ] != ']') + while (k >= 0 && jsonld[k] != '}' && jsonld[k] != ']') { k--; } #pragma warning disable format - jsonld = jsonld.Substring(0, k + 1); + jsonld = jsonld.Substring(0, k + 1); jsonld += ",\r\n" + " \"id\": \"" + id + "\"\r\n}\r\n"; - jsonld = "\"doc\": " + jsonld; - jsonld = "{\r\n\r\n" + header + jsonld + "\r\n\r\n}\r\n"; + jsonld = "\"doc\": " + jsonld; + jsonld = "{\r\n\r\n" + header + jsonld + "\r\n\r\n}\r\n"; #pragma warning restore format return jsonld; } - protected static void SendJsonResponse(Grapevine.Interfaces.Server.IHttpContext context, object obj, IContractResolver contractResolver = null) + private static JsonSerializerOptions _jsonSerializerOptions = new() {WriteIndented = true}; + + public static async Task SendJsonResponse(IHttpContext context, object obj, JsonConverter contractResolver = null) { - var queryString = context.Request.QueryString; - string refresh = queryString[ "refresh" ]; - if (refresh != null && refresh != "") + var queryString = context.Request.QueryString; + string refresh = queryString["refresh"]; + if (!string.IsNullOrEmpty(refresh)) { context.Response.Headers.Remove("Refresh"); context.Response.Headers.Add("Refresh", refresh); } - string jsonld = queryString[ "jsonld" ]; - string vc = queryString[ "vc" ]; + string jsonld = queryString["jsonld"]; + string vc = queryString["vc"]; - var settings = new JsonSerializerSettings(); if (contractResolver != null) - settings.ContractResolver = contractResolver; - var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings); + { + _jsonSerializerOptions.Converters.Add(contractResolver); + } + + var json = JsonSerializer.Serialize(obj, _jsonSerializerOptions); if (jsonld != null || vc != null) { jsonld = makeJsonLD(json, 0); - json = jsonld; + json = jsonld; - if (vc != null && jsonld != null && jsonld != "") + if (!string.IsNullOrEmpty(vc) && !string.IsNullOrEmpty(jsonld)) { string requestPath = "https://nameplate.h2894164.stratoserver.net/demo/sign?create_as_verifiable_presentation=false"; @@ -699,39 +649,28 @@ protected static void SendJsonResponse(Grapevine.Interfaces.Server.IHttpContext else handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; - var client = new HttpClient(handler); + using var client = new HttpClient(handler); client.Timeout = TimeSpan.FromSeconds(60); - bool error = false; - HttpResponseMessage response = new HttpResponseMessage(); try { - var content = new StringContent(jsonld, System.Text.Encoding.UTF8, "application/json"); - var task = Task.Run(async () => - { - response = await client.PostAsync( - requestPath, content); - }); - task.Wait(); - error = !response.IsSuccessStatusCode; - } - catch - { - error = true; - } + var content = new StringContent(jsonld, Encoding.UTF8, "application/json"); + var response = await client.PostAsync(requestPath, content); - if (!error) - { - json = response.Content.ReadAsStringAsync().Result; + if (response.IsSuccessStatusCode) + { + json = await response.Content.ReadAsStringAsync(); + } + else + { + json = $"ERROR POST; {response.StatusCode}; {requestPath}; {await response.Content.ReadAsStringAsync()}"; + Console.WriteLine(json); + } } - else + catch (Exception ex) { - string r = "ERROR POST; " + response.StatusCode.ToString(); - r += " ; " + requestPath; - if (response.Content != null) - r += " ; " + response.Content.ReadAsStringAsync().Result; - Console.WriteLine(r); - json = r; + json = $"ERROR POST; {ex.Message}"; + Console.WriteLine(json); } } } @@ -740,27 +679,28 @@ protected static void SendJsonResponse(Grapevine.Interfaces.Server.IHttpContext if (context.Request.RawUrl.Equals("/aas/0/core") && obj is ExpandoObject findAasReturn) { var value = new JsonObject(); - foreach (KeyValuePair kvp in findAasReturn) + foreach (var kvp in findAasReturn) { if (kvp.Key.Equals("AAS")) { - value[ "AAS" ] = Jsonization.Serialize.ToJsonObject((AssetAdministrationShell) kvp.Value); + value["AAS"] = Jsonization.Serialize.ToJsonObject((AssetAdministrationShell)kvp.Value); } else if (kvp.Key.Equals("Asset")) { - value[ "AssetInformation" ] = Jsonization.Serialize.ToJsonObject((AssetInformation) kvp.Value); + value["AssetInformation"] = Jsonization.Serialize.ToJsonObject((AssetInformation)kvp.Value); } } json = value.ToString(); } - var buffer = context.Request.ContentEncoding.GetBytes(json); + var buffer = Encoding.UTF8.GetBytes(json); var length = buffer.Length; + // Assuming allowCORS is a method that handles CORS headers AasxRestServer.TestResource.allowCORS(context); - context.Response.ContentType = ContentType.JSON; + context.Response.ContentType = ContentType.JSON; context.Response.ContentEncoding = Encoding.UTF8; context.Response.ContentLength64 = length; context.Response.SendResponse(buffer); @@ -768,8 +708,8 @@ protected static void SendJsonResponse(Grapevine.Interfaces.Server.IHttpContext protected static void SendTextResponse(Grapevine.Interfaces.Server.IHttpContext context, string txt, string mimeType = null) { - var queryString = context.Request.QueryString; - string refresh = queryString[ "refresh" ]; + var queryString = context.Request.QueryString; + string refresh = queryString["refresh"]; if (refresh != null && refresh != "") { context.Response.Headers.Remove("Refresh"); @@ -787,7 +727,7 @@ protected static void SendTextResponse(Grapevine.Interfaces.Server.IHttpContext } protected static void SendStreamResponse(IHttpContext context, Stream stream, - string headerAttachmentFileName = null) + string headerAttachmentFileName = null) { AasxRestServer.TestResource.allowCORS(context); @@ -831,19 +771,19 @@ public void EvalGetAasAndAsset(IHttpContext context, string aasid, bool deep = f AssetInformation asset = null; // result - res.AAS = findAasReturn.aas; + res.AAS = findAasReturn.aas; res.Asset = findAasReturn.aas.AssetInformation; // return as JSON - var cr = new AdminShellConverters.AdaptiveFilterContractResolver(deep: deep, complete: complete); + var cr = new AdminShellConverters.AdaptiveFilterContractResolver(deep, complete); context.Response.StatusCode = HttpStatusCode.Ok; SendJsonResponse(context, res, cr); } public void EvalGetAasEnv(IHttpContext context, string aasid) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -858,7 +798,7 @@ public void EvalGetAasEnv(IHttpContext context, string aasid) res.confirm = "Authorization = " + accessrights; } - if (this.Packages[ 0 ] == null || this.Packages[ 0 ].AasEnv == null) + if (this.Packages[0] == null || this.Packages[0].AasEnv == null) { context.Response.SendResponse(HttpStatusCode.InternalServerError, $"Error accessing internal data structures."); return; @@ -876,8 +816,8 @@ public void EvalGetAasEnv(IHttpContext context, string aasid) AasCore.Aas3_0.Environment copyenv = new AasCore.Aas3_0.Environment(); try { - var sourceEnvironment = Packages[ findAasReturn.iPackage ].AasEnv; - var aasList = new List() {findAasReturn.aas}; + var sourceEnvironment = Packages[findAasReturn.iPackage].AasEnv; + var aasList = new List() {findAasReturn.aas}; copyenv = copyenv.CreateFromExistingEnvironment(sourceEnvironment, aasList); } catch (Exception ex) @@ -898,12 +838,12 @@ public void EvalGetAasEnv(IHttpContext context, string aasid) if (findAasReturn.aas.IdShort != null) fn = findAasReturn.aas.IdShort + "." + fn; // serialize via helper - var jsonwriter = copyenv.SerialiazeJsonToStream(new StreamWriter(ms), leaveJsonWriterOpen: true); + var jsonwriter = copyenv.SerializeJsonToStream(new StreamWriter(ms), leaveJsonWriterOpen: true); // write out again ms.Position = 0; SendStreamResponse(context, ms, Path.GetFileName(fn)); - // bit ugly - jsonwriter.Close(); + // a bit ugly + jsonwriter.Flush(); } } @@ -913,7 +853,7 @@ public void EvalGetAasEnv(IHttpContext context, string aasid) res.env = copyenv; // return as JSON - var cr = new AdminShellConverters.AdaptiveFilterContractResolver(deep: true, complete: true); + var cr = new AdminShellConverters.AdaptiveFilterContractResolver(); SendJsonResponse(context, res, cr); } } @@ -930,8 +870,8 @@ public void EvalGetAasEnv(IHttpContext context, string aasid) public void EvalGetAasThumbnail(IHttpContext context, string aasid) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -946,7 +886,7 @@ public void EvalGetAasThumbnail(IHttpContext context, string aasid) res.confirm = "Authorization = " + accessrights; } - if (this.Packages[ 0 ] == null) + if (this.Packages[0] == null) { context.Response.SendResponse(HttpStatusCode.InternalServerError, $"Error accessing internal data structures."); return; @@ -962,8 +902,8 @@ public void EvalGetAasThumbnail(IHttpContext context, string aasid) // access the thumbnail // Note: in this version, the thumbnail is not specific to the AAS, but maybe in later versions ;-) - Uri thumbUri = null; - var thumbStream = this.Packages[ findAasReturn.iPackage ].GetLocalThumbnailStream(ref thumbUri); + Uri thumbUri = null; + var thumbStream = this.Packages[findAasReturn.iPackage].GetLocalThumbnailStream(ref thumbUri); if (thumbStream == null) { context.Response.SendResponse(HttpStatusCode.NotFound, $"No thumbnail available in package."); @@ -978,8 +918,8 @@ public void EvalGetAasThumbnail(IHttpContext context, string aasid) public void EvalPutAas(IHttpContext context) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -1005,7 +945,7 @@ public void EvalPutAas(IHttpContext context) AssetAdministrationShell aas = null; try { - aas = Newtonsoft.Json.JsonConvert.DeserializeObject(context.Request.Payload); + aas = System.Text.Json.JsonSerializer.Deserialize(context.Request.Payload); } catch (Exception ex) { @@ -1024,16 +964,16 @@ public void EvalPutAas(IHttpContext context) context.Server.Logger.Debug($"Putting AdministrationShell with IdShort {aas.IdShort ?? "--"} and id {aas.Id?.ToString() ?? "--"}"); bool emptyPackageAvailable = false; - int emptyPackageIndex = -1; + int emptyPackageIndex = -1; for (int envi = 0; envi < this.Packages.Length; envi++) { - if (this.Packages[ envi ] != null) + if (this.Packages[envi] != null) { - var existingAas = this.Packages[ envi ].AasEnv.FindAasById(aas.Id); + var existingAas = this.Packages[envi].AasEnv.FindAasById(aas.Id); if (existingAas != null) { - this.Packages[ envi ].AasEnv.AssetAdministrationShells.Remove(existingAas); - this.Packages[ envi ].AasEnv.AssetAdministrationShells.Add(aas); + this.Packages[envi].AasEnv.AssetAdministrationShells.Remove(existingAas); + this.Packages[envi].AasEnv.AssetAdministrationShells.Add(aas); SendTextResponse(context, "OK (update, index=" + envi + ")"); return; } @@ -1043,15 +983,15 @@ public void EvalPutAas(IHttpContext context) if (!emptyPackageAvailable) { emptyPackageAvailable = true; - emptyPackageIndex = envi; + emptyPackageIndex = envi; } } } if (emptyPackageAvailable) { - this.Packages[ emptyPackageIndex ] = new AdminShellPackageEnv(); - this.Packages[ emptyPackageIndex ].AasEnv.AssetAdministrationShells.Add(aas); + this.Packages[emptyPackageIndex] = new AdminShellPackageEnv(); + this.Packages[emptyPackageIndex].AasEnv.AssetAdministrationShells.Add(aas); SendTextResponse(context, "OK (new, index=" + emptyPackageIndex + ")"); return; } @@ -1062,8 +1002,8 @@ public void EvalPutAas(IHttpContext context) public void EvalPutAasxOnServer(IHttpContext context) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -1086,7 +1026,7 @@ public void EvalPutAasxOnServer(IHttpContext context) return; } - AasxFileInfo file = Newtonsoft.Json.JsonConvert.DeserializeObject(context.Request.Payload); + AasxFileInfo file = System.Text.Json.JsonSerializer.Deserialize(context.Request.Payload); if (!file.path.ToLower().EndsWith(".aasx")) { context.Response.SendResponse(HttpStatusCode.BadRequest, $"Not a path ending with \".aasx\"...:{file.path}. Aborting..."); @@ -1118,9 +1058,9 @@ public void EvalPutAasxOnServer(IHttpContext context) // instantiate aas foreach (var aas in aasEnv.AasEnv.AssetAdministrationShells) { - aas.IdShort += file.instancesIdentificationSuffix; - aas.Id += file.instancesIdentificationSuffix; - aas.AssetInformation.GlobalAssetId = file.instancesIdentificationSuffix; + aas.IdShort += file.instancesIdentificationSuffix; + aas.Id += file.instancesIdentificationSuffix; + aas.AssetInformation.GlobalAssetId = file.instancesIdentificationSuffix; foreach (var smref in aas.Submodels) { foreach (var key in smref.Keys) @@ -1156,7 +1096,7 @@ public void EvalPutAasxOnServer(IHttpContext context) string aasIdShort = ""; try { - aasIdShort = aasEnv.AasEnv.AssetAdministrationShells[ 0 ].IdShort; + aasIdShort = aasEnv.AasEnv.AssetAdministrationShells[0].IdShort; } catch (Exception ex) { @@ -1171,10 +1111,10 @@ public void EvalPutAasxOnServer(IHttpContext context) { for (int envi = 0; envi < this.Packages.Length; envi++) { - if (this.Packages[ envi ] == null) + if (this.Packages[envi] == null) { - this.Packages[ envi ] = aasEnv; - Program.envFileName[ envi ] = file.path; + this.Packages[envi] = aasEnv; + Program.envFileName[envi] = file.path; context.Response.StatusCode = HttpStatusCode.Ok; SendTextResponse(context, "OK (new, index=" + envi + ")"); return; @@ -1187,9 +1127,9 @@ public void EvalPutAasxOnServer(IHttpContext context) } else { - Packages[ findAasReturn.iPackage ] = aasEnv; - Program.envFileName[ findAasReturn.iPackage ] = file.path; - context.Response.StatusCode = HttpStatusCode.Ok; + Packages[findAasReturn.iPackage] = aasEnv; + Program.envFileName[findAasReturn.iPackage] = file.path; + context.Response.StatusCode = HttpStatusCode.Ok; SendTextResponse(context, "OK (update, index=" + findAasReturn.iPackage + ")"); return; } @@ -1197,8 +1137,8 @@ public void EvalPutAasxOnServer(IHttpContext context) public void EvalPutAasxToFilesystem(IHttpContext context, string aasid) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -1221,8 +1161,8 @@ public void EvalPutAasxToFilesystem(IHttpContext context, string aasid) return; } - AasxFileInfo file = Newtonsoft.Json.JsonConvert.DeserializeObject(context.Request.Payload); - Console.WriteLine("EvalPutAasxToFilesystem: " + JsonConvert.SerializeObject(file.path)); + AasxFileInfo file = System.Text.Json.JsonSerializer.Deserialize(context.Request.Payload); + Console.WriteLine("EvalPutAasxToFilesystem: " + JsonSerializer.Serialize(file.path, new JsonSerializerOptions { WriteIndented = true })); if (!file.path.ToLower().EndsWith(".aasx")) { context.Response.SendResponse(HttpStatusCode.BadRequest, $"Not a path ending with \".aasx\"...:{file.path}. Aborting..."); @@ -1242,9 +1182,9 @@ public void EvalPutAasxToFilesystem(IHttpContext context, string aasid) { try { - Packages[ findAasReturn.iPackage ].SaveAs(file.path, false, AdminShellPackageEnv.SerializationFormat.Json, null); - Program.envFileName[ findAasReturn.iPackage ] = file.path; - context.Response.StatusCode = HttpStatusCode.Ok; + Packages[findAasReturn.iPackage].SaveAs(file.path, false, AdminShellPackageEnv.SerializationFormat.Json, null); + Program.envFileName[findAasReturn.iPackage] = file.path; + context.Response.StatusCode = HttpStatusCode.Ok; SendTextResponse(context, "OK (saved)"); return; } @@ -1258,9 +1198,9 @@ public void EvalPutAasxToFilesystem(IHttpContext context, string aasid) public void EvalPutAasxReplacePackage(IHttpContext context, string aasid) { - dynamic res = new ExpandoObject(); - int index = -1; - string accessrights = null; + dynamic res = new ExpandoObject(); + int index = -1; + string accessrights = null; var aasInfo = this.FindAAS(aasid, context.Request.QueryString, context.Request.RawUrl); @@ -1269,7 +1209,7 @@ public void EvalPutAasxReplacePackage(IHttpContext context, string aasid) { accessrights = SecurityCheck(context, ref index); - var aas = Program.env[ aasInfo.iPackage ].AasEnv.AssetAdministrationShells[ 0 ]; + var aas = Program.env[aasInfo.iPackage].AasEnv.AssetAdministrationShells[0]; if (!checkAccessRights(context, accessrights, "/aasx", "UPDATE", "", "aas", aas)) { return; @@ -1308,7 +1248,7 @@ public void EvalPutAasxReplacePackage(IHttpContext context, string aasid) } */ - var packFn = Packages[ packIndex ].Filename; + var packFn = Packages[packIndex].Filename; Console.WriteLine($"Will replace AASX package on server: {packFn}"); // make temp file @@ -1330,7 +1270,7 @@ public void EvalPutAasxReplacePackage(IHttpContext context, string aasid) try { // free to overwrite - Packages[ packIndex ].Close(); + Packages[packIndex].Close(); // copy to back (rename experienced to be more error-prone) System.IO.File.Copy(packFn, packFn + ".bak", overwrite: true); @@ -1345,7 +1285,7 @@ public void EvalPutAasxReplacePackage(IHttpContext context, string aasid) try { // replace loaded original when saving - packFn = Program.envFileName[ packIndex ]; + packFn = Program.envFileName[packIndex]; Console.WriteLine($"Replace original AASX package on server: {packFn}"); // copy into same location @@ -1354,7 +1294,7 @@ public void EvalPutAasxReplacePackage(IHttpContext context, string aasid) // open again var newAasx = new AdminShellPackageEnv(packFn, true); if (newAasx != null) - Packages[ packIndex ] = newAasx; + Packages[packIndex] = newAasx; else { context.Response.SendResponse(HttpStatusCode.BadRequest, $"Cannot load new package {packFn} for replacing via PUT. Aborting."); @@ -1380,16 +1320,16 @@ public void EvalPutAasxReplacePackage(IHttpContext context, string aasid) public void EvalGetAasxByAssetId(IHttpContext context) { - string path = context.Request.PathInfo; - string[] split = path.Split('/'); - string node = split[ 2 ]; - string assetId = split[ 3 ].ToUpper(); + string path = context.Request.PathInfo; + string[] split = path.Split('/'); + string node = split[2]; + string assetId = split[3].ToUpper(); for (int envi = 0; envi < Packages.Length; envi++) { - if (this.Packages[ envi ] != null) + if (this.Packages[envi] != null) { - foreach (var aas in this.Packages[ envi ].AasEnv.AssetAdministrationShells) + foreach (var aas in this.Packages[envi].AasEnv.AssetAdministrationShells) { if (aas.AssetInformation != null) { @@ -1401,7 +1341,7 @@ public void EvalGetAasxByAssetId(IHttpContext context) if (assetId == url) { string headers = context.Request.Headers.ToString(); - string token = context.Request.Headers.Get("accept"); + string token = context.Request.Headers.Get("accept"); if (token == null || token != "application/aas") { // Human by browser @@ -1413,11 +1353,11 @@ public void EvalGetAasxByAssetId(IHttpContext context) lock (Program.changeAasxFile) { - string detailsImage = ""; - System.IO.Stream s = null; + string detailsImage = ""; + System.IO.Stream s = null; try { - s = Program.env[ envi ].GetLocalThumbnailStream(); + s = Program.env[envi].GetLocalThumbnailStream(); } catch { @@ -1456,7 +1396,7 @@ public void EvalGetAasxByAssetId(IHttpContext context) link + "" + "
" + "and set Headers / Accept application/aas" + "

"; - context.Response.ContentType = ContentType.HTML; + context.Response.ContentType = ContentType.HTML; context.Response.ContentEncoding = System.Text.Encoding.UTF8; context.Response.SendResponse(text); return; @@ -1476,8 +1416,8 @@ public void EvalGetAasxByAssetId(IHttpContext context) public void EvalDeleteAasAndAsset(IHttpContext context, string aasid, bool deleteAsset = false) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -1493,7 +1433,7 @@ public void EvalDeleteAasAndAsset(IHttpContext context, string aasid, bool delet } // datastructure update - if (this.Packages[ 0 ] == null || this.Packages[ 0 ].AasEnv == null || this.Packages[ 0 ].AasEnv.AssetAdministrationShells == null) + if (this.Packages[0] == null || this.Packages[0].AasEnv == null || this.Packages[0].AasEnv.AssetAdministrationShells == null) { context.Response.SendResponse(HttpStatusCode.InternalServerError, $"Error accessing internal data structures."); return; @@ -1513,11 +1453,11 @@ public void EvalDeleteAasAndAsset(IHttpContext context, string aasid, bool delet // delete context.Server.Logger.Debug($"Deleting AdministrationShell with IdShort {findAasReturn.aas.IdShort ?? "--"} and id {findAasReturn.aas.Id?.ToString() ?? "--"}"); - this.Packages[ findAasReturn.iPackage ].AasEnv.AssetAdministrationShells.Remove(findAasReturn.aas); + this.Packages[findAasReturn.iPackage].AasEnv.AssetAdministrationShells.Remove(findAasReturn.aas); - if (this.Packages[ findAasReturn.iPackage ].AasEnv.AssetAdministrationShells.Count == 0) + if (this.Packages[findAasReturn.iPackage].AasEnv.AssetAdministrationShells.Count == 0) { - this.Packages[ findAasReturn.iPackage ] = null; + this.Packages[findAasReturn.iPackage] = null; } else { @@ -1540,8 +1480,8 @@ public void EvalDeleteAasAndAsset(IHttpContext context, string aasid, bool delet public void EvalGetAssetLinks(IHttpContext context, string assetid) { - dynamic res1 = new ExpandoObject(); - int index = -1; + dynamic res1 = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -1564,28 +1504,28 @@ public void EvalGetAssetLinks(IHttpContext context, string assetid) } // do a manual search - var res = new List(); + var res = new List(); var specialHandles = this.CreateHandlesFromQueryString(context.Request.QueryString); - var handle = IdRefHandleStore.ResolveSpecific(assetid, specialHandles); + var handle = IdRefHandleStore.ResolveSpecific(assetid, specialHandles); if (handle != null && handle.identification != null) { - foreach (var aas in this.Packages[ 0 ].AasEnv.AssetAdministrationShells) + foreach (var aas in this.Packages[0].AasEnv.AssetAdministrationShells) if (aas.AssetInformation != null && (aas.AssetInformation.GlobalAssetId.Equals(handle.identification))) { dynamic o = new ExpandoObject(); o.identification = aas.Id; - o.IdShort = aas.IdShort; + o.IdShort = aas.IdShort; res.Add(o); } } else { - foreach (var aas in this.Packages[ 0 ].AasEnv.AssetAdministrationShells) + foreach (var aas in this.Packages[0].AasEnv.AssetAdministrationShells) if (aas.IdShort != null && aas.IdShort.Trim() != "" && aas.IdShort.Trim().ToLower() == assetid.Trim().ToLower()) { dynamic o = new ExpandoObject(); o.identification = aas.Id; - o.IdShort = aas.IdShort; + o.IdShort = aas.IdShort; res.Add(o); } } @@ -1597,8 +1537,8 @@ public void EvalGetAssetLinks(IHttpContext context, string assetid) public void EvalPutAsset(IHttpContext context) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -1624,7 +1564,7 @@ public void EvalPutAsset(IHttpContext context) AssetInformation asset = null; try { - asset = Newtonsoft.Json.JsonConvert.DeserializeObject(context.Request.Payload); + asset = System.Text.Json.JsonSerializer.Deserialize(context.Request.Payload); } catch (Exception ex) { @@ -1660,8 +1600,8 @@ public void EvalPutAsset(IHttpContext context) public void EvalPutAssetToAas(IHttpContext context, string aasid) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -1692,46 +1632,7 @@ public void EvalPutAssetToAas(IHttpContext context, string aasid) Console.WriteLine("ERROR PUT: No AAS with IdShort '{0}' found.", aasid); return; } - - // de-serialize asset - //AdminShell.Asset asset = null; - //try - //{ - // asset = Newtonsoft.Json.JsonConvert.DeserializeObject(context.Request.Payload); - //} - //catch (Exception ex) - //{ - // context.Response.SendResponse(HttpStatusCode.BadRequest, $"Cannot deserialize payload: {ex.Message}."); - // return; - //} - - //// need id for idempotent behaviour - //if (asset.identification == null) - //{ - // context.Response.SendResponse(HttpStatusCode.BadRequest, $"Identification of entity is (null); PUT cannot be performed."); - // Console.WriteLine("ERROR PUT: Identification of entity is (null); PUT cannot be performed."); - // return; - //} - - //// datastructure update - //if (this.Packages[findAasReturn.iPackage] == null || this.Packages[findAasReturn.iPackage].AasEnv == null || this.Packages[findAasReturn.iPackage].AasEnv.Assets == null) - //{ - // context.Response.SendResponse(HttpStatusCode.InternalServerError, $"Error accessing internal data structures."); - // return; - //} - - //// add Asset - //context.Server.Logger.Debug($"Adding Asset with IdShort {asset.IdShort ?? "--"} and id {asset.identification?.ToString() ?? "--"}"); - //var existingAsset = this.Packages[findAasReturn.iPackage].AasEnv.FindAsset(asset.identification); - //if (existingAsset != null) - // this.Packages[findAasReturn.iPackage].AasEnv.Assets.Remove(existingAsset); - //this.Packages[findAasReturn.iPackage].AasEnv.Assets.Add(asset); - - //// add AssetRef to AAS - //findAasReturn.aas.assetRef = new AdminShellV20.AssetRef(new AdminShellV20.Reference(new AdminShellV20.Key("Asset", true, asset.identification.idType, asset.identification.id))); - - //Console.WriteLine("{0} Received PUT Asset {1}", countPut++, asset.IdShort); - + // simple OK Program.signalNewData(2); context.Response.StatusCode = HttpStatusCode.Ok; @@ -1755,23 +1656,23 @@ public GetSubmodelsItem() public GetSubmodelsItem(IIdentifiable id, string IdShort, string kind) { - this.id = id; + this.id = id; this.IdShort = IdShort; - this.kind = kind; + this.kind = kind; } public GetSubmodelsItem(IIdentifiable idi, string kind) { - this.id = idi; + this.id = idi; this.IdShort = idi.IdShort; - this.kind = kind; + this.kind = kind; } } public void EvalGetSubmodels(IHttpContext context, string aasid) { - dynamic res1 = new ExpandoObject(); - int index = -1; + dynamic res1 = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -1800,7 +1701,7 @@ public void EvalGetSubmodels(IHttpContext context, string aasid) // get all submodels foreach (var smref in findAasReturn.aas.Submodels) { - var sm = this.Packages[ findAasReturn.iPackage ].AasEnv.FindSubmodel(smref); + var sm = this.Packages[findAasReturn.iPackage].AasEnv.FindSubmodel(smref); if (sm != null) { //res.Add(new GetSubmodelsItem(sm, sm.kind.kind)); @@ -1817,8 +1718,8 @@ public void EvalGetSubmodels(IHttpContext context, string aasid) public void EvalPutSubmodel(IHttpContext context, string aasid) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -1854,12 +1755,11 @@ public void EvalPutSubmodel(IHttpContext context, string aasid) Submodel submodel = null; try { - using (TextReader reader = new StringReader(context.Request.Payload)) - { - JsonSerializer serializer = new JsonSerializer(); - serializer.Converters.Add(new AdminShellConverters.JsonAasxConverter("modelType", "name")); - submodel = (Submodel) serializer.Deserialize(reader, typeof(Submodel)); - } + using var reader = new StringReader(context.Request.Payload); + _jsonSerializerOptions.Converters.Add(new AdminShellConverters.JsonAasxConverter("modelType", "name")); + + // Deserialize the JSON directly into a Submodel object + submodel = JsonSerializer.Deserialize(reader.ReadToEnd(), _jsonSerializerOptions); } catch (Exception ex) { @@ -1877,8 +1777,8 @@ public void EvalPutSubmodel(IHttpContext context, string aasid) } // datastructure update - if (this.Packages[ findAasReturn.iPackage ] == null || - this.Packages[ findAasReturn.iPackage ].AasEnv == null /*|| this.Packages[findAasReturn.iPackage].AasEnv.Assets == null*/) + if (this.Packages[findAasReturn.iPackage] == null || + this.Packages[findAasReturn.iPackage].AasEnv == null /*|| this.Packages[findAasReturn.iPackage].AasEnv.Assets == null*/) { context.Response.SendResponse(HttpStatusCode.InternalServerError, $"Error accessing internal data structures."); return; @@ -1886,22 +1786,22 @@ public void EvalPutSubmodel(IHttpContext context, string aasid) // add Submodel context.Server.Logger.Debug($"Adding Submodel with IdShort {submodel.IdShort ?? "--"} and id {submodel.Id?.ToString() ?? "--"}"); - var existingSm = this.Packages[ findAasReturn.iPackage ].AasEnv.FindSubmodelById(submodel.Id); + var existingSm = this.Packages[findAasReturn.iPackage].AasEnv.FindSubmodelById(submodel.Id); if (existingSm != null) { - int indexOfExistingSm = this.Packages[ findAasReturn.iPackage ].AasEnv.Submodels.IndexOf(existingSm); - this.Packages[ findAasReturn.iPackage ].AasEnv.Submodels.RemoveAt(indexOfExistingSm); - this.Packages[ findAasReturn.iPackage ].AasEnv.Submodels.Insert(indexOfExistingSm, submodel); + int indexOfExistingSm = this.Packages[findAasReturn.iPackage].AasEnv.Submodels.IndexOf(existingSm); + this.Packages[findAasReturn.iPackage].AasEnv.Submodels.RemoveAt(indexOfExistingSm); + this.Packages[findAasReturn.iPackage].AasEnv.Submodels.Insert(indexOfExistingSm, submodel); } else { - this.Packages[ findAasReturn.iPackage ].AasEnv.Submodels.Add(submodel); + this.Packages[findAasReturn.iPackage].AasEnv.Submodels.Add(submodel); } // add SubmodelRef to AAS - var key = new Key(KeyTypes.Submodel, submodel.Id); - var KeyList = new List() {key}; - Reference newsmr = new Reference(AasCore.Aas3_0.ReferenceTypes.ModelReference, KeyList); + var key = new Key(KeyTypes.Submodel, submodel.Id); + var KeyList = new List() {key}; + Reference newsmr = new Reference(AasCore.Aas3_0.ReferenceTypes.ModelReference, KeyList); //var newsmr = SubmodelRef.CreateNew("Submodel", submodel.Id); var existsmr = findAasReturn.aas.HasSubmodelReference(newsmr); if (!existsmr) @@ -1920,8 +1820,8 @@ public void EvalPutSubmodel(IHttpContext context, string aasid) public void EvalDeleteSubmodel(IHttpContext context, string aasid, string smid) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -1956,7 +1856,7 @@ public void EvalDeleteSubmodel(IHttpContext context, string aasid, string smid) if (smref != null) { context.Server.Logger.Debug( - $"Removing SubmodelRef {smid} from AAS with IdShort {findAasReturn.aas.IdShort ?? "--"} and id {findAasReturn.aas.Id?.ToString() ?? "--"}"); + $"Removing SubmodelRef {smid} from AAS with IdShort {findAasReturn.aas.IdShort ?? "--"} and id {findAasReturn.aas.Id?.ToString() ?? "--"}"); findAasReturn.aas.Submodels.Remove(smref); } @@ -1965,7 +1865,7 @@ public void EvalDeleteSubmodel(IHttpContext context, string aasid, string smid) if (sm != null) { context.Server.Logger.Debug($"Removing Submodel {smid} from data structures."); - this.Packages[ findAasReturn.iPackage ].AasEnv.Submodels.Remove(sm); + this.Packages[findAasReturn.iPackage].AasEnv.Submodels.Remove(sm); } // simple OK @@ -1973,8 +1873,8 @@ public void EvalDeleteSubmodel(IHttpContext context, string aasid, string smid) var cmt = ""; if (smref == null && sm == null) cmt += " (nothing deleted)"; - cmt += ((smref != null) ? " (SubmodelRef deleted)" : "") + ((sm != null) ? " (Submodel deleted)" : ""); - context.Response.StatusCode = HttpStatusCode.Ok; + cmt += ((smref != null) ? " (SubmodelRef deleted)" : "") + ((sm != null) ? " (Submodel deleted)" : ""); + context.Response.StatusCode = HttpStatusCode.Ok; SendTextResponse(context, "OK" + cmt); } @@ -1986,8 +1886,8 @@ public void EvalDeleteSubmodel(IHttpContext context, string aasid, string smid) public void EvalGetSubmodelContents(IHttpContext context, string aasid, string smid, bool deep = false, bool complete = false) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2013,15 +1913,15 @@ public void EvalGetSubmodelContents(IHttpContext context, string aasid, string s Console.WriteLine("{0} Received GET Submodel {1}", countGet++, sm.IdShort); // return as JSON - var cr = new AdminShellConverters.AdaptiveFilterContractResolver(deep: deep, complete: complete); + var cr = new AdminShellConverters.AdaptiveFilterContractResolver(deep, complete); context.Response.StatusCode = HttpStatusCode.Ok; SendJsonResponse(context, sm, cr); } public void EvalGetSubmodelContentsAsTable(IHttpContext context, string aasid, string smid) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2046,7 +1946,7 @@ public void EvalGetSubmodelContentsAsTable(IHttpContext context, string aasid, s } // AAS ENV - if (this.Packages[ 0 ] == null || this.Packages[ 0 ].AasEnv == null) + if (this.Packages[0] == null || this.Packages[0].AasEnv == null) { context.Response.SendResponse(HttpStatusCode.InternalServerError, $"Error accessing internal data structures."); return; @@ -2055,98 +1955,98 @@ public void EvalGetSubmodelContentsAsTable(IHttpContext context, string aasid, s // make a table var table = new List(); sm.RecurseOnSubmodelElements(null, (o, parents, sme) => - { - // start a row - dynamic row = new ExpandoObject(); - - // defaults - row.IdShorts = ""; - row.typeName = ""; - row.semIdType = ""; - row.semId = ""; - row.shortName = ""; - row.unit = ""; - row.Value = ""; - - // IdShort is a concatenation - var path = ""; - foreach (var p in parents) - path += p.IdShort + "/"; - - // SubnmodelElement general - row.IdShorts = path + sme.IdShort ?? "(-)"; - //row.typeName = sme.GetElementName(); - row.typeName = sme.GetType().ToString(); - if (sme.SemanticId == null || sme.SemanticId.Keys == null /*|| sme.semanticId.Keys.Count == 0*/) - { - } - else if (sme.SemanticId.Keys.Count > 1) - { - row.semId = "(complex)"; - } - else - { - row.semId = sme.SemanticId.Keys.First().Value; - //row.semIdType = sme.semanticId.Keys[0].idType; - //row.semId = sme.semanticId.Keys[0].Value; - } - - // try find a concept description - if (sme.SemanticId != null) - { - var cd = this.Packages[ 0 ].AasEnv.FindConceptDescriptionByReference(sme.SemanticId); - if (cd != null) - { - // TODO (jtikekar, 2023-09-04): Temporarily commented - //var ds = cd.GetIEC61360(); - //if (ds != null) - //{ - // row.shortName = (ds.shortName == null ? "" : ds.shortName.GetDefaultStr()); - // row.unit = ds.unit ?? ""; - //} - } - } - - // try add a value - if (sme is Property) - { - var p = sme as Property; - row.Value = "" + (p.Value ?? "") + ((p.ValueId != null) ? p.ValueId.ToString() : ""); - } - - if (sme is AasCore.Aas3_0.File) - { - var p = sme as AasCore.Aas3_0.File; - row.Value = "" + p.Value; - } - - if (sme is Blob) - { - var p = sme as Blob; - if (p.Value.Length < 128) - row.Value = "" + p.Value; - else - row.Value = "(" + p.Value.Length + " bytes)"; - } - - if (sme is ReferenceElement gre) - row.Value = "" + gre.Value.ToString(); - - if (sme is ReferenceElement mre) - row.Value = "" + mre.Value.ToString(); - - if (sme is RelationshipElement) - { - var p = sme as RelationshipElement; - row.Value = "" + (p.First?.ToString() ?? "(-)") + " <-> " + (p.Second?.ToString() ?? "(-)"); - } - - // now, add the row - table.Add(row); - - // recurse - return true; - }); + { + // start a row + dynamic row = new ExpandoObject(); + + // defaults + row.IdShorts = ""; + row.typeName = ""; + row.semIdType = ""; + row.semId = ""; + row.shortName = ""; + row.unit = ""; + row.Value = ""; + + // IdShort is a concatenation + var path = ""; + foreach (var p in parents) + path += p.IdShort + "/"; + + // SubnmodelElement general + row.IdShorts = path + sme.IdShort ?? "(-)"; + //row.typeName = sme.GetElementName(); + row.typeName = sme.GetType().ToString(); + if (sme.SemanticId == null || sme.SemanticId.Keys == null /*|| sme.semanticId.Keys.Count == 0*/) + { + } + else if (sme.SemanticId.Keys.Count > 1) + { + row.semId = "(complex)"; + } + else + { + row.semId = sme.SemanticId.Keys.First().Value; + //row.semIdType = sme.semanticId.Keys[0].idType; + //row.semId = sme.semanticId.Keys[0].Value; + } + + // try find a concept description + if (sme.SemanticId != null) + { + var cd = this.Packages[0].AasEnv.FindConceptDescriptionByReference(sme.SemanticId); + if (cd != null) + { + // TODO (jtikekar, 2023-09-04): Temporarily commented + //var ds = cd.GetIEC61360(); + //if (ds != null) + //{ + // row.shortName = (ds.shortName == null ? "" : ds.shortName.GetDefaultStr()); + // row.unit = ds.unit ?? ""; + //} + } + } + + // try add a value + if (sme is Property) + { + var p = sme as Property; + row.Value = "" + (p.Value ?? "") + ((p.ValueId != null) ? p.ValueId.ToString() : ""); + } + + if (sme is AasCore.Aas3_0.File) + { + var p = sme as AasCore.Aas3_0.File; + row.Value = "" + p.Value; + } + + if (sme is Blob) + { + var p = sme as Blob; + if (p.Value.Length < 128) + row.Value = "" + p.Value; + else + row.Value = "(" + p.Value.Length + " bytes)"; + } + + if (sme is ReferenceElement gre) + row.Value = "" + gre.Value.ToString(); + + if (sme is ReferenceElement mre) + row.Value = "" + mre.Value.ToString(); + + if (sme is RelationshipElement) + { + var p = sme as RelationshipElement; + row.Value = "" + (p.First?.ToString() ?? "(-)") + " <-> " + (p.Second?.ToString() ?? "(-)"); + } + + // now, add the row + table.Add(row); + + // recurse + return true; + }); // return as JSON context.Response.StatusCode = HttpStatusCode.Ok; @@ -2159,8 +2059,8 @@ public void EvalGetSubmodelContentsAsTable(IHttpContext context, string aasid, s public void EvalGetSubmodelElementContents(IHttpContext context, string aasid, string smid, string[] elemids, bool deep = false, bool complete = false) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2199,15 +2099,15 @@ public void EvalGetSubmodelElementContents(IHttpContext context, string aasid, s } // return as JSON - var cr = new AdminShellConverters.AdaptiveFilterContractResolver(deep: deep, complete: complete); + var cr = new AdminShellConverters.AdaptiveFilterContractResolver(deep, complete); context.Response.StatusCode = HttpStatusCode.Ok; SendJsonResponse(context, sme, cr); } public void EvalGetSubmodelElementsBlob(IHttpContext context, string aasid, string smid, string[] elemids) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2232,7 +2132,7 @@ public void EvalGetSubmodelElementsBlob(IHttpContext context, string aasid, stri } // find the right SubmodelElement - var fse = this.FindSubmodelElement(sm, sm.SubmodelElements, elemids); + var fse = this.FindSubmodelElement(sm, sm.SubmodelElements, elemids); var smeb = fse?.elem as Blob; if (smeb == null || smeb.Value == null || (smeb.Value.Length == 0)) { @@ -2260,7 +2160,7 @@ private string EvalGetSubmodelElementsProperty_EvalValue(Property smep) { // add noise dblval += Math.Sin((0.001 * DateTime.UtcNow.Millisecond) * 6.28); - strval = dblval.ToString(CultureInfo.InvariantCulture); + strval = dblval.ToString(CultureInfo.InvariantCulture); } return strval; @@ -2276,24 +2176,24 @@ private List EvalGetSubmodelElementsProperty_EvalValues( // recurse for results wrappers.RecurseOnSubmodelElements(null, new List(), - (_, pars, el) => - { - if (el is Property smep && pars != null) - { - var path = new List(); - path.Add("" + smep?.IdShort); - for (int i = pars.Count - 1; i >= 0; i--) - path.Insert(0, "" + pars[ i ].IdShort); - - dynamic tuple = new ExpandoObject(); - tuple.path = path; - tuple.Value = "" + EvalGetSubmodelElementsProperty_EvalValue(smep); - if (smep.ValueId != null) - tuple.ValueId = smep.ValueId; - - res.Add(tuple); - } - }); + (_, pars, el) => + { + if (el is Property smep && pars != null) + { + var path = new List(); + path.Add("" + smep?.IdShort); + for (int i = pars.Count - 1; i >= 0; i--) + path.Insert(0, "" + pars[i].IdShort); + + dynamic tuple = new ExpandoObject(); + tuple.path = path; + tuple.Value = "" + EvalGetSubmodelElementsProperty_EvalValue(smep); + if (smep.ValueId != null) + tuple.ValueId = smep.ValueId; + + res.Add(tuple); + } + }); // ok return res; @@ -2301,8 +2201,8 @@ private List EvalGetSubmodelElementsProperty_EvalValues( public void EvalGetSubmodelAllElementsProperty(IHttpContext context, string aasid, string smid, string[] elemids) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2362,8 +2262,8 @@ public void EvalGetSubmodelAllElementsProperty(IHttpContext context, string aasi public void EvalGetSubmodelElementsFile(IHttpContext context, string aasid, string smid, string[] elemids) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2388,7 +2288,7 @@ public void EvalGetSubmodelElementsFile(IHttpContext context, string aasid, stri } // find the right SubmodelElement - var fse = this.FindSubmodelElement(sm, sm.SubmodelElements, elemids); + var fse = this.FindSubmodelElement(sm, sm.SubmodelElements, elemids); var smef = fse?.elem as AasCore.Aas3_0.File; if (smef == null || smef.Value == null || smef.Value == "") { @@ -2397,7 +2297,7 @@ public void EvalGetSubmodelElementsFile(IHttpContext context, string aasid, stri } // access - var packageStream = this.Packages[ 0 ].GetLocalStreamFromPackage(smef.Value); + var packageStream = this.Packages[0].GetLocalStreamFromPackage(smef.Value); if (packageStream == null) { context.Response.SendResponse(HttpStatusCode.NotFound, $"No file contents available in package."); @@ -2412,8 +2312,8 @@ public void EvalGetSubmodelElementsFile(IHttpContext context, string aasid, stri public void EvalPutSubmodelElementContents(IHttpContext context, string aasid, string smid, string[] elemids) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2445,7 +2345,10 @@ public void EvalPutSubmodelElementContents(IHttpContext context, string aasid, s ISubmodelElement sme = null; try { - sme = Newtonsoft.Json.JsonConvert.DeserializeObject(context.Request.Payload, new AdminShellConverters.JsonAasxConverter("modelType", "name")); + var options = new JsonSerializerOptions(); + options.Converters.Add(new AdminShellConverters.JsonAasxConverter("modelType", "name")); + + sme = JsonSerializer.Deserialize(context.Request.Payload, options); } catch (Exception ex) { @@ -2453,6 +2356,7 @@ public void EvalPutSubmodelElementContents(IHttpContext context, string aasid, s return; } + // need id for idempotent behaviour if (sme.IdShort == null) { @@ -2470,9 +2374,9 @@ public void EvalPutSubmodelElementContents(IHttpContext context, string aasid, s } // Check query parameter - bool first = false; - var queryString = context.Request.QueryString; - string f = queryString[ "first" ]; + bool first = false; + var queryString = context.Request.QueryString; + string f = queryString["first"]; if (f != null && f != "") { first = true; @@ -2480,13 +2384,13 @@ public void EvalPutSubmodelElementContents(IHttpContext context, string aasid, s // special case: parent is Submodel itself var timeStamp = DateTime.UtcNow; - var updated = false; + var updated = false; if (elemids == null || elemids.Length < 1) { var existsmw = sm.FindSubmodelElementByIdShort(sme.IdShort); if (existsmw != null) { - updated = true; + updated = true; sme.TimeStampCreate = existsmw.TimeStampCreate; context.Server.Logger.Debug($"Removing old SubmodelElement {sme.IdShort} from Submodel {smid}."); int indexOfExistingSmw = sm.SubmodelElements.IndexOf(existsmw); @@ -2530,10 +2434,10 @@ public void EvalPutSubmodelElementContents(IHttpContext context, string aasid, s if (parent.elem != null && parent.elem is SubmodelElementCollection) { var parentsmc = parent.elem as SubmodelElementCollection; - var existsmw = parentsmc.FindFirstIdShortAs(sme.IdShort); + var existsmw = parentsmc.FindFirstIdShortAs(sme.IdShort); if (existsmw != null) { - updated = true; + updated = true; sme.TimeStampCreate = existsmw.TimeStampCreate; context.Server.Logger.Debug($"Removing old SubmodelElement {sme.IdShort} from SubmodelCollection."); int indexOfExistingSmw = parentsmc.Value.IndexOf(existsmw); @@ -2572,8 +2476,8 @@ public void EvalPutSubmodelElementContents(IHttpContext context, string aasid, s public void EvalDeleteSubmodelElementContents(IHttpContext context, string aasid, string smid, string[] elemids) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2607,12 +2511,12 @@ public void EvalDeleteSubmodelElementContents(IHttpContext context, string aasid // where to delete? var deleted = false; - var elinfo = string.Join(".", elemids); + var elinfo = string.Join(".", elemids); if (fse.parent == sm) { context.Server.Logger.Debug($"Deleting specified SubmodelElement {elinfo} from Submodel {smid}."); AasxRestServerLibrary.AasxRestServer.TestResource.eventMessage.add( - fse.submodelElement, "Remove", sm, (ulong) DateTime.UtcNow.Ticks); + fse.submodelElement, "Remove", sm, (ulong)DateTime.UtcNow.Ticks); sm.SubmodelElements.Remove(fse.submodelElement); deleted = true; } @@ -2633,8 +2537,8 @@ public void EvalDeleteSubmodelElementContents(IHttpContext context, string aasid public void EvalInvokeSubmodelElementOperation(IHttpContext context, string aasid, string smid, string[] elemids) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2659,7 +2563,7 @@ public void EvalInvokeSubmodelElementOperation(IHttpContext context, string aasi } // find the right SubmodelElement - var fse = this.FindSubmodelElement(sm, sm.SubmodelElements, elemids); + var fse = this.FindSubmodelElement(sm, sm.SubmodelElements, elemids); var smep = fse?.elem as Operation; if (smep == null) { @@ -2668,11 +2572,11 @@ public void EvalInvokeSubmodelElementOperation(IHttpContext context, string aasi } // make 1st expectation - int numExpectedInputArgs = smep.InputVariables?.Count ?? 0; - int numGivenInputArgs = 0; + int numExpectedInputArgs = smep.InputVariables?.Count ?? 0; + int numGivenInputArgs = 0; int numExpectedOutputArgs = smep.OutputVariables?.Count ?? 0; - var inputArguments = (new int[numExpectedInputArgs]).Select(x => "").ToList(); - var outputArguments = (new int[numExpectedOutputArgs]).Select(x => "my value").ToList(); + var inputArguments = (new int[numExpectedInputArgs]).Select(x => "").ToList(); + var outputArguments = (new int[numExpectedOutputArgs]).Select(x => "my value").ToList(); // is a payload required? Always, if at least one input argument required @@ -2689,14 +2593,14 @@ public void EvalInvokeSubmodelElementOperation(IHttpContext context, string aasi try { // serialize - var input = Newtonsoft.Json.JsonConvert.DeserializeObject>(context.Request.Payload); + var input = System.Text.Json.JsonSerializer.Deserialize>(context.Request.Payload); // set inputs if (input != null && input.Count > 0) { numGivenInputArgs = input.Count; for (int i = 0; i < numGivenInputArgs; i++) - inputArguments[ i ] = input[ i ]; + inputArguments[i] = input[i]; } } catch (Exception ex) @@ -2717,7 +2621,7 @@ public void EvalInvokeSubmodelElementOperation(IHttpContext context, string aasi if (smep.FindQualifierOfType("DEMO") != null) { for (int i = 0; i < Math.Min(numExpectedInputArgs, numExpectedOutputArgs); i++) - outputArguments[ i ] = "CALC on " + inputArguments[ i ]; + outputArguments[i] = "CALC on " + inputArguments[i]; } // return as little dynamic object @@ -2727,8 +2631,8 @@ public void EvalInvokeSubmodelElementOperation(IHttpContext context, string aasi public void EvalGetAllCds(IHttpContext context, string aasid) { - dynamic res1 = new ExpandoObject(); - int index = -1; + dynamic res1 = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2757,8 +2661,11 @@ public void EvalGetAllCds(IHttpContext context, string aasid) // create a new, filtered AasEnv // (this is expensive, but delivers us with a list of CDs which are in relation to the respective AAS) var copyenv = new AasCore.Aas3_0.Environment(); - copyenv = copyenv.CreateFromExistingEnvironment(this.Packages[ findAasReturn.iPackage ].AasEnv, - filterForAas: new List(new AssetAdministrationShell[] {(AssetAdministrationShell) findAasReturn.aas})); + copyenv = copyenv.CreateFromExistingEnvironment(this.Packages[findAasReturn.iPackage].AasEnv, + filterForAas: new List(new AssetAdministrationShell[] + { + (AssetAdministrationShell)findAasReturn.aas + })); // get all CDs and describe them foreach (var cd in copyenv.ConceptDescriptions) @@ -2769,7 +2676,7 @@ public void EvalGetAllCds(IHttpContext context, string aasid) // TODO (jtikekar, 2023-09-04): temporarily commented //o.shortName = cd.GetDefaultShortName(); o.identification = cd.Id; - o.isCaseOf = cd.IsCaseOf; + o.isCaseOf = cd.IsCaseOf; // add res.Add(o); @@ -2782,8 +2689,8 @@ public void EvalGetAllCds(IHttpContext context, string aasid) public void EvalGetCdContents(IHttpContext context, string aasid, string cdid) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2800,7 +2707,7 @@ public void EvalGetCdContents(IHttpContext context, string aasid, string cdid) // access AAS and CD var findAasReturn = this.FindAAS(aasid, context.Request.QueryString, context.Request.RawUrl); - var cd = this.FindCdWithoutAas(findAasReturn, cdid, context.Request.QueryString, context.Request.RawUrl); + var cd = this.FindCdWithoutAas(findAasReturn, cdid, context.Request.QueryString, context.Request.RawUrl); if (cd == null) { @@ -2815,8 +2722,8 @@ public void EvalGetCdContents(IHttpContext context, string aasid, string cdid) public void EvalDeleteSpecificCd(IHttpContext context, string aasid, string cdid) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2833,7 +2740,7 @@ public void EvalDeleteSpecificCd(IHttpContext context, string aasid, string cdid // access AAS and CD var findAasReturn = this.FindAAS(aasid, context.Request.QueryString, context.Request.RawUrl); - var cd = this.FindCdWithoutAas(findAasReturn, cdid, context.Request.QueryString, context.Request.RawUrl); + var cd = this.FindCdWithoutAas(findAasReturn, cdid, context.Request.QueryString, context.Request.RawUrl); if (cd == null) { context.Response.SendResponse(HttpStatusCode.NotFound, $"No AAS '{aasid}' or no ConceptDescription with id '{cdid}' found."); @@ -2842,10 +2749,10 @@ public void EvalDeleteSpecificCd(IHttpContext context, string aasid, string cdid // delete ?! var deleted = false; - if (this.Packages[ findAasReturn.iPackage ] != null && this.Packages[ findAasReturn.iPackage ].AasEnv != null && - this.Packages[ findAasReturn.iPackage ].AasEnv.ConceptDescriptions.Contains(cd)) + if (this.Packages[findAasReturn.iPackage] != null && this.Packages[findAasReturn.iPackage].AasEnv != null && + this.Packages[findAasReturn.iPackage].AasEnv.ConceptDescriptions.Contains(cd)) { - this.Packages[ findAasReturn.iPackage ].AasEnv.ConceptDescriptions.Remove(cd); + this.Packages[findAasReturn.iPackage].AasEnv.ConceptDescriptions.Remove(cd); deleted = true; } @@ -2861,8 +2768,8 @@ this.Packages[ findAasReturn.iPackage ].AasEnv.ConceptDescriptions.Contains(cd)) public void EvalGetHandlesIdentification(IHttpContext context) { - dynamic res1 = new ExpandoObject(); - int index = -1; + dynamic res1 = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2887,8 +2794,8 @@ public void EvalGetHandlesIdentification(IHttpContext context) public void EvalPostHandlesIdentification(IHttpContext context) { - dynamic res1 = new ExpandoObject(); - int index = -1; + dynamic res1 = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -2914,7 +2821,7 @@ public void EvalPostHandlesIdentification(IHttpContext context) List ids = null; try { - ids = Newtonsoft.Json.JsonConvert.DeserializeObject>(context.Request.Payload); + ids = System.Text.Json.JsonSerializer.Deserialize>(context.Request.Payload); } catch (Exception ex) { @@ -2955,10 +2862,11 @@ public void EvalGetServerProfile(IHttpContext context) // get the list dynamic res = new ExpandoObject(); var capabilities = new List(new ulong[] - { - 80, 81, 82, 10, 11, 12, 13, 15, 16, 20, 21, 30, 31, 40, 41, 42, 43, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 70, 71, 72, 73 - }); - res.apiversion = 1; + { + 80, 81, 82, 10, 11, 12, 13, 15, 16, 20, 21, 30, 31, 40, 41, 42, 43, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 70, 71, 72, + 73 + }); + res.apiversion = 1; res.capabilities = capabilities; // return this list @@ -2990,14 +2898,10 @@ public void EvalGetAuthenticateGuest(IHttpContext context) // string with real random numbers Byte[] barray = new byte[100]; randomNumberGenerator.GetBytes(barray); - sessionRandom[ sessionCount ] = Convert.ToBase64String(barray); + sessionRandom[sessionCount] = Convert.ToBase64String(barray); - dynamic res = new ExpandoObject(); - var payload = new Dictionary() - { - {"sessionID", sessionCount}, - {"sessionRandom", sessionRandom[ sessionCount ]} - }; + dynamic res = new ExpandoObject(); + var payload = new Dictionary() {{"sessionID", sessionCount}, {"sessionRandom", sessionRandom[sessionCount]}}; System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); GuestToken = Jose.JWT.Encode(payload, enc.GetBytes(secretString), JwsAlgorithm.HS256); @@ -3007,8 +2911,8 @@ public void EvalGetAuthenticateGuest(IHttpContext context) withAuthentification = true; - sessionUserType[ sessionCount ] = 'G'; - sessionUserName[ sessionCount ] = "guest"; + sessionUserType[sessionCount] = 'G'; + sessionUserName[sessionCount] = "guest"; sessionCount++; if (sessionCount >= 100) { @@ -3028,18 +2932,17 @@ public void EvalPostAuthenticateUser(IHttpContext context) Console.WriteLine("AuthenticateUser"); // POST User, Password bool userFound = false; - bool error = false; - - dynamic res = new ExpandoObject(); + bool error = false; - var parsed = JObject.Parse(context.Request.Payload); + dynamic res = new ExpandoObject(); + var parsed = JsonDocument.Parse(context.Request.Payload); - string user = null; + string user = null; string password = null; try { - user = parsed.SelectToken("user").Value(); - password = parsed.SelectToken("password").Value(); + user = parsed.RootElement.GetProperty("user").GetString(); + password = parsed.RootElement.GetProperty("password").GetString(); } catch { @@ -3052,7 +2955,7 @@ public void EvalPostAuthenticateUser(IHttpContext context) for (int i = 0; i < userCount; i++) { - if (user == securityUserName[ i ] && password == securityUserPassword[ i ]) + if (user == securityUserName[i] && password == securityUserPassword[i]) { userFound = true; break; @@ -3070,22 +2973,18 @@ public void EvalPostAuthenticateUser(IHttpContext context) // string with real random numbers Byte[] barray = new byte[100]; randomNumberGenerator.GetBytes(barray); - sessionRandom[ sessionCount ] = Convert.ToBase64String(barray); + sessionRandom[sessionCount] = Convert.ToBase64String(barray); - var payload = new Dictionary() - { - {"sessionID", sessionCount}, - {"sessionRandom", sessionRandom[ sessionCount ]} - }; + var payload = new Dictionary() {{"sessionID", sessionCount}, {"sessionRandom", sessionRandom[sessionCount]}}; - System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); - string token = Jose.JWT.Encode(payload, enc.GetBytes(secretString), JwsAlgorithm.HS256); + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + string token = Jose.JWT.Encode(payload, enc.GetBytes(secretString), JwsAlgorithm.HS256); Console.WriteLine("SessionID: " + sessionCount); Console.WriteLine("sessionRandom: " + token); - sessionUserType[ sessionCount ] = 'U'; - sessionUserName[ sessionCount ] = user; + sessionUserType[sessionCount] = 'U'; + sessionUserName[sessionCount] = user; sessionCount++; if (sessionCount >= 100) { @@ -3106,43 +3005,43 @@ public void EvalPostAuthenticateCert1(IHttpContext context) Console.WriteLine(); Console.WriteLine("Security 2 Server: /AuthenticateCert1"); // POST token with user - sessionUserType[ sessionCount ] = ' '; - sessionUserName[ sessionCount ] = ""; - sessionRandom[ sessionCount ] = ""; - sessionChallenge[ sessionCount ] = ""; + sessionUserType[sessionCount] = ' '; + sessionUserName[sessionCount] = ""; + sessionRandom[sessionCount] = ""; + sessionChallenge[sessionCount] = ""; bool error = false; - dynamic res = new ExpandoObject(); - X509Certificate2 x509 = null; - string user = null; - string token = null; - RSA publicKey = null; + dynamic res = new ExpandoObject(); + X509Certificate2 x509 = null; + string user = null; + string token = null; + RSA publicKey = null; try { - var parsed = JObject.Parse(context.Request.Payload); - token = parsed.SelectToken("token").Value(); + var parsed = JsonDocument.Parse(context.Request.Payload); + token = parsed.RootElement.GetProperty("token").GetString(); - var headers = Jose.JWT.Headers(token); - string x5c = headers[ "x5c" ].ToString(); + var headers = Jose.JWT.Headers(token); + string x5c = headers["x5c"].ToString(); if (x5c != "") { Console.WriteLine("Security 2.1a Server: x5c with certificate chain received"); - parsed = JObject.Parse(Jose.JWT.Payload(token)); - user = parsed.SelectToken("user").Value(); + parsed = JsonDocument.Parse(Jose.JWT.Payload(token)); + user = parsed.RootElement.GetProperty("user").GetString(); X509Store storeCA = new X509Store("CA", StoreLocation.CurrentUser); storeCA.Open(OpenFlags.ReadWrite); - bool valid = false; - - string[] x5c64 = JsonConvert.DeserializeObject(x5c); + bool valid = false; + + var x5c64 = JsonSerializer.Deserialize(x5c); - X509Certificate2Collection xcc = new X509Certificate2Collection(); - Byte[] certFileBytes = Convert.FromBase64String(x5c64[ 0 ]); - string fileCert = "./temp/" + user + ".cer"; + X509Certificate2Collection xcc = new X509Certificate2Collection(); + Byte[] certFileBytes = Convert.FromBase64String(x5c64[0]); + string fileCert = "./temp/" + user + ".cer"; System.IO.File.WriteAllBytes(fileCert, certFileBytes); Console.WriteLine("Security 2.1b Server: " + fileCert + " received"); @@ -3152,14 +3051,14 @@ public void EvalPostAuthenticateCert1(IHttpContext context) StringBuilder builder = new StringBuilder(); builder.AppendLine("-----BEGIN CERTIFICATE-----"); builder.AppendLine( - Convert.ToBase64String(x509.RawData, Base64FormattingOptions.InsertLineBreaks)); + Convert.ToBase64String(x509.RawData, Base64FormattingOptions.InsertLineBreaks)); builder.AppendLine("-----END CERTIFICATE-----"); Console.WriteLine("Certificate: "); Console.WriteLine(builder); for (int i = 1; i < x5c64.Length; i++) { - var cert = new X509Certificate2(Convert.FromBase64String(x5c64[ i ])); + var cert = new X509Certificate2(Convert.FromBase64String(x5c64[i])); Console.WriteLine("Security 2.1c Certificate in Chain: " + cert.Subject); if (cert.Subject != cert.Issuer) { @@ -3184,8 +3083,8 @@ public void EvalPostAuthenticateCert1(IHttpContext context) } else { - parsed = JObject.Parse(Jose.JWT.Payload(token)); - user = parsed.SelectToken("user").Value(); + parsed = JsonDocument.Parse(Jose.JWT.Payload(token)); + user = parsed.RootElement.GetProperty("user").GetString(); string fileCert = "./user/" + user + ".cer"; if (System.IO.File.Exists(fileCert)) @@ -3196,15 +3095,15 @@ public void EvalPostAuthenticateCert1(IHttpContext context) else { // receive .cer and verify against root - string certFileBase64 = parsed.SelectToken("certFile").Value(); - Byte[] certFileBytes = Convert.FromBase64String(certFileBase64); + string certFileBase64 = parsed.RootElement.GetProperty("certFile").GetString(); + Byte[] certFileBytes = Convert.FromBase64String(certFileBase64); fileCert = "./temp/" + user + ".cer"; System.IO.File.WriteAllBytes(fileCert, certFileBytes); Console.WriteLine("Security 2.1b Server: " + fileCert + " received"); x509 = new X509Certificate2(certFileBytes); - // check if certifcate is valid according to root certificates + // check if certificate is valid according to root certificates X509Chain chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; bool isValid = chain.Build(x509); @@ -3247,7 +3146,7 @@ public void EvalPostAuthenticateCert1(IHttpContext context) randomNumberGenerator.GetBytes(barray); Console.WriteLine("Security 2.3 Server: Create session unique challenge by real random"); - sessionChallenge[ sessionCount ] = Convert.ToBase64String(barray); + sessionChallenge[sessionCount] = Convert.ToBase64String(barray); } if (error) @@ -3258,15 +3157,15 @@ public void EvalPostAuthenticateCert1(IHttpContext context) } Console.WriteLine("sessionID: " + sessionCount); - Console.WriteLine("session challenge: " + sessionChallenge[ sessionCount ]); + Console.WriteLine("session challenge: " + sessionChallenge[sessionCount]); - sessionUserType[ sessionCount ] = 'T'; - sessionUserName[ sessionCount ] = user; - sessionUserPulicKey[ sessionCount ] = publicKey; + sessionUserType[sessionCount] = 'T'; + sessionUserName[sessionCount] = user; + sessionUserPulicKey[sessionCount] = publicKey; withAuthentification = true; - res.challenge = sessionChallenge[ sessionCount ]; + res.challenge = sessionChallenge[sessionCount]; context.Response.StatusCode = HttpStatusCode.Ok; SendJsonResponse(context, res); @@ -3277,22 +3176,22 @@ public void EvalPostAuthenticateCert2(IHttpContext context) Console.WriteLine(); Console.WriteLine("Security 3 Server: /AuthenticateCert2"); // POST token with user - sessionRandom[ sessionCount ] = ""; + sessionRandom[sessionCount] = ""; bool error = false; - dynamic res = new ExpandoObject(); - string token = null; - string challenge = null; - RSA publicKey = null; + dynamic res = new ExpandoObject(); + string token = null; + string challenge = null; + RSA publicKey = null; try { - var parsed = JObject.Parse(context.Request.Payload); - token = parsed.SelectToken("token").Value(); + var parsed = JsonDocument.Parse(context.Request.Payload); + token = parsed.RootElement.GetProperty("token").GetString(); - parsed = JObject.Parse(Jose.JWT.Payload(token)); - challenge = parsed.SelectToken("challenge").Value(); + parsed = JsonDocument.Parse(Jose.JWT.Payload(token)); + challenge = parsed.RootElement.GetProperty("challenge").GetString(); } catch { @@ -3300,7 +3199,7 @@ public void EvalPostAuthenticateCert2(IHttpContext context) error = true; } - if (challenge != sessionChallenge[ sessionCount ] || sessionChallenge[ sessionCount ] == null || sessionChallenge[ sessionCount ] == "") + if (challenge != sessionChallenge[sessionCount] || sessionChallenge[sessionCount] == null || sessionChallenge[sessionCount] == "") { error = true; } @@ -3309,7 +3208,7 @@ public void EvalPostAuthenticateCert2(IHttpContext context) { try { - publicKey = sessionUserPulicKey[ sessionCount ]; + publicKey = sessionUserPulicKey[sessionCount]; Jose.JWT.Decode(token, publicKey, JwsAlgorithm.RS256); // signed by user key? Console.WriteLine("Security 3.1 Server: Validate challenge signature with publicKey"); @@ -3328,17 +3227,14 @@ public void EvalPostAuthenticateCert2(IHttpContext context) Byte[] barray = new byte[100]; randomNumberGenerator.GetBytes(barray); Console.WriteLine("Security 3.2 Server: Create session unique bearerToken signed by real random"); - sessionRandom[ sessionCount ] = Convert.ToBase64String(barray); + sessionRandom[sessionCount] = Convert.ToBase64String(barray); - var payload = new Dictionary() - { - {"sessionID", sessionCount}, - }; + var payload = new Dictionary() {{"sessionID", sessionCount},}; try { var enc = new System.Text.ASCIIEncoding(); - token = Jose.JWT.Encode(payload, enc.GetBytes(sessionRandom[ sessionCount ]), JwsAlgorithm.HS256); + token = Jose.JWT.Encode(payload, enc.GetBytes(sessionRandom[sessionCount]), JwsAlgorithm.HS256); Console.WriteLine("Security 3.3 Server: Sign sessionID by server sessionRandom"); } catch @@ -3355,7 +3251,7 @@ public void EvalPostAuthenticateCert2(IHttpContext context) } Console.WriteLine("sessionID: " + sessionCount); - Console.WriteLine("session random: " + sessionRandom[ sessionCount ]); + Console.WriteLine("session random: " + sessionRandom[sessionCount]); Console.WriteLine("session bearerToken: " + token); sessionCount++; @@ -3374,31 +3270,31 @@ public void EvalPostAuthenticateCert2(IHttpContext context) } public static bool checkAccessLevel(string currentRole, string operation, string neededRights, - string objPath = "", string aasOrSubmodel = null, object objectAasOrSubmodel = null) + string objPath = "", string aasOrSubmodel = null, object objectAasOrSubmodel = null) { - string error = ""; + string error = ""; string getPolicy = null; - bool withAllow = false; + bool withAllow = false; return checkAccessLevelWithError(out error, currentRole, operation, neededRights, out withAllow, out getPolicy, - objPath, aasOrSubmodel, objectAasOrSubmodel); + objPath, aasOrSubmodel, objectAasOrSubmodel); } public static bool checkAccessLevelWithAllow(string currentRole, string operation, string neededRights, - out bool withAllow, string objPath = "", string aasOrSubmodel = null, object objectAasOrSubmodel = null, - string policy = null) + out bool withAllow, string objPath = "", string aasOrSubmodel = null, object objectAasOrSubmodel = null, + string policy = null) { - string error = ""; + string error = ""; string getPolicy = null; withAllow = false; return checkAccessLevelWithError(out error, currentRole, operation, neededRights, out withAllow, out getPolicy, - objPath, aasOrSubmodel, objectAasOrSubmodel, policy); + objPath, aasOrSubmodel, objectAasOrSubmodel, policy); } public static bool checkAccessLevelWithError(out string error, string currentRole, string operation, - string neededRights, out bool withAllow, out string getPolicy, - string objPath = "", string aasOrSubmodel = null, object objectAasOrSubmodel = null, string policy = null) + string neededRights, out bool withAllow, out string getPolicy, + string objPath = "", string aasOrSubmodel = null, object objectAasOrSubmodel = null, string policy = null) { - error = ""; + error = ""; getPolicy = null; withAllow = false; @@ -3422,25 +3318,25 @@ public static bool checkAccessLevelWithError(out string error, string currentRol " operation = " + operation + " neededRights = " + neededRights + " objPath = " + objPath - ); + ); if (objPath == "") { int iRole = 0; - while (securityRole != null && iRole < securityRole.Count && securityRole[ iRole ].name != null) + while (securityRole != null && iRole < securityRole.Count && securityRole[iRole].name != null) { - if (aasOrSubmodel == "aas" && securityRole[ iRole ].objType == "aas") + if (aasOrSubmodel == "aas" && securityRole[iRole].objType == "aas") /* (aasOrSubmodel == "submodel" && securityRole[iRole].objType == "sm")) */ { - if (objectAasOrSubmodel != null && securityRole[ iRole ].objReference == objectAasOrSubmodel && - securityRole[ iRole ].permission == neededRights) + if (objectAasOrSubmodel != null && securityRole[iRole].objReference == objectAasOrSubmodel && + securityRole[iRole].permission == neededRights) { - if ((securityRole[ iRole ].condition == "" && securityRole[ iRole ].name == currentRole) || - (securityRole[ iRole ].condition == "not" && securityRole[ iRole ].name != currentRole)) + if ((securityRole[iRole].condition == "" && securityRole[iRole].name == currentRole) || + (securityRole[iRole].condition == "not" && securityRole[iRole].name != currentRole)) { - if (securityRole[ iRole ].kind == "allow") + if (securityRole[iRole].kind == "allow") return true; - if (securityRole[ iRole ].kind == "deny") + if (securityRole[iRole].kind == "deny") { error = "DENY AAS " + (objectAasOrSubmodel as AssetAdministrationShell).Id; return false; @@ -3449,14 +3345,14 @@ public static bool checkAccessLevelWithError(out string error, string currentRol } } - if (securityRole[ iRole ].name == currentRole && securityRole[ iRole ].objType == "api" && - securityRole[ iRole ].permission == neededRights) + if (securityRole[iRole].name == currentRole && securityRole[iRole].objType == "api" && + securityRole[iRole].permission == neededRights) { - if (securityRole[ iRole ].apiOperation == "*" || securityRole[ iRole ].apiOperation == operation) + if (securityRole[iRole].apiOperation == "*" || securityRole[iRole].apiOperation == operation) { - if (securityRole[ iRole ].permission == neededRights) + if (securityRole[iRole].permission == neededRights) { - return checkPolicy(out error, securityRole[ iRole ], out getPolicy); + return checkPolicy(out error, securityRole[iRole], out getPolicy); } } } @@ -3469,8 +3365,8 @@ public static bool checkAccessLevelWithError(out string error, string currentRol { // next object with rule must have allow // no objects below must have deny - string deepestDeny = ""; - string deepestAllow = ""; + string deepestDeny = ""; + string deepestAllow = ""; securityRoleClass deepestAllowRole = null; foreach (var role in securityRole) { @@ -3483,14 +3379,14 @@ public static bool checkAccessLevelWithError(out string error, string currentRol { if (role.semanticId == "*" || (s.SemanticId != null && s.SemanticId.Keys != null && s.SemanticId.Keys.Count != 0)) { - if (role.semanticId == "*" || (role.semanticId.ToLower() == s.SemanticId.Keys[ 0 ].Value.ToLower())) + if (role.semanticId == "*" || (role.semanticId.ToLower() == s.SemanticId.Keys[0].Value.ToLower())) { if (role.kind == "allow") { if (deepestAllow == "") { - deepestAllow = s.IdShort; - withAllow = true; + deepestAllow = s.IdShort; + withAllow = true; deepestAllowRole = role; } } @@ -3514,8 +3410,8 @@ public static bool checkAccessLevelWithError(out string error, string currentRol { if (deepestAllow == "") { - deepestAllow = objPath; - withAllow = true; + deepestAllow = objPath; + withAllow = true; deepestAllowRole = role; } } @@ -3557,8 +3453,8 @@ public static bool checkAccessLevelWithError(out string error, string currentRol { if (role.objPath == objPath.Substring(0, role.objPath.Length)) { - deepestAllow = role.objPath; - withAllow = true; + deepestAllow = role.objPath; + withAllow = true; deepestAllowRole = role; } } @@ -3587,9 +3483,9 @@ public static bool checkAccessLevelWithError(out string error, string currentRol public static bool checkPolicy(out string error, securityRoleClass sr, out string getPolicy, string policy = null) { - error = ""; + error = ""; getPolicy = null; - Property pPolicy = null; + Property pPolicy = null; AasCore.Aas3_0.File fPolicy = null; if (sr.usage == null) @@ -3602,10 +3498,10 @@ public static bool checkPolicy(out string error, securityRoleClass sr, out strin case "accessPerDuration": if (sme is SubmodelElementCollection smc) { - Property maxCount = null; + Property maxCount = null; Property actualCount = null; - Property duration = null; - Property actualTime = null; + Property duration = null; + Property actualTime = null; foreach (var sme2 in smc.Value) { switch (sme2.IdShort) @@ -3652,7 +3548,7 @@ public static bool checkPolicy(out string error, securityRoleClass sr, out strin if (actualTime.Value == null || actualTime.Value == "") { - actualTime.Value = DateTime.UtcNow.ToString(); + actualTime.Value = DateTime.UtcNow.ToString(); actualCount.Value = null; } @@ -3706,7 +3602,7 @@ public static bool checkPolicy(out string error, securityRoleClass sr, out strin { try { - using (System.IO.Stream s = Program.env[ sr.usageEnvIndex ].GetLocalStreamFromPackage(fPolicy.Value)) + using (System.IO.Stream s = Program.env[sr.usageEnvIndex].GetLocalStreamFromPackage(fPolicy.Value)) using (SHA256 mySHA256 = SHA256.Create()) { if (s != null) @@ -3736,7 +3632,7 @@ public static bool checkPolicy(out string error, securityRoleClass sr, out strin } public bool checkAccessRights(IHttpContext context, string currentRole, string operation, string neededRights, - string objPath = "", string aasOrSubmodel = null, object objectAasOrSubmodel = null) + string objPath = "", string aasOrSubmodel = null, object objectAasOrSubmodel = null) { if (Program.secretStringAPI != null) { @@ -3753,15 +3649,15 @@ public bool checkAccessRights(IHttpContext context, string currentRole, string o // else { if (checkAccessLevel(currentRole, operation, neededRights, - objPath, aasOrSubmodel, objectAasOrSubmodel)) + objPath, aasOrSubmodel, objectAasOrSubmodel)) return true; if (currentRole == null) { if (AasxServer.Program.redirectServer != "") { - System.Collections.Specialized.NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString(string.Empty); - string originalRequest = context.Request.Url.ToString(); + System.Collections.Specialized.NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString(string.Empty); + string originalRequest = context.Request.Url.ToString(); queryString.Add("OriginalRequest", originalRequest); Console.WriteLine("\nRedirect OriginalRequset: " + originalRequest); string response = AasxServer.Program.redirectServer + "?" + "authType=" + AasxServer.Program.authType + "&" + queryString; @@ -3773,7 +3669,7 @@ public bool checkAccessRights(IHttpContext context, string currentRole, string o } dynamic res = new ExpandoObject(); - res.error = "You are not authorized for this operation!"; + res.error = "You are not authorized for this operation!"; context.Response.StatusCode = HttpStatusCode.Unauthorized; SendJsonResponse(context, res); @@ -3787,16 +3683,16 @@ public static string SecurityCheck(IHttpContext context, ref int index) static string checkUserPW(string userPW64) { - var credentialBytes = Convert.FromBase64String(userPW64); - var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] {':'}, 2); - string username = credentials[ 0 ]; - string password = credentials[ 1 ]; + var credentialBytes = Convert.FromBase64String(userPW64); + var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] {':'}, 2); + string username = credentials[0]; + string password = credentials[1]; int userCount = securityUserName.Count; for (int i = 0; i < userCount; i++) { - if (username == securityUserName[ i ] && password == securityUserPassword[ i ]) + if (username == securityUserName[i] && password == securityUserPassword[i]) { return (username); } @@ -3807,7 +3703,7 @@ static string checkUserPW(string userPW64) public static string SecurityCheck(NameValueCollection queryString, NameValueCollection headers, ref int index) { - string policy = ""; + string policy = ""; string policyRequestedResource = ""; return SecurityCheckWithPolicy(queryString, headers, ref index, out policy, out policyRequestedResource); @@ -3823,12 +3719,12 @@ class userCert public static object lockCertList = new object(); public static string SecurityCheckWithPolicy(NameValueCollection queryString, NameValueCollection headers, ref int index, - out string policy, out string policyRequestedResource) + out string policy, out string policyRequestedResource) { Console.WriteLine("SecurityCheck"); - bool error = false; + bool error = false; string accessrights = null; - policy = ""; + policy = ""; policyRequestedResource = ""; // receive token with sessionID inside @@ -3836,13 +3732,13 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na // read username for sessionID // check accessrights for username - dynamic res = new ExpandoObject(); - int id = -1; - string token = null; - string random = null; - string bearerToken = null; - string user = null; - string certificate = null; + dynamic res = new ExpandoObject(); + int id = -1; + string token = null; + string random = null; + string bearerToken = null; + string user = null; + string certificate = null; index = -1; // not found @@ -3850,7 +3746,7 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na // check for secret - string s = queryString[ "s" ]; + string s = queryString["s"]; if (s != null && s != "") { if (Program.secretStringAPI != null) @@ -3870,28 +3766,28 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na // string headers = request.Headers.ToString(); // Check bearer token - token = headers[ "Authorization" ]; + token = headers["Authorization"]; if (token != null) { split = token.Split(new Char[] {' ', '\t'}); - if (split[ 0 ] != null) + if (split[0] != null) { - if (split[ 0 ].ToLower() == "bearer") + if (split[0].ToLower() == "bearer") { - Console.WriteLine("Received bearer token = " + split[ 1 ]); - bearerToken = split[ 1 ]; + Console.WriteLine("Received bearer token = " + split[1]); + bearerToken = split[1]; } - if (bearerToken == null && split[ 0 ].ToLower() == "basic") + if (bearerToken == null && split[0].ToLower() == "basic") { try { if (Program.secretStringAPI != null) { - var credentialBytes = Convert.FromBase64String(split[ 1 ]); - var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] {':'}, 2); - string u = credentials[ 0 ]; - string p = credentials[ 1 ]; + var credentialBytes = Convert.FromBase64String(split[1]); + var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] {':'}, 2); + string u = credentials[0]; + string p = credentials[1]; Console.WriteLine("Received username+password http header = " + u + " : " + p); if (u == "secret") @@ -3906,7 +3802,7 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na } } - string username = checkUserPW(split[ 1 ]); + string username = checkUserPW(split[1]); if (username != null) { user = username; @@ -3929,7 +3825,7 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na bearerToken = split[1]; } */ - bearerToken = queryString[ "bearer" ]; + bearerToken = queryString["bearer"]; } if (bearerToken == null) @@ -3938,25 +3834,25 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na } // Check email token - token = headers[ "Email" ]; + token = headers["Email"]; if (token != null) { Console.WriteLine("Received Email token = " + token); - user = token; + user = token; error = false; } // Check email query string - token = queryString[ "Email" ]; + token = queryString["Email"]; if (token != null) { Console.WriteLine("Received Email query string = " + token); - user = token; + user = token; error = false; } // Username+password query string - token = queryString[ "_up" ]; + token = queryString["_up"]; if (token != null) { try @@ -3975,20 +3871,20 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na if (!error) { - JObject parsed2 = null; + JsonDocument parsed2 = null; try { if (bearerToken != null) { string serverName = ""; - string email = ""; + string email = ""; - parsed2 = JObject.Parse(Jose.JWT.Payload(bearerToken)); + parsed2 = JsonDocument.Parse(Jose.JWT.Payload(bearerToken)); try { - email = parsed2.SelectToken("email").Value(); + email = parsed2.RootElement.GetProperty("email").GetString(); } catch { @@ -3996,7 +3892,7 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na try { - serverName = parsed2.SelectToken("serverName").Value(); + serverName = parsed2.RootElement.GetProperty("serverName").GetString(); } catch { @@ -4005,7 +3901,7 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na try { - policy = parsed2.SelectToken("policy").Value(); + policy = parsed2.RootElement.GetProperty("policy").GetString(); } catch { @@ -4013,7 +3909,7 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na try { - policyRequestedResource = parsed2.SelectToken("policyRequestedResource").Value(); + policyRequestedResource = parsed2.RootElement.GetProperty("policyRequestedResource").GetString(); } catch { @@ -4027,7 +3923,7 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na try { - user = parsed2.SelectToken("userName").Value(); + user = parsed2.RootElement.GetProperty("userName").GetString(); user = user.ToLower(); } catch @@ -4043,7 +3939,7 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na StringBuilder builder = new StringBuilder(); builder.AppendLine("-----BEGIN CERTIFICATE-----"); builder.AppendLine( - Convert.ToBase64String(cert.RawData, Base64FormattingOptions.InsertLineBreaks)); + Convert.ToBase64String(cert.RawData, Base64FormattingOptions.InsertLineBreaks)); builder.AppendLine("-----END CERTIFICATE-----"); Console.WriteLine("Token Server Certificate: " + serverName); Console.WriteLine(builder); @@ -4059,7 +3955,7 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na try { - certificate = parsed2.SelectToken("certificate").Value(); + certificate = parsed2.RootElement.GetProperty("certificate").GetString(); } catch { @@ -4070,15 +3966,15 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na lock (lockCertList) { Byte[] certFileBytes = Convert.FromBase64String(certificate); - var x509 = new X509Certificate2(certFileBytes); - int i = 0; + var x509 = new X509Certificate2(certFileBytes); + int i = 0; for (i = 0; i < certList.Count; i++) { - if (certList[ i ].userName == user) + if (certList[i].userName == user) { - if (certList[ i ].certificate != null) - certList[ i ].certificate.Dispose(); - certList[ i ].certificate = x509; + if (certList[i].certificate != null) + certList[i].certificate.Dispose(); + certList[i].certificate = x509; break; } } @@ -4086,7 +3982,7 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na if (i == certList.Count) { var cl = new userCert(); - cl.userName = user; + cl.userName = user; cl.certificate = x509; certList.Add(cl); } @@ -4101,9 +3997,9 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na int i = 0; for (i = 0; i < certList.Count; i++) { - if (certList[ i ].userName == user) + if (certList[i].userName == user) { - x509 = certList[ i ].certificate; + x509 = certList[i].certificate; break; } } @@ -4142,12 +4038,12 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na { for (int i = 0; i < rightsCount; i++) { - if (securityRights[ i ].name.Contains("@")) // email address + if (securityRights[i].name.Contains("@")) // email address { - if (user == securityRights[ i ].name) + if (user == securityRights[i].name) { // accessrights = securityRightsValue[i]; - accessrights = securityRights[ i ].role; + accessrights = securityRights[i].role; return accessrights; } } @@ -4156,19 +4052,19 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na for (int i = 0; i < rightsCount; i++) { - if (!securityRights[ i ].name.Contains("@")) // domain name only or non email + if (!securityRights[i].name.Contains("@")) // domain name only or non email { string u = user; if (user.Contains("@")) { string[] splitUser = user.Split('@'); - u = splitUser[ 1 ]; // domain only + u = splitUser[1]; // domain only } - if (u == securityRights[ i ].name) + if (u == securityRights[i].name) { // accessrights = securityRightsValue[i]; - accessrights = securityRights[ i ].role; + accessrights = securityRights[i].role; return accessrights; } } @@ -4198,7 +4094,7 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na { string payload = null; - switch (sessionUserType[ id ]) + switch (sessionUserType[id]) { case 'G': case 'U': @@ -4252,9 +4148,9 @@ public static string SecurityCheckWithPolicy(NameValueCollection queryString, Na public void EvalGetListAAS(IHttpContext context, bool withasset = false) { - dynamic res = new ExpandoObject(); - int index = -1; - var aaslist = new List(); + dynamic res = new ExpandoObject(); + int index = -1; + var aaslist = new List(); Console.WriteLine("Security 4 Server: /server/listaas"); @@ -4267,10 +4163,10 @@ public void EvalGetListAAS(IHttpContext context, bool withasset = false) for (int i = 0; i < aascount; i++) { - if (AasxServer.Program.env[ i ] != null) + if (AasxServer.Program.env[i] != null) { - var aas = AasxServer.Program.env[ i ].AasEnv.AssetAdministrationShells[ 0 ]; - string IdShort = aas.IdShort; + var aas = AasxServer.Program.env[i].AasEnv.AssetAdministrationShells[0]; + string IdShort = aas.IdShort; string aasRights = "NONE"; if (securityRightsAAS != null && securityRightsAAS.Count != 0) securityRightsAAS.TryGetValue(IdShort, out aasRights); @@ -4288,7 +4184,7 @@ public void EvalGetListAAS(IHttpContext context, bool withasset = false) string s = i.ToString() + " : " + IdShort + " : " + aas.Id + " : " - + AasxServer.Program.envFileName[ i ]; + + AasxServer.Program.envFileName[i]; if (withasset) { //var asset = Program.env[i].AasEnv.FindAsset(aas.assetRef); @@ -4317,32 +4213,31 @@ public void EvalAssetId(IHttpContext context, int assetId) Console.WriteLine("Test Asset ID"); string headers = context.Request.Headers.ToString(); - string token = context.Request.Headers.Get("accept"); + string token = context.Request.Headers.Get("accept"); if (token != null) { if (token == "application/aas") { Console.WriteLine("Received Accept header = " + token); - // context.Response.ContentType = ContentType.JSON; +// context.Response.ContentType = ContentType.JSON; context.Response.AddHeader("Content-Type", "application/aas"); - res.client = "I40 IT client"; - res.assetID = assetId; + + res.client = "I40 IT client"; + res.assetID = assetId; res.humanEndpoint = "https://admin-shell-io.com:5001"; - res.restEndpoint = "http://" + AasxServer.Program.hostPort; + res.restEndpoint = "http://" + AasxServer.Program.hostPort; - var settings = new JsonSerializerSettings(); - // if (contractResolver != null) - // settings.ContractResolver = contractResolver; - var json = JsonConvert.SerializeObject(res, Formatting.Indented, settings); - var buffer = context.Request.ContentEncoding.GetBytes(json); + var json = JsonSerializer.Serialize(res, new JsonSerializerOptions { WriteIndented = true }); + var buffer = Encoding.UTF8.GetBytes(json); var length = buffer.Length; context.Response.ContentEncoding = Encoding.UTF8; context.Response.ContentLength64 = length; - context.Response.StatusCode = HttpStatusCode.Ok; + context.Response.StatusCode = HttpStatusCode.Ok; context.Response.SendResponse(buffer); return; + } } @@ -4352,9 +4247,9 @@ public void EvalAssetId(IHttpContext context, int assetId) public void EvalGetAASX(IHttpContext context, int fileIndex) { - dynamic res = new ExpandoObject(); - int index = -1; - string accessrights = null; + dynamic res = new ExpandoObject(); + int index = -1; + string accessrights = null; // check authentication if (withAuthentification) @@ -4372,7 +4267,7 @@ public void EvalGetAASX(IHttpContext context, int fileIndex) res.confirm = "Authorization = " + accessrights; */ - var aas = Program.env[ fileIndex ].AasEnv.AssetAdministrationShells[ 0 ]; + var aas = Program.env[fileIndex].AasEnv.AssetAdministrationShells[0]; if (!checkAccessRights(context, accessrights, "/aasx", "READ", "", "aas", aas)) { return; @@ -4394,14 +4289,14 @@ public void EvalGetAASX(IHttpContext context, int fileIndex) lock (Program.changeAasxFile) { - string fname = "./temp/" + Path.GetFileName(Program.envFileName[ fileIndex ]); - Program.env[ fileIndex ].SaveAs(fname); + string fname = "./temp/" + Path.GetFileName(Program.envFileName[fileIndex]); + Program.env[fileIndex].SaveAs(fname); // return as FILE FileStream packageStream = System.IO.File.OpenRead(fname); context.Response.StatusCode = HttpStatusCode.Ok; SendStreamResponse(context, packageStream, - Path.GetFileName(AasxServer.Program.envFileName[ fileIndex ])); + Path.GetFileName(AasxServer.Program.envFileName[fileIndex])); packageStream.Close(); // Reload @@ -4411,8 +4306,8 @@ public void EvalGetAASX(IHttpContext context, int fileIndex) public void EvalGetAASX2(IHttpContext context, int fileIndex) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication string accessrights = null; @@ -4459,15 +4354,15 @@ public void EvalGetAASX2(IHttpContext context, int fileIndex) res.confirm = "Authorization = " + accessrights; - Byte[] binaryFile = System.IO.File.ReadAllBytes(AasxServer.Program.envFileName[ fileIndex ]); + Byte[] binaryFile = System.IO.File.ReadAllBytes(AasxServer.Program.envFileName[fileIndex]); string binaryBase64 = Convert.ToBase64String(binaryFile); string payload = "{ \"file\" : \" " + binaryBase64 + " \" }"; - System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); - string fileToken = Jose.JWT.Encode(payload, enc.GetBytes(secretString), JwsAlgorithm.HS256); + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + string fileToken = Jose.JWT.Encode(payload, enc.GetBytes(secretString), JwsAlgorithm.HS256); - res.fileName = Path.GetFileName(AasxServer.Program.envFileName[ fileIndex ]); + res.fileName = Path.GetFileName(AasxServer.Program.envFileName[fileIndex]); res.fileData = fileToken; context.Response.StatusCode = HttpStatusCode.Ok; @@ -4480,7 +4375,7 @@ public void EvalGetFile(IHttpContext context, int envIndex, string filePath) { context.Response.StatusCode = HttpStatusCode.Ok; var fname = Path.GetFileName(filePath); - var s = Program.env[ envIndex ].GetLocalStreamFromPackage(filePath); + var s = Program.env[envIndex].GetLocalStreamFromPackage(filePath); SendStreamResponse(context, s, fname); } @@ -4571,10 +4466,10 @@ public static void securityInit() for (int i = 0; i < aascount; i++) { - var env = AasxServer.Program.env[ i ]; + var env = AasxServer.Program.env[i]; if (env != null) { - var aas = env.AasEnv.AssetAdministrationShells[ 0 ]; + var aas = env.AasEnv.AssetAdministrationShells[0]; if (aas.Submodels != null && aas.Submodels.Count > 0) { foreach (var smr in aas.Submodels) @@ -4599,17 +4494,17 @@ public static void securityInit() int countSme = sm.SubmodelElements.Count; for (int iSme = 0; iSme < countSme; iSme++) { - var sme = sm.SubmodelElements[ iSme ]; + var sme = sm.SubmodelElements[iSme]; if (sme is Property) continue; - var smec = sme as SubmodelElementCollection; + var smec = sme as SubmodelElementCollection; int countSmec = smec.Value.Count; switch (smec.IdShort) { case "authenticationServer": for (int iSmec = 0; iSmec < countSmec; iSmec++) { - var sme2 = smec.Value[ iSmec ]; + var sme2 = smec.Value[iSmec]; switch (sme2.IdShort) { case "endpoint": @@ -4623,18 +4518,18 @@ public static void securityInit() case "publicCertificate": var f = sme2 as AasCore.Aas3_0.File; serverCertfileNames = new string[1]; - serverCerts = new X509Certificate2[1]; - var s = Program.env[ i ].GetLocalStreamFromPackage(f.Value, init: true); + serverCerts = new X509Certificate2[1]; + var s = Program.env[i].GetLocalStreamFromPackage(f.Value, init: true); if (s != null) { using (var m = new MemoryStream()) { s.CopyTo(m); var b = m.GetBuffer(); - serverCerts[ 0 ] = new X509Certificate2(b); + serverCerts[0] = new X509Certificate2(b); string[] split = f.Value.Split('/'); - serverCertfileNames[ 0 ] = split[ 3 ]; - Console.WriteLine("Loaded auth server certifcate: " + serverCertfileNames[ 0 ]); + serverCertfileNames[0] = split[3]; + Console.WriteLine("Loaded auth server certifcate: " + serverCertfileNames[0]); } } @@ -4648,13 +4543,13 @@ public static void securityInit() for (int iSmec = 0; iSmec < countSmec; iSmec++) { - var smec2 = smec.Value[ iSmec ] as SubmodelElementCollection; - int countSmec2 = smec2.Value.Count; - List subjects = new List(); + var smec2 = smec.Value[iSmec] as SubmodelElementCollection; + int countSmec2 = smec2.Value.Count; + List subjects = new List(); for (int iSmec2 = 0; iSmec2 < countSmec2; iSmec2++) { - var smec3 = smec2.Value[ iSmec2 ] as SubmodelElementCollection; + var smec3 = smec2.Value[iSmec2] as SubmodelElementCollection; int countSmec3 = smec3.Value.Count; switch (smec3.IdShort) @@ -4662,7 +4557,7 @@ public static void securityInit() case "subjects": for (int iSmec3 = 0; iSmec3 < countSmec3; iSmec3++) { - var p = smec3.Value[ iSmec3 ] as Property; + var p = smec3.Value[iSmec3] as Property; switch (p.IdShort) { case "emailDomain": @@ -4679,7 +4574,7 @@ public static void securityInit() case "roles": for (int iSmec3 = 0; iSmec3 < countSmec3; iSmec3++) { - var p = smec3.Value[ iSmec3 ] as Property; + var p = smec3.Value[iSmec3] as Property; foreach (var s in subjects) { securityRightsClass sr = new securityRightsClass(); @@ -4698,7 +4593,7 @@ public static void securityInit() case "basicAuth": for (int iSmec = 0; iSmec < countSmec; iSmec++) { - if (smec.Value[ iSmec ] is Property p) + if (smec.Value[iSmec] is Property p) { securityUserName.Add(p.IdShort); securityUserPassword.Add(p.Value); @@ -4722,14 +4617,14 @@ public static void securityInit() int countSme = smc4.Value.Count; for (int iSme = 0; iSme < countSme; iSme++) { - var sme = smc4.Value[ iSme ]; // actual rule - var smc5 = sme as SubmodelElementCollection; - var smc6 = smc5?.FindFirstIdShortAs("targetSubjectAttributes"); - List role = new List(); - int iRole = 0; + var sme = smc4.Value[iSme]; // actual rule + var smc5 = sme as SubmodelElementCollection; + var smc6 = smc5?.FindFirstIdShortAs("targetSubjectAttributes"); + List role = new List(); + int iRole = 0; while (smc6?.Value.Count > iRole) { - if (smc6?.Value[ iRole ] is Property rp) + if (smc6?.Value[iRole] is Property rp) { role.Add(rp); } @@ -4738,9 +4633,9 @@ public static void securityInit() } smc6 = smc5?.FindFirstIdShortAs("permissionsPerObject"); - var smc7 = smc6?.Value[ 0 ] as SubmodelElementCollection; - var objProp = smc7?.FindFirstIdShortAs("object"); - var objRef = smc7?.FindFirstIdShortAs("object"); + var smc7 = smc6?.Value[0] as SubmodelElementCollection; + var objProp = smc7?.FindFirstIdShortAs("object"); + var objRef = smc7?.FindFirstIdShortAs("object"); object aasObject = null; if (objRef != null) { @@ -4750,17 +4645,17 @@ public static void securityInit() var smc8 = smc7?.FindFirstIdShortAs("permission"); var smc9 = smc7?.FindFirstIdShortAs("usage"); - int countSmc8 = smc8.Value.Count; + int countSmc8 = smc8.Value.Count; List listPermission = new List(); - Property kind = null; + Property kind = null; for (int iSmc8 = 0; iSmc8 < countSmc8; iSmc8++) { - var sme9 = smc8.Value[ iSmc8 ]; + var sme9 = smc8.Value[iSmc8]; if (sme9 is Property) kind = sme9 as Property; if (sme9 is ReferenceElement) { - var refer = sme9 as ReferenceElement; + var refer = sme9 as ReferenceElement; var permission = env.AasEnv.FindReferableByReference(refer.Value); if (!(permission is Property)) continue; @@ -4777,20 +4672,20 @@ public static void securityInit() securityRoleClass src = new securityRoleClass(); if (smc9 != null) { - src.usage = smc9; + src.usage = smc9; src.usageEnvIndex = i; } if (r.IdShort.Contains(":")) { - split = r.IdShort.Split(':'); - src.condition = split[ 0 ].ToLower(); - src.name = split[ 1 ]; + split = r.IdShort.Split(':'); + src.condition = split[0].ToLower(); + src.name = split[1]; } else { src.condition = ""; - src.name = r.IdShort; + src.name = r.IdShort; } if (objProp != null) @@ -4800,22 +4695,22 @@ public static void securityInit() if (value.Contains("api")) { split = value.Split(':'); - if (split[ 0 ] == "api") + if (split[0] == "api") { - src.objType = split[ 0 ]; - src.apiOperation = split[ 1 ]; + src.objType = split[0]; + src.apiOperation = split[1]; } } if (value.Contains("semanticid")) { split = value.Split(':'); - if (split[ 0 ] == "semanticid") + if (split[0] == "semanticid") { - src.objType = split[ 0 ]; - src.semanticId = split[ 1 ]; + src.objType = split[0]; + src.semanticId = split[1]; for (int j = 2; j < split.Length; j++) - src.semanticId += ":" + split[ j ]; + src.semanticId += ":" + split[j]; } } } @@ -4828,9 +4723,9 @@ public static void securityInit() src.objType = "aas"; if (aasObject is Submodel) { - src.objType = "sm"; + src.objType = "sm"; src.submodel = aasObject as Submodel; - src.objPath = src.submodel.IdShort; + src.objPath = src.submodel.IdShort; } if (aasObject is ISubmodelElement smep) @@ -4840,12 +4735,12 @@ public static void securityInit() string path = rp.IdShort; while (rp.Parent != null) { - rp = (IReferable) rp.Parent; + rp = (IReferable)rp.Parent; path = rp.IdShort + "." + path; } src.submodel = rp as Submodel; - src.objPath = path; + src.objPath = path; } } } @@ -4874,9 +4769,9 @@ public static X509Certificate2 serverCertFind(string authServerName) { for (int i = 0; i < serverCertfileNames.Length; i++) { - if (Path.GetFileName(serverCertfileNames[ i ]) == authServerName + ".cer") + if (Path.GetFileName(serverCertfileNames[i]) == authServerName + ".cer") { - return serverCerts[ i ]; + return serverCerts[i]; } } } @@ -4888,8 +4783,8 @@ public static X509Certificate2 serverCertFind(string authServerName) public void EvalPutCd(IHttpContext context, string aasid) { - dynamic res = new ExpandoObject(); - int index = -1; + dynamic res = new ExpandoObject(); + int index = -1; // check authentication if (withAuthentification) @@ -4923,7 +4818,7 @@ public void EvalPutCd(IHttpContext context, string aasid) ConceptDescription cd = null; try { - cd = Newtonsoft.Json.JsonConvert.DeserializeObject(context.Request.Payload); + cd = System.Text.Json.JsonSerializer.Deserialize(context.Request.Payload); } catch (Exception ex) { @@ -4939,8 +4834,8 @@ public void EvalPutCd(IHttpContext context, string aasid) } // datastructure update - if (this.Packages[ findAasReturn.iPackage ] == null || - this.Packages[ findAasReturn.iPackage ].AasEnv == null /*|| this.Packages[findAasReturn.iPackage].AasEnv.Assets == null*/) + if (this.Packages[findAasReturn.iPackage] == null || + this.Packages[findAasReturn.iPackage].AasEnv == null /*|| this.Packages[findAasReturn.iPackage].AasEnv.Assets == null*/) { context.Response.SendResponse(HttpStatusCode.InternalServerError, $"Error accessing internal data structures."); return; @@ -4948,10 +4843,10 @@ public void EvalPutCd(IHttpContext context, string aasid) // add Submodel context.Server.Logger.Debug($"Adding ConceptDescription with IdShort {cd.IdShort ?? "--"} and id {cd.Id?.ToString() ?? "--"}"); - var existingCd = this.Packages[ findAasReturn.iPackage ].AasEnv.FindConceptDescriptionById(cd.Id); + var existingCd = this.Packages[findAasReturn.iPackage].AasEnv.FindConceptDescriptionById(cd.Id); if (existingCd != null) - this.Packages[ findAasReturn.iPackage ].AasEnv.ConceptDescriptions.Remove(existingCd); - this.Packages[ findAasReturn.iPackage ].AasEnv.ConceptDescriptions.Add(cd); + this.Packages[findAasReturn.iPackage].AasEnv.ConceptDescriptions.Remove(existingCd); + this.Packages[findAasReturn.iPackage].AasEnv.ConceptDescriptions.Add(cd); // simple OK Program.signalNewData(2); diff --git a/src/AasxServerStandardBib/AasxHttpHandleStore.cs b/src/AasxServerStandardBib/AasxHttpHandleStore.cs index 4ea6dae6c..3a0739d68 100644 --- a/src/AasxServerStandardBib/AasxHttpHandleStore.cs +++ b/src/AasxServerStandardBib/AasxHttpHandleStore.cs @@ -1,5 +1,4 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; /* Copyright (c) 2018-2019 Festo AG & Co. KG , author: Michael Hoffmeister @@ -15,17 +14,18 @@ specification Details of the Administration Shell. The hereby stated approach is namespace AasxRestServerLibrary { + using System.Text.Json.Serialization; + /// /// Describes a handle to a Identification or Reference to be used in HTTP REST APIs /// public abstract class AasxHttpHandle { - [JsonProperty(PropertyName = "key")] - public string Key; - [JsonIgnore] - public DateTime ExpiresInternal; - [JsonProperty(PropertyName = "expires")] - public string Expires; // http-date, see https://stackoverflow.com/questions/21120882/the-date-time-format-used-in-http-headers + [JsonPropertyName("key")] public string Key { get; set; } + + [JsonIgnore] public DateTime ExpiresInternal { get; set; } + + [JsonPropertyName("expires")] public string Expires { get; set; } // http-date, see https://stackoverflow.com/questions/21120882/the-date-time-format-used-in-http-headers } /// @@ -44,7 +44,7 @@ public AasxHttpHandleIdentification(string src, string keyPreset = null) else this.Key = keyPreset; this.ExpiresInternal = DateTime.UtcNow.AddMinutes(60); - this.Expires = this.ExpiresInternal.ToString("R"); + this.Expires = this.ExpiresInternal.ToString("R"); //this.identification = new IIdentifiable(src); this.identification = src; } @@ -101,4 +101,4 @@ public List FindAll() where T : class return res; } } -} +} \ No newline at end of file diff --git a/src/AasxServerStandardBib/AasxPluginOptionSerialization.cs b/src/AasxServerStandardBib/AasxPluginOptionSerialization.cs index df328d792..c66d9663d 100644 --- a/src/AasxServerStandardBib/AasxPluginOptionSerialization.cs +++ b/src/AasxServerStandardBib/AasxPluginOptionSerialization.cs @@ -8,16 +8,12 @@ This source code may use other Open Source software components (see LICENSE.txt) */ using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; namespace AasxIntegrationBase { + using System.Text.Json; + using System.Text.Json.Serialization; + // see: https://stackoverflow.com/questions/11099466/ // using-a-custom-type-discriminator-to-tell-json-net-which-type-of-a-class-hierarc @@ -45,84 +41,29 @@ public DisplayNameAttribute(string displayName, bool noTypeLookup = false) } } - /// - /// Serialization Binder for AASX Options. Allows modified $typename via [DisplayNameAttribute] - /// - public class DisplayNameSerializationBinder : DefaultSerializationBinder + public static class AasxPluginOptionSerialization { - private Dictionary _nameToType; - private Dictionary _typeToName; - - public DisplayNameSerializationBinder(Type[] startingTypes) - { - if (startingTypes == null) - return; - - _nameToType = new Dictionary(); - _typeToName = new Dictionary(); - - foreach (var startingType in startingTypes) - { - var customDisplayNameTypes = - // this.GetType() - startingType - .Assembly - //concat with references if desired - .GetTypes() - .Where(x => x - .GetCustomAttributes(false) - .Any(y => y is DisplayNameAttribute)); - - foreach (var t in customDisplayNameTypes) - { - var dn = t.GetCustomAttributes(false).OfType().First().DisplayName; - var ntu = t.GetCustomAttributes(false).OfType().First().NoTypeLookup; - // MIHO, 21-05-24: added existence check to make more buller proof - if (!ntu && !_nameToType.ContainsKey(dn)) - _nameToType.Add(dn, t); - if (!_typeToName.ContainsKey(t)) - _typeToName.Add(t, dn); - } - } - } - - public override void BindToName(Type serializedType, out string assemblyName, out string typeName) + public static JsonSerializerOptions GetDefaultJsonOptions(Type[] startingTypes) { - if (false == _typeToName.ContainsKey(serializedType)) - { - base.BindToName(serializedType, out assemblyName, out typeName); - return; - } + var options = new JsonSerializerOptions + { + // Custom serialization binder if needed (not directly supported in System.Text.Json) + // SerializationBinder = new DisplayNameSerializationBinder(startingTypes), - var name = _typeToName[serializedType]; + // Ignore null values during serialization + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - assemblyName = null; - typeName = name; - } + // Serialize reference loops (not directly supported in System.Text.Json) + // ReferenceHandler = ReferenceHandler.Serialize, - public override Type BindToType(string assemblyName, string typeName) - { - if (_nameToType.ContainsKey(typeName)) - return _nameToType[typeName]; + // Include type information for objects (similar to TypeNameHandling.Objects) + // Consider alternatives based on specific requirements - return base.BindToType(assemblyName, typeName); - } - } + // Set other options as needed + WriteIndented = false // Example of setting indentation + }; - public static class AasxPluginOptionSerialization - { - public static JsonSerializerSettings GetDefaultJsonSettings(Type[] startingTypes) - { - JsonSerializerSettings settings = new JsonSerializerSettings - { - SerializationBinder = new DisplayNameSerializationBinder(startingTypes), - NullValueHandling = NullValueHandling.Ignore, - ReferenceLoopHandling = ReferenceLoopHandling.Serialize, - TypeNameHandling = TypeNameHandling.Objects /*, - Formatting = Formatting.Indented */ - }; - return settings; + return options; } - } } diff --git a/src/AasxServerStandardBib/AasxRestClient.cs b/src/AasxServerStandardBib/AasxRestClient.cs index 1a3099b0c..2a0d5774b 100644 --- a/src/AasxServerStandardBib/AasxRestClient.cs +++ b/src/AasxServerStandardBib/AasxRestClient.cs @@ -3,13 +3,14 @@ using AdminShellNS; using Extensions; using Grapevine.Client; -using Newtonsoft.Json.Linq; using System; using System.IO; using System.Net; namespace AasxRestServerLibrary { + using System.Text.Json; + public class AasxRestClient : IAasxOnlineConnection { // Instance management @@ -183,8 +184,8 @@ public string UpdatePropertyValue(AasCore.Aas3_0.Environment env, Submodel submo throw new Exception($"REST {respose.ResponseUri} response {respose.StatusCode} with {respose.StatusDescription}"); var json = respose.GetContent(); - var parsed = JObject.Parse(json); - var value = parsed.SelectToken("value").Value(); + var parsed = JsonDocument.Parse(json); + var value = parsed.RootElement.GetProperty("value").GetString(); return value; } } diff --git a/src/AasxServerStandardBib/AasxRestServer.cs b/src/AasxServerStandardBib/AasxRestServer.cs index 9e0b5b6a9..6d8626de3 100644 --- a/src/AasxServerStandardBib/AasxRestServer.cs +++ b/src/AasxServerStandardBib/AasxRestServer.cs @@ -1,6 +1,5 @@ #define MICHA -using AasCore.Aas3_0; using AasxMqttClient; using AasxServerDB; using AasxServer; @@ -12,7 +11,6 @@ using Grapevine.Server.Attributes; using Grapevine.Shared; using Microsoft.IdentityModel.Tokens; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Globalization; @@ -38,6 +36,8 @@ specification Details of the Administration Shell. The hereby stated approach is namespace AasxRestServerLibrary { + using System.Text.Json; + public class AasxRestServer { static string translateURL(string url) @@ -2219,13 +2219,22 @@ class testData void sendJson(IHttpContext context, object o) { - var json = JsonConvert.SerializeObject(o, Formatting.Indented); - var buffer = context.Request.ContentEncoding.GetBytes(json); + // Serialize the object to JSON + var options = new JsonSerializerOptions + { + WriteIndented = true // Formatting.Indented equivalent + }; + var json = JsonSerializer.Serialize(o, options); + + // Convert JSON string to byte array + var buffer = Encoding.UTF8.GetBytes(json); var length = buffer.Length; context.Response.ContentType = ContentType.JSON; context.Response.ContentEncoding = Encoding.UTF8; context.Response.ContentLength64 = length; + + // Send the response context.Response.SendResponse(buffer); } @@ -2279,11 +2288,11 @@ public static void add(IReferable o, string op, ISubmodel rootSubmodel, ulong ch { case "Add": reason = AasPayloadStructuralChangeItem.ChangeReason.Create; - json = JsonConvert.SerializeObject(smec, Newtonsoft.Json.Formatting.Indented, - new JsonSerializerSettings - { - NullValueHandling = NullValueHandling.Ignore - }); + json = JsonSerializer.Serialize(smec, new JsonSerializerOptions + { + WriteIndented = true, + IgnoreNullValues = true + }); break; case "Remove": reason = AasPayloadStructuralChangeItem.ChangeReason.Delete; @@ -2724,7 +2733,7 @@ static void GetEventMsgRecurseDiff( AasPayloadStructuralChangeItem.ChangeReason.Create, path: p2, // Assumption: models will be serialized correctly - data: JsonConvert.SerializeObject(sme))); + data: JsonSerializer.Serialize(sme))); } else { @@ -2811,7 +2820,7 @@ static void GetEventMsgRecurseDiff( AasPayloadStructuralChangeItem.ChangeReason.Create, path: p2, // Assumption: models will be serialized correctly - data: JsonConvert.SerializeObject(sme))); + data: JsonSerializer.Serialize(sme))); } } else if (sme.TimeStamp > minimumDate && sme.TimeStamp != sme.TimeStampCreate) @@ -2832,19 +2841,24 @@ public static void allowCORS(Grapevine.Interfaces.Server.IHttpContext context) context.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD"); } - public static void SendJsonResponse(Grapevine.Interfaces.Server.IHttpContext context, object obj) + public static void SendJsonResponse(IHttpContext context, object obj) { - // make JSON - var settings = AasxIntegrationBase.AasxPluginOptionSerialization.GetDefaultJsonSettings( - new[] {typeof(AdminShellEvents.AasEventMsgEnvelope)}); - settings.TypeNameHandling = TypeNameHandling.Auto; - settings.Formatting = Formatting.Indented; - var json = JsonConvert.SerializeObject(obj, settings); - - // build buffer - var buffer = context.Request.ContentEncoding.GetBytes(json); + // Configure JSON serialization options + var options = AasxIntegrationBase.AasxPluginOptionSerialization.GetDefaultJsonOptions( + new[] { typeof(AdminShellEvents.AasEventMsgEnvelope) }); + + // Additional options settings (not directly translatable to System.Text.Json) + // options.TypeNameHandling = TypeNameHandling.Auto; // No direct equivalent + // options.Formatting = Formatting.Indented; // Handled by JsonSerializerOptions + + // Serialize the object to JSON + var json = JsonSerializer.Serialize(obj, options); + + // Convert JSON string to byte array + var buffer = Encoding.UTF8.GetBytes(json); var length = buffer.Length; + // Handle 'refresh' query parameter var queryString = context.Request.QueryString; string refresh = queryString[ "refresh" ]; if (refresh != null && refresh != "") @@ -2853,14 +2867,17 @@ public static void SendJsonResponse(Grapevine.Interfaces.Server.IHttpContext con context.Response.Headers.Add("Refresh", refresh); } + // Set CORS headers (assuming allowCORS(context) handles this) allowCORS(context); context.Response.ContentType = ContentType.JSON; context.Response.ContentEncoding = Encoding.UTF8; context.Response.ContentLength64 = length; + + // Send the response context.Response.SendResponse(buffer); } - + public class diffEntry { public string mode = ""; diff --git a/src/AasxServerStandardBib/AasxServerStandardBib.csproj b/src/AasxServerStandardBib/AasxServerStandardBib.csproj index f0e92aaeb..bb0a80d8a 100644 --- a/src/AasxServerStandardBib/AasxServerStandardBib.csproj +++ b/src/AasxServerStandardBib/AasxServerStandardBib.csproj @@ -35,7 +35,6 @@ - diff --git a/src/AasxServerStandardBib/Interfaces/IAssetAdministrationShellService.cs b/src/AasxServerStandardBib/Interfaces/IAssetAdministrationShellService.cs index 90ccade4b..fd38afed1 100644 --- a/src/AasxServerStandardBib/Interfaces/IAssetAdministrationShellService.cs +++ b/src/AasxServerStandardBib/Interfaces/IAssetAdministrationShellService.cs @@ -15,7 +15,7 @@ public interface IAssetAdministrationShellService void DeleteSubmodelElementByPath(string aasIdentifier, string submodelIdentifier, string idShortPath); void DeleteSubmodelReferenceById(string aasIdentifier, string submodelIdentifier); void DeleteThumbnail(string aasIdentifier); - List GetAllAssetAdministrationShells(List assetIds = null, string idShort = null); + List GetAllAssetAdministrationShells(List? assetIds = null, string? idShort = null); List GetAllSubmodelElements(string aasIdentifier, string submodelIdentifier); List GetAllSubmodelReferencesFromAas(string aasIdentifier); IAssetAdministrationShell GetAssetAdministrationShellById(string aasIdentifier); @@ -35,4 +35,4 @@ public interface IAssetAdministrationShellService void UpdateSubmodelElementByPath(string aasIdentifier, string submodelIdentifier, string idShortPath, ISubmodelElement newSme); void UpdateThumbnail(string aasIdentifier, string fileName, string contentType, Stream stream); } -} +} \ No newline at end of file diff --git a/src/AasxServerStandardBib/Logging/ApplicationLogging.cs b/src/AasxServerStandardBib/Logging/ApplicationLogging.cs index 3e07b5ee7..39a2c33bc 100644 --- a/src/AasxServerStandardBib/Logging/ApplicationLogging.cs +++ b/src/AasxServerStandardBib/Logging/ApplicationLogging.cs @@ -1,13 +1,55 @@ using Microsoft.Extensions.Logging; +using System; -//This class has been added to use the logger in static classes, without DI -namespace AasxServerStandardBib.Logging +namespace AasxServerStandardBib.Logging; + +/// +/// Static class for managing application-wide logging and creating logger instances. +/// Use this class where direct injection of is not feasible. +/// +/// +/// // Using ApplicationLogging to create logger instances +/// var logger = ApplicationLogging.CreateLogger -MyClass-(); +/// logger.LogDebug("Debug message"); +/// logger.LogError("Error message"); +/// +/// // Using ApplicationLogging to create a logger with a specific category +/// var customLogger = ApplicationLogging.CreateLogger("CustomCategory"); +/// customLogger.LogInformation("Information message"); +/// customLogger.LogWarning("Warning message"); +/// +/// +/// +public static class ApplicationLogging { - public static class ApplicationLogging - { - public static ILoggerFactory LoggerFactory { get; set; } - public static ILogger CreateLogger() => LoggerFactory.CreateLogger(); - public static ILogger CreateLogger(string categoryName) => LoggerFactory.CreateLogger(categoryName); + private static ILoggerFactory _loggerFactory { get; set; } + + static ApplicationLogging() => _loggerFactory = new LoggerFactory(); + /// + /// Gets or sets the factory for creating ILogger instances. + /// + public static ILoggerFactory LoggerFactory + { + get => _loggerFactory; + set + { + ArgumentNullException.ThrowIfNull(value); + _loggerFactory = value; + } } -} + + /// + /// Creates a logger instance for the specified type . + /// + /// The type to create a logger for. + /// An instance of logger for the specified type. + public static ILogger CreateLogger() => LoggerFactory.CreateLogger(); + + /// + /// Creates a logger instance with the specified category name. + /// + /// The name of the category for the logger. + /// An instance of logger for the specified category. + public static ILogger CreateLogger(string categoryName) => LoggerFactory.CreateLogger(categoryName); +} \ No newline at end of file diff --git a/src/AasxServerStandardBib/Logging/IAppLogger.cs b/src/AasxServerStandardBib/Logging/IAppLogger.cs index 5270c6fb5..2c898288f 100644 --- a/src/AasxServerStandardBib/Logging/IAppLogger.cs +++ b/src/AasxServerStandardBib/Logging/IAppLogger.cs @@ -1,10 +1,36 @@ -namespace AasxServerStandardBib.Logging +namespace AasxServerStandardBib.Logging; + +/// +/// Represents a generic interface for logging messages of different levels. +/// +/// The type associated with the logger. +public interface IAppLogger { - public interface IAppLogger - { - void LogInformation(string message, params object[] args); - void LogWarning(string message, params object[] args); - void LogError(string message, params object[] args); - void LogDebug(string message, params object[] args); - } + /// + /// Logs a debug message. + /// + /// The message to log. + /// Optional arguments to format into the message. + void LogInformation(string message, params object[] args); + + /// + /// Logs an error message. + /// + /// The message to log. + /// Optional arguments to format into the message. + void LogWarning(string message, params object[] args); + + /// + /// Logs an information message. + /// + /// The message to log. + /// Optional arguments to format into the message. + void LogError(string message, params object[] args); + + /// + /// Logs a warning message. + /// + /// The message to log. + /// Optional arguments to format into the message. + void LogDebug(string message, params object[] args); } \ No newline at end of file diff --git a/src/AasxServerStandardBib/Logging/LogMessages.cs b/src/AasxServerStandardBib/Logging/LogMessages.cs new file mode 100644 index 000000000..0a2f8186b --- /dev/null +++ b/src/AasxServerStandardBib/Logging/LogMessages.cs @@ -0,0 +1,70 @@ +namespace AasxServerStandardBib.Logging; + +using System; +using Microsoft.Extensions.Logging; + +/// +/// Static class defining LoggerMessage delegates for various log levels. +/// +internal static class LogMessages +{ + private static readonly Action _logDebugMessage = + LoggerMessage.Define( + LogLevel.Debug, + new EventId(1, nameof(LogDebugMessage)), + "{Message}" + ); + + private static readonly Action _logErrorMessage = + LoggerMessage.Define( + LogLevel.Error, + new EventId(2, nameof(LogErrorMessage)), + "{Message}" + ); + + private static readonly Action _logInformationMessage = + LoggerMessage.Define( + LogLevel.Information, + new EventId(3, nameof(LogInformationMessage)), + "{Message}" + ); + + private static readonly Action _logWarningMessage = + LoggerMessage.Define( + LogLevel.Warning, + new EventId(4, nameof(LogWarningMessage)), + "{Message}" + ); + + /// + /// Logs a debug message. + /// + /// The logger instance. + /// The message to log. + /// Optional exception associated with the log message. + public static void LogDebugMessage(ILogger logger, string message, Exception? exception = null) => _logDebugMessage(logger, message, exception); + + /// + /// Logs an error message. + /// + /// The logger instance. + /// The message to log. + /// Optional exception associated with the log message. + public static void LogErrorMessage(ILogger logger, string message, Exception? exception = null) => _logErrorMessage(logger, message, exception); + + /// + /// Logs an information message. + /// + /// The logger instance. + /// The message to log. + /// Optional exception associated with the log message. + public static void LogInformationMessage(ILogger logger, string message, Exception? exception = null) => _logInformationMessage(logger, message, exception); + + /// + /// Logs a warning message. + /// + /// The logger instance. + /// The message to log. + /// Optional exception associated with the log message. + public static void LogWarningMessage(ILogger logger, string message, Exception? exception = null) => _logWarningMessage(logger, message, exception); +} \ No newline at end of file diff --git a/src/AasxServerStandardBib/Logging/LoggerAdapter.cs b/src/AasxServerStandardBib/Logging/LoggerAdapter.cs index 4b9b30e6e..7f0fe6ac4 100644 --- a/src/AasxServerStandardBib/Logging/LoggerAdapter.cs +++ b/src/AasxServerStandardBib/Logging/LoggerAdapter.cs @@ -1,22 +1,55 @@ using Microsoft.Extensions.Logging; using System; -namespace AasxServerStandardBib.Logging +namespace AasxServerStandardBib.Logging; + +using System.Globalization; + +/// +/// Adapter class that implements for logging messages using Microsoft.Extensions.Logging. +/// +/// The type of the class for which the logger is being created. +public class LoggerAdapter : IAppLogger { - public class LoggerAdapter : IAppLogger + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + /// The factory for creating ILogger instances. + /// Thrown when is null. + public LoggerAdapter(ILoggerFactory loggerFactory) + { + ArgumentNullException.ThrowIfNull(loggerFactory); + _logger = loggerFactory.CreateLogger(); + ApplicationLogging.LoggerFactory = loggerFactory; + } + + /// + public void LogDebug(string message, params object[] args) + { + var formattedMessage = string.Format(CultureInfo.InvariantCulture, message, args); + LogMessages.LogDebugMessage(_logger, formattedMessage); + } + + /// + public void LogError(string message, params object[] args) + { + var formattedMessage = string.Format(CultureInfo.InvariantCulture, message, args); + LogMessages.LogErrorMessage(_logger, formattedMessage); + } + + /// + public void LogInformation(string message, params object[] args) + { + var formattedMessage = string.Format(CultureInfo.InvariantCulture, message, args); + LogMessages.LogInformationMessage(_logger, formattedMessage); + } + + /// + public void LogWarning(string message, params object[] args) { - private readonly ILogger _logger; - - public LoggerAdapter(ILoggerFactory loggerFactory) - { - ArgumentNullException.ThrowIfNull(loggerFactory); - _logger = loggerFactory.CreateLogger(); - ApplicationLogging.LoggerFactory = loggerFactory; - } - - public void LogDebug(string message, params object[] args) => _logger.LogDebug(message, args); - public void LogError(string message, params object[] args) => _logger.LogError(message, args); - public void LogInformation(string message, params object[] args) => _logger.LogInformation(message, args); - public void LogWarning(string message, params object[] args) => _logger.LogWarning(message, args); + var formattedMessage = string.Format(CultureInfo.InvariantCulture, message, args); + LogMessages.LogWarningMessage(_logger, formattedMessage); } -} +} \ No newline at end of file diff --git a/src/AasxServerStandardBib/MqttClient.cs b/src/AasxServerStandardBib/MqttClient.cs index 21503b37f..4f35911f8 100644 --- a/src/AasxServerStandardBib/MqttClient.cs +++ b/src/AasxServerStandardBib/MqttClient.cs @@ -28,6 +28,8 @@ MQTTnet Copyright (c) 2016-2019 Christian Kratky namespace AasxMqttClient { + using System.Text.Json; + public class MqttClient { public MqttClient() @@ -69,7 +71,7 @@ public static async Task StartAsync(AdminShellPackageEnv[] package, GrapevineLog var message2 = new MqttApplicationMessageBuilder() .WithTopic("Submodel_" + sm.IdShort) - .WithPayload(Newtonsoft.Json.JsonConvert.SerializeObject(sm)) + .WithPayload(JsonSerializer.Serialize(sm)) .WithExactlyOnceQoS() .WithRetainFlag() .Build(); diff --git a/src/AasxServerStandardBib/Program.cs b/src/AasxServerStandardBib/Program.cs index f78a0bab0..320c4dbec 100644 --- a/src/AasxServerStandardBib/Program.cs +++ b/src/AasxServerStandardBib/Program.cs @@ -7,8 +7,6 @@ using Jose; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Opc.Ua; using Opc.Ua.Configuration; using Opc.Ua.Server; @@ -18,7 +16,6 @@ using System.CommandLine.Help; using System.CommandLine.IO; using System.ComponentModel; -using System.Globalization; using System.IO; using System.Linq; using System.Net; @@ -32,9 +29,7 @@ using System.Timers; using System.Xml; using System.Xml.Serialization; -using Formatting = Newtonsoft.Json.Formatting; using AasxServerDB.Context; -using Microsoft.IdentityModel.Tokens; /* Copyright (c) 2019-2020 PHOENIX CONTACT GmbH & Co. KG , author: Andreas Orzelski @@ -43,6 +38,10 @@ namespace AasxServer { + using System.Text.Json; + using System.Text.Json.Serialization; + using AasxTimeSeries; + /// /// Checks whether the console will persist after the program exits. /// This should run only on Windows as it depends on kernel32.dll. @@ -51,7 +50,7 @@ namespace AasxServer /// static class WindowsConsoleWillBeDestroyedAtTheEnd { - [ DllImport("kernel32.dll", SetLastError = true) ] + [DllImport("kernel32.dll", SetLastError = true)] static extern uint GetConsoleProcessList(uint[] processList, uint processCount); public static bool Check() @@ -74,7 +73,7 @@ public static string getBetween(AdminShellPackageEnv env, string strStart, strin { int Start, End; Start = strSource.IndexOf(strStart, 0) + strStart.Length; - End = strSource.IndexOf(strEnd, Start); + End = strSource.IndexOf(strEnd, Start); return strSource.Substring(Start, End - Start); } @@ -85,7 +84,7 @@ public static void saveEnv(int envIndex) { Console.WriteLine("SAVE: " + envFileName[envIndex]); string requestedFileName = envFileName[envIndex]; - string copyFileName = Path.GetTempFileName().Replace(".tmp", ".aasx"); + string copyFileName = Path.GetTempFileName().Replace(".tmp", ".aasx"); System.IO.File.Copy(requestedFileName, copyFileName, true); AasxServer.Program.env[envIndex].SaveAs(copyFileName); System.IO.File.Copy(copyFileName, requestedFileName, true); @@ -108,7 +107,7 @@ public static void loadAllPackages() foreach (var aasIDDB in aasIDDBList) loadPackageForAas(aasIDDB, out _, out _); - isLoaded = true; + isLoaded = true; Program.isLoadingDB = false; Program.signalNewData(2); } @@ -123,10 +122,10 @@ public static bool loadPackageForAas(string aasIdentifier, out IAssetAdministrat int i = envimin; while (i < env.Length) { - if (env[ i ] == null) + if (env[i] == null) break; - var aas = env[ i ].AasEnv.AssetAdministrationShells.Where(a => a.Id.Equals(aasIdentifier)); + var aas = env[i].AasEnv.AssetAdministrationShells.Where(a => a.Id.Equals(aasIdentifier)); if (aas.Any()) { output = aas.First(); @@ -147,33 +146,33 @@ public static bool loadPackageForAas(string aasIdentifier, out IAssetAdministrat lock (Program.changeAasxFile) { - envFileName[ i ] = Converter.GetAASXPath(aasId: aasIdentifier); - if (envFileName[ i ].Equals("")) + envFileName[i] = Converter.GetAASXPath(aasId: aasIdentifier); + if (envFileName[i].Equals("")) return false; - if (env[ i ] != null) + if (env[i] != null) { - Console.WriteLine("UNLOAD: " + envFileName[ i ]); - if (env[ i ].getWrite()) + Console.WriteLine("UNLOAD: " + envFileName[i]); + if (env[i].getWrite()) { saveEnv(i); - env[ i ].setWrite(false); + env[i].setWrite(false); } - env[ i ].Close(); + env[i].Close(); } if (!withDbFiles) { - Console.WriteLine("LOAD: " + envFileName[ i ]); - env[ i ] = new AdminShellPackageEnv(envFileName[ i ]); + Console.WriteLine("LOAD: " + envFileName[i]); + env[i] = new AdminShellPackageEnv(envFileName[i]); DateTime timeStamp = DateTime.Now; - var a = env[ i ].AasEnv.AssetAdministrationShells[ 0 ]; + var a = env[i].AasEnv.AssetAdministrationShells[0]; a.TimeStampCreate = timeStamp; a.SetTimeStamp(timeStamp); - foreach (var submodel in env[ i ].AasEnv.Submodels) + foreach (var submodel in env[i].AasEnv.Submodels) { submodel.TimeStampCreate = timeStamp; submodel.SetTimeStamp(timeStamp); @@ -189,8 +188,8 @@ public static bool loadPackageForAas(string aasIdentifier, out IAssetAdministrat Console.WriteLine("LOAD: " + aasIdentifier); var aasDBList = db.AASSets.Where(a => a.Identifier == aasIdentifier); var aasDB = aasDBList.First(); - env[ i ] = Converter.GetPackageEnv(envFileName[ i ], aasDB); - output = env[ i ].AasEnv.AssetAdministrationShells[ 0 ]; + env[i] = Converter.GetPackageEnv(envFileName[i], aasDB); + output = env[i].AasEnv.AssetAdministrationShells[0]; } } @@ -210,10 +209,10 @@ public static bool loadPackageForSubmodel(string submodelIdentifier, out ISubmod int i = envimin; while (i < env.Length) { - if (env[ i ] == null) + if (env[i] == null) break; - var submodels = env[ i ].AasEnv.Submodels.Where(s => s.Id.Equals(submodelIdentifier)); + var submodels = env[i].AasEnv.Submodels.Where(s => s.Id.Equals(submodelIdentifier)); if (submodels.Any()) { output = submodels.First(); @@ -234,39 +233,39 @@ public static bool loadPackageForSubmodel(string submodelIdentifier, out ISubmod lock (Program.changeAasxFile) { - envFileName[ i ] = Converter.GetAASXPath(submodelId: submodelIdentifier); - if (envFileName[ i ].Equals("")) + envFileName[i] = Converter.GetAASXPath(submodelId: submodelIdentifier); + if (envFileName[i].Equals("")) return false; - if (env[ i ] != null) + if (env[i] != null) { - Console.WriteLine("UNLOAD: " + envFileName[ i ]); - if (env[ i ].getWrite()) + Console.WriteLine("UNLOAD: " + envFileName[i]); + if (env[i].getWrite()) { saveEnv(i); - env[ i ].setWrite(false); + env[i].setWrite(false); } - env[ i ].Close(); + env[i].Close(); } if (!withDbFiles) { - Console.WriteLine("LOAD: " + envFileName[ i ]); - env[ i ] = new AdminShellPackageEnv(envFileName[ i ]); + Console.WriteLine("LOAD: " + envFileName[i]); + env[i] = new AdminShellPackageEnv(envFileName[i]); DateTime timeStamp = DateTime.Now; - var a = env[ i ].AasEnv.AssetAdministrationShells[ 0 ]; + var a = env[i].AasEnv.AssetAdministrationShells[0]; a.TimeStampCreate = timeStamp; a.SetTimeStamp(timeStamp); - foreach (var submodel in env[ i ].AasEnv.Submodels) + foreach (var submodel in env[i].AasEnv.Submodels) { submodel.TimeStampCreate = timeStamp; submodel.SetTimeStamp(timeStamp); submodel.SetAllParents(timeStamp); } - var submodels = env[ i ].AasEnv.Submodels.Where(s => s.Id.Equals(submodelIdentifier)); + var submodels = env[i].AasEnv.Submodels.Where(s => s.Id.Equals(submodelIdentifier)); if (submodels.Any()) { output = submodels.First(); @@ -282,8 +281,8 @@ public static bool loadPackageForSubmodel(string submodelIdentifier, out ISubmod Console.WriteLine("LOAD Submodel: " + submodelDB.IdShort); var aasDBList = db.AASSets.Where(a => a.AASXId == submodelDB.AASXId); var aasDB = aasDBList.First(); - env[ i ] = Converter.GetPackageEnv(envFileName[ i ], aasDB); - output = Converter.GetSubmodel(smDB: submodelDB); + env[i] = Converter.GetPackageEnv(envFileName[i], aasDB); + output = Converter.GetSubmodel(smDB: submodelDB); } } @@ -458,7 +457,7 @@ private static async Task Run(CommandLineArguments a) } envVariables.TryGetValue("AASREPOSITORY", out externalRepository); - + if (a.Connect != null) { if (a.Connect.Length == 0) @@ -476,13 +475,13 @@ private static async Task Run(CommandLineArguments a) { bool parsable = true; - string[] c = a.Connect[ 0 ].Split(','); + string[] c = a.Connect[0].Split(','); if (c.Length == 3) { int rate = 0; try { - rate = Convert.ToInt32(c[ 2 ]); + rate = Convert.ToInt32(c[2]); } catch (FormatException) { @@ -491,15 +490,15 @@ private static async Task Run(CommandLineArguments a) if (parsable) { - if (c[ 0 ].Length == 0 || c[ 1 ].Length == 0 || c[ 2 ].Length == 0 || rate <= 0) + if (c[0].Length == 0 || c[1].Length == 0 || c[2].Length == 0 || rate <= 0) { parsable = false; } else { - Program.connectServer = c[ 0 ]; - Program.connectNodeName = c[ 1 ]; - Program.connectUpdateRate = Convert.ToInt32(c[ 2 ]); + Program.connectServer = c[0]; + Program.connectNodeName = c[1]; + Program.connectUpdateRate = Convert.ToInt32(c[2]); } } } @@ -513,7 +512,7 @@ private static async Task Run(CommandLineArguments a) Console.Error.WriteLine( "Invalid --connect. " + "Expected a comma-separated values (server, node name, period in milliseconds), " + - $"but got: {a.Connect[ 0 ]}"); + $"but got: {a.Connect[0]}"); return 1; } } @@ -630,15 +629,15 @@ private static async Task Run(CommandLineArguments a) { externalBlazor = "http://" + blazorHostPort; } - + externalBlazor = externalBlazor.Replace("\r", ""); externalBlazor = externalBlazor.Replace("\n", ""); - + if (string.IsNullOrEmpty(externalRepository)) { externalRepository = externalBlazor; } - + Query.ExternalBlazor = externalBlazor; /* @@ -778,11 +777,12 @@ private static async Task Run(CommandLineArguments a) { // try { - fn = fileNames[ fi ]; - if (fn.ToLower().Contains("globalsecurity") || fn.ToLower().Contains("registry")) + fn = fileNames[fi]; + if (fn.ToLower(System.Globalization.CultureInfo.CurrentCulture).Contains("globalsecurity", StringComparison.InvariantCulture) || + fn.ToLower(System.Globalization.CultureInfo.CurrentCulture).Contains("registry", StringComparison.InvariantCulture)) { - envFileName[ envi ] = fn; - env[ envi ] = new AdminShellPackageEnv(fn, true, false); + envFileName[envi] = fn; + env[envi] = new AdminShellPackageEnv(fn, true, false); //TODO:jtikekar //AasxHttpContextHelper.securityInit(); // read users and access rights from AASX Security //AasxHttpContextHelper.serverCertsInit(); // load certificates of auth servers @@ -808,15 +808,15 @@ private static async Task Run(CommandLineArguments a) // Convert to newest version only if (saveTemp == -1) { - env[ envi ] = new AdminShellPackageEnv(fn, true, false); - if (env[ envi ] == null) + env[envi] = new AdminShellPackageEnv(fn, true, false); + if (env[envi] == null) { Console.Error.WriteLine($"Cannot open {fn}. Aborting.."); return 1; } Console.WriteLine((fi + 1) + "/" + fileNames.Length + " " + watch.ElapsedMilliseconds / 1000 + "s " + "SAVE TO TEMP: " + fn); - Program.env[ envi ].SaveAs(tempName); + Program.env[envi].SaveAs(tempName); fi++; continue; } @@ -827,11 +827,11 @@ private static async Task Run(CommandLineArguments a) } Console.WriteLine((fi + 1) + "/" + fileNames.Length + " " + watch.ElapsedMilliseconds / 1000 + "s" + " Loading {0}...", fn); - envFileName[ envi ] = fn; + envFileName[envi] = fn; if (!withDb) { - env[ envi ] = new AdminShellPackageEnv(fn, true, false); - if (env[ envi ] == null) + env[envi] = new AdminShellPackageEnv(fn, true, false); + if (env[envi] == null) { Console.Error.WriteLine($"Cannot open {fn}. Aborting.."); return 1; @@ -840,8 +840,8 @@ private static async Task Run(CommandLineArguments a) else { VisitorAASX.LoadAASXInDB(fn, createFilesOnly, withDbFiles); - envFileName[ envi ] = null; - env[ envi ] = null; + envFileName[envi] = null; + env[envi] = null; } // check if signed @@ -849,16 +849,16 @@ private static async Task Run(CommandLineArguments a) if (System.IO.File.Exists(fileCert)) { X509Certificate2 x509 = new X509Certificate2(fileCert); - envSymbols[ envi ] = "S"; - envSubjectIssuer[ envi ] = x509.Subject; + envSymbols[envi] = "S"; + envSubjectIssuer[envi] = x509.Subject; X509Chain chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; bool isValid = chain.Build(x509); if (isValid) { - envSymbols[ envi ] += ";V"; - envSubjectIssuer[ envi ] += ";" + x509.Issuer; + envSymbols[envi] += ";V"; + envSubjectIssuer[envi] += ";" + x509.Issuer; } } } @@ -911,12 +911,12 @@ private static async Task Run(CommandLineArguments a) for (int j = 0; j < fileNames.Length; j++) { - fn = fileNames[ j ]; + fn = fileNames[j]; if (fn != "" && envi < envimax) { - envFileName[ envi ] = fn; - envSymbols[ envi ] = "L"; // Show lock + envFileName[envi] = fn; + envSymbols[envi] = "L"; // Show lock } envi++; @@ -947,6 +947,17 @@ private static async Task Run(CommandLineArguments a) // MICHA MICHA AasxTimeSeries.TimeSeries.timeSeriesInit(); + /* OZOZ + var _energyModelInstances = new List(); + foreach (var penv in AasxServer.Program.env) + { + EnergyModelInstance.TagAllAasAndSm(penv?.AasEnv, DateTime.UtcNow); + _energyModelInstances.AddRange( + EnergyModelInstance.FindAllSmInstances(penv?.AasEnv)); + } + EnergyModelInstance.StartAllAsOneThread(_energyModelInstances); + */ + AasxTask.taskInit(); RunScript(true); @@ -980,7 +991,7 @@ private static async Task Run(CommandLineArguments a) } Console.WriteLine($"OPC client will be updating every: {a.OpcClientRate} milliseconds"); - SetOPCClientTimer((double) a.OpcClientRate); // read again everytime timer expires + SetOPCClientTimer((double)a.OpcClientRate); // read again everytime timer expires } SetScriptTimer(1000); // also updates balzor view @@ -1121,9 +1132,9 @@ public static void Main(string[] args) AasContext._con = con; if (con != null) { - if (con[ "DatabaseConnection:ConnectionString" ] != null) + if (con["DatabaseConnection:ConnectionString"] != null) { - AasContext.IsPostgres = con[ "DatabaseConnection:ConnectionString" ].ToLower().Contains("host"); + AasContext.IsPostgres = con["DatabaseConnection:ConnectionString"].ToLower().Contains("host"); } } @@ -1254,57 +1265,55 @@ public aasDirectoryParameters() /* End Point Definition */ public class AASxEndpoint { - [ XmlElement(ElementName = "address") ] - public string address = ""; + [XmlElement(ElementName = "address")] public string address = ""; - [ XmlElement(ElementName = "type") ] public string type = ""; + [XmlElement(ElementName = "type")] public string type = ""; } /* Submodel Descriptor Definition */ public class SubmodelDescriptors { - [ XmlElement(ElementName = "administration") ] [ JsonIgnore ] + [XmlElement(ElementName = "administration")] [JsonIgnore] //public AdminShell.Administration administration = null; public AdministrativeInformation administration = null; - [ XmlElement(ElementName = "description") ] [ JsonIgnore ] + [XmlElement(ElementName = "description")] [JsonIgnore] //public AdminShell.Description description = null; public List description = null; - [ XmlElement(ElementName = "idShort") ] [ JsonIgnore ] + [XmlElement(ElementName = "idShort")] [JsonIgnore] public string idShort = ""; - [ XmlElement(ElementName = "identification") ] [ JsonIgnore ] + [XmlElement(ElementName = "identification")] [JsonIgnore] public string identification = null; - [ XmlElement(ElementName = "semanticId") ] + [XmlElement(ElementName = "semanticId")] public Reference semanticId = null; - [ XmlElement(ElementName = "endpoints") ] + [XmlElement(ElementName = "endpoints")] public List endpoints = new List(); } /* AAS Descriptor Definiton */ public class aasDescriptor { - [ XmlElement(ElementName = "administration") ] [ JsonIgnore ] + [XmlElement(ElementName = "administration")] [JsonIgnore] public AdministrativeInformation administration = null; - [ XmlElement(ElementName = "description") ] [ JsonIgnore ] + [XmlElement(ElementName = "description")] [JsonIgnore] public List description = new(new List()); - [ XmlElement(ElementName = "idShort") ] - public string idShort = ""; + [XmlElement(ElementName = "idShort")] public string idShort = ""; - [ XmlElement(ElementName = "identification") ] [ JsonIgnore ] + [XmlElement(ElementName = "identification")] [JsonIgnore] public string identification = null; - [ XmlElement(ElementName = "assets") ] public List assets = new List(); + [XmlElement(ElementName = "assets")] public List assets = new List(); - [ XmlElement(ElementName = "endpoints") ] + [XmlElement(ElementName = "endpoints")] public List endpoints = new List(); - [ XmlElement(ElementName = "submodelDescriptors") ] + [XmlElement(ElementName = "submodelDescriptors")] public List submodelDescriptors = new List(); } @@ -1317,12 +1326,12 @@ public static aasDescriptor creatAASDescriptor(AdminShellPackageEnv adminShell) aasDescriptor aasD = new aasDescriptor(); string endpointAddress = "http://" + hostPort; - aasD.idShort = adminShell.AasEnv.AssetAdministrationShells[ 0 ].IdShort; - aasD.identification = adminShell.AasEnv.AssetAdministrationShells[ 0 ].Id; - aasD.description = adminShell.AasEnv.AssetAdministrationShells[ 0 ].Description; + aasD.idShort = adminShell.AasEnv.AssetAdministrationShells[0].IdShort; + aasD.identification = adminShell.AasEnv.AssetAdministrationShells[0].Id; + aasD.description = adminShell.AasEnv.AssetAdministrationShells[0].Description; AASxEndpoint endp = new AASxEndpoint(); - endp.address = endpointAddress + "/aas/" + adminShell.AasEnv.AssetAdministrationShells[ 0 ].IdShort; + endp.address = endpointAddress + "/aas/" + adminShell.AasEnv.AssetAdministrationShells[0].IdShort; aasD.endpoints.Add(endp); int submodelCount = adminShell.AasEnv.Submodels.Count; @@ -1330,15 +1339,15 @@ public static aasDescriptor creatAASDescriptor(AdminShellPackageEnv adminShell) { SubmodelDescriptors sdc = new SubmodelDescriptors(); - sdc.administration = adminShell.AasEnv.Submodels[ i ].Administration as AdministrativeInformation; - sdc.description = adminShell.AasEnv.Submodels[ i ].Description; - sdc.identification = adminShell.AasEnv.Submodels[ i ].Id; - sdc.idShort = adminShell.AasEnv.Submodels[ i ].IdShort; - sdc.semanticId = adminShell.AasEnv.Submodels[ i ].SemanticId as Reference; + sdc.administration = adminShell.AasEnv.Submodels[i].Administration as AdministrativeInformation; + sdc.description = adminShell.AasEnv.Submodels[i].Description; + sdc.identification = adminShell.AasEnv.Submodels[i].Id; + sdc.idShort = adminShell.AasEnv.Submodels[i].IdShort; + sdc.semanticId = adminShell.AasEnv.Submodels[i].SemanticId as Reference; AASxEndpoint endpSub = new AASxEndpoint(); - endpSub.address = endpointAddress + "/aas/" + adminShell.AasEnv.AssetAdministrationShells[ 0 ].IdShort + - "/submodels/" + adminShell.AasEnv.Submodels[ i ].IdShort; + endpSub.address = endpointAddress + "/aas/" + adminShell.AasEnv.AssetAdministrationShells[0].IdShort + + "/submodels/" + adminShell.AasEnv.Submodels[i].IdShort; endpSub.type = "http"; sdc.endpoints.Add(endpSub); @@ -1457,28 +1466,30 @@ public static void connectThreadLoop() { aasListParameters alp = new aasListParameters(); - if (Program.env[ j ] != null) + if (Program.env[j] != null) { alp.index = j; /* Create Detail part 2 Descriptor Start */ - aasDescriptor aasDsecritpor = Program.creatAASDescriptor(Program.env[ j ]); + aasDescriptor aasDsecritpor = Program.creatAASDescriptor(Program.env[j]); TransmitData aasDsecritporTData = new TransmitData {source = connectNodeName}; aasDsecritporTData.type = "register"; aasDsecritporTData.destination = "VWS_AAS_Registry"; - var aasDescriptorJsonData = JsonConvert.SerializeObject(aasDsecritpor, Newtonsoft.Json.Formatting.Indented, - new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore}); + var options = new JsonSerializerOptions {WriteIndented = true, IgnoreNullValues = true}; + + var aasDescriptorJsonData = System.Text.Json.JsonSerializer.Serialize(aasDsecritpor, options); + aasDsecritporTData.publish.Add(aasDescriptorJsonData); descriptortf.data.Add(aasDsecritporTData); /* Create Detail part 2 Descriptor END */ - alp.idShort = Program.env[ j ].AasEnv.AssetAdministrationShells[ 0 ].IdShort; - alp.identification = Program.env[ j ].AasEnv.AssetAdministrationShells[ 0 ].Id; - alp.fileName = Program.envFileName[ j ]; + alp.idShort = Program.env[j].AasEnv.AssetAdministrationShells[0].IdShort; + alp.identification = Program.env[j].AasEnv.AssetAdministrationShells[0].Id; + alp.fileName = Program.envFileName[j]; alp.assetId = ""; //var asset = Program.env[j].AasEnv.FindAsset(Program.env[j].AasEnv.AssetAdministrationShells[0].assetRef); - var asset = Program.env[ j ].AasEnv.AssetAdministrationShells[ 0 ].AssetInformation; + var asset = Program.env[j].AasEnv.AssetAdministrationShells[0].AssetInformation; if (asset != null) alp.humanEndPoint = blazorHostPort; alp.restEndPoint = hostPort; @@ -1487,12 +1498,12 @@ public static void connectThreadLoop() } } - string decriptorData = JsonConvert.SerializeObject(descriptortf, Formatting.Indented); + string decriptorData = System.Text.Json.JsonSerializer.Serialize(descriptortf, new JsonSerializerOptions {WriteIndented = true,}); Program.publishDescriptorData(decriptorData); td = new TransmitData {source = connectNodeName}; - var json = JsonConvert.SerializeObject(adp, Newtonsoft.Json.Formatting.Indented); + string json = System.Text.Json.JsonSerializer.Serialize(adp, new JsonSerializerOptions {WriteIndented = true,}); td.type = "directory"; td.destination = getDirectoryDestination; td.publish.Add(json); @@ -1526,8 +1537,7 @@ public static void connectThreadLoop() res.fileType = getaasxFile_fileType; res.fileTransmitted = getaasxFile_fileTransmitted; - string responseJson = JsonConvert.SerializeObject(res, Formatting.Indented); - + string responseJson = System.Text.Json.JsonSerializer.Serialize(res, new JsonSerializerOptions {WriteIndented = true,}); td.destination = getaasxFile_destination; td.type = "getaasxBlock"; td.publish.Add(responseJson); @@ -1558,9 +1568,9 @@ public static void connectThreadLoop() } int envi = 0; - while (env[ envi ] != null) + while (env[envi] != null) { - foreach (var sm in env[ envi ].AasEnv.Submodels) + foreach (var sm in env[envi].AasEnv.Submodels) { if (sm != null && sm.IdShort != null) { @@ -1574,7 +1584,7 @@ public static void connectThreadLoop() while (j < count) // Scan qualifiers { - var p = sm.Qualifiers[ j ] as Qualifier; + var p = sm.Qualifiers[j] as Qualifier; if (p.Type == "PUBLISH") { @@ -1590,7 +1600,7 @@ public static void connectThreadLoop() { td = new TransmitData {source = connectNodeName}; - var json = JsonConvert.SerializeObject(sm, Newtonsoft.Json.Formatting.Indented); + var json = System.Text.Json.JsonSerializer.Serialize(sm, new JsonSerializerOptions {WriteIndented = true,}); td.type = "submodel"; td.publish.Add(json); tf.data.Add(td); @@ -1602,7 +1612,7 @@ public static void connectThreadLoop() envi++; } - string publish = JsonConvert.SerializeObject(tf, Formatting.Indented); + string publish = System.Text.Json.JsonSerializer.Serialize(tf, new JsonSerializerOptions {WriteIndented = true,}); HttpClient httpClient; if (clientHandler != null) @@ -1634,7 +1644,7 @@ public static void connectThreadLoop() try { TransmitFrame tf2 = new TransmitFrame(); - tf2 = Newtonsoft.Json.JsonConvert.DeserializeObject(content); + tf2 = JsonSerializer.Deserialize(content); node = tf2.source; foreach (TransmitData td2 in tf2.data) @@ -1652,7 +1662,7 @@ public static void connectThreadLoop() dynamic res = new System.Dynamic.ExpandoObject(); - Byte[] binaryFile = System.IO.File.ReadAllBytes(Program.envFileName[ aasIndex ]); + Byte[] binaryFile = System.IO.File.ReadAllBytes(Program.envFileName[aasIndex]); string binaryBase64 = Convert.ToBase64String(binaryFile); string payload = "{ \"file\" : \" " + binaryBase64 + " \" }"; @@ -1662,10 +1672,10 @@ public static void connectThreadLoop() if (fileToken.Length <= blockSize) { - res.fileName = Path.GetFileName(Program.envFileName[ aasIndex ]); + res.fileName = Path.GetFileName(Program.envFileName[aasIndex]); res.fileData = fileToken; - string responseJson = JsonConvert.SerializeObject(res, Formatting.Indented); + string responseJson = System.Text.Json.JsonSerializer.Serialize(res, new JsonSerializerOptions {WriteIndented = true,}); TransmitData tdp = new TransmitData(); @@ -1678,7 +1688,7 @@ public static void connectThreadLoop() else { getaasxFile_destination = td2.source; - getaasxFile_fileName = Path.GetFileName(Program.envFileName[ aasIndex ]); + getaasxFile_fileName = Path.GetFileName(Program.envFileName[aasIndex]); getaasxFile_fileData = fileToken; getaasxFile_fileType = "getaasxFileStream"; getaasxFile_fileLenBase64 = getaasxFile_fileData.Length; @@ -1693,16 +1703,16 @@ public static void connectThreadLoop() dynamic res = new System.Dynamic.ExpandoObject(); - Byte[] binaryFile = System.IO.File.ReadAllBytes(Program.envFileName[ aasIndex ]); + Byte[] binaryFile = System.IO.File.ReadAllBytes(Program.envFileName[aasIndex]); string binaryBase64 = Convert.ToBase64String(binaryFile); if (binaryBase64.Length <= blockSize) { - res.fileName = Path.GetFileName(Program.envFileName[ aasIndex ]); + res.fileName = Path.GetFileName(Program.envFileName[aasIndex]); res.fileData = binaryBase64; - Byte[] fileBytes = Convert.FromBase64String(binaryBase64); + Byte[] fileBytes = Convert.FromBase64String(binaryBase64); + string responseJson = System.Text.Json.JsonSerializer.Serialize(res, new JsonSerializerOptions {WriteIndented = true,}); - string responseJson = JsonConvert.SerializeObject(res, Formatting.Indented); TransmitData tdp = new TransmitData(); @@ -1715,7 +1725,7 @@ public static void connectThreadLoop() else { getaasxFile_destination = td2.source; - getaasxFile_fileName = Path.GetFileName(Program.envFileName[ aasIndex ]); + getaasxFile_fileName = Path.GetFileName(Program.envFileName[aasIndex]); getaasxFile_fileData = binaryBase64; getaasxFile_fileType = "getaasxFile"; getaasxFile_fileLenBase64 = getaasxFile_fileData.Length; @@ -1729,7 +1739,7 @@ public static void connectThreadLoop() string[] split = td2.type.Split('.'); foreach (var smc in AasxTimeSeries.TimeSeries.timeSeriesSubscribe) { - if (smc.IdShort == split[ 0 ]) + if (smc.IdShort == split[0]) { foreach (var tsb in AasxTimeSeries.TimeSeries.timeSeriesBlockList) { @@ -1743,45 +1753,7 @@ public static void connectThreadLoop() if (tsb.block == smc) { - foreach (string data in td2.publish) - { - using (TextReader reader = new StringReader(data)) - { - JsonSerializer serializer = new JsonSerializer(); - serializer.Converters.Add(new AdminShellConverters.JsonAasxConverter("modelType", "name")); - var smcData = (SubmodelElementCollection) serializer.Deserialize(reader, - typeof(SubmodelElementCollection)); - if (smcData != null && smc.Value.Count < 100) - { - if (tsb.data != null) - { - int maxCollections = Convert.ToInt32(tsb.maxCollections.Value); - int actualCollections = tsb.data.Value.Count; - if (actualCollections < maxCollections || - (tsb.sampleMode.Value == "continuous" && actualCollections == maxCollections)) - { - tsb.data.Value.Add(smcData); - actualCollections++; - } - - if (actualCollections > maxCollections) - { - tsb.data.Value.RemoveAt(0); - actualCollections--; - } - - tsb.actualCollections.Value = actualCollections.ToString(); - /* - tsb.lowDataIndex = - Convert.ToInt32(tsb.data.Value[0].submodelElement.IdShort.Substring("data".Length)); - tsb.highDataIndex = - Convert.ToInt32(tsb.data.Value[tsb.data.Value.Count - 1].submodelElement.IdShort.Substring("data".Length)); - */ - signalNewData(1); - } - } - } - } + transformTsbBlock(td2, smc, tsb); } } } @@ -1795,11 +1767,12 @@ public static void connectThreadLoop() Submodel submodel = null; try { - using (TextReader reader = new StringReader(sm)) + using (var reader = new StringReader(sm)) { - JsonSerializer serializer = new JsonSerializer(); - serializer.Converters.Add(new AdminShellConverters.JsonAasxConverter("modelType", "name")); - submodel = (Submodel) serializer.Deserialize(reader, typeof(Submodel)); + var options = new JsonSerializerOptions(); + options.Converters.Add(new AdminShellConverters.JsonAasxConverter("modelType", "name")); + + submodel = System.Text.Json.JsonSerializer.Deserialize(reader.ReadToEnd(), options); } } catch (Exception) @@ -1817,9 +1790,9 @@ public static void connectThreadLoop() IAssetAdministrationShell aas = null; envi = 0; - while (env[ envi ] != null) + while (env[envi] != null) { - aas = env[ envi ].AasEnv.FindAasWithSubmodelId(submodel.Id); + aas = env[envi].AasEnv.FindAasWithSubmodelId(submodel.Id); if (aas != null) break; envi++; @@ -1829,13 +1802,13 @@ public static void connectThreadLoop() if (aas != null) { // datastructure update - if (env == null || env[ envi ].AasEnv == null /*|| env[envi].AasEnv.Assets == null*/) + if (env == null || env[envi].AasEnv == null /*|| env[envi].AasEnv.Assets == null*/) { Console.WriteLine("Error accessing internal data structures."); return; } - var existingSm = env[ envi ].AasEnv.FindSubmodelById(submodel.Id); + var existingSm = env[envi].AasEnv.FindSubmodelById(submodel.Id); if (existingSm != null) { bool toSubscribe = Program.submodelsToSubscribe.Contains(existingSm); @@ -1848,7 +1821,7 @@ public static void connectThreadLoop() while (j < eqcount) // Scan qualifiers { - var p = existingSm.Qualifiers[ j ] as Qualifier; + var p = existingSm.Qualifiers[j] as Qualifier; if (p.Type == "SUBSCRIBE") { @@ -1872,7 +1845,7 @@ public static void connectThreadLoop() while (k < c2) // Scan qualifiers { - var q = submodel.Qualifiers[ k ] as Qualifier; + var q = submodel.Qualifiers[k] as Qualifier; if (q.Type == "PUBLISH") { @@ -1891,8 +1864,8 @@ public static void connectThreadLoop() int smi = 0; while (smi < escount) { - var sme1 = submodel.SubmodelElements[ smi ]; - var sme2 = existingSm.SubmodelElements[ smi ]; + var sme1 = submodel.SubmodelElements[smi]; + var sme2 = existingSm.SubmodelElements[smi]; if (sme1 is Property) { @@ -1913,8 +1886,8 @@ public static void connectThreadLoop() if (!overwrite) { - env[ envi ].AasEnv.Submodels.Remove(existingSm); - env[ envi ].AasEnv.Submodels.Add(submodel); + env[envi].AasEnv.Submodels.Remove(existingSm); + env[envi].AasEnv.Submodels.Add(submodel); // add SubmodelRef to AAS // access the AAS @@ -1956,6 +1929,53 @@ public static void connectThreadLoop() } } + private static void transformTsbBlock(TransmitData td2, SubmodelElementCollection smc, TimeSeries.TimeSeriesBlock tsb) + { + foreach (var data in td2.publish) + { + var options = new JsonSerializerOptions(); + options.Converters.Add(new AdminShellConverters.JsonAasxConverter("modelType", "name")); + + SubmodelElementCollection smcData; + + using (TextReader reader = new StringReader(data)) + { + string jsonString = reader.ReadToEnd(); + smcData = System.Text.Json.JsonSerializer.Deserialize(jsonString, options); + + if (smcData != null && smc.Value.Count < 100) + { + if (tsb.data != null) + { + int maxCollections = Convert.ToInt32(tsb.maxCollections.Value); + int actualCollections = tsb.data.Value.Count; + if (actualCollections < maxCollections || + (tsb.sampleMode.Value == "continuous" && actualCollections == maxCollections)) + { + tsb.data.Value.Add(smcData); + actualCollections++; + } + + if (actualCollections > maxCollections) + { + tsb.data.Value.RemoveAt(0); + actualCollections--; + } + + tsb.actualCollections.Value = actualCollections.ToString(); + /* + tsb.lowDataIndex = + Convert.ToInt32(tsb.data.Value[0].submodelElement.IdShort.Substring("data".Length)); + tsb.highDataIndex = + Convert.ToInt32(tsb.data.Value[tsb.data.Value.Count - 1].submodelElement.IdShort.Substring("data".Length)); + */ + signalNewData(1); + } + } + } + } + } + static bool timerSet = false; private static void SetOPCClientTimer(double value) @@ -2060,7 +2080,7 @@ private static void OnRestTimedEvent(Object source, ElapsedEventArgs e) string PUTURL = ""; // Search for submodel REST and scan qualifiers for GET and PUT commands - foreach (var sm in env[ 0 ].AasEnv.Submodels) + foreach (var sm in env[0].AasEnv.Submodels) { if (sm != null && sm.IdShort != null && sm.IdShort == "REST") { @@ -2071,7 +2091,7 @@ private static void OnRestTimedEvent(Object source, ElapsedEventArgs e) while (j < count) // Scan qualifiers { - var p = sm.Qualifiers[ j ] as Qualifier; + var p = sm.Qualifiers[j] as Qualifier; if (p.Type == "GETSUBMODEL") { @@ -2117,12 +2137,11 @@ private static void OnRestTimedEvent(Object source, ElapsedEventArgs e) Submodel submodel = null; try { - using (TextReader reader = new StringReader(sm)) - { - JsonSerializer serializer = new JsonSerializer(); - serializer.Converters.Add(new AdminShellConverters.JsonAasxConverter("modelType", "name")); - submodel = (Submodel) serializer.Deserialize(reader, typeof(Submodel)); - } + var options = new JsonSerializerOptions(); + options.Converters.Add(new AdminShellConverters.JsonAasxConverter("modelType", "name")); + using var reader = new StringReader(sm); + var jsonString = reader.ReadToEnd(); + submodel = System.Text.Json.JsonSerializer.Deserialize(jsonString, options); } catch (Exception) { @@ -2137,20 +2156,20 @@ private static void OnRestTimedEvent(Object source, ElapsedEventArgs e) return; } - var aas = env[ 0 ].AasEnv.FindAasWithSubmodelId(submodel.Id); + var aas = env[0].AasEnv.FindAasWithSubmodelId(submodel.Id); // datastructure update - if (env == null || env[ 0 ].AasEnv == null /*|| env[0].AasEnv.Assets == null*/) + if (env == null || env[0].AasEnv == null /*|| env[0].AasEnv.Assets == null*/) { Console.WriteLine("Error accessing internal data structures."); return; } // add Submodel - var existingSm = env[ 0 ].AasEnv.FindSubmodelById(submodel.Id); + var existingSm = env[0].AasEnv.FindSubmodelById(submodel.Id); if (existingSm != null) - env[ 0 ].AasEnv.Submodels.Remove(existingSm); - env[ 0 ].AasEnv.Submodels.Add(submodel); + env[0].AasEnv.Submodels.Remove(existingSm); + env[0].AasEnv.Submodels.Add(submodel); // add SubmodelRef to AAS // access the AAS @@ -2168,11 +2187,12 @@ private static void OnRestTimedEvent(Object source, ElapsedEventArgs e) Console.WriteLine("{0} PUT Submodel {1} from URL {2}.", countGetPut++, PUTSUBMODEL, PUTURL); { - foreach (var sm in env[ 0 ].AasEnv.Submodels) + var jsonOptions = new JsonSerializerOptions {WriteIndented = true}; + foreach (var sm in env[0].AasEnv.Submodels) { if (sm != null && sm.IdShort != null && sm.IdShort == PUTSUBMODEL) { - var json = JsonConvert.SerializeObject(sm, Newtonsoft.Json.Formatting.Indented); + var json = System.Text.Json.JsonSerializer.Serialize(sm, jsonOptions); try { @@ -2262,9 +2282,9 @@ static Boolean ReadOPCClient(bool initial) lock (Program.changeAasxFile) { int i = 0; - while (env[ i ] != null) + while (env[i] != null) { - foreach (var sm in env[ i ].AasEnv.Submodels) + foreach (var sm in env[i].AasEnv.Submodels) { if (sm != null && sm.IdShort != null) { @@ -2284,7 +2304,7 @@ static Boolean ReadOPCClient(bool initial) while (j < count) // URL, Username, Password, Namespace, Path { - var p = sm.Qualifiers[ j ] as Qualifier; + var p = sm.Qualifiers[j] as Qualifier; switch (p.Type) { @@ -2311,9 +2331,9 @@ static Boolean ReadOPCClient(bool initial) if (split.Length == 2) { string value = ""; - if (envVariables.TryGetValue(split[ 0 ], out value)) + if (envVariables.TryGetValue(split[0], out value)) { - if (split[ 1 ] != value) + if (split[1] != value) URL = ""; // continue } } @@ -2393,12 +2413,12 @@ static Boolean ReadOPCClient(bool initial) count = sm.SubmodelElements.Count; for (j = 0; j < count; j++) { - var sme = sm.SubmodelElements[ j ]; + var sme = sm.SubmodelElements[j]; // some preparations for multiple AAS below int serverNamespaceIdx = 3; //could be gotten directly from the nodeMgr in OPCWrite instead, only pass the string part of the Id string AASSubmodel - = env[ i ].AasEnv.AssetAdministrationShells[ 0 ].IdShort + "." + + = env[i].AasEnv.AssetAdministrationShells[0].IdShort + "." + sm.IdShort; // for multiple AAS, use something like env.AasEnv.AssetAdministrationShells[i].IdShort; string serverNodePrefix = string.Format("ns={0};s=AASROOT.{1}", serverNamespaceIdx, AASSubmodel); string nodePath = Path; // generally starts with Submodel idShort @@ -2431,18 +2451,18 @@ static void RunScript(bool init) lock (Program.changeAasxFile) { int i = 0; - while (i < env.Length && env[ i ] != null) + while (i < env.Length && env[i] != null) { - if (env[ i ].AasEnv.Submodels != null) + if (env[i].AasEnv.Submodels != null) { - foreach (var sm in env[ i ].AasEnv.Submodels) + foreach (var sm in env[i].AasEnv.Submodels) { if (sm != null && sm.IdShort != null) { int count = sm.Qualifiers != null ? sm.Qualifiers.Count : 0; if (count != 0) { - var q = sm.Qualifiers[ 0 ] as Qualifier; + var q = sm.Qualifiers[0] as Qualifier; if (q.Type == "SCRIPT") { // Triple @@ -2453,13 +2473,13 @@ static void RunScript(bool init) int smi = 0; while (smi < count) { - var sme1 = sm.SubmodelElements[ smi++ ]; + var sme1 = sm.SubmodelElements[smi++]; if (sme1.Qualifiers == null || sme1.Qualifiers.Count == 0) { continue; } - var qq = sme1.Qualifiers[ 0 ] as Qualifier; + var qq = sme1.Qualifiers[0] as Qualifier; if (qq.Type == "Add") { @@ -2536,11 +2556,11 @@ static void RunScript(bool init) if (sme1.Qualifiers.Count == 3) { - qq = sme1.Qualifiers[ 1 ] as Qualifier; + qq = sme1.Qualifiers[1] as Qualifier; if (qq.Type != "Username") continue; username = qq.Value; - qq = sme1.Qualifiers[ 2 ] as Qualifier; + qq = sme1.Qualifiers[2] as Qualifier; if (qq.Type != "Password") continue; password = qq.Value; @@ -2564,16 +2584,12 @@ static void RunScript(bool init) if (response != "") { var r12 = sme1 as ReferenceElement; - var ref12 = env[ i ].AasEnv.FindReferableByReference(r12.GetModelReference()); + var ref12 = env[i].AasEnv.FindReferableByReference(r12.GetModelReference()); if (ref12 is SubmodelElementCollection) { - var c1 = ref12 as SubmodelElementCollection; - // if (c1.Value.Count == 0) - { - // dynamic model = JObject.Parse(response); - JObject parsed = JObject.Parse(response); - parseJson(c1, parsed, null); - } + var c1 = ref12 as SubmodelElementCollection; + var parsed = JsonDocument.Parse(response); + ParseJson(c1, parsed, null); } } @@ -2585,25 +2601,25 @@ static void RunScript(bool init) continue; } - var sme2 = sm.SubmodelElements[ smi++ ]; + var sme2 = sm.SubmodelElements[smi++]; if (sme2.Qualifiers.Count == 0) { continue; } - qq = sme2.Qualifiers[ 0 ] as Qualifier; + qq = sme2.Qualifiers[0] as Qualifier; if (qq.Type != "SearchList" || smi >= count) { continue; } - var sme3 = sm.SubmodelElements[ smi++ ]; + var sme3 = sm.SubmodelElements[smi++]; if (sme3.Qualifiers.Count == 0) { continue; } - qq = sme3.Qualifiers[ 0 ] as Qualifier; + qq = sme3.Qualifiers[0] as Qualifier; if (qq.Type != "SearchResult") { break; @@ -2616,9 +2632,9 @@ sme2 is ReferenceElement && var r1 = sme1 as ReferenceElement; var r2 = sme2 as ReferenceElement; var r3 = sme3 as ReferenceElement; - var ref1 = env[ i ].AasEnv.FindReferableByReference(r1.GetModelReference()); - var ref2 = env[ i ].AasEnv.FindReferableByReference(r2.GetModelReference()); - var ref3 = env[ i ].AasEnv.FindReferableByReference(r3.GetModelReference()); + var ref1 = env[i].AasEnv.FindReferableByReference(r1.GetModelReference()); + var ref2 = env[i].AasEnv.FindReferableByReference(r2.GetModelReference()); + var ref3 = env[i].AasEnv.FindReferableByReference(r3.GetModelReference()); if (ref1 is Property && ref2 is Submodel && ref3 is Property) { var p1 = ref1 as Property; @@ -2628,7 +2644,7 @@ sme2 is ReferenceElement && int count2 = sm2.SubmodelElements.Count; for (int j = 0; j < count2; j++) { - var sme = sm2.SubmodelElements[ j ]; + var sme = sm2.SubmodelElements[j]; if (sme.IdShort == p1.Value) { p3.Value = (sme as Property).Value; @@ -2642,6 +2658,7 @@ sme2 is ReferenceElement && } } } + i++; } } @@ -2649,136 +2666,90 @@ sme2 is ReferenceElement && return; } - public static bool parseJson(SubmodelElementCollection c, JObject o, List filter, + public static bool ParseJson(SubmodelElementCollection c, object o, List filter, Property minDiffAbsolute = null, Property minDiffPercent = null, AdminShellPackageEnv envaas = null) { - int newMode = 0; - DateTime timeStamp = DateTime.UtcNow; - bool ok = false; + var newMode = 0; + var timeStamp = DateTime.UtcNow; + var ok = false; - int iMinDiffAbsolute = 1; - int iMinDiffPercent = 0; + var iMinDiffAbsolute = 1; + var iMinDiffPercent = 0; if (minDiffAbsolute != null) iMinDiffAbsolute = Convert.ToInt32(minDiffAbsolute.Value); if (minDiffPercent != null) iMinDiffPercent = Convert.ToInt32(minDiffPercent.Value); - foreach (JProperty jp1 in (JToken) o) + switch (o) { - if (filter != null && filter.Count != 0) - { - if (!filter.Contains(jp1.Name)) - continue; - } - - SubmodelElementCollection c2; - switch (jp1.Value.Type) - { - case JTokenType.Array: - c2 = c.FindFirstIdShortAs(jp1.Name); - if (c2 == null) - { - //c2 = SubmodelElementCollection.CreateNew(jp1.Name); - c2 = new SubmodelElementCollection(idShort: jp1.Name); - c.Value.Add(c2); - c2.TimeStampCreate = timeStamp; - c2.SetTimeStamp(timeStamp); - newMode = 1; - } - - int count = 1; - foreach (JObject el in jp1.Value) - { - string n = jp1.Name + "_array_" + count++; - SubmodelElementCollection c3 = - c2.FindFirstIdShortAs(n); - if (c3 == null) - { - c3 = new SubmodelElementCollection(idShort: n); - c2.Value.Add(c3); - c3.TimeStampCreate = timeStamp; - c3.SetTimeStamp(timeStamp); - newMode = 1; - } - - ok |= parseJson(c3, el, filter, envaas: envaas); - } - - break; - case JTokenType.Object: - c2 = c.FindFirstIdShortAs(jp1.Name); - if (c2 == null) - { - c2 = new SubmodelElementCollection(idShort: jp1.Name); - c.Value.Add(c2); - c2.TimeStampCreate = timeStamp; - c2.SetTimeStamp(timeStamp); - newMode = 1; - } - - foreach (JObject el in jp1.Value) + case JsonDocument doc: + ok |= ParseJson(c, doc.RootElement, filter, minDiffAbsolute, minDiffPercent, envaas); + break; + case JsonElement el: + foreach (JsonProperty jp1 in el.EnumerateObject()) + { + if (filter != null && filter.Count != 0) { - ok |= parseJson(c2, el, filter, envaas: envaas); + if (!filter.Contains(jp1.Name)) + continue; } - break; - default: - Property p = c.FindFirstIdShortAs(jp1.Name); - if (p == null) + SubmodelElementCollection c2; + switch (jp1.Value.ValueKind) { - p = new Property(DataTypeDefXsd.String, idShort: jp1.Name); - c.Value.Add(p); - p.TimeStampCreate = timeStamp; - p.SetTimeStamp(timeStamp); - newMode = 1; - } + case JsonValueKind.Array: + c2 = c.FindFirstIdShortAs(jp1.Name); + if (c2 == null) + { + c2 = new SubmodelElementCollection(idShort: jp1.Name); + c.Value.Add(c2); + c2.TimeStampCreate = timeStamp; + c2.SetTimeStamp(timeStamp); + newMode = 1; + } - // see https://github.com/JamesNK/Newtonsoft.Json/issues/874 - try - { - if (p.Value == "") - p.Value = "0"; - string value = (jp1.Value as JValue).ToString(CultureInfo.InvariantCulture); - if (!value.Contains(".")) - { - int v = Convert.ToInt32(value); - int lastv = Convert.ToInt32(p.Value); - int delta = Math.Abs(v - lastv); - if (delta >= iMinDiffAbsolute && delta >= lastv * iMinDiffPercent / 100) + var count = 1; + foreach (var subEl in jp1.Value.EnumerateArray()) { - p.Value = value; - p.SetTimeStamp(timeStamp); - ok = true; + var n = $"{jp1.Name}_array_{count++}"; + var c3 = + c2.FindFirstIdShortAs(n); + if (c3 == null) + { + c3 = new SubmodelElementCollection(idShort: n); + c2.Value.Add(c3); + c3.TimeStampCreate = timeStamp; + c3.SetTimeStamp(timeStamp); + newMode = 1; + } + + ok |= ParseJson(c3, subEl, filter, minDiffAbsolute, minDiffPercent, envaas); } - } - else - { - /* - double v = Convert.ToDouble(value, CultureInfo.InvariantCulture); - double lastv = Convert.ToDouble(p.Value, CultureInfo.InvariantCulture); - double delta = Math.Abs(v - lastv); - if (delta >= iMinDiffAbsolute && delta >= lastv * iMinDiffPercent / 100) + + break; + case JsonValueKind.Object: + c2 = c.FindFirstIdShortAs(jp1.Name); + if (c2 == null) { - p.Value = value; - p.setTimeStamp(timeStamp); - ok = true; + c2 = new SubmodelElementCollection(idShort: jp1.Name); + c.Value.Add(c2); + c2.TimeStampCreate = timeStamp; + c2.SetTimeStamp(timeStamp); + newMode = 1; } - */ - p.Value = value; - p.SetTimeStamp(timeStamp); - ok = true; - } - } - catch - { + + ok |= ParseJson(c2, jp1.Value, filter, minDiffAbsolute, minDiffPercent, envaas); + break; } - break; - } + } + + break; + default: + throw new ArgumentException("Unsupported argument type for JSON parsing."); } - if (envaas != null) - envaas.setWrite(true); + envaas?.setWrite(true); Program.signalNewData(newMode); return ok; } @@ -2787,19 +2758,19 @@ private static void WalkSubmodelElement(ISubmodelElement sme, string nodePath, s { if (sme is Property) { - var p = sme as Property; - string clientNodeName = nodePath + p.IdShort; - string serverNodeId = string.Format("{0}.{1}.Value", serverNodePrefix, p.IdShort); - NodeId clientNode = new NodeId(clientNodeName, (ushort) clientNamespace); + var p = sme as Property; + var clientNodeName = nodePath + p.IdShort; + var serverNodeId = $"{serverNodePrefix}.{p.IdShort}.Value"; + var clientNode = new NodeId(clientNodeName, (ushort)clientNamespace); UpdatePropertyFromOPCClient(p, serverNodeId, client, clientNode); } else if (sme is SubmodelElementCollection) { var collection = sme as SubmodelElementCollection; - for (int i = 0; i < collection.Value.Count; i++) + foreach (var t in collection.Value) { - string newNodeIdBase = nodePath + "." + collection.IdShort; - WalkSubmodelElement(collection.Value[ i ], newNodeIdBase, serverNodePrefix, client, clientNamespace); + var newNodeIdBase = $"{nodePath}.{collection.IdShort}"; + WalkSubmodelElement(t, newNodeIdBase, serverNodePrefix, client, clientNamespace); } } } @@ -2818,10 +2789,10 @@ private static void UpdatePropertyFromOPCClient(Property p, string serverNodeId, string[] split = (clientNodeId.ToString()).Split('#'); if (split.Length == 2) { - uint i = Convert.ToUInt16(split[ 1 ]); + uint i = Convert.ToUInt16(split[1]); split = clientNodeId.ToString().Split('='); - split = split[ 1 ].Split(';'); - ushort ns = Convert.ToUInt16(split[ 0 ]); + split = split[1].Split(';'); + ushort ns = Convert.ToUInt16(split[0]); clientNodeId = new NodeId(i, ns); Console.WriteLine("New node id: ", clientNodeId.ToString()); } @@ -3066,7 +3037,7 @@ private async void StatusThread() IList sessions = server.CurrentInstance.SessionManager.GetSessions(); for (int ii = 0; ii < sessions.Count; ii++) { - Opc.Ua.Server.Session session = sessions[ ii ]; + Opc.Ua.Server.Session session = sessions[ii]; PrintSessionStatus(session, "-Status-", true); } diff --git a/src/AasxServerStandardBib/SecurityClient.cs b/src/AasxServerStandardBib/SecurityClient.cs index e014ec0ed..d85a1b95a 100644 --- a/src/AasxServerStandardBib/SecurityClient.cs +++ b/src/AasxServerStandardBib/SecurityClient.cs @@ -19,12 +19,13 @@ using IdentityModel; using IdentityModel.Client; using Microsoft.IdentityModel.Tokens; -using Newtonsoft.Json.Linq; using System.Security.Cryptography; using System.Linq; namespace AasxServer { + using System.Text.Json; + public class AasxTask { public SubmodelElementCollection def = null; @@ -45,7 +46,7 @@ public static void taskInit() if (System.IO.File.Exists(proxyFile)) { try - { + { // Open the text file using a stream reader. using (StreamReader sr = new StreamReader(proxyFile)) { @@ -63,18 +64,18 @@ public static void taskInit() { // Test for proxy Console.WriteLine("Read proxyFile: " + proxyFile); - bool error = false; + bool error = false; string proxyAddress = ""; - string username = ""; - string password = ""; + string username = ""; + string password = ""; try - { + { // Open the text file using a stream reader. using (StreamReader sr = new StreamReader(proxyFile)) { proxyAddress = sr.ReadLine(); - username = sr.ReadLine(); - password = sr.ReadLine(); + username = sr.ReadLine(); + password = sr.ReadLine(); } } catch (IOException e) @@ -82,7 +83,7 @@ public static void taskInit() Console.WriteLine("The file " + proxyFile + " could not be read:"); Console.WriteLine(e.Message); error = true; - } + } if (!error) { @@ -102,10 +103,10 @@ public static void taskInit() for (int i = 0; i < aascount; i++) { - var env = AasxServer.Program.env[ i ]; + var env = AasxServer.Program.env[i]; if (env != null) { - var aas = env.AasEnv.AssetAdministrationShells[ 0 ]; + var aas = env.AasEnv.AssetAdministrationShells[0]; if (aas.Submodels != null && aas.Submodels.Count > 0) { foreach (var smr in aas.Submodels) @@ -119,18 +120,18 @@ public static void taskInit() countSme = sm.SubmodelElements.Count; for (int iSme = 0; iSme < countSme; iSme++) { - var sme = sm.SubmodelElements[ iSme ]; + var sme = sm.SubmodelElements[iSme]; if (sme is SubmodelElementCollection smec) { var nextTask = new AasxTask(); AasxTask.taskList.Add(nextTask); - nextTask.def = smec; + nextTask.def = smec; nextTask.envIndex = i; int countSmec = smec.Value.Count; for (int iSmec = 0; iSmec < countSmec; iSmec++) { - var sme2 = smec.Value[ iSmec ]; + var sme2 = smec.Value[iSmec]; var idShort = sme2.IdShort.ToLower(); switch (idShort) @@ -139,28 +140,28 @@ public static void taskInit() if (sme2 is Property) { nextTask.taskType = sme2 as Property; - } + } break; case "cycletime": if (sme2 is Property) { nextTask.cycleTime = sme2 as Property; - } + } break; case "cyclecount": if (sme2 is Property) { nextTask.cycleCount = sme2 as Property; - } + } break; case "nextcycle": if (sme2 is Property) { nextTask.nextCycle = sme2 as Property; - } + } break; } @@ -186,7 +187,7 @@ static void runOperations(SubmodelElementCollection smec, int envIndex, DateTime int countSmec = smec.Value.Count; for (int iSmec = 0; iSmec < countSmec; iSmec++) { - var sme2 = smec.Value[ iSmec ]; + var sme2 = smec.Value[iSmec]; if (sme2 is Operation op) { @@ -213,7 +214,7 @@ static void runOperations(SubmodelElementCollection smec, int envIndex, DateTime if (idShort.Substring(0, 3) == "get") { operation_get_put(op, envIndex, timeStamp); - } + } break; } @@ -230,15 +231,15 @@ static void operation_authenticate(Operation op, int envIndex, DateTime timeStam return; } - Property authType = null; - Property authServerEndPoint = null; - AasCore.Aas3_0.File authServerCertificate = null; - AasCore.Aas3_0.File clientCertificate = null; - Property clientCertificatePassWord = null; - Property accessToken = null; - Property userName = null; - Property passWord = null; - Property clientToken = null; + Property authType = null; + Property authServerEndPoint = null; + AasCore.Aas3_0.File authServerCertificate = null; + AasCore.Aas3_0.File clientCertificate = null; + Property clientCertificatePassWord = null; + Property accessToken = null; + Property userName = null; + Property passWord = null; + Property clientToken = null; var smec = new SubmodelElementCollection(); foreach (var input in op.InputVariables) @@ -246,7 +247,7 @@ static void operation_authenticate(Operation op, int envIndex, DateTime timeStam var inputRef = input.Value; if (!(inputRef is ReferenceElement)) return; - var refElement = Program.env[ envIndex ].AasEnv.FindReferableByReference((inputRef as ReferenceElement).Value); + var refElement = Program.env[envIndex].AasEnv.FindReferableByReference((inputRef as ReferenceElement).Value); if (refElement is SubmodelElementCollection re) smec = re; } @@ -254,7 +255,7 @@ static void operation_authenticate(Operation op, int envIndex, DateTime timeStam int countSmec = smec.Value.Count; for (int iSmec = 0; iSmec < countSmec; iSmec++) { - var sme2 = smec.Value[ iSmec ]; + var sme2 = smec.Value[iSmec]; var idShort = sme2.IdShort.ToLower(); switch (idShort) @@ -263,104 +264,104 @@ static void operation_authenticate(Operation op, int envIndex, DateTime timeStam if (sme2 is Property) { authType = sme2 as Property; - } + } break; case "authserverendpoint": if (sme2 is Property) { authServerEndPoint = sme2 as Property; - } + } break; case "accesstoken": if (sme2 is Property) { accessToken = sme2 as Property; - } + } break; case "clienttoken": if (sme2 is Property) { clientToken = sme2 as Property; - } + } break; case "username": if (sme2 is Property) { userName = sme2 as Property; - } + } break; case "password": if (sme2 is Property) { passWord = sme2 as Property; - } + } break; case "authservercertificate": if (sme2 is AasCore.Aas3_0.File) { authServerCertificate = sme2 as AasCore.Aas3_0.File; - } + } break; case "clientcertificate": if (sme2 is AasCore.Aas3_0.File) { clientCertificate = sme2 as AasCore.Aas3_0.File; - } + } break; case "clientcertificatepassword": if (sme2 is Property) { clientCertificatePassWord = sme2 as Property; - } + } break; } } - if (authType != null) - { - switch (authType.Value.ToLower()) - { - case "openid": - if (authServerEndPoint != null && authServerCertificate != null && clientCertificate != null - && accessToken != null) - { - if (accessToken.Value == null) - accessToken.Value = ""; - - if (accessToken.Value != "") - { - bool valid = true; - var jwtToken = new JwtSecurityToken(accessToken.Value); - if ((jwtToken == null) || (jwtToken.ValidFrom > DateTime.UtcNow) || (jwtToken.ValidTo < DateTime.UtcNow)) - valid = false; - if (valid) return; - accessToken.Value = ""; - } - - if (createAccessToken(envIndex, authServerEndPoint, authServerCertificate, - clientCertificate, clientCertificatePassWord, - accessToken, clientToken)) - accessToken.SetTimeStamp(timeStamp); - } - - break; - } - } + if (authType != null) + { + switch (authType.Value.ToLower()) + { + case "openid": + if (authServerEndPoint != null && authServerCertificate != null && clientCertificate != null + && accessToken != null) + { + if (accessToken.Value == null) + accessToken.Value = ""; + + if (accessToken.Value != "") + { + bool valid = true; + var jwtToken = new JwtSecurityToken(accessToken.Value); + if ((jwtToken == null) || (jwtToken.ValidFrom > DateTime.UtcNow) || (jwtToken.ValidTo < DateTime.UtcNow)) + valid = false; + if (valid) return; + accessToken.Value = ""; + } + + if (createAccessToken(envIndex, authServerEndPoint, authServerCertificate, + clientCertificate, clientCertificatePassWord, + accessToken, clientToken)) + accessToken.SetTimeStamp(timeStamp); + } + + break; + } + } } static bool createAccessToken(int envIndex, Property authServerEndPoint, AasCore.Aas3_0.File authServerCertificate, - AasCore.Aas3_0.File clientCertificate, Property clientCertificatePassWord, - Property accessToken, Property clientToken, - string policy = "", string policyRequestedResource = "") + AasCore.Aas3_0.File clientCertificate, Property clientCertificatePassWord, + Property accessToken, Property clientToken, + string policy = "", string policyRequestedResource = "") { var handler = new HttpClientHandler(); @@ -368,8 +369,8 @@ static bool createAccessToken(int envIndex, Property authServerEndPoint, AasCore handler.Proxy = proxy; else handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; - var client = new HttpClient(handler); - DiscoveryDocumentResponse disco = null; + var client = new HttpClient(handler); + DiscoveryDocumentResponse disco = null; if (authServerEndPoint == null) return false; @@ -380,12 +381,11 @@ static bool createAccessToken(int envIndex, Property authServerEndPoint, AasCore Stream s = null; try { - s = AasxServer.Program.env[ envIndex ].GetLocalStreamFromPackage(authServerCertificate.Value, access: FileAccess.Read); + s = AasxServer.Program.env[envIndex].GetLocalStreamFromPackage(authServerCertificate.Value, access: FileAccess.Read); + } + catch + { } - catch - { - - } if (s == null) { @@ -396,24 +396,23 @@ static bool createAccessToken(int envIndex, Property authServerEndPoint, AasCore using (var m = new System.IO.MemoryStream()) { s.CopyTo(m); - var b = m.GetBuffer(); + var b = m.GetBuffer(); var serverCert = new X509Certificate2(b); Console.WriteLine("Auth server certificate: " + authServerCertificate.Value); s.Close(); } - string[] x5c = null; - X509Certificate2 certificate = null; - string certificatePassword = clientCertificatePassWord.Value; - Stream s2 = null; + string[] x5c = null; + X509Certificate2 certificate = null; + string certificatePassword = clientCertificatePassWord.Value; + Stream s2 = null; try { - s2 = AasxServer.Program.env[ envIndex ].GetLocalStreamFromPackage(clientCertificate.Value, access: FileAccess.Read); + s2 = AasxServer.Program.env[envIndex].GetLocalStreamFromPackage(clientCertificate.Value, access: FileAccess.Read); + } + catch + { } - catch - { - - } if (s2 == null) { @@ -443,29 +442,30 @@ static bool createAccessToken(int envIndex, Property authServerEndPoint, AasCore string[] X509Base64 = new string[xc.Count]; - int j = xc.Count; + int j = xc.Count; var xce = xc.GetEnumerator(); for (int i = 0; i < xc.Count; i++) { xce.MoveNext(); - X509Base64[ --j ] = Convert.ToBase64String(xce.Current.GetRawCertData()); + X509Base64[--j] = Convert.ToBase64String(xce.Current.GetRawCertData()); // X509Base64[ --j ] = Base64UrlEncoder.Encode(xce.Current.GetRawCertData()); } + x5c = X509Base64; - var credential = new X509SigningCredentials(certificate); - string clientId = "client.jwt"; - string email = ""; - string subject = certificate.Subject; - var split = subject.Split(new Char[] { ',' }); - if (split[ 0 ] != "") + var credential = new X509SigningCredentials(certificate); + string clientId = "client.jwt"; + string email = ""; + string subject = certificate.Subject; + var split = subject.Split(new Char[] {','}); + if (split[0] != "") { - var split2 = split[ 0 ].Split(new Char[] { '=' }); - if (split2[ 0 ] == "E") + var split2 = split[0].Split(new Char[] {'='}); + if (split2[0] == "E") { - email = split2[ 1 ]; + email = split2[1]; } - } + } Console.WriteLine("email: " + email); @@ -484,34 +484,33 @@ static bool createAccessToken(int envIndex, Property authServerEndPoint, AasCore if (policyRequestedResource != "") claimList.Add(new Claim("policyRequestedResource", policyRequestedResource, ClaimValueTypes.String)); var token = new JwtSecurityToken( - clientId, - disco.TokenEndpoint, - claimList, - now, - now.AddMinutes(1), - credential - ); + clientId, + disco.TokenEndpoint, + claimList, + now, + now.AddMinutes(1), + credential + ); token.Header.Add("x5c", x5c); - var tokenHandler = new JwtSecurityTokenHandler(); + var tokenHandler = new JwtSecurityTokenHandler(); string clientLongToken = tokenHandler.WriteToken(token); TokenResponse response = null; // client.Timeout = TimeSpan.FromSeconds(20); task = Task.Run(async () => - { - response = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest - { - Address = disco.TokenEndpoint, - Scope = "resource1.scope1", - - ClientAssertion = - { - Type = OidcConstants.ClientAssertionTypes.JwtBearer, - Value = clientLongToken - } - }); - }); + { + response = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest + { + Address = disco.TokenEndpoint, + Scope = "resource1.scope1", + ClientAssertion = + { + Type = OidcConstants.ClientAssertionTypes.JwtBearer, + Value = clientLongToken + } + }); + }); task.Wait(); if (response.IsError) return false; @@ -530,26 +529,32 @@ static bool createAccessToken(int envIndex, Property authServerEndPoint, AasCore // create client token if (policy != "" && accessToken.Value != "" && clientToken.Value == "") { - var parsed = JObject.Parse(Jose.JWT.Payload(accessToken.Value)); + var parsed = JsonDocument.Parse(Jose.JWT.Payload(accessToken.Value)); - string userName = ""; + var userName = ""; try { - userName = parsed.SelectToken("userName").Value(); + if (parsed.RootElement.TryGetProperty("userName", out var userNameElement)) + { + userName = userNameElement.GetString(); + } } - catch - { - + catch + { + // ignored } - string expires = ""; + var expires = ""; try { - expires = parsed.SelectToken("exp").Value(); + if (parsed.RootElement.TryGetProperty("exp", out var expiresElement)) + { + expires = expiresElement.GetString(); + } } - catch - { - + catch + { + // ignored } if (userName != "" && expires != "") @@ -563,7 +568,6 @@ static bool createAccessToken(int envIndex, Property authServerEndPoint, AasCore new Claim(JwtClaimTypes.JwtId, Guid.NewGuid().ToString()), new Claim(JwtClaimTypes.Subject, clientId), new Claim(JwtClaimTypes.IssuedAt, now.ToEpochTime().ToString(), ClaimValueTypes.Integer64), - new Claim("userName", userName), }; if (policy != "") @@ -571,15 +575,15 @@ static bool createAccessToken(int envIndex, Property authServerEndPoint, AasCore if (policyRequestedResource != "") claimList.Add(new Claim("policyRequestedResource", policyRequestedResource, ClaimValueTypes.String)); var token = new JwtSecurityToken( - clientId, - policyRequestedResource, - claimList, - now, - now.AddDays(1), - credential) - ; + clientId, + policyRequestedResource, + claimList, + now, + now.AddDays(1), + credential) + ; var tokenHandler = new JwtSecurityTokenHandler(); - var t = tokenHandler.WriteToken(token); + var t = tokenHandler.WriteToken(token); if (t != null) { clientToken.Value = t; @@ -590,7 +594,7 @@ static bool createAccessToken(int envIndex, Property authServerEndPoint, AasCore } return false; - } + } static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) { @@ -604,55 +608,55 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) if (opName.Substring(0, 4) == "get-") opName = "get"; - SubmodelElementCollection authentication = null; - Property authType = null; - Property authServerEndPoint = null; - Property accessToken = null; - Property userName = null; - Property passWord = null; - AasCore.Aas3_0.File authServerCertificate = null; - AasCore.Aas3_0.File clientCertificate = null; - Property clientCertificatePassWord = null; - Property clientToken = null; - - Property endPoint = null; - Property path = null; + SubmodelElementCollection authentication = null; + Property authType = null; + Property authServerEndPoint = null; + Property accessToken = null; + Property userName = null; + Property passWord = null; + AasCore.Aas3_0.File authServerCertificate = null; + AasCore.Aas3_0.File clientCertificate = null; + Property clientCertificatePassWord = null; + Property clientToken = null; + + Property endPoint = null; + Property path = null; SubmodelElementCollection elementCollection = null; - Submodel elementSubmodel = null; - Property steps = null; - Property loop = null; - Property duration = null; + Submodel elementSubmodel = null; + Property steps = null; + Property loop = null; + Property duration = null; Property lastDiff = null; - Property status = null; - Property mode = null; + Property status = null; + Property mode = null; SubmodelElementCollection smec = null; - Submodel sm = null; - Property p = null; + Submodel sm = null; + Property p = null; - HttpClient client = null; + HttpClient client = null; HttpClientHandler handler = null; foreach (var input in op.InputVariables) { smec = null; - sm = null; - p = null; + sm = null; + p = null; var inputRef = input.Value; if (inputRef is Property) { p = (inputRef as Property); - } + } if (inputRef is ReferenceElement) { - var refElement = Program.env[ envIndex ].AasEnv.FindReferableByReference((inputRef as ReferenceElement).Value); + var refElement = Program.env[envIndex].AasEnv.FindReferableByReference((inputRef as ReferenceElement).Value); if (refElement is SubmodelElementCollection) smec = refElement as SubmodelElementCollection; if (refElement is Submodel) sm = refElement as Submodel; - } + } switch (inputRef.IdShort.ToLower()) { @@ -687,27 +691,27 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) loop = p; break; } - } + } foreach (var output in op.OutputVariables) { smec = null; - sm = null; - p = null; + sm = null; + p = null; var outputRef = output.Value; if (outputRef is Property) { p = (outputRef as Property); - } + } if (outputRef is ReferenceElement) { - var refElement = Program.env[ envIndex ].AasEnv.FindReferableByReference((outputRef as ReferenceElement).Value); + var refElement = Program.env[envIndex].AasEnv.FindReferableByReference((outputRef as ReferenceElement).Value); if (refElement is SubmodelElementCollection) smec = refElement as SubmodelElementCollection; if (refElement is Submodel) sm = refElement as Submodel; - } + } switch (outputRef.IdShort.ToLower()) { @@ -732,7 +736,7 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) int countSmec = smec.Value.Count; for (int iSmec = 0; iSmec < countSmec; iSmec++) { - var sme2 = smec.Value[ iSmec ]; + var sme2 = smec.Value[iSmec]; var idShort = sme2.IdShort.ToLower(); switch (idShort) @@ -741,71 +745,71 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) if (sme2 is Property) { authType = sme2 as Property; - } + } - break; + break; case "accesstoken": if (sme2 is Property) { accessToken = sme2 as Property; - } + } - break; + break; case "clienttoken": if (sme2 is Property) { clientToken = sme2 as Property; - } + } - break; + break; case "username": if (sme2 is Property) { userName = sme2 as Property; - } + } - break; + break; case "password": if (sme2 is Property) { passWord = sme2 as Property; - } + } - break; + break; case "authservercertificate": if (sme2 is AasCore.Aas3_0.File) { authServerCertificate = sme2 as AasCore.Aas3_0.File; - } + } - break; + break; case "authserverendpoint": if (sme2 is Property) { authServerEndPoint = sme2 as Property; - } + } - break; + break; case "clientcertificate": if (sme2 is AasCore.Aas3_0.File) { clientCertificate = sme2 as AasCore.Aas3_0.File; - } + } - break; + break; case "clientcertificatepassword": if (sme2 is Property) { clientCertificatePassWord = sme2 as Property; - } + } break; } @@ -816,7 +820,7 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) if (loop != null) { loopCount = Convert.ToInt32(loop.Value); - } + } var watch = System.Diagnostics.Stopwatch.StartNew(); @@ -826,37 +830,37 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) { loop.Value = l + 1 + ""; loop.SetTimeStamp(timeStamp); - } + } if (duration != null) { - duration.Value = watch.ElapsedMilliseconds + " ms"; + duration.Value = watch.ElapsedMilliseconds + " ms"; duration.TimeStamp = timeStamp; - } + } Program.signalNewData(0); string requestPath = endPoint.Value; if (path.Value != "") requestPath += "/" + path.Value; - HttpResponseMessage response = null; - Task task = null; - string diffPath = ""; - var splitPath = path.Value.Split('/'); - string aasPath = splitPath[ 0 ]; - string subPath = ""; - int i = 1; - string pre = ""; + HttpResponseMessage response = null; + Task task = null; + string diffPath = ""; + var splitPath = path.Value.Split('/'); + string aasPath = splitPath[0]; + string subPath = ""; + int i = 1; + string pre = ""; while (i < splitPath.Length) { - subPath += pre + splitPath[ i ]; - pre = "."; + subPath += pre + splitPath[i]; + pre = "."; i++; } if (status != null) { - status.Value = "OK"; + status.Value = "OK"; status.TimeStamp = timeStamp; } @@ -877,20 +881,21 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) { opName = "get"; requestPath = endPoint.Value + "/aas/" + aasPath + - "/submodels/" + splitPath[ 1 ] + "/elements"; + "/submodels/" + splitPath[1] + "/elements"; i = 2; while (i < splitPath.Length) { - requestPath += "/" + splitPath[ i ]; + requestPath += "/" + splitPath[i]; i++; } + requestPath += "/complete"; } else { last = DateTime.Parse(lastDiff.Value).ToUniversalTime(); requestPath = endPoint.Value + - "/diffjson/aas/" + splitPath[ 0 ] + + "/diffjson/aas/" + splitPath[0] + "?path=" + subPath; requestPath += "."; // to avoid wrong data by prefix only requestPath += "&time=" + lastDiff.Value; @@ -905,12 +910,12 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) handler.Proxy = proxy; else handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; - } + } - client = new HttpClient(handler); + client = new HttpClient(handler); client.Timeout = TimeSpan.FromSeconds(20); - string policy = ""; + string policy = ""; string policyRequestedResource = ""; // test, if usage policy is needed if (steps != null && steps.Value != "") @@ -920,9 +925,9 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) accessToken.Value = ""; if (!createAccessToken(envIndex, authServerEndPoint, authServerCertificate, - clientCertificate, clientCertificatePassWord, - accessToken, clientToken, - "", "")) + clientCertificate, clientCertificatePassWord, + accessToken, clientToken, + "", "")) continue; accessToken.TimeStamp = timeStamp; Console.WriteLine("Create Token1"); @@ -948,7 +953,7 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) "HEAD " + requestPath; status.TimeStamp = timeStamp; Program.signalNewData(0); - } + } continue; } @@ -977,13 +982,13 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) { clientToken.Value = ""; if (!createAccessToken(envIndex, authServerEndPoint, authServerCertificate, - clientCertificate, clientCertificatePassWord, - accessToken, clientToken, - policy, policyRequestedResource)) + clientCertificate, clientCertificatePassWord, + accessToken, clientToken, + policy, policyRequestedResource)) continue; clientToken.TimeStamp = timeStamp; Console.WriteLine("Create Token2"); - } + } if (steps.Value.Contains("2")) { @@ -1008,7 +1013,7 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) "GET " + requestPath; status.TimeStamp = timeStamp; Program.signalNewData(0); - } + } continue; } @@ -1019,36 +1024,42 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) continue; } - string json = response.Content.ReadAsStringAsync().Result; - SubmodelElementCollection receiveCollection = null; - Submodel receiveSubmodel = null; + string json = response.Content.ReadAsStringAsync().Result; + SubmodelElementCollection? receiveCollection = null; + Submodel receiveSubmodel = null; try { if (opName == "get") { if (elementCollection != null) { - JObject parsed = JObject.Parse(json); - foreach (JProperty jp1 in (JToken) parsed) + var serializerOptions = new JsonSerializerOptions {Converters = {new AdminShellConverters.JsonAasxConverter("modelType", "name")}}; + var parsed = JsonNode.Parse(json); + foreach (var property in parsed?.AsObject()) { - if (jp1.Name == "elem") + if (property.Key != "elem") { - string text = jp1.Value.ToString(); - receiveCollection = Newtonsoft.Json.JsonConvert.DeserializeObject( - text, new AdminShellConverters.JsonAasxConverter("modelType", "name")); - elementCollection.Value = receiveCollection.Value; - elementCollection.SetAllParentsAndTimestamps(elementCollection, timeStamp, elementCollection.TimeStampCreate); - elementCollection.SetTimeStamp(timeStamp); + continue; } + + var text = property.Value?.ToString(); + if (text != null) + { + receiveCollection = JsonSerializer.Deserialize(text, serializerOptions); + } + + elementCollection.Value = receiveCollection?.Value; + elementCollection.SetAllParentsAndTimestamps(elementCollection, timeStamp, elementCollection.TimeStampCreate); + elementCollection.SetTimeStamp(timeStamp); } - } + } if (elementSubmodel != null) { // receiveSubmodel = Newtonsoft.Json.JsonConvert.DeserializeObject( // json, new AdminShellConverters.JsonAasxConverter("modelType", "name")); MemoryStream mStrm = new MemoryStream(Encoding.UTF8.GetBytes(json)); - JsonNode node = System.Text.Json.JsonSerializer.DeserializeAsync(mStrm).Result; + JsonNode node = System.Text.Json.JsonSerializer.DeserializeAsync(mStrm).Result; receiveSubmodel = Jsonization.Deserialize.SubmodelFrom(node); receiveSubmodel.SetTimeStamp(timeStamp); @@ -1059,31 +1070,31 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) continue; receiveSubmodel.Id = elementSubmodel.Id; - var aas = Program.env[ envIndex ].AasEnv.FindAasWithSubmodelId(elementSubmodel.Id); + var aas = Program.env[envIndex].AasEnv.FindAasWithSubmodelId(elementSubmodel.Id); // datastructure update - if (Program.env == null || Program.env[ envIndex ].AasEnv == null /*|| Program.env[ envIndex ].AasEnv.Assets == null*/) + if (Program.env == null || Program.env[envIndex].AasEnv == null /*|| Program.env[ envIndex ].AasEnv.Assets == null*/) continue; // add Submodel - var existingSm = Program.env[ envIndex ].AasEnv.FindSubmodelById(elementSubmodel.Id); + var existingSm = Program.env[envIndex].AasEnv.FindSubmodelById(elementSubmodel.Id); if (existingSm != null) - Program.env[ envIndex ].AasEnv.Submodels.Remove(existingSm); - Program.env[ envIndex ].AasEnv.Submodels.Add(receiveSubmodel); + Program.env[envIndex].AasEnv.Submodels.Remove(existingSm); + Program.env[envIndex].AasEnv.Submodels.Add(receiveSubmodel); for (int s = 0; s < aas.Submodels.Count; s++) { - if (aas.Submodels[ s ].Keys[ 0 ].Value == existingSm.Id) + if (aas.Submodels[s].Keys[0].Value == existingSm.Id) { aas.Submodels.RemoveAt(s); break; } - } + } aas.Submodels.Add(receiveSubmodel.GetModelReference()); continue; } - } + } if (opName == "getdiff") { @@ -1104,13 +1115,13 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) if (splitPath.Length < 2) continue; requestPath = endPoint.Value + "/aas/" + aasPath + - "/submodels/" + splitPath[ 0 ] + "/elements"; + "/submodels/" + splitPath[0] + "/elements"; i = 1; while (i < splitPath.Length) { - requestPath += "/" + splitPath[ i ]; + requestPath += "/" + splitPath[i]; i++; - } + } requestPath += "/complete"; try @@ -1125,7 +1136,7 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) response.Content.ReadAsStringAsync().Result + " ; " + "GET " + requestPath; Program.signalNewData(0); - } + } continue; } @@ -1136,44 +1147,43 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) } json = response.Content.ReadAsStringAsync().Result; - JObject parsed = JObject.Parse(json); - foreach (JProperty jp1 in (JToken) parsed) + var parsed = JsonDocument.Parse(json); + + var serializerOptions + = new JsonSerializerOptions {Converters = {new AdminShellConverters.JsonAasxConverter("modelType", "name")}}; + foreach (var text in from jp1 in parsed.RootElement.EnumerateObject() where jp1.Name == "elem" select jp1.Value.GetRawText()) { - if (jp1.Name == "elem") - { - string text = jp1.Value.ToString(); - receiveCollection = Newtonsoft.Json.JsonConvert.DeserializeObject( - text, new AdminShellConverters.JsonAasxConverter("modelType", "name")); - break; - } + receiveCollection = JsonSerializer.Deserialize( + text, serializerOptions); + break; } - bool found = false; - foreach (var smew in elementCollection.Value) + var found = false; + if (elementCollection != null) { - var sme = smew; - if (sme.IdShort == receiveCollection.IdShort) + foreach (var sme in elementCollection.Value.Where(sme => sme.IdShort == receiveCollection.IdShort)) { if (sme is SubmodelElementCollection smc) { if (d.mode == "UPDATE") { - smc.Value = receiveCollection.Value; + smc.Value = receiveCollection?.Value; smc.SetAllParentsAndTimestamps(elementCollection, timeStamp, elementCollection.TimeStampCreate); smc.SetTimeStamp(timeStamp); } + found = true; break; } } - } - if (!found && d.mode == "CREATE") - { - elementCollection.Value.Add(receiveCollection); - receiveCollection.SetAllParentsAndTimestamps(elementCollection, timeStamp, timeStamp); - receiveCollection.SetTimeStamp(timeStamp); - } + if (!found && d.mode == "CREATE") + { + elementCollection.Value.Add(receiveCollection); + receiveCollection.SetAllParentsAndTimestamps(elementCollection, timeStamp, timeStamp); + receiveCollection.SetTimeStamp(timeStamp); + } + } break; } @@ -1183,6 +1193,7 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) } } catch + { continue; } @@ -1201,9 +1212,9 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) handler.Proxy = proxy; else handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; - } + } - client = new HttpClient(handler); + client = new HttpClient(handler); client.Timeout = TimeSpan.FromSeconds(20); if (accessToken != null) client.SetBearerToken(accessToken.Value); @@ -1211,8 +1222,8 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) if (opName == "put" || opName == "putdiff") { SubmodelElementCollection diffCollection = null; - DateTime last = new DateTime(); - int count = 1; + DateTime last = new DateTime(); + int count = 1; if (mode != null && mode.Value == "clear") opName = "put"; if (opName == "putdiff") @@ -1222,7 +1233,7 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) if (elementCollection == null) continue; diffCollection = elementCollection; - count = elementCollection.Value.Count; + count = elementCollection.Value.Count; if (lastDiff.Value == "") { // get "latestData" from server @@ -1245,7 +1256,7 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) status.Value = response.StatusCode.ToString() + " ; " + response.Content.ReadAsStringAsync().Result + " ; " + "GET " + requestPath; - } + } error = true; } @@ -1256,16 +1267,16 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) } int highDataIndex = -1; - int lowDataIndex = 0; - int totalSamples = 0; + int lowDataIndex = 0; + int totalSamples = 0; if (!error) { try { - string json = response.Content.ReadAsStringAsync().Result; - MemoryStream mStrm = new MemoryStream(Encoding.UTF8.GetBytes(json)); - JsonNode node = System.Text.Json.JsonSerializer.DeserializeAsync(mStrm).Result; - var receiveCollection = Jsonization.Deserialize.SubmodelElementCollectionFrom(node); + string json = response.Content.ReadAsStringAsync().Result; + MemoryStream mStrm = new MemoryStream(Encoding.UTF8.GetBytes(json)); + JsonNode node = System.Text.Json.JsonSerializer.DeserializeAsync(mStrm).Result; + var receiveCollection = Jsonization.Deserialize.SubmodelElementCollectionFrom(node); // JObject parsed = JObject.Parse(json); // foreach (JProperty jp1 in (JToken) parsed) @@ -1283,24 +1294,24 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) if (ep.IdShort == "highDataIndex") { highDataIndex = Convert.ToInt32(ep.Value); - lowDataIndex = highDataIndex + 1; - } + lowDataIndex = highDataIndex + 1; + } if (ep.IdShort == "totalSamples") { totalSamples = Convert.ToInt32(ep.Value); } } - } + } if (elementCollection.Value.Count == 1) { - if (elementCollection.Value[ 0 ] is SubmodelElementCollection smc) + if (elementCollection.Value[0] is SubmodelElementCollection smc) { if (smc.IdShort == "latestData") { if (smc.Value.Count == 0) - continue; + continue; foreach (var sme in smc.Value) { @@ -1310,12 +1321,12 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) if (ep.IdShort == "highDataIndex") { ep.Value = highDataIndex.ToString(); - } + } if (ep.IdShort == "lowDataIndex") { ep.Value = lowDataIndex.ToString(); - } + } if (ep.IdShort == "totalSamples") { @@ -1333,7 +1344,7 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) { error = true; } - } + } if (error || highDataIndex == -1) { @@ -1353,27 +1364,27 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) for (i = 0; i < count; i++) { - bool error = false; + bool error = false; string statusValue = ""; - string json = ""; + string json = ""; try { if (opName == "putdiff") { - var sme = diffCollection.Value[ i ]; + var sme = diffCollection.Value[i]; if (!(sme is SubmodelElementCollection)) continue; elementCollection = sme as SubmodelElementCollection; - diffPath = "." + elementCollection.IdShort; + diffPath = "." + elementCollection.IdShort; if (elementCollection.TimeStamp <= last) elementCollection = null; - } + } if (elementCollection != null) { var j = Jsonization.Serialize.ToJsonObject(elementCollection); json = j.ToJsonString(); - } + } if (elementSubmodel != null) { @@ -1387,7 +1398,7 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) " new " + diffCollection.Value.Count; Console.WriteLine(statusValue); error = true; - } + } if (json != "") { @@ -1397,26 +1408,26 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) if (opName == "put" || (elementCollection != null && elementCollection.IdShort == "latestData")) { task = Task.Run(async () => - { - response = await client.PutAsync( - requestPath + diffPath, content); - }); - } + { + response = await client.PutAsync( + requestPath + diffPath, content); + }); + } else if (opName == "putdiff") { task = Task.Run(async () => - { - response = await client.PostAsync( - requestPath, content); - }); - } + { + response = await client.PostAsync( + requestPath, content); + }); + } task.Wait(); } catch { error = true; - } + } if (error || !response.IsSuccessStatusCode) { @@ -1426,9 +1437,10 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) response.Content.ReadAsStringAsync().Result + " ; " + "PUT " + requestPath; } + error = true; } - } + } if (error) { @@ -1436,7 +1448,7 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) { status.Value = statusValue; Program.signalNewData(0); - } + } continue; } @@ -1445,23 +1457,23 @@ static void operation_get_put(Operation op, int envIndex, DateTime timeStamp) if (lastDiff != null) lastDiff.Value = "" + timeStamp.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); } - } + } if (loop != null) { - loop.Value = loopCount + ""; + loop.Value = loopCount + ""; loop.TimeStamp = timeStamp; - } + } watch.Stop(); if (duration != null) { - duration.Value = watch.ElapsedMilliseconds + " ms"; + duration.Value = watch.ElapsedMilliseconds + " ms"; duration.TimeStamp = timeStamp; - } + } Program.signalNewData(2); // new tree, nodes opened - } + } static void operation_limitCount(Operation op, int envIndex, DateTime timeStamp) { @@ -1472,30 +1484,30 @@ static void operation_limitCount(Operation op, int envIndex, DateTime timeStamp) if (op.InputVariables.Count != 3) { return; - } + } SubmodelElementCollection collection = null; - Property limit = null; - Property prefix = null; - SubmodelElementCollection smec = null; - Property p = null; + Property limit = null; + Property prefix = null; + SubmodelElementCollection smec = null; + Property p = null; foreach (var input in op.InputVariables) { smec = null; - p = null; + p = null; var inputRef = input.Value; if (inputRef is Property) { p = (inputRef as Property); - } + } if (inputRef is ReferenceElement) { - var refElement = Program.env[ envIndex ].AasEnv.FindReferableByReference((inputRef as ReferenceElement).Value); + var refElement = Program.env[envIndex].AasEnv.FindReferableByReference((inputRef as ReferenceElement).Value); if (refElement is SubmodelElementCollection) smec = refElement as SubmodelElementCollection; - } + } switch (inputRef.IdShort.ToLower()) { @@ -1512,33 +1524,33 @@ static void operation_limitCount(Operation op, int envIndex, DateTime timeStamp) prefix = p; break; } - } + } if (collection == null || limit == null || prefix == null) return; try { - int count = Convert.ToInt32(limit.Value); - string pre = prefix.Value; - int preCount = 0; - int i = 0; + int count = Convert.ToInt32(limit.Value); + string pre = prefix.Value; + int preCount = 0; + int i = 0; while (i < collection.Value.Count) { - if (pre == collection.Value[ i ].IdShort.Substring(0, pre.Length)) + if (pre == collection.Value[i].IdShort.Substring(0, pre.Length)) preCount++; i++; - } + } i = 0; while (preCount > count && i < collection.Value.Count) { - if (pre == collection.Value[ i ].IdShort.Substring(0, pre.Length)) + if (pre == collection.Value[i].IdShort.Substring(0, pre.Length)) { - IReferable r = collection.Value[ i ]; - var sm = r.GetParentSubmodel(); + IReferable r = collection.Value[i]; + var sm = r.GetParentSubmodel(); AasxRestServerLibrary.AasxRestServer.TestResource.eventMessage.add( - r, "Remove", sm, (ulong)timeStamp.Ticks); + r, "Remove", sm, (ulong)timeStamp.Ticks); collection.Value.RemoveAt(i); preCount--; } @@ -1549,9 +1561,8 @@ static void operation_limitCount(Operation op, int envIndex, DateTime timeStamp) } } catch - { - - } + { + } Program.signalNewData(1); } @@ -1580,7 +1591,7 @@ public class cfpNode public static cfpNode root = null; public static string asbuilt_total = null; - public static Property pCO2eqTotal = null; + public static Property pCO2eqTotal = null; public static bool cfpValid = false; public static DateTime lastCreateTimestamp = new DateTime(); public static bool credentialsChanged = false; @@ -1588,7 +1599,7 @@ public class cfpNode public static void resetTimeStamp() { lastCreateTimestamp = new DateTime(); - credentialsChanged = true; + credentialsChanged = true; } static string cleanupIdShort(String text) @@ -1604,12 +1615,12 @@ static string cleanupIdShort(String text) public static string hashBOM = ""; public static long logCount = 0; - public static long logCountModulo = 30; + public static long logCountModulo = 30; public static bool createCfpTree(int envIndex, DateTime timeStamp) { - bool changed = false; - string digest = ""; + bool changed = false; + string digest = ""; cfpValid = true; if (logCount % logCountModulo == 0) @@ -1622,15 +1633,15 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) } // GET actual BOM - AdminShellPackageEnv env = null; - int aascount = AasxServer.Program.env.Length; + AdminShellPackageEnv env = null; + int aascount = AasxServer.Program.env.Length; for (int i = 0; i < aascount; i++) { - env = AasxServer.Program.env[ i ]; + env = AasxServer.Program.env[i]; if (env != null) { - var aas = env.AasEnv.AssetAdministrationShells[ 0 ]; + var aas = env.AasEnv.AssetAdministrationShells[0]; // if (aas.IdShort != "ZveiControlCabinetAas - EXTERNAL") // continue; @@ -1640,138 +1651,135 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) // foreach (var smr in aas.Submodels) for (int j = 0; j < aas.Submodels.Count; j++) { - var smr = aas.Submodels[ j ]; - var sm = env.AasEnv.FindSubmodel(smr); + var smr = aas.Submodels[j]; + var sm = env.AasEnv.FindSubmodel(smr); if (sm != null && sm.IdShort != null) { if (sm.IdShort.Contains("BillOfMaterial")) { - if (sm.Extensions != null && sm.Extensions.Count != 0 && sm.Extensions[ 0 ].Name == "endpoint") + if (sm.Extensions != null && sm.Extensions.Count != 0 && sm.Extensions[0].Name == "endpoint") { - var requestPath = sm.Extensions[0].Value; - - string queryPara = ""; - string userPW = ""; - string urlEdcWrapper = ""; - string replace = ""; - if (AasxCredentials.get(cs.credentials, requestPath, out queryPara, out userPW, out urlEdcWrapper, out replace)) - { - if (replace != "") - requestPath = replace; - if (queryPara != "") - queryPara = "?" + queryPara; - if (urlEdcWrapper != "") - requestPath = urlEdcWrapper; - } - - var handler = new HttpClientHandler() - { - ServerCertificateCustomValidationCallback = delegate { return true; }, - }; - - if (!requestPath.Contains("localhost")) - { - if (AasxServer.AasxTask.proxy != null) - handler.Proxy = AasxServer.AasxTask.proxy; - else - handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; - } - - var client = new HttpClient(handler); - - if (userPW != "") + var requestPath = sm.Extensions[0].Value; + + string queryPara = ""; + string userPW = ""; + string urlEdcWrapper = ""; + string replace = ""; + if (AasxCredentials.get(cs.credentials, requestPath, out queryPara, out userPW, out urlEdcWrapper, out replace)) + { + if (replace != "") + requestPath = replace; + if (queryPara != "") + queryPara = "?" + queryPara; + if (urlEdcWrapper != "") + requestPath = urlEdcWrapper; + } + + var handler = new HttpClientHandler() {ServerCertificateCustomValidationCallback = delegate { return true; },}; + + if (!requestPath.Contains("localhost")) + { + if (AasxServer.AasxTask.proxy != null) + handler.Proxy = AasxServer.AasxTask.proxy; + else + handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; + } + + var client = new HttpClient(handler); + + if (userPW != "") client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", userPW); string clientToken = ""; - if (sm.Extensions != null && sm.Extensions.Count > 1 && sm.Extensions[ 1 ].Name == "clientToken") - clientToken = sm.Extensions[ 1 ].Value; + if (sm.Extensions != null && sm.Extensions.Count > 1 && sm.Extensions[1].Name == "clientToken") + clientToken = sm.Extensions[1].Value; if (clientToken != "") - client.SetBearerToken(clientToken); - - client.DefaultRequestHeaders.Clear(); - - bool success = false; - HttpResponseMessage response = new HttpResponseMessage(); - try - { - requestPath += queryPara; - if (logCount % logCountModulo == 0) - Console.WriteLine("GET Submodel " + requestPath); - client.Timeout = TimeSpan.FromSeconds(3); - var task1 = Task.Run(async () => { response = await client.GetAsync(requestPath); }); - task1.Wait(); - if (response.IsSuccessStatusCode) - { - var json = response.Content.ReadAsStringAsync().Result; - byte[] buffer = Encoding.UTF8.GetBytes(json); - digest += Convert.ToBase64String(SHA256.HashData(buffer)); - // if (digest != hashBOM) - // changed= true; - // hashBOM = digest; - MemoryStream mStrm = new MemoryStream(Encoding.UTF8.GetBytes(json)); - JsonNode node = System.Text.Json.JsonSerializer.DeserializeAsync(mStrm).Result; - newsm = new Submodel(""); - newsm = Jsonization.Deserialize.SubmodelFrom(node); - newsm.IdShort += " - COPY"; - newsm.Extensions = sm.Extensions; - newsm.SetAllParentsAndTimestamps(null, timeStamp, timeStamp); - env.AasEnv.Submodels.Remove(sm); - env.AasEnv.Submodels.Add(newsm); - success = true; - } + client.SetBearerToken(clientToken); + + client.DefaultRequestHeaders.Clear(); + + bool success = false; + HttpResponseMessage response = new HttpResponseMessage(); + try + { + requestPath += queryPara; + if (logCount % logCountModulo == 0) + Console.WriteLine("GET Submodel " + requestPath); + client.Timeout = TimeSpan.FromSeconds(3); + var task1 = Task.Run(async () => { response = await client.GetAsync(requestPath); }); + task1.Wait(); + if (response.IsSuccessStatusCode) + { + var json = response.Content.ReadAsStringAsync().Result; + byte[] buffer = Encoding.UTF8.GetBytes(json); + digest += Convert.ToBase64String(SHA256.HashData(buffer)); + // if (digest != hashBOM) + // changed= true; + // hashBOM = digest; + MemoryStream mStrm = new MemoryStream(Encoding.UTF8.GetBytes(json)); + JsonNode node = System.Text.Json.JsonSerializer.DeserializeAsync(mStrm).Result; + newsm = new Submodel(""); + newsm = Jsonization.Deserialize.SubmodelFrom(node); + newsm.IdShort += " - COPY"; + newsm.Extensions = sm.Extensions; + newsm.SetAllParentsAndTimestamps(null, timeStamp, timeStamp); + env.AasEnv.Submodels.Remove(sm); + env.AasEnv.Submodels.Add(newsm); + success = true; + } + } + catch + { + success = false; } - catch - { - success = false; - } - - if (!success) - { - if (sm.IdShort != "BillOfMaterial - NO ACCESS") - { - if (hashBOM != "") - changed = true; - hashBOM = ""; - newsm = new Submodel(sm.Id); - newsm.IdShort = "BillOfMaterial - NO ACCESS"; - newsm.Extensions = sm.Extensions; - newsm.SetAllParentsAndTimestamps(null, timeStamp, timeStamp); - env.AasEnv.Submodels.Remove(sm); - env.AasEnv.Submodels.Add(newsm); - } - - Console.WriteLine("NO ACCESS: aas " + aas.IdShort + " sm " + sm.IdShort); - cfpValid = false; - } - } - - break; - } - } - } - } - } + + if (!success) + { + if (sm.IdShort != "BillOfMaterial - NO ACCESS") + { + if (hashBOM != "") + changed = true; + hashBOM = ""; + newsm = new Submodel(sm.Id); + newsm.IdShort = "BillOfMaterial - NO ACCESS"; + newsm.Extensions = sm.Extensions; + newsm.SetAllParentsAndTimestamps(null, timeStamp, timeStamp); + env.AasEnv.Submodels.Remove(sm); + env.AasEnv.Submodels.Add(newsm); + } + + Console.WriteLine("NO ACCESS: aas " + aas.IdShort + " sm " + sm.IdShort); + cfpValid = false; + } + } + + break; + } + } + } + } + } } Dictionary assetCfp = new Dictionary(); // cfpNode root = new cfpNode(); aascount = AasxServer.Program.env.Length; - root = null; + root = null; ISubmodel co2eqSubmodel = null; // Collect data from all AAS into cfpNode(s) for (int i = 0; i < aascount; i++) { - env = AasxServer.Program.env[ i ]; + env = AasxServer.Program.env[i]; if (env != null) { - var aas = env.AasEnv.AssetAdministrationShells[ 0 ]; + var aas = env.AasEnv.AssetAdministrationShells[0]; //var assetId = aas.assetRef.Keys[ 0 ].Value; var assetId = aas.AssetInformation.GlobalAssetId; - var cfp = new cfpNode(); - cfp.envIndex = i; - cfp.aas = aas as AssetAdministrationShell; - cfp.asset = assetId; + var cfp = new cfpNode(); + cfp.envIndex = i; + cfp.aas = aas as AssetAdministrationShell; + cfp.asset = assetId; cfp.productDesignation = aas.IdShort; if (aas.Submodels != null && aas.Submodels.Count > 0) @@ -1788,10 +1796,10 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) { Console.WriteLine("NO ACCESS: aas " + aas.IdShort + " sm " + sm.IdShort); cfpValid = false; - } + } if (sm.SubmodelElements != null) - { + { co2eqSubmodel = sm; foreach (var v in sm.SubmodelElements) { @@ -1800,8 +1808,8 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) if (c.IdShort.Contains("FootprintInformationModule") || c.IdShort.Contains("FootprintInformationCombination")) { - string lifeCyclePhase = ""; - Property co2eq = null; + string lifeCyclePhase = ""; + Property co2eq = null; foreach (var v2 in c.Value) { switch (v2.IdShort) @@ -1809,54 +1817,54 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) case "LifeCyclePhase": lifeCyclePhase = v2.ValueAsText(); break; - case "CO2eq": + case "CO2eq": co2eq = v2 as Property; break; } - } + } switch (lifeCyclePhase) { case "Cradle-to-gate": if (c.IdShort.Contains("FootprintInformationModule")) { - co2eq.Value = co2eq.Value.Replace(",", "."); + co2eq.Value = co2eq.Value.Replace(",", "."); cfp.cradleToGateModule = co2eq; - } + } if (c.IdShort.Contains("FootprintInformationCombination")) { - co2eq.Value = co2eq.Value.Replace(",", "."); + co2eq.Value = co2eq.Value.Replace(",", "."); cfp.cradleToGateCombination = co2eq; - } + } break; case "Production": if (c.IdShort.Contains("FootprintInformationModule")) { - co2eq.Value = co2eq.Value.Replace(",", "."); + co2eq.Value = co2eq.Value.Replace(",", "."); cfp.productionModule = co2eq; - } + } if (c.IdShort.Contains("FootprintInformationCombination")) { - co2eq.Value = co2eq.Value.Replace(",", "."); + co2eq.Value = co2eq.Value.Replace(",", "."); cfp.productionCombination = co2eq; - } + } break; case "Distribution": if (c.IdShort.Contains("FootprintInformationModule")) { - co2eq.Value = co2eq.Value.Replace(",", "."); + co2eq.Value = co2eq.Value.Replace(",", "."); cfp.distributionModule = co2eq; - } + } if (c.IdShort.Contains("FootprintInformationCombination")) { - co2eq.Value = co2eq.Value.Replace(",", "."); + co2eq.Value = co2eq.Value.Replace(",", "."); cfp.distributionCombination = co2eq; - } + } break; } @@ -1864,7 +1872,7 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) } } } - } + } // ZVEI Level 2 if (sm.IdShort.Contains("CarbonFootprint")) @@ -1873,7 +1881,7 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) { Console.WriteLine("NO ACCESS: aas " + aas.IdShort + " sm " + sm.IdShort); cfpValid = false; - } + } if (sm.SubmodelElements != null) { @@ -1884,8 +1892,8 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) { if (c.IdShort.Contains("ProductCarbonFootprint")) { - string lifeCyclePhase = ""; - Property co2eq = null; + string lifeCyclePhase = ""; + Property co2eq = null; foreach (var v2 in c.Value) { switch (v2.IdShort) @@ -1898,7 +1906,7 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) co2eq = v2 as Property; break; } - } + } switch (lifeCyclePhase) { @@ -1906,15 +1914,15 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) case "A1-A3": if (c.IdShort.Contains("ProductCarbonFootprint")) { - co2eq.Value = co2eq.Value.Replace(",", "."); + co2eq.Value = co2eq.Value.Replace(",", "."); cfp.cradleToGateModule = co2eq; - } + } if (c.IdShort.Contains("FootprintInformationCombination")) { - co2eq.Value = co2eq.Value.Replace(",", "."); + co2eq.Value = co2eq.Value.Replace(",", "."); cfp.cradleToGateCombination = co2eq; - } + } break; case "Production": @@ -1922,15 +1930,15 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) case "A3 - production": if (c.IdShort.Contains("ProductCarbonFootprint")) { - co2eq.Value = co2eq.Value.Replace(",", "."); + co2eq.Value = co2eq.Value.Replace(",", "."); cfp.productionModule = co2eq; - } + } if (c.IdShort.Contains("FootprintInformationCombination")) { - co2eq.Value = co2eq.Value.Replace(",", "."); + co2eq.Value = co2eq.Value.Replace(",", "."); cfp.productionCombination = co2eq; - } + } break; case "Distribution": @@ -1938,15 +1946,15 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) case "A1 – raw material supply (and upstream production)": if (c.IdShort.Contains("ProductCarbonFootprint")) { - co2eq.Value = co2eq.Value.Replace(",", "."); + co2eq.Value = co2eq.Value.Replace(",", "."); cfp.distributionModule = co2eq; - } + } if (c.IdShort.Contains("FootprintInformationCombination")) { - co2eq.Value = co2eq.Value.Replace(",", "."); + co2eq.Value = co2eq.Value.Replace(",", "."); cfp.distributionCombination = co2eq; - } + } break; } @@ -1954,7 +1962,7 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) } } } - } + } if (sm.IdShort.Contains("BillOfMaterial")) { @@ -1962,7 +1970,7 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) { Console.WriteLine("NO ACCESS: aas " + aas.IdShort + " sm " + sm.IdShort); cfpValid = false; - } + } if (sm.SubmodelElements != null) { @@ -1986,12 +1994,12 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) } } } - } + } // assetBOM.Add(assetId, bom); cfp.bom = bom; } - } + } if (sm.IdShort.Contains("TechnicalData") && sm.SubmodelElements != null) { @@ -2014,7 +2022,7 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) } } } - } + } if (sm.IdShort.Contains("Nameplate") && sm.SubmodelElements != null) { @@ -2033,14 +2041,14 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) { s = ls.Text; break; //english has priority over German - } + } if (ls.Language.ToLower() == "de") { if (s != null) s = ls.Text; } - } + } if (s != null) cfp.productDesignation = s; @@ -2048,7 +2056,7 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) } } } - } + } // Weight if (sm.IdShort.Contains("WeightInformation")) @@ -2057,7 +2065,7 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) { Console.WriteLine("NO ACCESS: aas " + aas.IdShort + " sm " + sm.IdShort); cfpValid = false; - } + } if (sm.SubmodelElements != null) { @@ -2075,15 +2083,15 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) case "ProductWeight": if (c.IdShort.Contains("WeightInformationModule")) { - cfp.weightModule = v2 as Property; + cfp.weightModule = v2 as Property; cfp.weightModule.Value = cfp.weightModule.Value.Replace(",", "."); - } + } if (c.IdShort.Contains("WeightInformationCombination")) { - cfp.weightCombination = v2 as Property; + cfp.weightCombination = v2 as Property; cfp.weightCombination.Value = cfp.weightCombination.Value.Replace(",", "."); - } + } break; } @@ -2095,12 +2103,12 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) } } } - } + } if (!assetCfp.ContainsKey(assetId)) { assetCfp.Add(assetId, cfp); - } + } /* if (i == envIndex) @@ -2115,27 +2123,28 @@ public static bool createCfpTree(int envIndex, DateTime timeStamp) { //TODO: elements need proper deep clone method implemented within AAS metamodel classes if (asbuilt_total == null) - asbuilt_total = new String(root.cradleToGateCombination.Value); - if (co2eqSubmodel != null) - { - pCO2eqTotal = null; - foreach (var sme in co2eqSubmodel.SubmodelElements) - { - if (sme is Property p && p.IdShort == "CO2eqTotal") - { - pCO2eqTotal = p; - } - } - if (pCO2eqTotal == null) - { - pCO2eqTotal = new Property(DataTypeDefXsd.String, idShort: "CO2eqTotal"); - co2eqSubmodel.SubmodelElements.Add(pCO2eqTotal); - pCO2eqTotal.SetAllParentsAndTimestamps(co2eqSubmodel, timeStamp, co2eqSubmodel.TimeStampCreate); - pCO2eqTotal.SetTimeStamp(timeStamp); - pCO2eqTotal.Value = "0"; - } - } - } + asbuilt_total = new String(root.cradleToGateCombination.Value); + if (co2eqSubmodel != null) + { + pCO2eqTotal = null; + foreach (var sme in co2eqSubmodel.SubmodelElements) + { + if (sme is Property p && p.IdShort == "CO2eqTotal") + { + pCO2eqTotal = p; + } + } + + if (pCO2eqTotal == null) + { + pCO2eqTotal = new Property(DataTypeDefXsd.String, idShort: "CO2eqTotal"); + co2eqSubmodel.SubmodelElements.Add(pCO2eqTotal); + pCO2eqTotal.SetAllParentsAndTimestamps(co2eqSubmodel, timeStamp, co2eqSubmodel.TimeStampCreate); + pCO2eqTotal.SetTimeStamp(timeStamp); + pCO2eqTotal.Value = "0"; + } + } + } if (Program.showWeight && root.weightCombination != null) { @@ -2191,10 +2200,10 @@ public static void operation_calculate_cfp(Operation op, int envIndex, DateTime // Iterate tree and calculate CFP values bool changed = createCfpTree(envIndex, timeStamp); - cfpNode node = root; - cfpNode parent = null; - List stack = new List(); - int sp = -1; + cfpNode node = root; + cfpNode parent = null; + List stack = new List(); + int sp = -1; while (node != null) { @@ -2207,10 +2216,10 @@ public static void operation_calculate_cfp(Operation op, int envIndex, DateTime if (node.cradleToGateModule != null) { node.cradleToGateCombination.Value = node.cradleToGateModule.Value; - } + } node.cradleToGateCombination.SetTimeStamp(timeStamp); - } + } if (node.productionCombination != null) { @@ -2218,31 +2227,34 @@ public static void operation_calculate_cfp(Operation op, int envIndex, DateTime if (node.productionModule != null) { node.productionCombination.Value = node.productionModule.Value; - } + } node.productionCombination.SetTimeStamp(timeStamp); } + if (node.distributionCombination != null) { node.distributionCombination.Value = "0.0"; if (node.distributionModule != null) { node.distributionCombination.Value = node.distributionModule.Value; - } + } node.distributionCombination.SetTimeStamp(timeStamp); } + if (node.weightCombination != null) { node.weightCombination.Value = "0.0"; if (node.weightModule != null) { node.weightCombination.Value = node.weightModule.Value; - } + } node.weightCombination.SetTimeStamp(timeStamp); } } + // move up, if all children iterated if (node.iChild == node.children.Count) { @@ -2253,12 +2265,12 @@ public static void operation_calculate_cfp(Operation op, int envIndex, DateTime } else { - parent = stack[ sp ]; + parent = stack[sp]; if (parent.cradleToGateCombination != null) { Property p = node.cradleToGateModule; if (node.cradleToGateCombination != null) - p = node.cradleToGateCombination; + p = node.cradleToGateCombination; if (p != null) { @@ -2266,18 +2278,18 @@ public static void operation_calculate_cfp(Operation op, int envIndex, DateTime double value2 = 0.0; try { - value1 = Convert.ToDouble(parent.cradleToGateCombination.Value, CultureInfo.InvariantCulture); - value2 = Convert.ToDouble(p.Value, CultureInfo.InvariantCulture); - value1 = Math.Round(value1 + value2, 8); + value1 = Convert.ToDouble(parent.cradleToGateCombination.Value, CultureInfo.InvariantCulture); + value2 = Convert.ToDouble(p.Value, CultureInfo.InvariantCulture); + value1 = Math.Round(value1 + value2, 8); parent.cradleToGateCombination.Value = value1.ToString(CultureInfo.InvariantCulture); parent.cradleToGateCombination.SetTimeStamp(timeStamp); - } - catch - { - + } + catch + { } } } + if (parent.productionCombination != null) { Property p = node.productionModule; @@ -2289,18 +2301,18 @@ public static void operation_calculate_cfp(Operation op, int envIndex, DateTime double value2 = 0.0; try { - value1 = Convert.ToDouble(parent.productionCombination.Value, CultureInfo.InvariantCulture); - value2 = Convert.ToDouble(p.Value, CultureInfo.InvariantCulture); - value1 = Math.Round(value1 + value2, 8); + value1 = Convert.ToDouble(parent.productionCombination.Value, CultureInfo.InvariantCulture); + value2 = Convert.ToDouble(p.Value, CultureInfo.InvariantCulture); + value1 = Math.Round(value1 + value2, 8); parent.productionCombination.Value = value1.ToString(CultureInfo.InvariantCulture); parent.productionCombination.SetTimeStamp(timeStamp); - } - catch - { - + } + catch + { } } } + if (parent.distributionCombination != null) { Property p = node.distributionModule; @@ -2312,18 +2324,18 @@ public static void operation_calculate_cfp(Operation op, int envIndex, DateTime double value2 = 0.0; try { - value1 = Convert.ToDouble(parent.distributionCombination.Value, CultureInfo.InvariantCulture); - value2 = Convert.ToDouble(p.Value, CultureInfo.InvariantCulture); - value1 = Math.Round(value1 + value2, 8); + value1 = Convert.ToDouble(parent.distributionCombination.Value, CultureInfo.InvariantCulture); + value2 = Convert.ToDouble(p.Value, CultureInfo.InvariantCulture); + value1 = Math.Round(value1 + value2, 8); parent.distributionCombination.Value = value1.ToString(CultureInfo.InvariantCulture); parent.distributionCombination.SetTimeStamp(timeStamp); - } - catch - { - + } + catch + { } } } + if (parent.weightCombination != null) { Property p = node.weightModule; @@ -2335,20 +2347,20 @@ public static void operation_calculate_cfp(Operation op, int envIndex, DateTime double value2 = 0.0; try { - value1 = Convert.ToDouble(parent.weightCombination.Value, CultureInfo.InvariantCulture); - value2 = Convert.ToDouble(p.Value, CultureInfo.InvariantCulture); - value1 = Math.Round(value1 + value2, 8); + value1 = Convert.ToDouble(parent.weightCombination.Value, CultureInfo.InvariantCulture); + value2 = Convert.ToDouble(p.Value, CultureInfo.InvariantCulture); + value1 = Math.Round(value1 + value2, 8); parent.weightCombination.Value = value1.ToString(CultureInfo.InvariantCulture); parent.weightCombination.SetTimeStamp(timeStamp); - } - catch - { - + } + catch + { } } } + parent = null; - node = stack[ sp ]; + node = stack[sp]; stack.RemoveAt(sp); sp--; } @@ -2358,33 +2370,34 @@ public static void operation_calculate_cfp(Operation op, int envIndex, DateTime // Interate children stack.Add(node); sp++; - node = node.children[ node.iChild++ ]; + node = node.children[node.iChild++]; } } - if (pCO2eqTotal != null) - { - pCO2eqTotal.Value = root.cradleToGateCombination.Value; - } + if (pCO2eqTotal != null) + { + pCO2eqTotal.Value = root.cradleToGateCombination.Value; + } + // once = true; // if (root != null && root.bomTimestamp > lastCreateTimestamp) if (changed || credentialsChanged) { Program.signalNewData(1); lastCreateTimestamp = timeStamp; - credentialsChanged = false; + credentialsChanged = false; } } static void saveAASXtoTemp() { bool newData = false; - int envi = 0; + int envi = 0; while (envi < Program.env.Length) { if (!Program.withDb) { - string fn = Program.envFileName[ envi ]; + string fn = Program.envFileName[envi]; if (fn != null && fn != "") { @@ -2394,14 +2407,14 @@ static void saveAASXtoTemp() lock (Program.changeAasxFile) { Console.WriteLine("SAVE TEMP: " + fn); - Program.env[ envi ].SaveAs("./temp/" + fn, true); + Program.env[envi].SaveAs("./temp/" + fn, true); DateTime timeStamp = DateTime.Now; - foreach (var submodel in Program.env[ envi ].AasEnv.Submodels) + foreach (var submodel in Program.env[envi].AasEnv.Submodels) { submodel.TimeStampCreate = timeStamp; submodel.SetTimeStamp(timeStamp); submodel.SetAllParents(timeStamp); - } + } newData = true; } @@ -2410,24 +2423,25 @@ static void saveAASXtoTemp() } else { - if (Program.env[ envi ] != null && Program.env[ envi ].getWrite()) + if (Program.env[envi] != null && Program.env[envi].getWrite()) { lock (Program.changeAasxFile) { - Edit.Update(Program.env[ envi ]); + Edit.Update(Program.env[envi]); newData = true; } } // delete of aas handeling } + envi++; - } + } if (newData) Program.signalNewData(0); } - static Thread tasksThread; + static Thread tasksThread; public static void tasksSamplingLoop() { @@ -2459,37 +2473,37 @@ public static void tasksCyclic() bool taskRun = false; for (int i = 0; i < taskList.Count; i++) { - var t = taskList[ i ]; + var t = taskList[i]; if (t.taskType?.Value.ToLower() == "cyclic") { if (t.nextExecution > timeStamp) - continue; + continue; if (t.cycleCount != null) { if (t.cycleCount.Value == "") - t.cycleCount.Value = "0"; + t.cycleCount.Value = "0"; t.cycleCount.Value = (Convert.ToInt32(t.cycleCount.Value) + 1).ToString(); t.cycleCount.SetTimeStamp(timeStamp); - } + } t.nextExecution = timeStamp.AddMilliseconds(Convert.ToInt32(t.cycleTime.Value)); if (t.nextCycle != null) { t.nextCycle.Value = t.nextExecution.ToString(); t.nextCycle.SetTimeStamp(timeStamp); - } + } Program.signalNewData(0); runOperations(t.def, t.envIndex, timeStamp); taskRun = true; } - } + } if (taskRun) System.GC.Collect(); } } -} +} \ No newline at end of file diff --git a/src/AasxServerStandardBib/Services/AssetAdministrationShellService.cs b/src/AasxServerStandardBib/Services/AssetAdministrationShellService.cs index cd765251b..0f20c6e8e 100644 --- a/src/AasxServerStandardBib/Services/AssetAdministrationShellService.cs +++ b/src/AasxServerStandardBib/Services/AssetAdministrationShellService.cs @@ -3,7 +3,7 @@ using AasxServerStandardBib.Exceptions; using AasxServerStandardBib.Interfaces; using AasxServerStandardBib.Logging; -using AdminShellNS; +using AdminShellNS; using AdminShellNS.Extensions; using Extensions; using Microsoft.IdentityModel.Tokens; @@ -183,7 +183,7 @@ public void DeleteSubmodelReferenceById(string aasIdentifier, string submodelIde - public List GetAllAssetAdministrationShells(List assetIds = null, string idShort = null) + public List GetAllAssetAdministrationShells(List? assetIds = null, string? idShort = null) { var output = _packageEnvService.GetAllAssetAdministrationShells(); diff --git a/src/AasxServerStandardBib/TimeSeries.cs b/src/AasxServerStandardBib/TimeSeries.cs index 656d7c698..2c68c5e73 100644 --- a/src/AasxServerStandardBib/TimeSeries.cs +++ b/src/AasxServerStandardBib/TimeSeries.cs @@ -1,8 +1,5 @@ - using AasxServer; using Extensions; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Opc.Ua; using Org.Webpki.JsonCanonicalizer; using SampleClient; @@ -18,6 +15,8 @@ namespace AasxTimeSeries { + using System.Text.Json; + public enum TimeSeriesDestFormat { Plain, TimeSeries10 } public static class TimeSeries @@ -53,11 +52,15 @@ public class TimeSeriesBlock public List samplesProperties = null; public List samplesValues = null; public string samplesTimeStamp = ""; + public int samplesValuesCount = 0; + // public int totalSamples = 0; public Property totalSamples = null; + // public int lowDataIndex = 0; public Property lowDataIndex = null; + // public int highDataIndex = -1; public Property highDataIndex = null; @@ -121,27 +124,29 @@ public static void timeSeriesInit() // nextSme = true; break; } + j++; } } + if (nextSme) continue; - var smec = sme as SubmodelElementCollection; + var smec = sme as SubmodelElementCollection; int countSmec = smec.Value.Count; var tsb = new TimeSeriesBlock(); - tsb.submodel = sm; - tsb.block = smec; - tsb.data = tsb.block; + tsb.submodel = sm; + tsb.block = smec; + tsb.data = tsb.block; tsb.samplesProperties = new List(); - tsb.samplesValues = new List(); + tsb.samplesValues = new List(); for (int dataSections = 0; dataSections < 2; dataSections++) { for (int iSmec = 0; iSmec < countSmec; iSmec++) { - var sme2 = smec.Value[iSmec]; + var sme2 = smec.Value[iSmec]; var idShort = sme2.IdShort; if (idShort.Contains("opcNode")) idShort = "opcNode"; @@ -154,12 +159,14 @@ public static void timeSeriesInit() { tsb.sourceType = (sme2 as Property).Value; } + break; case "sourceAddress": if (sme2 is Property) { tsb.sourceAddress = (sme2 as Property).Value; } + break; case "sourceNames": if (sme2 is Property) @@ -171,6 +178,7 @@ public static void timeSeriesInit() tsb.sourceNames.Add(s); } } + break; case "destFormat": if (sme2 is Property) @@ -186,116 +194,134 @@ public static void timeSeriesInit() break; } } + break; case "username": if (sme2 is Property) { tsb.username = (sme2 as Property).Value; } + break; case "password": if (sme2 is Property) { tsb.password = (sme2 as Property).Value; } + break; case "plotRowOffset": if (sme2 is Property) { tsb.plotRowOffset = Convert.ToInt32((sme2 as Property).Value); } + break; case "correctionMinutes": if (sme2 is Property) { tsb.correctionMinutes = Convert.ToInt32((sme2 as Property).Value); } + break; case "data": if (sme2 is SubmodelElementCollection) { tsb.data = sme2 as SubmodelElementCollection; } + if (sme2 is ReferenceElement) { var refElement = Program.env[0].AasEnv.FindReferableByReference((sme2 as ReferenceElement).GetModelReference()); if (refElement is SubmodelElementCollection) tsb.data = refElement as SubmodelElementCollection; } + break; case "minDiffPercent": if (sme2 is Property) { tsb.minDiffPercent = sme2 as Property; } + break; case "minDiffAbsolute": if (sme2 is Property) { tsb.minDiffAbsolute = sme2 as Property; } + break; case "sampleStatus": if (sme2 is Property) { tsb.sampleStatus = sme2 as Property; } + break; case "sampleMode": if (sme2 is Property) { tsb.sampleMode = sme2 as Property; } + break; case "sampleRate": if (sme2 is Property) { tsb.sampleRate = sme2 as Property; } + break; case "maxSamples": if (sme2 is Property) { tsb.maxSamples = sme2 as Property; } + break; case "actualSamples": if (sme2 is Property) { - tsb.actualSamples = sme2 as Property; + tsb.actualSamples = sme2 as Property; tsb.actualSamples.Value = "0"; } + break; case "maxSamplesInCollection": if (sme2 is Property) { tsb.maxSamplesInCollection = sme2 as Property; } + break; case "actualSamplesInCollection": if (sme2 is Property) { - tsb.actualSamplesInCollection = sme2 as Property; + tsb.actualSamplesInCollection = sme2 as Property; tsb.actualSamplesInCollection.Value = "0"; } + break; case "maxCollections": if (sme2 is Property) { tsb.maxCollections = sme2 as Property; } + break; case "actualCollections": if (sme2 is Property) { - tsb.actualCollections = sme2 as Property; + tsb.actualCollections = sme2 as Property; tsb.actualCollections.Value = "0"; } + break; case "opcNode": if (sme2 is Property) { - string node = (sme2 as Property).Value; + string node = (sme2 as Property).Value; string[] split = node.Split(','); if (tsb.opcNodes == null) tsb.opcNodes = new List(); @@ -307,11 +333,12 @@ public static void timeSeriesInit() p.SetTimeStamp(timeStamp); tsb.samplesValues.Add(""); } + break; case "modbusNode": if (sme2 is Property) { - string node = (sme2 as Property).Value; + string node = (sme2 as Property).Value; string[] split = node.Split(','); if (tsb.modbusNodes == null) tsb.modbusNodes = new List(); @@ -323,8 +350,10 @@ public static void timeSeriesInit() p.SetTimeStamp(timeStamp); tsb.samplesValues.Add(""); } + break; } + if (tsb.sourceType == "aas" && sme2 is ReferenceElement r) { var el = env.AasEnv.FindReferableByReference(r.GetModelReference()); @@ -335,6 +364,7 @@ public static void timeSeriesInit() } } } + if (dataSections == 0) { if (tsb.data != null) @@ -342,6 +372,7 @@ public static void timeSeriesInit() countSmec = smec.Value.Count; } } + tsb.opcLastTimeStamp = DateTime.UtcNow + TimeSpan.FromMinutes(tsb.correctionMinutes) - TimeSpan.FromMinutes(2); if (tsb.data != null) @@ -362,40 +393,45 @@ public static void timeSeriesInit() tsb.latestData.Value.Add(latestDataProperty); tsb.lowDataIndex = latestDataProperty as Property; } + latestDataProperty.SetTimeStamp(timeStamp); latestDataProperty = tsb.latestData.FindFirstIdShortAs("highDataIndex"); if (latestDataProperty == null) { //latestDataProperty = new Property(DataTypeDefXsd.String,idShort:"highDataIndex"); - latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "highDataIndex", value: "-1"); + latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "highDataIndex", value: "-1"); latestDataProperty.TimeStampCreate = timeStamp; tsb.latestData.Value.Add(latestDataProperty); tsb.highDataIndex = latestDataProperty as Property; } + latestDataProperty.SetTimeStamp(timeStamp); latestDataProperty = tsb.latestData.FindFirstIdShortAs("totalSamples"); if (latestDataProperty == null) { //latestDataProperty = new Property(DataTypeDefXsd.String,idShort:"totalSamples"); - latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "totalSamples", value: "0"); + latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "totalSamples", value: "0"); latestDataProperty.TimeStampCreate = timeStamp; tsb.latestData.Value.Add(latestDataProperty); tsb.totalSamples = latestDataProperty as Property; } + latestDataProperty.SetTimeStamp(timeStamp); latestDataProperty = tsb.latestData.FindFirstIdShortAs("timeStamp"); if (latestDataProperty == null) { //latestDataProperty = new Property(DataTypeDefXsd.String,idShort:"timeStamp"); - latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "timeStamp"); + latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "timeStamp"); latestDataProperty.TimeStampCreate = timeStamp; tsb.latestData.Value.Add(latestDataProperty); } + latestDataProperty.SetTimeStamp(timeStamp); } + if (tsb.sampleRate != null) tsb.threadCounter = Convert.ToInt32(tsb.sampleRate.Value); timeSeriesBlockList.Add(tsb); @@ -414,6 +450,7 @@ public static void timeSeriesInit() { timeSeriesSampling(false); } + timeSeriesSampling(true); } else @@ -437,6 +474,7 @@ public static void timeSeriesSamplingLoop() private static long opcClientRate = 0; private static long opcClientCount = 0; + public static void SetOPCClientThread(double value) { opcClientRate = (long)value; @@ -537,7 +575,7 @@ private static void Sign(SubmodelElementCollection smc, DateTime timestamp) Console.WriteLine("Sign"); // string certFile = "Andreas_Orzelski_Chain.pfx"; - string certPW = "i40"; + string certPW = "i40"; if (System.IO.File.Exists(certFile)) { // ServicePointManager.ServerCertificateValidationCallback = @@ -581,14 +619,14 @@ private static void Sign(SubmodelElementCollection smc, DateTime timestamp) smec.Add(sigT); smec.Add(signature); string s = null; - s = JsonConvert.SerializeObject(smc, Formatting.Indented); + s = System.Text.Json.JsonSerializer.Serialize(smc, new JsonSerializerOptions {WriteIndented = true}); json.Value = s; Console.WriteLine("Canonicalize"); JsonCanonicalizer jsonCanonicalizer = new JsonCanonicalizer(s); - string result = jsonCanonicalizer.GetEncodedString(); + string result = jsonCanonicalizer.GetEncodedString(); canonical.Value = result; - subject.Value = certificate.Subject; + subject.Value = certificate.Subject; X509Certificate2Collection xc = new X509Certificate2Collection(); xc.Import(certFile, certPW, X509KeyStorageFlags.PersistKeySet); @@ -599,7 +637,7 @@ private static void Sign(SubmodelElementCollection smc, DateTime timestamp) Property c = new Property(DataTypeDefXsd.String, idShort: "certificate_" + (j + 1)); c.SetTimeStamp(timestamp); c.TimeStampCreate = timestamp; - c.Value = Convert.ToBase64String(xc[j].GetRawCertData()); + c.Value = Convert.ToBase64String(xc[j].GetRawCertData()); x5c.Add(c); } @@ -612,10 +650,10 @@ private static void Sign(SubmodelElementCollection smc, DateTime timestamp) return; algorithm.Value = "RS256"; - byte[] data = Encoding.UTF8.GetBytes(result); + byte[] data = Encoding.UTF8.GetBytes(result); byte[] signed = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); signature.Value = Convert.ToBase64String(signed); - sigT.Value = DateTime.UtcNow.ToString("yyyy'-'MM'-'dd' 'HH':'mm':'ss"); + sigT.Value = DateTime.UtcNow.ToString("yyyy'-'MM'-'dd' 'HH':'mm':'ss"); } } // ReSharper disable EmptyGeneralCatchClause @@ -634,13 +672,13 @@ private static void Sign(SubmodelElementCollection smc, DateTime timestamp) static void modbusByteSwap(Byte[] bytes) { int len = bytes.Length; - int i = 0; + int i = 0; while (i < len - 1) { byte b = bytes[i + 1]; - bytes[i + 1] = bytes[i]; - bytes[i] = b; - i += 2; + bytes[i + 1] = bytes[i]; + bytes[i] = b; + i += 2; } } @@ -663,7 +701,7 @@ public static bool timeSeriesSampling(bool final) if (tsb.sampleStatus.Value == "stop") { tsb.sampleStatus.Value = "stopped"; - final = true; + final = true; } else { @@ -680,10 +718,10 @@ public static bool timeSeriesSampling(bool final) tsb.threadCounter = Convert.ToInt32(tsb.sampleRate.Value); - int actualSamples = Convert.ToInt32(tsb.actualSamples.Value); - int maxSamples = Convert.ToInt32(tsb.maxSamples.Value); + int actualSamples = Convert.ToInt32(tsb.actualSamples.Value); + int maxSamples = Convert.ToInt32(tsb.maxSamples.Value); int actualSamplesInCollection = Convert.ToInt32(tsb.actualSamplesInCollection.Value); - int maxSamplesInCollection = Convert.ToInt32(tsb.maxSamplesInCollection.Value); + int maxSamplesInCollection = Convert.ToInt32(tsb.maxSamplesInCollection.Value); if (final || actualSamples < maxSamples) { @@ -697,12 +735,13 @@ public static bool timeSeriesSampling(bool final) tsb.block.FindFirstIdShortAs("jsonData"); if (c == null) { - c = new SubmodelElementCollection(); - c.IdShort = "jsonData"; + c = new SubmodelElementCollection(); + c.IdShort = "jsonData"; c.TimeStampCreate = timeStamp; tsb.block.Value.Add(c); c.SetTimeStamp(timeStamp); } + if (parseJSON(tsb.sourceAddress, "", "", c, tsb.sourceNames, tsb.minDiffAbsolute, tsb.minDiffPercent)) { foreach (var el in c.Value) @@ -722,6 +761,7 @@ public static bool timeSeriesSampling(bool final) valueCount = 0; } } + if (tsb.sourceType == "opchd" && tsb.sourceAddress != "") { GetHistory(tsb); @@ -729,17 +769,19 @@ public static bool timeSeriesSampling(bool final) if (table != null) valueCount = table.Count; } + if (tsb.sourceType == "opcda" && tsb.sourceAddress != "") { valueCount = GetDAData(tsb); } + if (tsb.sourceType == "modbus" && tsb.sourceAddress != "") { valueCount = GetModbus(tsb); } DateTime dt; - int valueIndex = 0; + int valueIndex = 0; while (valueIndex < valueCount) { if (tsb.sourceType == "opchd" && tsb.sourceAddress != "") @@ -765,12 +807,12 @@ public static bool timeSeriesSampling(bool final) { if (tsb.samplesTimeStamp == "") { - latestTimeStamp = TimeStamp.TimeStamp.DateTimeToString(dt); + latestTimeStamp = TimeStamp.TimeStamp.DateTimeToString(dt); tsb.samplesTimeStamp += latestTimeStamp; } else { - latestTimeStamp = dt.ToString("HH:mm:ss.fff"); + latestTimeStamp = dt.ToString("HH:mm:ss.fff"); tsb.samplesTimeStamp += "," + latestTimeStamp; } } @@ -782,11 +824,12 @@ public static bool timeSeriesSampling(bool final) if (latestDataProperty == null) { //latestDataProperty = new Property(DataTypeDefXsd.String,idShort:"lowDataIndex"); - latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "lowDataIndex", value: "0"); + latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "lowDataIndex", value: "0"); latestDataProperty.TimeStampCreate = timeStamp; tsb.latestData.Value.Add(latestDataProperty); tsb.lowDataIndex = latestDataProperty as Property; } + (latestDataProperty as Property).Value = "" + tsb.lowDataIndex.Value; latestDataProperty.SetTimeStamp(timeStamp); @@ -794,11 +837,12 @@ public static bool timeSeriesSampling(bool final) if (latestDataProperty == null) { //latestDataProperty = new Property(DataTypeDefXsd.String,idShort:"highDataIndex"); - latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "highDataIndex", value: "-1"); + latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "highDataIndex", value: "-1"); latestDataProperty.TimeStampCreate = timeStamp; tsb.latestData.Value.Add(latestDataProperty); tsb.highDataIndex = latestDataProperty as Property; } + // (latestDataProperty as Property).Value = "" + tsb.highDataIndex; latestDataProperty.SetTimeStamp(timeStamp); @@ -806,11 +850,12 @@ public static bool timeSeriesSampling(bool final) if (latestDataProperty == null) { //latestDataProperty = new Property(DataTypeDefXsd.String,idShort:"totalSamples"); - latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "totalSamples", value: "0"); + latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "totalSamples", value: "0"); latestDataProperty.TimeStampCreate = timeStamp; tsb.latestData.Value.Add(latestDataProperty); tsb.totalSamples = latestDataProperty as Property; } + // (latestDataProperty as Property).Value = "" + tsb.highDataIndex; latestDataProperty.SetTimeStamp(timeStamp); @@ -818,17 +863,18 @@ public static bool timeSeriesSampling(bool final) if (latestDataProperty == null) { //latestDataProperty = new Property(DataTypeDefXsd.String,idShort:"timeStamp"); - latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "timeStamp"); + latestDataProperty = new Property(DataTypeDefXsd.String, idShort: "timeStamp"); latestDataProperty.TimeStampCreate = timeStamp; tsb.latestData.Value.Add(latestDataProperty); } + (latestDataProperty as Property).Value = TimeStamp.TimeStamp.DateTimeToString(dt); latestDataProperty.SetTimeStamp(timeStamp); updateMode = 1; for (int i = 0; i < tsb.samplesProperties.Count; i++) { - string latestDataName = tsb.samplesProperties[i].IdShort; + string latestDataName = tsb.samplesProperties[i].IdShort; string latestDataValue = ""; if (tsb.samplesValues[i] != "") @@ -852,6 +898,7 @@ public static bool timeSeriesSampling(bool final) latestDataValue = "0"; break; } + if (tsb.destFormat == TimeSeriesDestFormat.TimeSeries10) { tsb.samplesValues[i] += $"[{tsb.totalSamples.Value}, {latestDataValue}]"; @@ -861,6 +908,7 @@ public static bool timeSeriesSampling(bool final) tsb.samplesValues[i] += latestDataValue; } } + if (tsb.sourceType == "opcda") { latestDataValue = opcDAValues[i]; @@ -873,6 +921,7 @@ public static bool timeSeriesSampling(bool final) latestDataValue = "0"; break; } + if (tsb.destFormat == TimeSeriesDestFormat.TimeSeries10) { tsb.samplesValues[i] += $"[{tsb.totalSamples.Value}, {latestDataValue}]"; @@ -881,8 +930,10 @@ public static bool timeSeriesSampling(bool final) { tsb.samplesValues[i] += latestDataValue; } + Console.WriteLine(tsb.opcNodes[i] + " " + opcDAValues[i]); } + if (tsb.sourceType == "modbus") { latestDataValue = modbusValues[i]; @@ -894,6 +945,7 @@ public static bool timeSeriesSampling(bool final) { tsb.samplesValues[i] += latestDataValue; } + Console.WriteLine(tsb.modbusNodes[i] + " " + modbusValues[i]); } } @@ -916,7 +968,7 @@ public static bool timeSeriesSampling(bool final) if (latestDataProperty == null) { //latestDataProperty = new Property(DataTypeDefXsd.String,idShort:latestDataName); - latestDataProperty = new Property(DataTypeDefXsd.String, idShort: latestDataName); + latestDataProperty = new Property(DataTypeDefXsd.String, idShort: latestDataName); latestDataProperty.TimeStampCreate = timeStamp; string val = "{ grp:1, src: \"Event\"," + @@ -933,15 +985,17 @@ public static bool timeSeriesSampling(bool final) latestDataProperty.Qualifiers.Add(q); tsb.latestData.Value.Add(latestDataProperty); } + (latestDataProperty as Property).Value = latestDataValue; latestDataProperty.SetTimeStamp(timeStamp); } + tsb.samplesValuesCount++; actualSamples++; // tsb.totalSamples++; int totalSamples = Convert.ToInt32(tsb.totalSamples.Value); totalSamples++; - tsb.totalSamples.Value = totalSamples.ToString(); + tsb.totalSamples.Value = totalSamples.ToString(); tsb.actualSamples.Value = "" + actualSamples; tsb.actualSamples.SetTimeStamp(timeStamp); actualSamplesInCollection++; @@ -957,23 +1011,24 @@ public static bool timeSeriesSampling(bool final) var first = tsb.data.FindFirstIdShortAs( - firstName); + firstName); if (first != null) { - actualSamples -= maxSamplesInCollection; - tsb.actualSamples.Value = "" + actualSamples; + actualSamples -= maxSamplesInCollection; + tsb.actualSamples.Value = "" + actualSamples; tsb.actualSamples.SetTimeStamp(timeStamp); AasxRestServerLibrary.AasxRestServer.TestResource.eventMessage.add( - first, "Remove", tsb.submodel, (ulong)timeStamp.Ticks); + first, "Remove", tsb.submodel, (ulong)timeStamp.Ticks); tsb.data.Value.Remove(first); tsb.data.SetTimeStamp(timeStamp); // tsb.lowDataIndex++; int index = Convert.ToInt32(tsb.lowDataIndex.Value); tsb.lowDataIndex.Value = (index + 1).ToString(); - updateMode = 1; + updateMode = 1; } } } + if (actualSamplesInCollection >= maxSamplesInCollection) { if (actualSamplesInCollection > 0) @@ -994,9 +1049,12 @@ public static bool timeSeriesSampling(bool final) semanticIdKey: PrefTimeSeries10.CD_TimeSeriesSegment.Value); */ nextCollection = new SubmodelElementCollection(idShort: "Segment_" + tsb.highDataIndex.Value, - value: new List()); + value: new List()); nextCollection.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, - new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_TimeSeriesSegment.Value) }); + new List() + { + new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_TimeSeriesSegment.Value) + }); nextCollection.SetTimeStamp(timeStamp); /* @@ -1005,9 +1063,9 @@ public static bool timeSeriesSampling(bool final) "TSvariable_timeStamp", semanticIdKey: PrefTimeSeries10.CD_TimeSeriesVariable.Value); */ var smcvar = new SubmodelElementCollection(idShort: "TSvariable_timeStamp", - value: new List()); + value: new List()); smcvar.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, - new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_TimeSeriesVariable.Value) }); + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_TimeSeriesVariable.Value)}); smcvar.SetTimeStamp(timeStamp); nextCollection.Value.Add(smcvar); @@ -1018,7 +1076,7 @@ public static bool timeSeriesSampling(bool final) */ var newSme1 = new Property(DataTypeDefXsd.String, idShort: "RecordId"); newSme1.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, - new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_RecordId.Value) }); + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_RecordId.Value)}); newSme1.SetTimeStamp(timeStamp); (newSme1 as Property).Value = "timeStamp"; smcvar.Value.Add(newSme1); @@ -1028,7 +1086,8 @@ public static bool timeSeriesSampling(bool final) "UtcTime", semanticIdKey: PrefTimeSeries10.CD_UtcTime.Value); */ var newSme2 = new Property(DataTypeDefXsd.String, idShort: "UtcTime"); - newSme2.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_UtcTime.Value) }); + newSme2.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_UtcTime.Value)}); newSme2.SetTimeStamp(timeStamp); smcvar.Value.Add(newSme2); @@ -1038,7 +1097,8 @@ public static bool timeSeriesSampling(bool final) smeValue: tsb.samplesTimeStamp); */ var newSme3 = new Blob("BLOB", idShort: "timeStamp"); - newSme3.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_ValueArray.Value) }); + newSme3.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_ValueArray.Value)}); newSme3.SetTimeStamp(timeStamp); (newSme3 as Blob).Value = Encoding.ASCII.GetBytes(tsb.samplesTimeStamp); smcvar.Value.Add(newSme3); @@ -1071,8 +1131,9 @@ public static bool timeSeriesSampling(bool final) semanticIdKey: PrefTimeSeries10.CD_TimeSeriesVariable.Value); */ var smcvar = new SubmodelElementCollection(idShort: "TSvariable_" + tsb.samplesProperties[i].IdShort, - value: new List()); - smcvar.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_TimeSeriesVariable.Value) }); + value: new List()); + smcvar.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_TimeSeriesVariable.Value)}); smcvar.SetTimeStamp(timeStamp); nextCollection.Value.Add(smcvar); @@ -1082,7 +1143,8 @@ public static bool timeSeriesSampling(bool final) smeValue: "" + tsb.samplesProperties[i].IdShort); */ var newSme = new Property(DataTypeDefXsd.String, idShort: "RecordId"); - newSme.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_RecordId.Value) }); + newSme.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_RecordId.Value)}); newSme.SetTimeStamp(timeStamp); (newSme as Property).Value = "" + tsb.samplesProperties[i].IdShort; smcvar.Value.Add(newSme); @@ -1095,7 +1157,8 @@ public static bool timeSeriesSampling(bool final) semanticIdKey: PrefTimeSeries10.CD_GeneratedFloat.Value); */ var newSme2 = new Property(DataTypeDefXsd.String, idShort: "" + tsb.samplesProperties[i].IdShort); - newSme2.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_GeneratedFloat.Value) }); + newSme2.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_GeneratedFloat.Value)}); newSme2.SetTimeStamp(timeStamp); smcvar.Value.Add(newSme2); } @@ -1107,7 +1170,11 @@ public static bool timeSeriesSampling(bool final) semanticIdKey: PrefTimeSeries10.CD_GeneratedInteger.Value); */ var newSme2 = new Property(DataTypeDefXsd.String, idShort: "" + tsb.samplesProperties[i].IdShort); - newSme2.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_GeneratedInteger.Value) }); + newSme2.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, + new List() + { + new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_GeneratedInteger.Value) + }); newSme2.SetTimeStamp(timeStamp); smcvar.Value.Add(newSme2); } @@ -1118,7 +1185,8 @@ public static bool timeSeriesSampling(bool final) smeValue: tsb.samplesValues[i]); */ var newSme3 = new Blob("BLOB", idShort: "ValueArray"); - newSme3.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_ValueArray.Value) }); + newSme3.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_ValueArray.Value)}); newSme3.SetTimeStamp(timeStamp); (newSme3 as Blob).Value = Encoding.ASCII.GetBytes(tsb.samplesValues[i]); smcvar.Value.Add(newSme3); @@ -1135,27 +1203,28 @@ public static bool timeSeriesSampling(bool final) tsb.samplesValues[i] = ""; } + Sign(nextCollection, timeStamp); tsb.data.Add(nextCollection); tsb.data.SetTimeStamp(timeStamp); AasxRestServerLibrary.AasxRestServer.TestResource.eventMessage.add( - nextCollection, "Add", tsb.submodel, (ulong)timeStamp.Ticks); - tsb.samplesValuesCount = 0; - actualSamplesInCollection = 0; + nextCollection, "Add", tsb.submodel, (ulong)timeStamp.Ticks); + tsb.samplesValuesCount = 0; + actualSamplesInCollection = 0; tsb.actualSamplesInCollection.Value = "" + actualSamplesInCollection; tsb.actualSamplesInCollection.SetTimeStamp(timeStamp); updateMode = 1; - var json = JsonConvert.SerializeObject(nextCollection, Newtonsoft.Json.Formatting.Indented, - new JsonSerializerSettings - { - NullValueHandling = NullValueHandling.Ignore - }); + var options = new JsonSerializerOptions {WriteIndented = true, IgnoreNullValues = true}; + + var json = JsonSerializer.Serialize(nextCollection, options); Program.connectPublish(tsb.block.IdShort + "." + nextCollection.IdShort, json); } } + valueIndex++; } } + if (final || actualSamplesInCollection >= maxSamplesInCollection) { if (actualSamplesInCollection > 0) @@ -1175,8 +1244,9 @@ public static bool timeSeriesSampling(bool final) semanticIdKey: PrefTimeSeries10.CD_TimeSeriesSegment.Value); */ nextCollection = new SubmodelElementCollection(idShort: "Segment_" + tsb.highDataIndex.Value, - value: new List()); - nextCollection.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_TimeSeriesSegment.Value) }); + value: new List()); + nextCollection.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_TimeSeriesSegment.Value)}); nextCollection.SetTimeStamp(timeStamp); /* @@ -1185,8 +1255,9 @@ public static bool timeSeriesSampling(bool final) "TSvariable_timeStamp", semanticIdKey: PrefTimeSeries10.CD_TimeSeriesVariable.Value); */ var smcvar = new SubmodelElementCollection(idShort: "TSvariable_timeStamp", - value: new List()); - smcvar.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_TimeSeriesVariable.Value) }); + value: new List()); + smcvar.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_TimeSeriesVariable.Value)}); smcvar.SetTimeStamp(timeStamp); nextCollection.Value.Add(smcvar); @@ -1196,7 +1267,8 @@ public static bool timeSeriesSampling(bool final) smeValue: "timeStamp"); */ var newSme = new Property(DataTypeDefXsd.String, idShort: "RecordId"); - newSme.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_RecordId.Value) }); + newSme.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_RecordId.Value)}); newSme.SetTimeStamp(timeStamp); (newSme as Property).Value = "timeStamp"; smcvar.Value.Add(newSme); @@ -1206,7 +1278,8 @@ public static bool timeSeriesSampling(bool final) "UtcTime", semanticIdKey: PrefTimeSeries10.CD_UtcTime.Value); */ var newSme2 = new Property(DataTypeDefXsd.String, idShort: "UtcTime"); - newSme2.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_UtcTime.Value) }); + newSme2.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_UtcTime.Value)}); newSme2.SetTimeStamp(timeStamp); smcvar.Value.Add(newSme2); @@ -1216,7 +1289,8 @@ public static bool timeSeriesSampling(bool final) smeValue: tsb.samplesTimeStamp); */ var newSme3 = new Blob("BLOB", idShort: "timeStamp"); - newSme3.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_ValueArray.Value) }); + newSme3.SemanticId = new Reference(AasCore.Aas3_0.ReferenceTypes.ExternalReference, + new List() {new Key(KeyTypes.GlobalReference, PrefTimeSeries10.CD_ValueArray.Value)}); newSme3.SetTimeStamp(timeStamp); (newSme3 as Blob).Value = Encoding.ASCII.GetBytes(tsb.samplesTimeStamp); smcvar.Value.Add(newSme3); @@ -1229,33 +1303,36 @@ public static bool timeSeriesSampling(bool final) var p = new Property(DataTypeDefXsd.String, idShort: "timeStamp"); p.Value = tsb.samplesTimeStamp; p.SetTimeStamp(timeStamp); - p.TimeStampCreate = timeStamp; + p.TimeStampCreate = timeStamp; tsb.samplesTimeStamp = ""; nextCollection.Value.Add(p); nextCollection.SetTimeStamp(timeStamp); nextCollection.TimeStampCreate = timeStamp; } + for (int i = 0; i < tsb.samplesProperties.Count; i++) { var p = new Property(DataTypeDefXsd.String, idShort: tsb.samplesProperties[i].IdShort); p.Value = tsb.samplesValues[i]; p.SetTimeStamp(timeStamp); - p.TimeStampCreate = timeStamp; + p.TimeStampCreate = timeStamp; tsb.samplesValues[i] = ""; nextCollection.Value.Add(p); } + Sign(nextCollection, timeStamp); tsb.data.Add(nextCollection); tsb.data.SetTimeStamp(timeStamp); AasxRestServerLibrary.AasxRestServer.TestResource.eventMessage.add( - nextCollection, "Add", tsb.submodel, (ulong)timeStamp.Ticks); - tsb.samplesValuesCount = 0; - actualSamplesInCollection = 0; + nextCollection, "Add", tsb.submodel, (ulong)timeStamp.Ticks); + tsb.samplesValuesCount = 0; + actualSamplesInCollection = 0; tsb.actualSamplesInCollection.Value = "" + actualSamplesInCollection; tsb.actualSamplesInCollection.SetTimeStamp(timeStamp); updateMode = 1; } } + //// if (updateMode != 0) Program.signalNewData(updateMode); } @@ -1268,7 +1345,7 @@ public static bool timeSeriesSampling(bool final) } static bool parseJSON(string url, string username, string password, SubmodelElementCollection c, - List filter, Property minDiffAbsolute, Property minDiffPercent) + List filter, Property minDiffAbsolute, Property minDiffPercent) { if (url == "posttimeseries") { @@ -1278,16 +1355,18 @@ static bool parseJSON(string url, string username, string password, SubmodelElem AasxRestServerLibrary.AasxRestServer.TestResource.posttimeseriesPayload = ""; try { - JObject parsed = JObject.Parse(payload); - if (Program.parseJson(c, parsed, filter, minDiffAbsolute, minDiffPercent)) + var parsed = JsonDocument.Parse(payload); + if (Program.ParseJson(c, parsed, filter, minDiffAbsolute, minDiffPercent)) return true; } catch (Exception ex) { Console.WriteLine("GetJSON() expection: " + ex.Message); } + return false; } + return false; } @@ -1299,7 +1378,7 @@ static bool parseJSON(string url, string username, string password, SubmodelElem { var authToken = System.Text.Encoding.ASCII.GetBytes(username + ":" + password); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", - Convert.ToBase64String(authToken)); + Convert.ToBase64String(authToken)); } Console.WriteLine("GetJSON: " + url); @@ -1310,8 +1389,8 @@ static bool parseJSON(string url, string username, string password, SubmodelElem if (response != "") { - JObject parsed = JObject.Parse(response); - if (Program.parseJson(c, parsed, filter, minDiffAbsolute, minDiffPercent)) + var parsed = JsonDocument.Parse(response); + if (Program.ParseJson(c, parsed, filter, minDiffAbsolute, minDiffPercent)) return true; } } @@ -1319,6 +1398,7 @@ static bool parseJSON(string url, string username, string password, SubmodelElem { Console.WriteLine("GetJSON() expection: " + ex.Message); } + return false; } @@ -1336,7 +1416,7 @@ static bool parseJSON(string url, string username, string password, SubmodelElem public static int GetModbus(TimeSeriesBlock tsb) { int minDiffAbsolute = 1; - int minDiffPercent = 0; + int minDiffPercent = 0; if (tsb.minDiffAbsolute != null) minDiffAbsolute = Convert.ToInt32(tsb.minDiffAbsolute.Value); if (tsb.minDiffPercent != null) @@ -1360,20 +1440,21 @@ public static int GetModbus(TimeSeriesBlock tsb) { string[] split = tsb.modbusNodes[i].Split(','); byte[] modbusValue = mbClient.Read( - (byte)Convert.ToInt32(split[0]), - Modbus.ModbusTCPClient.FunctionCode.ReadHoldingRegisters, - (ushort)Convert.ToInt32(split[1]), - (ushort)Convert.ToInt32(split[2])); + (byte)Convert.ToInt32(split[0]), + Modbus.ModbusTCPClient.FunctionCode.ReadHoldingRegisters, + (ushort)Convert.ToInt32(split[1]), + (ushort)Convert.ToInt32(split[2])); modbusByteSwap(modbusValue); switch (split[3]) { case "float": - float f = BitConverter.ToSingle(modbusValue, 0); + float f = BitConverter.ToSingle(modbusValue, 0); string value = Convert.ToInt32(f).ToString(); modbusValues.Add(value); break; } } + if (lastModbusValues == null) { lastModbusValues = new List(modbusValues); @@ -1384,12 +1465,13 @@ public static int GetModbus(TimeSeriesBlock tsb) bool keep = false; for (int i = 0; i < modbusValues.Count; i++) { - int v = Convert.ToInt32(modbusValues[i]); + int v = Convert.ToInt32(modbusValues[i]); int lastv = Convert.ToInt32(lastModbusValues[i]); int delta = Math.Abs(v - lastv); if (delta >= minDiffAbsolute && delta >= lastv * minDiffPercent / 100) keep = true; } + if (keep) { lastModbusValues = new List(modbusValues); @@ -1426,7 +1508,7 @@ public static int GetDAData(TimeSeriesBlock tsb) for (int i = 0; i < tsb.opcNodes.Count; i++) { string[] split = tsb.opcNodes[i].Split(','); - string value = opc.ReadSubmodelElementValue(split[1], (ushort)Convert.ToInt32(split[0])); + string value = opc.ReadSubmodelElementValue(split[1], (ushort)Convert.ToInt32(split[0])); opcDAValues.Add(value); } } @@ -1466,7 +1548,7 @@ public static void GetHistory(TimeSeriesBlock tsb) session?.Close(); session?.Dispose(); session = null; - opc = null; + opc = null; } /* session?.Close(); @@ -1474,6 +1556,7 @@ public static void GetHistory(TimeSeriesBlock tsb) session = null; */ } + public static void Connect(TimeSeriesBlock tsb) { Console.WriteLine("Connect OPC UA"); @@ -1484,51 +1567,52 @@ public static void Connect(TimeSeriesBlock tsb) if (session == null) { Console.WriteLine("ERROR: Session not connected " - + tsb.sourceAddress + " " + tsb.username + " " + tsb.password); + + tsb.sourceAddress + " " + tsb.username + " " + tsb.password); } else { // get current time on server - tsb.opcLastTimeStamp = (DateTime)session.ReadValue(new NodeId(2258, 0)).Value; + tsb.opcLastTimeStamp = (DateTime)session.ReadValue(new NodeId(2258, 0)).Value; tsb.opcLastTimeStamp -= TimeSpan.FromMinutes(1); } } + public static void GetData(TimeSeriesBlock tsb) { if (session != null) { ReadRawModifiedDetails details = new ReadRawModifiedDetails(); - details.StartTime = startTime; - details.EndTime = endTime; + details.StartTime = startTime; + details.EndTime = endTime; details.NumValuesPerNode = 0; - details.IsReadModified = false; - details.ReturnBounds = true; + details.IsReadModified = false; + details.ReturnBounds = true; var nodesToRead = new HistoryReadValueIdCollection(); for (int i = 0; i < tsb.opcNodes.Count; i++) { - var nodeToRead = new HistoryReadValueId(); - string[] split = tsb.opcNodes[i].Split(','); + var nodeToRead = new HistoryReadValueId(); + string[] split = tsb.opcNodes[i].Split(','); nodeToRead.NodeId = new NodeId(split[1], (ushort)Convert.ToInt32(split[0])); nodesToRead.Add(nodeToRead); } table = new List>(); - HistoryReadResultCollection results = null; - DiagnosticInfoCollection diagnosticInfos = null; + HistoryReadResultCollection results = null; + DiagnosticInfoCollection diagnosticInfos = null; bool loop = true; while (loop) { session.HistoryRead( - null, - new ExtensionObject(details), - TimestampsToReturn.Both, - false, - nodesToRead, - out results, - out diagnosticInfos); + null, + new ExtensionObject(details), + TimestampsToReturn.Both, + false, + nodesToRead, + out results, + out diagnosticInfos); ClientBase.ValidateResponse(results, nodesToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead); @@ -1556,7 +1640,7 @@ public static void GetData(TimeSeriesBlock tsb) if (sourceTimeStamp >= startTime) { bool isValid = true; - var row = new List(); + var row = new List(); row.Add(sourceTimeStamp); foreach (HistoryData historyData in historyDatas) @@ -1572,6 +1656,7 @@ public static void GetData(TimeSeriesBlock tsb) break; } } + if (isValid) { table.Add(row); @@ -1588,10 +1673,11 @@ public static void GetData(TimeSeriesBlock tsb) loop = false; break; } + nodesToRead[i].ContinuationPoint = results[i].ContinuationPoint; } } } } } -} +} \ No newline at end of file diff --git a/src/AasxServerStandardBib/TimeSeriesPlotting.cs b/src/AasxServerStandardBib/TimeSeriesPlotting.cs index 8fd5fd213..dd10f2ede 100644 --- a/src/AasxServerStandardBib/TimeSeriesPlotting.cs +++ b/src/AasxServerStandardBib/TimeSeriesPlotting.cs @@ -1,18 +1,15 @@ - -using AdminShellNS; +using AdminShellNS; using Extensions; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using ScottPlot; using System; using System.Collections.Generic; using System.Globalization; using System.Reflection; -using System.Text; -//using static AdminShellNS.AdminShellV20; namespace AasxServerStandardBib { + using System.Text.Json; + public class TimeSeriesPlotting { public enum TimeSeriesTimeAxis { None, Utc, Tai, Plain, Duration } @@ -52,6 +49,7 @@ public static CumulativeDataItems GenerateCumulativeDataItems( res.Position.Add(pos); pos += 1.0; } + return res; } @@ -107,7 +105,7 @@ public List RenderTimeSeries(double defPlotHeight, string d // which kind of chart? if (tsd.Args != null && (tsd.Args.type == PlotArguments.Type.Bars - || tsd.Args.type == PlotArguments.Type.Pie)) + || tsd.Args.type == PlotArguments.Type.Pie)) { // // Cumulative plots (e.g. the last sample, bars, pie, ..) @@ -129,8 +127,8 @@ public List RenderTimeSeries(double defPlotHeight, string d // generate cumulative data //var cum = tsd.DataSet.GenerateCumulativeData(pvc.LatestSamplePosition); - var cum = tsd.DataSet.GenerateCumulativeData(10); // TODO: Hardcoded value -1 instead of using LatestSamplePosition - var cumdi = GenerateCumulativeDataItems(cum, defaultLang); + var cum = tsd.DataSet.GenerateCumulativeData(10); // TODO: Hardcoded value -1 instead of using LatestSamplePosition + var cumdi = GenerateCumulativeDataItems(cum, defaultLang); var plottable = GenerateCumulativePlottable(plt, cumdi, tsd.Args); if (plottable == null) continue; @@ -138,7 +136,7 @@ public List RenderTimeSeries(double defPlotHeight, string d // render the plottable into panel //panel.Children.Add(pvc); - plt.Render(/* skipIfCurrentlyRendering: true */); + plt.Render( /* skipIfCurrentlyRendering: true */); plt.SaveFig("wwwroot/images/scottplot/smc_timeseries_clientid" + sessionNumber + ".png"); @@ -167,8 +165,8 @@ public List RenderTimeSeries(double defPlotHeight, string d PlotHelpers.SetOverallPlotProperties(null, plt, tsd.Args, defPlotHeight); ScottPlot.Plot lastPlot = null; - var xLabels = "Time ( "; - int yAxisNum = 0; + var xLabels = "Time ( "; + int yAxisNum = 0; // TODO: wpfPlot name variable var wpfPlot = plt; @@ -180,7 +178,7 @@ public List RenderTimeSeries(double defPlotHeight, string d var moveOrder = new List>(); // for each signal - double? yMin = null, yMax = null; + double? yMin = null, yMax = null; TimeSeriesDataSet lastTimeRecord = null; foreach (var tsds in tsd.DataSet) @@ -192,8 +190,8 @@ public List RenderTimeSeries(double defPlotHeight, string d // if its a time axis, skip but remember for following axes if (tsds.TimeAxis != TimeSeriesTimeAxis.None) { - lastTimeRecord = tsds; - xLabels += "" + tsds.DataSetId + " "; + lastTimeRecord = tsds; + xLabels += "" + tsds.DataSetId + " "; continue; } @@ -249,15 +247,15 @@ public List RenderTimeSeries(double defPlotHeight, string d // factory new Plottable - ScottPlot.Plottable.BarPlot bars = null; + ScottPlot.Plottable.BarPlot bars = null; ScottPlot.Plottable.ScatterPlot scatter = null; if (tsds.Args != null && tsds.Args.type == PlotArguments.Type.Bars) { // Bars bars = wpfPlot.AddBar( - positions: timeDStoUse.RenderDataToLimits(), - values: tsds.RenderDataToLimits()); + positions: timeDStoUse.RenderDataToLimits(), + values: tsds.RenderDataToLimits()); PlotHelpers.SetPlottableProperties(scatter, tsds.Args); @@ -266,7 +264,7 @@ public List RenderTimeSeries(double defPlotHeight, string d { // Note: pretty trivial approach, yet var timeDelta = (timeDStoUse.Data[1] - timeDStoUse.Data[0]); - var bw = timeDelta * .8; + var bw = timeDelta * .8; // apply bar width? if (tsds.Args?.barwidth != null) @@ -288,8 +286,8 @@ public List RenderTimeSeries(double defPlotHeight, string d } bars.Label = PlotHelpers.EvalDisplayText("" + tsds.DataSetId, - tsds.DataPoint, tsds.DataPointCD, - addMinimalTxt: true, defaultLang: defaultLang, useIdShort: false); + tsds.DataPoint, tsds.DataPointCD, + addMinimalTxt: true, defaultLang: defaultLang, useIdShort: false); tsds.Plottable = bars; } @@ -299,13 +297,13 @@ public List RenderTimeSeries(double defPlotHeight, string d { // Default: Scatter plot scatter = wpfPlot.AddScatter( - //xs: timeDStoUse.Data, - //ys: tsds.Data, - xs: xsFilteredList.ToArray(), - ys: ysFilteredList.ToArray(), - label: PlotHelpers.EvalDisplayText("" + tsds.DataSetId, - tsds.DataPoint, tsds.DataPointCD, - addMinimalTxt: true, defaultLang: defaultLang, useIdShort: false)); + //xs: timeDStoUse.Data, + //ys: tsds.Data, + xs: xsFilteredList.ToArray(), + ys: ysFilteredList.ToArray(), + label: PlotHelpers.EvalDisplayText("" + tsds.DataSetId, + tsds.DataPoint, tsds.DataPointCD, + addMinimalTxt: true, defaultLang: defaultLang, useIdShort: false)); PlotHelpers.SetPlottableProperties(scatter, tsds.Args); @@ -318,15 +316,15 @@ public List RenderTimeSeries(double defPlotHeight, string d } // axis treatment? - bool sameAxis = (tsds.Args?.sameaxis == true) && (yAxisNum != 0); - int assignAxis = -1; - ScottPlot.Renderable.Axis yAxis3 = null; + bool sameAxis = (tsds.Args?.sameaxis == true) && (yAxisNum != 0); + int assignAxis = -1; + ScottPlot.Renderable.Axis yAxis3 = null; if (!sameAxis) { yAxisNum++; if (yAxisNum >= 2) { - yAxis3 = wpfPlot.AddAxis(ScottPlot.Renderable.Edge.Right, axisIndex: yAxisNum); + yAxis3 = wpfPlot.AddAxis(ScottPlot.Renderable.Edge.Right, axisIndex: yAxisNum); assignAxis = yAxisNum; } } @@ -376,7 +374,7 @@ public List RenderTimeSeries(double defPlotHeight, string d // time axis if (lastTimeRecord != null && (lastTimeRecord.TimeAxis == TimeSeriesTimeAxis.Utc - || lastTimeRecord.TimeAxis == TimeSeriesTimeAxis.Tai)) + || lastTimeRecord.TimeAxis == TimeSeriesTimeAxis.Tai)) { wpfPlot.XAxis.DateTimeFormat(true); } @@ -684,6 +682,7 @@ public TimeSeriesDataSet FindDataForTimeAxis(bool findUtc = false, bool findTai if (tsd.TimeAxis == TimeSeriesTimeAxis.Tai && findTai) return tsd; } + return null; } } @@ -703,7 +702,7 @@ public class TimeSeriesDataSet public TimeSeriesMinMaxDouble ValueLimits = TimeSeriesMinMaxDouble.Invalid; protected TimeSeriesMinMaxInt _dataLimits; - protected double[] data = new[] { 0.0 }; + protected double[] data = new[] {0.0}; public double[] Data { get { return data; } } public ScottPlot.Plottable.IPlottable Plottable; @@ -723,7 +722,7 @@ public void DataAdd(string json, bool fillTimeGaps = false) // now, if the first time, start with good limits if (_dataLimits == null) - _dataLimits = new TimeSeriesMinMaxInt() { Min = tempLimits.Min, Max = tempLimits.Min }; + _dataLimits = new TimeSeriesMinMaxInt() {Min = tempLimits.Min, Max = tempLimits.Min}; // extend to the left? if (tempLimits.Min < _dataLimits.Min) @@ -757,7 +756,7 @@ public void DataAdd(string json, bool fillTimeGaps = false) if (fillTimeGaps && temp[0].Value.HasValue) { var startIndex = temp[0].Index; - var startVal = temp[0].Value.Value; + var startVal = temp[0].Value.Value; for (int i = startIndex - 1; i >= _dataLimits.Min; i--) { // data to the left present? -> stop @@ -791,7 +790,7 @@ public void DataAdd(int index, double value, int headroom = 1024) { // now, if the first time, start with good limits if (_dataLimits == null) - _dataLimits = new TimeSeriesMinMaxInt() { Min = index, Max = index }; + _dataLimits = new TimeSeriesMinMaxInt() {Min = index, Max = index}; // extend to the left? if (index < _dataLimits.Min) @@ -921,21 +920,21 @@ public TimeSeriesMinMaxInt GetMinMaxIndex() if (dp.Index > res.Max) res.Max = dp.Index; } + return res; } public void Add(string json, TimeSeriesTimeAxis timeAxis) { // simple state machine approch to pseudo parse-json - var state = 0; - int i = 0; - var err = false; + var state = 0; + int i = 0; + var err = false; var bufIndex = ""; var bufValue = ""; while (!err && i < json.Length) { - switch (state) { // expecting inner '[' @@ -943,12 +942,11 @@ public void Add(string json, TimeSeriesTimeAxis timeAxis) if (json[i] == '[') { // prepare first buffer - state = 1; + state = 1; bufIndex = ""; i++; } - else - if (json[i] == ',' || Char.IsWhiteSpace(json[i])) + else if (json[i] == ',' || Char.IsWhiteSpace(json[i])) { // ignore whitespace i++; @@ -958,6 +956,7 @@ public void Add(string json, TimeSeriesTimeAxis timeAxis) // break with error err = true; } + break; // parsing 1st buffer: index @@ -965,18 +964,16 @@ public void Add(string json, TimeSeriesTimeAxis timeAxis) if (json[i] == ',') { // prepare second buffer - state = 2; + state = 2; bufValue = ""; i++; } - else - if ("0123456789-+.TZ\"".IndexOf(json[i]) >= 0) + else if ("0123456789-+.TZ\"".IndexOf(json[i]) >= 0) { bufIndex += json[i]; i++; } - else - if (Char.IsWhiteSpace(json[i])) + else if (Char.IsWhiteSpace(json[i])) { // ignore whitespace i++; @@ -986,6 +983,7 @@ public void Add(string json, TimeSeriesTimeAxis timeAxis) // break with error err = true; } + break; // parsing 2nd buffer: value @@ -995,18 +993,14 @@ public void Add(string json, TimeSeriesTimeAxis timeAxis) // ok, finalize if (int.TryParse(bufIndex, out int iIndex)) { - var dp = new TimeSeriesDataPoint() - { - Index = iIndex, - ValStr = bufValue - }; + var dp = new TimeSeriesDataPoint() {Index = iIndex, ValStr = bufValue}; if (timeAxis == TimeSeriesTimeAxis.Utc || timeAxis == TimeSeriesTimeAxis.Tai) { // strict time string if (DateTime.TryParseExact(bufValue, - "yyyy-MM-dd'T'HH:mm:ss.FFFFFFF'Z'", CultureInfo.InvariantCulture, - DateTimeStyles.AdjustToUniversal, out DateTime dt)) + "yyyy-MM-dd'T'HH:mm:ss.FFFFFFF'Z'", CultureInfo.InvariantCulture, + DateTimeStyles.AdjustToUniversal, out DateTime dt)) { dp.Value = dt.ToOADate(); } @@ -1019,9 +1013,10 @@ public void Add(string json, TimeSeriesTimeAxis timeAxis) { // plain time or plain value if (double.TryParse(bufValue, NumberStyles.Float, - CultureInfo.InvariantCulture, out double fValue)) + CultureInfo.InvariantCulture, out double fValue)) dp.Value = fValue; } + this.Add(dp); } @@ -1029,14 +1024,12 @@ public void Add(string json, TimeSeriesTimeAxis timeAxis) state = 0; i++; } - else - if ("0123456789-+.:TZ\"".IndexOf(json[i]) >= 0) + else if ("0123456789-+.:TZ\"".IndexOf(json[i]) >= 0) { bufValue += json[i]; i++; } - else - if (Char.IsWhiteSpace(json[i])) + else if (Char.IsWhiteSpace(json[i])) { // ignore whitespace i++; @@ -1046,11 +1039,10 @@ public void Add(string json, TimeSeriesTimeAxis timeAxis) // break with error err = true; } + break; } - } - } } @@ -1058,10 +1050,11 @@ public class TimeSeriesMinMaxDouble { public double Min; public double Max; - public bool IsValid { get { return Min != double.MaxValue && Max != double.MinValue; } } - public double Span { get { return Max - Min; } } + public bool IsValid { get { return Min != double.MaxValue && Max != double.MinValue; } } + public double Span { get { return Max - Min; } } + public static TimeSeriesMinMaxDouble Invalid => - new TimeSeriesMinMaxDouble() { Min = double.MaxValue, Max = double.MinValue }; + new TimeSeriesMinMaxDouble() {Min = double.MaxValue, Max = double.MinValue}; } public class TimeSeriesMinMaxInt @@ -1069,9 +1062,10 @@ public class TimeSeriesMinMaxInt public int Min; public int Max; public bool IsValid { get { return Min != int.MaxValue && Max != int.MinValue; } } - public int Span { get { return Max - Min; } } + public int Span { get { return Max - Min; } } + public static TimeSeriesMinMaxInt Invalid => - new TimeSeriesMinMaxInt() { Min = int.MaxValue, Max = int.MinValue }; + new TimeSeriesMinMaxInt() {Min = int.MaxValue, Max = int.MinValue}; } public class ListOfTimeSeriesDataSet : List @@ -1234,7 +1228,7 @@ public static PlotArguments Parse(string json) try { - var res = Newtonsoft.Json.JsonConvert.DeserializeObject(json); + var res = JsonSerializer.Deserialize(json); return res; } catch (Exception ex) @@ -1265,10 +1259,10 @@ public ScottPlot.Styles.IStyle GetScottStyle() } public static void TimeSeriesAddSegmentData( - ZveiTimeSeriesDataV10 pcts, - //AdminShell.Key.MatchMode mm, - TimeSeriesData tsd, - SubmodelElementCollection smcseg) + ZveiTimeSeriesDataV10 pcts, + //AdminShell.Key.MatchMode mm, + TimeSeriesData tsd, + SubmodelElementCollection smcseg) { // access if (pcts == null || smcseg == null) @@ -1276,34 +1270,35 @@ public static void TimeSeriesAddSegmentData( // challenge is to select SMes, which are NOT from a known semantic id! var tsvAllowed = new[] - { - //pcts.CD_RecordId.Id, - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/RecordId/1/0" /*pcts.CD_RecordId.Id*/, - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/UtcTime/1/0" /*pcts.CD_UtcTime.Id*/, - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/TaiTime/1/0" /*pcts.CD_TaiTime.Id*/, - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/Time/1/0" /*pcts.CD_Time.Id*/, - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeDuration/1/0" /*pcts.CD_TimeDuration.Id*/, - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/ValueArray/1/0" /*pcts.CD_ValueArray.Id*/, - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/ExternalDataFile/1/0" /*pcts.CD_ExternalDataFile.Id*/ - }; + { + //pcts.CD_RecordId.Id, + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/RecordId/1/0" /*pcts.CD_RecordId.Id*/, + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/UtcTime/1/0" /*pcts.CD_UtcTime.Id*/, + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/TaiTime/1/0" /*pcts.CD_TaiTime.Id*/, + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/Time/1/0" /*pcts.CD_Time.Id*/, + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeDuration/1/0" /*pcts.CD_TimeDuration.Id*/, + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/ValueArray/1/0" /*pcts.CD_ValueArray.Id*/, + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/ExternalDataFile/1/0" /*pcts.CD_ExternalDataFile.Id*/ + }; var tsrAllowed = new[] - { - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/RecordId/1/0" /*pcts.CD_RecordId.Id*/, - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/UtcTime/1/0" /*pcts.CD_UtcTime.Id*/, - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/TaiTime/1/0" /*pcts.CD_TaiTime.Id*/, - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/Time/1/0" /*pcts.CD_Time.Id*/, - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeDuration/1/0" /*pcts.CD_TimeDuration.Id*/, - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/ValueArray/1/0" /*pcts.CD_ValueArray.Id*/ - }; + { + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/RecordId/1/0" /*pcts.CD_RecordId.Id*/, + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/UtcTime/1/0" /*pcts.CD_UtcTime.Id*/, + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/TaiTime/1/0" /*pcts.CD_TaiTime.Id*/, + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/Time/1/0" /*pcts.CD_Time.Id*/, + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeDuration/1/0" /*pcts.CD_TimeDuration.Id*/, + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/ValueArray/1/0" /*pcts.CD_ValueArray.Id*/ + }; // find variables? foreach (var smcvar in smcseg.Value.FindAllSemanticIdAs( - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeSeriesVariable/1/0" /*pcts.CD_TimeSeriesVariable.Id*/)) + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeSeriesVariable/1/0" /*pcts.CD_TimeSeriesVariable.Id*/)) { // makes only sense with record id var recid = "" + smcvar.Value.FindFirstSemanticIdAs( - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/RecordId/1/0" /*pcts.CD_RecordId.Id*/)?.Value?.Trim(); + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/RecordId/1/0" /*pcts.CD_RecordId.Id*/)?.Value + ?.Trim(); if (recid.Length < 1) continue; @@ -1311,7 +1306,7 @@ public static void TimeSeriesAddSegmentData( //var valarr = "" + smcvar.Value.FindFirstSemanticIdAs(pcts.CD_ValueArray.Id)?.Value?.Trim(); var vv = smcvar.Value.FindFirstSemanticIdAs("https://admin-shell.io/sandbox/zvei/TimeSeriesData/ValueArray/1/0"); var valarr = "" + smcvar.Value.FindFirstSemanticIdAs("https://admin-shell.io/sandbox/zvei/TimeSeriesData/ValueArray/1/0" - /*pcts.CD_ValueArray.Id*/).Value.ToString().Trim(); + /*pcts.CD_ValueArray.Id*/).Value.ToString().Trim(); valarr = System.Text.Encoding.ASCII.GetString(vv.Value); if (valarr.Length < 1) continue; @@ -1321,7 +1316,7 @@ public static void TimeSeriesAddSegmentData( if (ds == null) { // add - ds = new TimeSeriesDataSet() { DataSetId = recid }; + ds = new TimeSeriesDataSet() {DataSetId = recid}; tsd.DataSet.Add(ds); // at this very moment, check if this is a time series @@ -1347,11 +1342,12 @@ public static void TimeSeriesAddSegmentData( // find records? foreach (var smcrec in smcseg.Value.FindAllSemanticIdAs( - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeSeriesRecord/1/0" /*pcts.CD_TimeSeriesRecord.Id)*/)) + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeSeriesRecord/1/0" /*pcts.CD_TimeSeriesRecord.Id)*/)) { // makes only sense with a numerical record id var recid = "" + smcrec.Value.FindFirstSemanticIdAs( - "https://admin-shell.io/sandbox/zvei/TimeSeriesData/RecordId/1/0" /*pcts.CD_RecordId.Id*/)?.Value?.Trim(); + "https://admin-shell.io/sandbox/zvei/TimeSeriesData/RecordId/1/0" /*pcts.CD_RecordId.Id*/)?.Value + ?.Trim(); if (recid.Length < 1) continue; if (!int.TryParse(recid, out var dataIndex)) @@ -1380,7 +1376,7 @@ public static void TimeSeriesAddSegmentData( if (ds == null) { // add - ds = new TimeSeriesDataSet() { DataSetId = dsid }; + ds = new TimeSeriesDataSet() {DataSetId = dsid}; tsd.DataSet.Add(ds); // find a DataPoint description? .. store it! @@ -1396,10 +1392,7 @@ public static void TimeSeriesAddSegmentData( else { // create this - ds.AssignedTimeDS = new TimeSeriesDataSet() - { - DataSetId = "Time_" + timeSpec.Item1.ToString() - }; + ds.AssignedTimeDS = new TimeSeriesDataSet() {DataSetId = "Time_" + timeSpec.Item1.ToString()}; tsd.TimeDsLookup[timeSpec.Item1] = ds.AssignedTimeDS; } @@ -1409,7 +1402,7 @@ public static void TimeSeriesAddSegmentData( // now access the value of the data point as float value if (!double.TryParse(pdp.Value, NumberStyles.Float, - CultureInfo.InvariantCulture, out var dataValue)) + CultureInfo.InvariantCulture, out var dataValue)) continue; // TimeDS and time is required @@ -1434,8 +1427,8 @@ public static void TimeSeriesAddSegmentData( { // strict time string if (DateTime.TryParseExact(bufValue, - "yyyy-MM-dd'T'HH:mm:ssZ", CultureInfo.InvariantCulture, - DateTimeStyles.AdjustToUniversal, out DateTime dt)) + "yyyy-MM-dd'T'HH:mm:ssZ", CultureInfo.InvariantCulture, + DateTimeStyles.AdjustToUniversal, out DateTime dt)) { return dt.ToOADate(); } @@ -1443,7 +1436,7 @@ public static void TimeSeriesAddSegmentData( // plain time or plain value if (double.TryParse(bufValue, NumberStyles.Float, - CultureInfo.InvariantCulture, out double fValue)) + CultureInfo.InvariantCulture, out double fValue)) return fValue; // no? @@ -1484,16 +1477,16 @@ public ZveiTimeSeriesDataV10() // Referable this.ReadLibrary( - Assembly.GetExecutingAssembly(), "Resources." + "ZveiTimeSeriesDataV10.json"); + Assembly.GetExecutingAssembly(), "Resources." + "ZveiTimeSeriesDataV10.json"); // this.RetrieveEntriesFromLibraryByReflection(typeof(ZveiTimeSeriesDataV10), useFieldNames: true); } } protected static Tuple - DetectTimeSpecifier( - ZveiTimeSeriesDataV10 pcts, - //AdminShell.Key.MatchMode mm, - SubmodelElementCollection smc) + DetectTimeSpecifier( + ZveiTimeSeriesDataV10 pcts, + //AdminShell.Key.MatchMode mm, + SubmodelElementCollection smc) { // access if (smc?.Value == null || pcts == null) @@ -1533,9 +1526,10 @@ public class LibraryEntry public string contents = ""; public LibraryEntry() { } + public LibraryEntry(string name, string contents) { - this.name = name; + this.name = name; this.contents = contents; } } @@ -1556,52 +1550,34 @@ public LibraryEntry(string name, string contents) public AasxDefinitionBase() { } - public AasxDefinitionBase(Assembly assembly, string resourceName) - { - this.theLibrary = BuildLibrary(assembly, resourceName); - } + public AasxDefinitionBase(Assembly assembly, string resourceName) => theLibrary = BuildLibrary(assembly, resourceName); // // Rest // - public void ReadLibrary(Assembly assembly, string resourceName) - { - this.theLibrary = BuildLibrary(assembly, resourceName); - } + public void ReadLibrary(Assembly assembly, string resourceName) => theLibrary = BuildLibrary(assembly, resourceName); protected Dictionary BuildLibrary(Assembly assembly, string resourceName) { // empty result var res = new Dictionary(); - // access resource - //var stream = assembly.GetManifestResourceStream(resourceName); - //if (stream == null) - // return res; - // read text - //TextReader tr = new StreamReader(stream); - //var jsonStr = tr.ReadToEnd(); - var jsonStr = "{ \"SM_TimeSeriesData\": { \"semanticId\": { \"keys\": [ { \"type\": \"GlobalReference\", \"local\": false, \"value\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/1/0\", \"index\": 0, \"idType\": \"IRI\" } ] }, \"qualifiers\": [], \"hasDataSpecification\": [], \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TimeSeriesData\", \"category\": null, \"modelType\": { \"name\": \"Submodel\" }, \"kind\": \"Template\", \"descriptions\": [ { \"language\": \"de\", \"text\": \"Enthält Zeitreihendaten und Referenzen auf Zeitreihendaten, um diese entlang des Asset Lebenszyklus aufzufinden und semantisch zu beschreiben.\" }, { \"language\": \"en\", \"text\": \"Contains time series data and references to time series data to discover and semantically describe them along the asset lifecycle.\" } ] }, \"CD_TimeSeries\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeSeries/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TimeSeries\", \"category\": null, \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitreihe\" }, { \"language\": \"en\", \"text\": \"Time series\" } ], \"shortName\": [ { \"language\": \"de\", \"text\": \"Zeitreihe\" }, { \"language\": \"en\", \"text\": \"TimeSeries\" } ], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Abfolge von Datenpunkten in aufeinanderfolgender Reihenfolge über einen bestimmten Zeitraum.\" }, { \"language\": \"en\", \"text\": \"Sequence of data points in successive order over a specified period of time.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_Name\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/Name/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"Name\", \"category\": \"PARAMETER\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Name der Zeitreihe\" }, { \"language\": \"en\", \"text\": \"Name of the time series\" } ], \"shortName\": [ { \"language\": \"de\", \"text\": \"Name\" }, { \"language\": \"en\", \"text\": \"Name\" } ], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"STRING_TRANSLATABLE\", \"definition\": [ { \"language\": \"de\", \"text\": \"Aussagekräftiger Name zur Beschriftung.\" }, { \"language\": \"en\", \"text\": \"Meaningful name for labeling\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_Description\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/Description/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"Description\", \"category\": \"PARAMETER\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Beschreibung der Zeitreihe\" }, { \"language\": \"en\", \"text\": \"Description of the time series\" } ], \"shortName\": [ { \"language\": \"de\", \"text\": \"Beschreibung\" }, { \"language\": \"en\", \"text\": \"Description\" } ], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"STRING_TRANSLATABLE\", \"definition\": [ { \"language\": \"de\", \"text\": \"Kurze Beschreibung der Zeitreihendaten.\" }, { \"language\": \"en\", \"text\": \"Short description of the time series.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_TimeSeriesSegment\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeSeriesSegment/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TimeSeriesSegment\", \"category\": null, \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitreihensegment\" }, { \"language\": \"en\", \"text\": \"Time series segment\" } ], \"shortName\": [ { \"language\": \"de\", \"text\": \"Segment\" }, { \"language\": \"en\", \"text\": \"Segment\" } ], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Abfolge von Datenpunkten in aufeinanderfolgender Reihenfolge über einen bestimmten Zeitraum.\" }, { \"language\": \"en\", \"text\": \"Sequence of data points in successive order over a specified period of time.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_RecordCount\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/RecordCount/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"RecordCount\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Anzahl der Datensätze\" }, { \"language\": \"en\", \"text\": \"Record count\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"REAL_COUNT\", \"definition\": [ { \"language\": \"de\", \"text\": \"Gibt an, wie viele Datensätze in einem Segment vorhanden sind.\" }, { \"language\": \"en\", \"text\": \"Indicates how many records are present in a segment.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_StartTime\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/StartTime/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"StartTime\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Startzeit\" }, { \"language\": \"en\", \"text\": \"Start time\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Enthält den ersten aufgezeichneten Zeitstempel des Zeitreihensegments und stellt somit den Anfang einer Zeitreihe dar. Zeitformat und -skala entspricht dem der Zeitreihe.\" }, { \"language\": \"en\", \"text\": \"Contains the first recorded timestamp of the time series segment and thus represents the beginning of a time series. Time format and scale corresponds to that of the time series.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_EndTime\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/EndTime/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"EndTime\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Endzeit\" }, { \"language\": \"en\", \"text\": \"End time\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Enthält den letzten aufgezeichneten Zeitstempel des Zeitreihensegments und stellt somit das Ende einer Zeitreihe dar. Zeitformat und -skala entspricht dem der Zeitreihe.\" }, { \"language\": \"en\", \"text\": \"Contains the last recorded timestamp of the time series segment and thus represents the end of a time series. Time format and scale corresponds to that of the time series.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_SamplingInterval\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/SamplingInterval/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"SamplingInterval\", \"category\": \"PARAMETER\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Abtastintervall\" }, { \"language\": \"en\", \"text\": \"Sampling interval\" } ], \"shortName\": [], \"unit\": \"s\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": \"t\", \"dataType\": \"REAL_MEASURE\", \"definition\": [ { \"language\": \"de\", \"text\": \"Der zeitliche Abstand zwischen zwei Datenpunkten (Länge eines Zyklus).\" }, { \"language\": \"en\", \"text\": \"The time period between two time series records (Length of cycle).\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_SamplingRate\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/SamplingRate/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"SamplingRate\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Abtastrate\" }, { \"language\": \"en\", \"text\": \"Sampling rate\" } ], \"shortName\": [], \"unit\": \"Hz\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"REAL_MEASURE\", \"definition\": [ { \"language\": \"de\", \"text\": \"Definiert die Anzahl der Abtastungen pro Sekunde für eine regelmäßige Zeitreihe in Hz.\" }, { \"language\": \"en\", \"text\": \"Defines the number of samples per second for a regular time series in Hz.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_TimeSeriesRecord\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeSeriesRecord/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TimeSeriesRecord\", \"category\": null, \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitreihen-Datensatz\" }, { \"language\": \"en\", \"text\": \"Time series record\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Ein Zeitreihen-Datensatz ist durch seine ID innerhalb der Zeitreihe eindeutig und beinhaltet die auf die ID referenzierten Zeitstempel und Variablenwerte. Vergleichbar mit einer Zeile in einer Tabelle.\" }, { \"language\": \"en\", \"text\": \"A time series record is unique by its ID within the time series and contains the timestamps and variable values referenced to the ID. Similar to a row in a table.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_RecordId\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/RecordId/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"RecordId\", \"category\": \"PARAMETER\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"ID\" }, { \"language\": \"en\", \"text\": \"ID\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"STRING\", \"definition\": [ { \"language\": \"en\", \"text\": \"Labels the record within a time series with a unique ID.\" }, { \"language\": \"de\", \"text\": \"Kennzeichnet den Datensatz innerhalb einer Zeitreihe mit einer eindeutigen ID. \" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_UtcTime\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/UtcTime/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"UtcTime\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitstempel UTC\" }, { \"language\": \"en\", \"text\": \"timestamp UTC\" } ], \"shortName\": [ { \"language\": \"de\", \"text\": \"Zeitstempel UTC\" }, { \"language\": \"en\", \"text\": \"timestamp UTC\" } ], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"TIMESTAMP\", \"definition\": [ { \"language\": \"de\", \"text\": \"Zeitstempel nach ISO 8601 auf der Zeitskala der koordinierten Weltzeit (UTC).\" }, { \"language\": \"en\", \"text\": \"Timestamp according to ISO 8601 on the timescale ccordinated universal time (UTC).\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_TaiTime\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/TaiTime/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TaiTime\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitstempel TAI\" }, { \"language\": \"en\", \"text\": \"timestamp TAI\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"TIMESTAMP\", \"definition\": [ { \"language\": \"de\", \"text\": \"Zeitstempel nach ISO 8601 auf der Zeitskala internationale Atomzeit (TAI).\" }, { \"language\": \"en\", \"text\": \"Timestamp according to ISO 8601 on the timescale international atomic time (TAI).\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_Time\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/Time/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"Time\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitstempel\" }, { \"language\": \"en\", \"text\": \"Timestamp\" } ], \"shortName\": [], \"unit\": \"s\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": \"t\", \"dataType\": \"REAL_MEASURE\", \"definition\": [ { \"language\": \"de\", \"text\": \"Zeitpunktangabe in Sekunden. Zeitpunkte referenzieren auf die Startzeit des Zeitreihensegments.\" }, { \"language\": \"en\", \"text\": \"Point of Time in seconds. Time points refer to the start time of the time series segment.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_TimeDuration\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeDuration/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TimeDuration\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitdauer\" }, { \"language\": \"en\", \"text\": \"Timeduration\" } ], \"shortName\": [], \"unit\": \"s\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": \"\", \"dataType\": \"REAL_MEASURE\", \"definition\": [ { \"language\": \"de\", \"text\": \"Angabe der zeitlichen Dauer in Sekunden (Anzahl der Sekunden). Zeitdauern referenzieren auf den jeweils vorangegangenen Eintrag im Zeitreihensegment.\" }, { \"language\": \"en\", \"text\": \"Time duration specification in seconds. (number of seconds). Time durations refer to the previous entry in the time series segment.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_TimeSeriesVariable\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeSeriesVariable/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TimeSeriesVariable\", \"category\": null, \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitreihenvariable\" }, { \"language\": \"en\", \"text\": \"Time series variable\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Eine Zeitreihenvariable bildet eine Wertereihe, bestehend aus RecordID und einer weiteren Dimension der Zeitreihe, als Array ab. Vergleichbar einer Spalte in einer Tabelle. Variablen können Zeitstempel oder Datenpunkte sein.\" }, { \"language\": \"en\", \"text\": \"A time series variable contains the sequence of values, consisting of RecordID and another dimension of the time series, as an array. Similar to a column in a table. Variables can be timestamps or data points.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_ValueArray\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/ValueArray/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"ValueArray\", \"category\": \"PARAMETER\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Wertereihe\" }, { \"language\": \"en\", \"text\": \"Value Array\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Wertereihe einer einer Zeitreihe. Die Reihenfolge der Dimensionen und deren semantische Beueutung ergibt sich aus den Definitionen innerhalb der Zeitreihenvariable. \" }, { \"language\": \"en\", \"text\": \"Values of a time series. The order of the dimensions and their semantic meaning results from the definitions within the time series variable. \" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_ExternalDataFile\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/ExternalDataFile/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"ExternalDataFile\", \"category\": null, \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Externe Datendatei\" }, { \"language\": \"en\", \"text\": \"External data file\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Externe Datendatei, welche Zeitreihendaten in einem beliebigen Format beinhaltet.\" }, { \"language\": \"en\", \"text\": \"External data file containing time series data in any format.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null } }"; - //stream.Close(); + var jsonStr + = "{ \"SM_TimeSeriesData\": { \"semanticId\": { \"keys\": [ { \"type\": \"GlobalReference\", \"local\": false, \"value\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/1/0\", \"index\": 0, \"idType\": \"IRI\" } ] }, \"qualifiers\": [], \"hasDataSpecification\": [], \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TimeSeriesData\", \"category\": null, \"modelType\": { \"name\": \"Submodel\" }, \"kind\": \"Template\", \"descriptions\": [ { \"language\": \"de\", \"text\": \"Enthält Zeitreihendaten und Referenzen auf Zeitreihendaten, um diese entlang des Asset Lebenszyklus aufzufinden und semantisch zu beschreiben.\" }, { \"language\": \"en\", \"text\": \"Contains time series data and references to time series data to discover and semantically describe them along the asset lifecycle.\" } ] }, \"CD_TimeSeries\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeSeries/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TimeSeries\", \"category\": null, \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitreihe\" }, { \"language\": \"en\", \"text\": \"Time series\" } ], \"shortName\": [ { \"language\": \"de\", \"text\": \"Zeitreihe\" }, { \"language\": \"en\", \"text\": \"TimeSeries\" } ], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Abfolge von Datenpunkten in aufeinanderfolgender Reihenfolge über einen bestimmten Zeitraum.\" }, { \"language\": \"en\", \"text\": \"Sequence of data points in successive order over a specified period of time.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_Name\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/Name/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"Name\", \"category\": \"PARAMETER\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Name der Zeitreihe\" }, { \"language\": \"en\", \"text\": \"Name of the time series\" } ], \"shortName\": [ { \"language\": \"de\", \"text\": \"Name\" }, { \"language\": \"en\", \"text\": \"Name\" } ], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"STRING_TRANSLATABLE\", \"definition\": [ { \"language\": \"de\", \"text\": \"Aussagekräftiger Name zur Beschriftung.\" }, { \"language\": \"en\", \"text\": \"Meaningful name for labeling\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_Description\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/Description/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"Description\", \"category\": \"PARAMETER\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Beschreibung der Zeitreihe\" }, { \"language\": \"en\", \"text\": \"Description of the time series\" } ], \"shortName\": [ { \"language\": \"de\", \"text\": \"Beschreibung\" }, { \"language\": \"en\", \"text\": \"Description\" } ], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"STRING_TRANSLATABLE\", \"definition\": [ { \"language\": \"de\", \"text\": \"Kurze Beschreibung der Zeitreihendaten.\" }, { \"language\": \"en\", \"text\": \"Short description of the time series.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_TimeSeriesSegment\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeSeriesSegment/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TimeSeriesSegment\", \"category\": null, \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitreihensegment\" }, { \"language\": \"en\", \"text\": \"Time series segment\" } ], \"shortName\": [ { \"language\": \"de\", \"text\": \"Segment\" }, { \"language\": \"en\", \"text\": \"Segment\" } ], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Abfolge von Datenpunkten in aufeinanderfolgender Reihenfolge über einen bestimmten Zeitraum.\" }, { \"language\": \"en\", \"text\": \"Sequence of data points in successive order over a specified period of time.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_RecordCount\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/RecordCount/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"RecordCount\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Anzahl der Datensätze\" }, { \"language\": \"en\", \"text\": \"Record count\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"REAL_COUNT\", \"definition\": [ { \"language\": \"de\", \"text\": \"Gibt an, wie viele Datensätze in einem Segment vorhanden sind.\" }, { \"language\": \"en\", \"text\": \"Indicates how many records are present in a segment.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_StartTime\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/StartTime/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"StartTime\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Startzeit\" }, { \"language\": \"en\", \"text\": \"Start time\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Enthält den ersten aufgezeichneten Zeitstempel des Zeitreihensegments und stellt somit den Anfang einer Zeitreihe dar. Zeitformat und -skala entspricht dem der Zeitreihe.\" }, { \"language\": \"en\", \"text\": \"Contains the first recorded timestamp of the time series segment and thus represents the beginning of a time series. Time format and scale corresponds to that of the time series.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_EndTime\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/EndTime/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"EndTime\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Endzeit\" }, { \"language\": \"en\", \"text\": \"End time\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Enthält den letzten aufgezeichneten Zeitstempel des Zeitreihensegments und stellt somit das Ende einer Zeitreihe dar. Zeitformat und -skala entspricht dem der Zeitreihe.\" }, { \"language\": \"en\", \"text\": \"Contains the last recorded timestamp of the time series segment and thus represents the end of a time series. Time format and scale corresponds to that of the time series.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_SamplingInterval\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/SamplingInterval/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"SamplingInterval\", \"category\": \"PARAMETER\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Abtastintervall\" }, { \"language\": \"en\", \"text\": \"Sampling interval\" } ], \"shortName\": [], \"unit\": \"s\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": \"t\", \"dataType\": \"REAL_MEASURE\", \"definition\": [ { \"language\": \"de\", \"text\": \"Der zeitliche Abstand zwischen zwei Datenpunkten (Länge eines Zyklus).\" }, { \"language\": \"en\", \"text\": \"The time period between two time series records (Length of cycle).\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_SamplingRate\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/SamplingRate/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"SamplingRate\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Abtastrate\" }, { \"language\": \"en\", \"text\": \"Sampling rate\" } ], \"shortName\": [], \"unit\": \"Hz\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"REAL_MEASURE\", \"definition\": [ { \"language\": \"de\", \"text\": \"Definiert die Anzahl der Abtastungen pro Sekunde für eine regelmäßige Zeitreihe in Hz.\" }, { \"language\": \"en\", \"text\": \"Defines the number of samples per second for a regular time series in Hz.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_TimeSeriesRecord\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeSeriesRecord/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TimeSeriesRecord\", \"category\": null, \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitreihen-Datensatz\" }, { \"language\": \"en\", \"text\": \"Time series record\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Ein Zeitreihen-Datensatz ist durch seine ID innerhalb der Zeitreihe eindeutig und beinhaltet die auf die ID referenzierten Zeitstempel und Variablenwerte. Vergleichbar mit einer Zeile in einer Tabelle.\" }, { \"language\": \"en\", \"text\": \"A time series record is unique by its ID within the time series and contains the timestamps and variable values referenced to the ID. Similar to a row in a table.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_RecordId\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/RecordId/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"RecordId\", \"category\": \"PARAMETER\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"ID\" }, { \"language\": \"en\", \"text\": \"ID\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"STRING\", \"definition\": [ { \"language\": \"en\", \"text\": \"Labels the record within a time series with a unique ID.\" }, { \"language\": \"de\", \"text\": \"Kennzeichnet den Datensatz innerhalb einer Zeitreihe mit einer eindeutigen ID. \" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_UtcTime\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/UtcTime/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"UtcTime\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitstempel UTC\" }, { \"language\": \"en\", \"text\": \"timestamp UTC\" } ], \"shortName\": [ { \"language\": \"de\", \"text\": \"Zeitstempel UTC\" }, { \"language\": \"en\", \"text\": \"timestamp UTC\" } ], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"TIMESTAMP\", \"definition\": [ { \"language\": \"de\", \"text\": \"Zeitstempel nach ISO 8601 auf der Zeitskala der koordinierten Weltzeit (UTC).\" }, { \"language\": \"en\", \"text\": \"Timestamp according to ISO 8601 on the timescale ccordinated universal time (UTC).\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_TaiTime\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/TaiTime/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TaiTime\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitstempel TAI\" }, { \"language\": \"en\", \"text\": \"timestamp TAI\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"TIMESTAMP\", \"definition\": [ { \"language\": \"de\", \"text\": \"Zeitstempel nach ISO 8601 auf der Zeitskala internationale Atomzeit (TAI).\" }, { \"language\": \"en\", \"text\": \"Timestamp according to ISO 8601 on the timescale international atomic time (TAI).\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_Time\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/Time/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"Time\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitstempel\" }, { \"language\": \"en\", \"text\": \"Timestamp\" } ], \"shortName\": [], \"unit\": \"s\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": \"t\", \"dataType\": \"REAL_MEASURE\", \"definition\": [ { \"language\": \"de\", \"text\": \"Zeitpunktangabe in Sekunden. Zeitpunkte referenzieren auf die Startzeit des Zeitreihensegments.\" }, { \"language\": \"en\", \"text\": \"Point of Time in seconds. Time points refer to the start time of the time series segment.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_TimeDuration\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeDuration/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TimeDuration\", \"category\": \"VARIABLE\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitdauer\" }, { \"language\": \"en\", \"text\": \"Timeduration\" } ], \"shortName\": [], \"unit\": \"s\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": \"\", \"dataType\": \"REAL_MEASURE\", \"definition\": [ { \"language\": \"de\", \"text\": \"Angabe der zeitlichen Dauer in Sekunden (Anzahl der Sekunden). Zeitdauern referenzieren auf den jeweils vorangegangenen Eintrag im Zeitreihensegment.\" }, { \"language\": \"en\", \"text\": \"Time duration specification in seconds. (number of seconds). Time durations refer to the previous entry in the time series segment.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_TimeSeriesVariable\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/TimeSeriesVariable/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"TimeSeriesVariable\", \"category\": null, \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Zeitreihenvariable\" }, { \"language\": \"en\", \"text\": \"Time series variable\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Eine Zeitreihenvariable bildet eine Wertereihe, bestehend aus RecordID und einer weiteren Dimension der Zeitreihe, als Array ab. Vergleichbar einer Spalte in einer Tabelle. Variablen können Zeitstempel oder Datenpunkte sein.\" }, { \"language\": \"en\", \"text\": \"A time series variable contains the sequence of values, consisting of RecordID and another dimension of the time series, as an array. Similar to a column in a table. Variables can be timestamps or data points.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_ValueArray\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/ValueArray/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"ValueArray\", \"category\": \"PARAMETER\", \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Wertereihe\" }, { \"language\": \"en\", \"text\": \"Value Array\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Wertereihe einer einer Zeitreihe. Die Reihenfolge der Dimensionen und deren semantische Beueutung ergibt sich aus den Definitionen innerhalb der Zeitreihenvariable. \" }, { \"language\": \"en\", \"text\": \"Values of a time series. The order of the dimensions and their semantic meaning results from the definitions within the time series variable. \" } ] } } ], \"isCaseOf\": [], \"descriptions\": null }, \"CD_ExternalDataFile\": { \"identification\": { \"idType\": \"IRI\", \"id\": \"https://admin-shell.io/sandbox/zvei/TimeSeriesData/ExternalDataFile/1/0\" }, \"administration\": { \"version\": \"1\", \"revision\": \"0\" }, \"idShort\": \"ExternalDataFile\", \"category\": null, \"modelType\": { \"name\": \"ConceptDescription\" }, \"embeddedDataSpecifications\": [ { \"dataSpecification\": { \"keys\": [] }, \"dataSpecificationContent\": { \"preferredName\": [ { \"language\": \"de\", \"text\": \"Externe Datendatei\" }, { \"language\": \"en\", \"text\": \"External data file\" } ], \"shortName\": [], \"unit\": \"\", \"unitId\": null, \"valueFormat\": null, \"sourceOfDefinition\": null, \"symbol\": null, \"dataType\": \"\", \"definition\": [ { \"language\": \"de\", \"text\": \"Externe Datendatei, welche Zeitreihendaten in einem beliebigen Format beinhaltet.\" }, { \"language\": \"en\", \"text\": \"External data file containing time series data in any format.\" } ] } } ], \"isCaseOf\": [], \"descriptions\": null } }"; - // Parse into root - var root = JObject.Parse(jsonStr); + // Parse JSON string into JsonDocument + var doc = JsonDocument.Parse(jsonStr); - // decompose - foreach (var child in root.Children()) + // Traverse the JSON document + foreach (JsonProperty prop in doc.RootElement.EnumerateObject()) { - // just look for 1. level properties - var prop = child as JProperty; - if (prop == null) - continue; - - // ok - var name = prop.Name; + // Get property name and contents + var name = prop.Name; var contents = prop.Value.ToString(); - // populate + // Populate dictionary res.Add(name, new LibraryEntry(name, contents)); } @@ -1628,7 +1604,7 @@ public T RetrieveReferable(string name) where T : IReferable // try de-serialize try { - var r = JsonConvert.DeserializeObject(entry.contents); + var r = JsonSerializer.Deserialize(entry.contents); return r; } catch (Exception ex) @@ -1662,7 +1638,7 @@ public static ConceptDescription CreateSparseConceptDescription( // options if (isCaseOf != null) - cd.IsCaseOf = new List(new[] { isCaseOf }); + cd.IsCaseOf = new List(new[] {isCaseOf}); // ok return cd; @@ -1683,7 +1659,7 @@ public virtual IReferable[] GetAllReferables() } public void RetrieveEntriesFromLibraryByReflection(Type typeToReflect = null, - bool useAttributes = false, bool useFieldNames = false) + bool useAttributes = false, bool useFieldNames = false) { // access if (this.theLibrary == null || typeToReflect == null) @@ -1699,7 +1675,7 @@ public void RetrieveEntriesFromLibraryByReflection(Type typeToReflect = null, var libName = "" + fi.Name; // test - var ok = false; + var ok = false; var isSM = fi.FieldType == typeof(Submodel); var isCD = fi.FieldType == typeof(ConceptDescription); @@ -1722,6 +1698,7 @@ public void RetrieveEntriesFromLibraryByReflection(Type typeToReflect = null, fi.SetValue(this, sm); this.theReflectedReferables.Add(sm); } + if (isCD) { var cd = this.RetrieveReferable(libName); @@ -1732,7 +1709,7 @@ public void RetrieveEntriesFromLibraryByReflection(Type typeToReflect = null, } public void AddEntriesByReflection(Type typeToReflect = null, - bool useAttributes = false, bool useFieldNames = false) + bool useAttributes = false, bool useFieldNames = false) { // access if (typeToReflect == null) @@ -1745,7 +1722,7 @@ public void AddEntriesByReflection(Type typeToReflect = null, var fiName = "" + fi.Name; // test - var ok = false; + var ok = false; var isSM = fi.FieldType == typeof(Submodel); var isCD = fi.FieldType == typeof(ConceptDescription); @@ -1856,11 +1833,11 @@ public static void SetPlottableProperties( } public static string EvalDisplayText( - string minmalText, ISubmodelElement sme, - ConceptDescription cd = null, - bool addMinimalTxt = false, - string defaultLang = null, - bool useIdShort = true) + string minmalText, ISubmodelElement sme, + ConceptDescription cd = null, + bool addMinimalTxt = false, + string defaultLang = null, + bool useIdShort = true) { var res = "" + minmalText; if (sme != null) @@ -1893,6 +1870,7 @@ public static string EvalDisplayText( res += $" ({minmalText})"; } } + return res; } @@ -1910,9 +1888,9 @@ public class CumulativeDataItems } public static ScottPlot.Plottable.IPlottable GenerateCumulativePlottable( - ScottPlot.Plot wpfPlot, - CumulativeDataItems cumdi, - PlotArguments args) + ScottPlot.Plot wpfPlot, + CumulativeDataItems cumdi, + PlotArguments args) { // access if (wpfPlot == null || cumdi == null || args == null) @@ -1921,11 +1899,11 @@ public static ScottPlot.Plottable.IPlottable GenerateCumulativePlottable( if (args.type == PlotArguments.Type.Pie) { var pie = wpfPlot.AddPie(cumdi.Value.ToArray()); - pie.SliceLabels = cumdi.Label.ToArray(); - pie.ShowLabels = args.labels; - pie.ShowValues = args.values; + pie.SliceLabels = cumdi.Label.ToArray(); + pie.ShowLabels = args.labels; + pie.ShowValues = args.values; pie.ShowPercentages = args.percent; - pie.SliceFont.Size = 9.0f; + pie.SliceFont.Size = 9.0f; return pie; } @@ -1940,4 +1918,4 @@ public static ScottPlot.Plottable.IPlottable GenerateCumulativePlottable( return null; } } -} +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3.Tests/Controllers/DescriptionAPIApiControllerTests.cs b/src/IO.Swagger.Lib.V3.Tests/Controllers/DescriptionAPIApiControllerTests.cs new file mode 100644 index 000000000..bed4e0195 --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/Controllers/DescriptionAPIApiControllerTests.cs @@ -0,0 +1,84 @@ +namespace AasxServerBlazorTests.Controllers; + +using System.Security.Claims; +using System.Text.Json; +using IO.Swagger.Controllers; +using IO.Swagger.Models; +using JetBrains.Annotations; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +[TestSubject(typeof(DescriptionAPIApiController))] +public class DescriptionAPIApiControllerTests +{ + [Fact] + public void GetDescription_ShouldReturn200WithServiceDescription() + { + // Arrange + var mockServiceDescription = new Mock(); + var expectedServiceDescription = new ServiceDescription + { + Profiles = new List + { + ServiceDescription.ServiceProfiles.AasxFileServerServiceSpecificationSSP001, + ServiceDescription.ServiceProfiles.SubmodelRepositoryServiceSpecificationSSP001, + ServiceDescription.ServiceProfiles.AssetAdministrationShellRepositoryServiceSpecificationSSP001, + ServiceDescription.ServiceProfiles.AssetAdministrationShellRegistryServiceSpecificationSSP001, + ServiceDescription.ServiceProfiles.DiscoveryServiceSpecificationSSP001, + ServiceDescription.ServiceProfiles.ConceptDescriptionServiceSpecificationSSP001 + } + }; + var serializedProfiles = JsonSerializer.Serialize(expectedServiceDescription); + mockServiceDescription.Setup(x => x.ToJson()).Returns(serializedProfiles); + var controller = new DescriptionAPIApiController(mockServiceDescription.Object); + + // Act + var result = controller.GetDescription(); + + // Assert + result.Should().BeOfType(); + var objectResult = result as ObjectResult; + objectResult.Should().NotBeNull(); + objectResult!.Value.Should().BeEquivalentTo(serializedProfiles); + } + + [Fact] + public void GetDescription_ShouldReturn401WhenUnauthorized() + { + // Arrange + var mockServiceDescription = new Mock(); + var controller = new DescriptionAPIApiController(mockServiceDescription.Object); + controller.ControllerContext = new ControllerContext {HttpContext = new DefaultHttpContext()}; + + // Simulate unauthorized access + controller.ControllerContext.HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity()); + + // Act + var result = controller.GetDescription(); + + // Assert + var objectResult = result as ObjectResult; + objectResult.Should().NotBeNull(); + } + + [Fact] + public void GetDescription_ShouldReturn403WhenForbidden() + { + // Arrange + var mockServiceDescription = new Mock(); + var controller = new DescriptionAPIApiController(mockServiceDescription.Object); + controller.ControllerContext = new ControllerContext {HttpContext = new DefaultHttpContext()}; + + // Simulate forbidden access + controller.ControllerContext.HttpContext.User = new ClaimsPrincipal( + new ClaimsIdentity(new Claim[] {new Claim(ClaimTypes.Role, "ForbiddenRole")}) + ); + + // Act + var result = controller.GetDescription(); + + // Assert + var objectResult = result as ObjectResult; + objectResult.Should().NotBeNull(); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3.Tests/Models/MessageTests.cs b/src/IO.Swagger.Lib.V3.Tests/Models/MessageTests.cs new file mode 100644 index 000000000..07595e88c --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/Models/MessageTests.cs @@ -0,0 +1,172 @@ +namespace IO.Swagger.Lib.V3.Tests.Models; + +using System.Text.Json; +using System.Text.Json.Serialization; +using JetBrains.Annotations; +using Swagger.Models; + +[TestSubject(typeof(Message))] +public class MessageTests +{ + [Fact] + public void ToString_ReturnsExpectedString() + { + // Arrange + var message = new Message + { + Code = "123", + CorrelationId = "abc", + MessageType = MessageTypeEnum.Info, + Text = "Sample message", + Timestamp = "2023-07-02T14:30:00Z" + }; + + var expectedString + = $"class Message {{\n Code: {message.Code}\n CorrelationId: {message.CorrelationId}\n MessageType: Info\n Text: {message.Text}\n Timestamp: {message.Timestamp}\n}}\n"; + + // Act + var result = message.ToString(); + + // Assert + result.Should().Be(expectedString); + } + + [Fact] + public void ToJson_ReturnsValidJsonString() + { + // Arrange + var message = new Message + { + Code = "123", + CorrelationId = "abc", + MessageType = MessageTypeEnum.Info, + Text = "Sample message", + Timestamp = "2023-07-02T14:30:00Z" + }; + + var expectedJson = JsonSerializer.Serialize(message, new JsonSerializerOptions {WriteIndented = true, Converters = {new JsonStringEnumConverter()}}); + + // Act + var result = message.ToJson(); + + // Assert + result.Should().Be(expectedJson); + } + + [Fact] + public void Equals_ReturnsTrue_WhenMessagesAreEqual() + { + // Arrange + var message1 = new Message + { + Code = "123", + CorrelationId = "abc", + MessageType = MessageTypeEnum.Info, + Text = "Sample message", + Timestamp = "2023-07-02T14:30:00Z" + }; + + var message2 = new Message + { + Code = "123", + CorrelationId = "abc", + MessageType = MessageTypeEnum.Info, + Text = "Sample message", + Timestamp = "2023-07-02T14:30:00Z" + }; + + // Act + var result = message1.Equals(message2); + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void GetHashCode_ReturnsSameValue_WhenMessagesAreEqual() + { + // Arrange + var message1 = new Message + { + Code = "123", + CorrelationId = "abc", + MessageType = MessageTypeEnum.Info, + Text = "Sample message", + Timestamp = "2023-07-02T14:30:00Z" + }; + + var message2 = new Message + { + Code = "123", + CorrelationId = "abc", + MessageType = MessageTypeEnum.Info, + Text = "Sample message", + Timestamp = "2023-07-02T14:30:00Z" + }; + + // Act + var hashCode1 = message1.GetHashCode(); + var hashCode2 = message2.GetHashCode(); + + // Assert + hashCode1.Should().Be(hashCode2); + } + + [Fact] + public void Operators_Equality_ReturnsTrue_WhenMessagesAreEqual() + { + // Arrange + var message1 = new Message + { + Code = "123", + CorrelationId = "abc", + MessageType = MessageTypeEnum.Info, + Text = "Sample message", + Timestamp = "2023-07-02T14:30:00Z" + }; + + var message2 = new Message + { + Code = "123", + CorrelationId = "abc", + MessageType = MessageTypeEnum.Info, + Text = "Sample message", + Timestamp = "2023-07-02T14:30:00Z" + }; + + // Act + var isEqual = message1 == message2; + + // Assert + isEqual.Should().BeTrue(); + } + + [Fact] + public void Operators_Inequality_ReturnsFalse_WhenMessagesAreEqual() + { + // Arrange + var message1 = new Message + { + Code = "123", + CorrelationId = "abc", + MessageType = MessageTypeEnum.Info, + Text = "Sample message", + Timestamp = "2023-07-02T14:30:00Z" + }; + + var message2 = new Message + { + Code = "123", + CorrelationId = "abc", + MessageType = MessageTypeEnum.Info, + Text = "Sample message", + Timestamp = "2023-07-02T14:30:00Z" + }; + + // Act + var isNotEqual = message1 != message2; + + // Assert + isNotEqual.Should().BeFalse(); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3.Tests/Models/ServiceDescriptionTests.cs b/src/IO.Swagger.Lib.V3.Tests/Models/ServiceDescriptionTests.cs new file mode 100644 index 000000000..6c784410e --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/Models/ServiceDescriptionTests.cs @@ -0,0 +1,180 @@ +namespace IO.Swagger.Lib.V3.Tests.Models; + +using JetBrains.Annotations; +using Swagger.Models; + +[TestSubject(typeof(ServiceDescription))] +public class ServiceDescriptionTests +{ + [Fact] + public void ToString_ShouldReturnFormattedString() + { + // Arrange + var serviceDescription = new ServiceDescription + { + Profiles = new List + { + ServiceDescription.ServiceProfiles.DiscoveryServiceSpecificationSSP001 + } + }; + + // Act + var result = serviceDescription.ToString(); + + // Assert + result.Should().Contain("class ServiceDescription {"); + result.Should().Contain("Profiles:"); + } + + [Fact] + public void ToJson_ShouldReturnIndentedJsonString() + { + // Arrange + var serviceDescription = new ServiceDescription + { + Profiles = new List + { + ServiceDescription.ServiceProfiles.DiscoveryServiceSpecificationSSP001 + } + }; + + // Act + var result = serviceDescription.ToJson(); + + // Assert + result.Should().NotBeNullOrEmpty(); + result.Should().Contain("\"Profiles\":"); + result.Should().Contain("\"DiscoveryServiceSpecificationSSP001\""); + } + + [Fact] + public void Equals_WithSameObject_ShouldReturnTrue() + { + // Arrange + var serviceDescription = new ServiceDescription + { + Profiles = new List + { + ServiceDescription.ServiceProfiles.DiscoveryServiceSpecificationSSP001 + } + }; + + // Act + var result = serviceDescription.Equals(serviceDescription); + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void Equals_WithEqualObject_ShouldReturnTrue() + { + // Arrange + var profiles = new List + { + ServiceDescription.ServiceProfiles.DiscoveryServiceSpecificationSSP001 + }; + + var serviceDescription1 = new ServiceDescription { Profiles = profiles }; + var serviceDescription2 = new ServiceDescription { Profiles = profiles }; + + // Act + var result = serviceDescription1.Equals(serviceDescription2); + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void Equals_WithDifferentObject_ShouldReturnFalse() + { + // Arrange + var serviceDescription1 = new ServiceDescription + { + Profiles = new List + { + ServiceDescription.ServiceProfiles.DiscoveryServiceSpecificationSSP001 + } + }; + + var serviceDescription2 = new ServiceDescription + { + Profiles = new List + { + ServiceDescription.ServiceProfiles.AssetAdministrationShellRepositoryServiceSpecificationSSP001 + } + }; + + // Act + var result = serviceDescription1.Equals(serviceDescription2); + + // Assert + result.Should().BeFalse(); + } + + [Fact] + public void GetHashCode_ShouldReturnCorrectHashCode() + { + // Arrange + var profiles = new List + { + ServiceDescription.ServiceProfiles.DiscoveryServiceSpecificationSSP001 + }; + + var serviceDescription = new ServiceDescription { Profiles = profiles }; + var expectedHashCode = 41; + expectedHashCode = (expectedHashCode * 59) + profiles.GetHashCode(); + + // Act + var result = serviceDescription.GetHashCode(); + + // Assert + result.Should().Be(expectedHashCode); + } + + [Fact] + public void OperatorEquals_WithEqualObjects_ShouldReturnTrue() + { + // Arrange + var profiles = new List + { + ServiceDescription.ServiceProfiles.DiscoveryServiceSpecificationSSP001 + }; + + var serviceDescription1 = new ServiceDescription { Profiles = profiles }; + var serviceDescription2 = new ServiceDescription { Profiles = profiles }; + + // Act + var result = serviceDescription1 == serviceDescription2; + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void OperatorNotEquals_WithDifferentObjects_ShouldReturnTrue() + { + // Arrange + var serviceDescription1 = new ServiceDescription + { + Profiles = new List + { + ServiceDescription.ServiceProfiles.DiscoveryServiceSpecificationSSP001 + } + }; + + var serviceDescription2 = new ServiceDescription + { + Profiles = new List + { + ServiceDescription.ServiceProfiles.SubmodelServiceSpecificationSSP002 + } + }; + + // Act + var result = serviceDescription1 != serviceDescription2; + + // Assert + result.Should().BeTrue(); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3.Tests/Services/GenerateSerializationServiceTests.cs b/src/IO.Swagger.Lib.V3.Tests/Services/GenerateSerializationServiceTests.cs new file mode 100644 index 000000000..c0aaa10f8 --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/Services/GenerateSerializationServiceTests.cs @@ -0,0 +1,125 @@ +namespace AasxServerBlazorTests.Services; + +using AasCore.Aas3_0; +using AasxServerStandardBib.Interfaces; +using AasxServerStandardBib.Logging; +using IO.Swagger.Lib.V3.Services; +using JetBrains.Annotations; + +[TestSubject(typeof(GenerateSerializationService))] +public class GenerateSerializationServiceTests +{ + private readonly Mock> _mockLogger; + private readonly Mock _mockAasService; + private readonly Mock _mockSubmodelService; + private readonly GenerateSerializationService _service; + + public GenerateSerializationServiceTests() + { + _mockLogger = new Mock>(); + _mockAasService = new Mock(); + _mockSubmodelService = new Mock(); + _service = new GenerateSerializationService(_mockLogger.Object, _mockAasService.Object, _mockSubmodelService.Object); + } + + [Fact] + public void Constructor_ShouldThrowArgumentNullException_WhenLoggerIsNull() + { + Action act = () => new GenerateSerializationService(null, _mockAasService.Object, _mockSubmodelService.Object); + act.Should().Throw().WithParameterName("logger"); + } + + [Fact] + public void Constructor_ShouldThrowArgumentNullException_WhenAasServiceIsNull() + { + Action act = () => new GenerateSerializationService(_mockLogger.Object, null, _mockSubmodelService.Object); + act.Should().Throw().WithParameterName("aasService"); + } + + [Fact] + public void Constructor_ShouldThrowArgumentNullException_WhenSubmodelServiceIsNull() + { + Action act = () => new GenerateSerializationService(_mockLogger.Object, _mockAasService.Object, null); + act.Should().Throw().WithParameterName("submodelService"); + } + + [Fact] + public void GenerateSerializationByIds_ShouldReturnEmptyEnvironment_WhenNoIdsProvided() + { + // Arrange + _mockAasService.Setup(x => x.GetAllAssetAdministrationShells(It.IsAny?>(), It.IsAny())).Returns([]); + _mockSubmodelService.Setup(x => x.GetAllSubmodels(It.IsAny(), It.IsAny())).Returns([]); + + // Act + var result = _service.GenerateSerializationByIds(); + + // Assert + result.AssetAdministrationShells.Should().BeEmpty(); + result.Submodels.Should().BeEmpty(); + } + + [Fact] + public void GenerateSerializationByIds_ShouldFetchAASs_WhenAasIdsProvided() + { + // Arrange + var aasId = "aas1"; + var mockAas = new Mock(); + mockAas.SetupGet(x => x.Id).Returns(aasId); + + _mockAasService.Setup(x => x.GetAllAssetAdministrationShells(It.IsAny?>(), It.IsAny())).Returns([mockAas.Object]); + _mockSubmodelService.Setup(x => x.GetAllSubmodels(It.IsAny(), It.IsAny())).Returns([]); + + // Act + var result = _service.GenerateSerializationByIds(new List {aasId}); + + // Assert + result.AssetAdministrationShells.Should().HaveCount(1); + result.AssetAdministrationShells.First().Id.Should().Be(aasId); + } + + [Fact] + public void GenerateSerializationByIds_ShouldFetchSubmodels_WhenSubmodelIdsProvided() + { + // Arrange + var submodelId = "submodel1"; + var mockSubmodel = new Mock(); + mockSubmodel.SetupGet(x => x.Id).Returns(submodelId); + + _mockAasService.Setup(x => x.GetAllAssetAdministrationShells(It.IsAny?>(), It.IsAny())).Returns([]); + _mockSubmodelService.Setup(x => x.GetAllSubmodels(It.IsAny(),It.IsAny())).Returns([mockSubmodel.Object]); + + // Act + var result = _service.GenerateSerializationByIds(null, new List {submodelId}); + + // Assert + result.Submodels.Should().HaveCount(1); + result.Submodels.First().Id.Should().Be(submodelId); + } + + [Fact] + public void GenerateSerializationByIds_ShouldFetchAASsAndSubmodels_WhenBothIdsProvided() + { + // Arrange + var aasId = "aas1"; + var submodelId = "submodel1"; + + var mockAas = new Mock(); + mockAas.SetupGet(x => x.Id).Returns(aasId); + + var mockSubmodel = new Mock(); + mockSubmodel.SetupGet(x => x.Id).Returns(submodelId); + + _mockAasService.Setup(x => x.GetAllAssetAdministrationShells(It.IsAny?>(), It.IsAny())).Returns([mockAas.Object]); + _mockSubmodelService.Setup(x => x.GetAllSubmodels(It.IsAny(),It.IsAny())).Returns([mockSubmodel.Object]); + + // Act + var result = _service.GenerateSerializationByIds(new List {aasId}, new List {submodelId}); + + // Assert + result.AssetAdministrationShells.Should().HaveCount(1); + result.AssetAdministrationShells.First().Id.Should().Be(aasId); + + result.Submodels.Should().HaveCount(1); + result.Submodels.First().Id.Should().Be(submodelId); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Controllers/AASXFileServerAPIApi.cs b/src/IO.Swagger.Lib.V3/Controllers/AASXFileServerAPIApi.cs index 7dd840de5..cb8821ee8 100644 --- a/src/IO.Swagger.Lib.V3/Controllers/AASXFileServerAPIApi.cs +++ b/src/IO.Swagger.Lib.V3/Controllers/AASXFileServerAPIApi.cs @@ -7,6 +7,7 @@ * Contact: info@idtwin.org * Generated by: https://github.com/swagger-api/swagger-codegen.git */ + using AasSecurity.Exceptions; using AasxServerStandardBib.Interfaces; using AasxServerStandardBib.Logging; @@ -24,257 +25,291 @@ using System.Linq; using System.Net.Mime; -namespace IO.Swagger.Controllers +namespace IO.Swagger.Controllers; + +using System.Threading.Tasks; + +/// +/// +/// +[Authorize(AuthenticationSchemes = "AasSecurityAuth")] +[ApiController] +public class AASXFileServerAPIApiController : ControllerBase { + private readonly IAppLogger _logger; + private readonly IBase64UrlDecoderService _decoderService; + private readonly IAasxFileServerInterfaceService _fileService; + private readonly IPaginationService _paginationService; + private readonly IAuthorizationService _authorizationService; + + public AASXFileServerAPIApiController(IAppLogger logger, IBase64UrlDecoderService decoderService, + IAasxFileServerInterfaceService fileService, IPaginationService paginationService, IAuthorizationService authorizationService) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + ; + _decoderService = decoderService ?? throw new ArgumentNullException(nameof(decoderService)); + ; + _fileService = fileService ?? throw new ArgumentNullException(nameof(fileService)); + _paginationService = paginationService ?? throw new ArgumentNullException(nameof(paginationService)); + _authorizationService = authorizationService ?? throw new ArgumentNullException(nameof(authorizationService)); + } + /// - /// + /// Deletes a specific AASX package from the server /// - [Authorize(AuthenticationSchemes = "AasSecurityAuth")] - [ApiController] - public class AASXFileServerAPIApiController : ControllerBase + /// The package Id (UTF8-BASE64-URL-encoded) + /// Deleted successfully + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Unauthorized, e.g. the server refused the authorization attempt. + /// Forbidden + /// Not Found + /// Internal Server Error + /// Default error handling for unmentioned status codes + [HttpDelete] + [Route("/packages/{packageId}")] + [ValidateModelState] + [SwaggerOperation("DeleteAASXByPackageId")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 401, type: typeof(Result), description: "Unauthorized, e.g. the server refused the authorization attempt.")] + [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] + [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual IActionResult DeleteAASXByPackageId([FromRoute] [Required] string packageId) { - private readonly IAppLogger _logger; - private readonly IBase64UrlDecoderService _decoderService; - private readonly IAasxFileServerInterfaceService _fileService; - private readonly IPaginationService _paginationService; - private readonly IAuthorizationService _authorizationService; + var decodedPackageId = _decoderService.Decode("packageId", packageId); - public AASXFileServerAPIApiController(IAppLogger logger, IBase64UrlDecoderService decoderService, IAasxFileServerInterfaceService fileService, IPaginationService paginationService, IAuthorizationService authorizationService) + _logger.LogInformation($"Received request to delete the AASX Package with package id {decodedPackageId}"); + var aas = _fileService.GetAssetAdministrationShellByPackageId(decodedPackageId); + var authResult = _authorizationService.AuthorizeAsync(User, aas, "SecurityPolicy").Result; + if (!authResult.Succeeded) { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); ; - _decoderService = decoderService ?? throw new ArgumentNullException(nameof(decoderService)); ; - _fileService = fileService ?? throw new ArgumentNullException(nameof(fileService)); - _paginationService = paginationService ?? throw new ArgumentNullException(nameof(paginationService)); - _authorizationService = authorizationService ?? throw new ArgumentNullException(nameof(authorizationService)); - } - /// - /// Deletes a specific AASX package from the server - /// - /// The package Id (UTF8-BASE64-URL-encoded) - /// Deleted successfully - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Unauthorized, e.g. the server refused the authorization attempt. - /// Forbidden - /// Not Found - /// Internal Server Error - /// Default error handling for unmentioned status codes - [HttpDelete] - [Route("/packages/{packageId}")] - [ValidateModelState] - [SwaggerOperation("DeleteAASXByPackageId")] - [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] - [SwaggerResponse(statusCode: 401, type: typeof(Result), description: "Unauthorized, e.g. the server refused the authorization attempt.")] - [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] - [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] - [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] - [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult DeleteAASXByPackageId([FromRoute][Required] string? packageId) - { - var decodedPackageId = _decoderService.Decode("packageId", packageId); + var failedReasons = authResult.Failure.FailureReasons; + var authorizationFailureReasons = failedReasons.ToList(); + if (authorizationFailureReasons.Count != 0) + { + throw new NotAllowed(authorizationFailureReasons.First().Message); // TODO (jtikekar, 2023-09-04): write AuthResultMiddlewareHandler + } - _logger.LogInformation($"Received request to delete the AASX Package with package id {decodedPackageId}"); - var aas = _fileService.GetAssetAdministrationShellByPackageId(decodedPackageId); - var authResult = _authorizationService.AuthorizeAsync(User, aas, "SecurityPolicy").Result; - if (!authResult.Succeeded) + if (HttpContext.Response.StatusCode == 307) { - var failedReasons = authResult.Failure.FailureReasons; - if (failedReasons != null && failedReasons.Any()) - { - throw new NotAllowed(failedReasons.First().Message); // TODO (jtikekar, 2023-09-04): write AuthResultMiddlewareHandler - } - else if (HttpContext.Response.StatusCode == 307) - { - var url = HttpContext.Response.Headers["redirectInfo"].First(); - return new RedirectResult(url); - } + var url = HttpContext.Response.Headers["redirectInfo"].First(); + return new RedirectResult(url ?? string.Empty); } + } - _fileService.DeleteAASXByPackageId(decodedPackageId); + _fileService.DeleteAASXByPackageId(decodedPackageId); - return NoContent(); - } + return NoContent(); + } - /// - /// Returns a specific AASX package from the server - /// - /// The package Id (UTF8-BASE64-URL-encoded) - /// Requested AASX package - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Unauthorized, e.g. the server refused the authorization attempt. - /// Forbidden - /// Not Found - /// Internal Server Error - /// Default error handling for unmentioned status codes - [HttpGet] - [Route("/packages/{packageId}")] - [ValidateModelState] - [SwaggerOperation("GetAASXByPackageId")] - [SwaggerResponse(statusCode: 200, type: typeof(byte[]), description: "Requested AASX package")] - [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] - [SwaggerResponse(statusCode: 401, type: typeof(Result), description: "Unauthorized, e.g. the server refused the authorization attempt.")] - [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] - [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] - [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] - [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult GetAASXByPackageId([FromRoute][Required] string? packageId) - { - var decodedPackageId = _decoderService.Decode("packageId", packageId); + /// + /// Returns a specific AASX package from the server + /// + /// The package Id (UTF8-BASE64-URL-encoded) + /// Requested AASX package + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Unauthorized, e.g. the server refused the authorization attempt. + /// Forbidden + /// Not Found + /// Internal Server Error + /// Default error handling for unmentioned status codes + [HttpGet] + [Route("/packages/{packageId}")] + [ValidateModelState] + [SwaggerOperation("GetAASXByPackageId")] + [SwaggerResponse(statusCode: 200, type: typeof(byte[]), description: "Requested AASX package")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 401, type: typeof(Result), description: "Unauthorized, e.g. the server refused the authorization attempt.")] + [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] + [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual async Task GetAASXByPackageId([FromRoute] [Required] string packageId) + { + var decodedPackageId = _decoderService.Decode("packageId", packageId); + + _logger.LogInformation($"Received request to get the AASX Package with package id {decodedPackageId}"); - _logger.LogInformation($"Received request to get the AASX Package with package id {decodedPackageId}"); + if (decodedPackageId == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedPackageId)} is null"); + } - var fileName = _fileService.GetAASXByPackageId(decodedPackageId, out byte[] content, out long fileSize, out IAssetAdministrationShell aas); + var fileName = _fileService.GetAASXByPackageId(decodedPackageId, out var content, out var fileSize, out var aas); - var authResult = _authorizationService.AuthorizeAsync(User, aas, "SecurityPolicy").Result; - if (!authResult.Succeeded) + var authResult = _authorizationService.AuthorizeAsync(User, aas, "SecurityPolicy").Result; + if (!authResult.Succeeded) + { + var failedReasons = authResult.Failure.FailureReasons; + var authorizationFailureReasons = failedReasons.ToList(); + if (authorizationFailureReasons.Count != 0) { - var failedReasons = authResult.Failure.FailureReasons; - if (failedReasons != null && failedReasons.Any()) - { - throw new NotAllowed(failedReasons.First().Message); // TODO (jtikekar, 2023-09-04): write AuthResultMiddlewareHandler - } - else if (HttpContext.Response.StatusCode == 307) - { - var url = HttpContext.Response.Headers["redirectInfo"].First(); - return new RedirectResult(url); - } + throw new NotAllowed(authorizationFailureReasons.First().Message); // TODO (jtikekar, 2023-09-04): write AuthResultMiddlewareHandler } - //content-disposition so that the aasx file can be downloaded from the web browser. - ContentDisposition contentDisposition = new() + if (HttpContext.Response.StatusCode == 307) { - FileName = fileName - }; - - HttpContext.Response.Headers.Add("Content-Disposition", contentDisposition.ToString()); - HttpContext.Response.Headers.Add("X-FileName", fileName); - HttpContext.Response.ContentLength = fileSize; - HttpContext.Response.Body.WriteAsync(content); - return new EmptyResult(); + var url = HttpContext.Response.Headers["redirectInfo"].First(); + return new RedirectResult(url ?? string.Empty); + } } - /// - /// Returns a list of available AASX packages at the server - /// - /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) - /// The maximum number of elements in the response array - /// A server-generated identifier retrieved from pagingMetadata that specifies from which position the result listing should continue - /// Requested package list - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Unauthorized, e.g. the server refused the authorization attempt. - /// Forbidden - /// Internal Server Error - /// Default error handling for unmentioned status codes - [HttpGet] - [Route("/packages")] - [ValidateModelState] - [SwaggerOperation("GetAllAASXPackageIds")] - [SwaggerResponse(statusCode: 200, type: typeof(PackageDescriptionPagedResult), description: "Requested package list")] - [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] - [SwaggerResponse(statusCode: 401, type: typeof(Result), description: "Unauthorized, e.g. the server refused the authorization attempt.")] - [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] - [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] - [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult GetAllAASXPackageIds([FromQuery] string? aasId, [FromQuery] int? limit, [FromQuery] string cursor) - { - var decodedAasId = _decoderService.Decode("aasId", aasId); + //content-disposition so that the aasx file can be downloaded from the web browser. + ContentDisposition contentDisposition = new() {FileName = fileName}; + + HttpContext.Response.Headers.Append("Content-Disposition", contentDisposition.ToString()); + HttpContext.Response.Headers.Append("X-FileName", fileName); - _logger.LogInformation($"Received request to get all the AASX packages."); - var packages = _fileService.GetAllAASXPackageIds(decodedAasId); + HttpContext.Response.ContentLength = fileSize; + await HttpContext.Response.Body.WriteAsync(content); + return new EmptyResult(); + } + + /// + /// Returns a list of available AASX packages at the server + /// + /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) + /// The maximum number of elements in the response array + /// A server-generated identifier retrieved from pagingMetadata that specifies from which position the result listing should continue + /// Requested package list + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Unauthorized, e.g. the server refused the authorization attempt. + /// Forbidden + /// Internal Server Error + /// Default error handling for unmentioned status codes + [HttpGet] + [Route("/packages")] + [ValidateModelState] + [SwaggerOperation("GetAllAASXPackageIds")] + [SwaggerResponse(statusCode: 200, type: typeof(PackageDescriptionPagedResult), description: "Requested package list")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 401, type: typeof(Result), description: "Unauthorized, e.g. the server refused the authorization attempt.")] + [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual IActionResult GetAllAASXPackageIds([FromQuery] string? aasId, [FromQuery] int? limit, [FromQuery] string? cursor) + { + _logger.LogInformation($"Received request to get all the AASX packages."); + var decodedAasId = _decoderService.Decode("aasId", aasId); - var authResult = _authorizationService.AuthorizeAsync(User, packages, "SecurityPolicy").Result; - if (!authResult.Succeeded) + if (decodedAasId == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasId)} is null"); + } + + var packages = _fileService.GetAllAASXPackageIds(decodedAasId); + + var authResult = _authorizationService.AuthorizeAsync(User, packages, "SecurityPolicy").Result; + if (!authResult.Succeeded) + { + var failedReasons = authResult.Failure.FailureReasons; + var authorizationFailureReasons = failedReasons.ToList(); + if (authorizationFailureReasons.Count != 0) { - var failedReasons = authResult.Failure.FailureReasons; - if (failedReasons != null && failedReasons.Any()) - { - throw new NotAllowed(failedReasons.First().Message); // TODO (jtikekar, 2023-09-04): write AuthResultMiddlewareHandler - } + throw new NotAllowed(authorizationFailureReasons.First().Message); // TODO (jtikekar, 2023-09-04): write AuthResultMiddlewareHandler } + } + + var paginatedPackages = _paginationService.GetPaginatedPackageDescriptionList(packages, new PaginationParameters(cursor, limit)); + return new ObjectResult(paginatedPackages); + } - var paginatedPackages = _paginationService.GetPaginatedPackageDescriptionList(packages, new PaginationParameters(cursor, limit)); - return new ObjectResult(paginatedPackages); + /// + /// Creates an AASX package at the server + /// + /// Included AAS Ids + /// AASX Package + /// + [HttpPost] + [Route("/packages")] + [ValidateModelState] + [SwaggerOperation("PostAASXPackage")] + public virtual IActionResult PostAASXPackage([FromQuery] string? aasIds, IFormFile? file) + { + _logger.LogInformation($"Received request to create a new AASX Package."); + + if (file == null) + { + return Ok("No file was provided."); } - /// - /// Creates an AASX package at the server - /// - /// Included AAS Ids - /// AASX Package - /// - [HttpPost] - [Route("/packages")] - [ValidateModelState] - [SwaggerOperation("PostAASXPackage")] - public virtual IActionResult PostAASXPackage([FromQuery] string aasIds, IFormFile file) + var authResult = _authorizationService.AuthorizeAsync(User, "", "SecurityPolicy").Result; + if (!authResult.Succeeded) { - _logger.LogInformation($"Received request to create a new AASX Package."); + var failedReasons = authResult.Failure.FailureReasons; + var authorizationFailureReasons = failedReasons.ToList(); + if (authorizationFailureReasons.Count != 0) + { + throw new NotAllowed(authorizationFailureReasons.First().Message); // TODO (jtikekar, 2023-09-04): write AuthResultMiddlewareHandler + } - var authResult = _authorizationService.AuthorizeAsync(User, "", "SecurityPolicy").Result; - if (!authResult.Succeeded) + if (HttpContext.Response.StatusCode == 307) { - var failedReasons = authResult.Failure.FailureReasons; - if (failedReasons != null && failedReasons.Any()) - { - throw new NotAllowed(failedReasons.First().Message); // TODO (jtikekar, 2023-09-04): write AuthResultMiddlewareHandler - } - else if (HttpContext.Response.StatusCode == 307) - { - var url = HttpContext.Response.Headers["redirectInfo"].First(); - return new RedirectResult(url); - } + var url = HttpContext.Response.Headers["redirectInfo"].First(); + return new RedirectResult(url ?? string.Empty); } + } + + // TODO (jtikekar, 2023-09-04): aasIds + var stream = new MemoryStream(); + file.CopyTo(stream); + var packageId = _fileService.PostAASXPackage(stream.ToArray(), file.FileName); + return CreatedAtAction(nameof(PostAASXPackage), packageId); + } - // TODO (jtikekar, 2023-09-04): aasIds - var stream = new MemoryStream(); - file.CopyTo(stream); - var packageId = _fileService.PostAASXPackage(stream.ToArray(), file.FileName); - return CreatedAtAction(nameof(PostAASXPackage), packageId); + /// + /// Updates the AASX package at the server + /// + /// Package ID from the package list (BASE64-URL-encoded) + /// AASX Package + /// Included AAS Identifiers + /// + [HttpPut] + [Route("/packages/{packageId}")] + [ValidateModelState] + [SwaggerOperation("PutAASXPackageById")] + public virtual IActionResult PutAASXPackageById([FromRoute] [Required] string packageId, IFormFile? file, [FromQuery] string? aasIds) + { + if (file == null) + { + return Ok("No file was provided."); } - /// - /// Updates the AASX package at the server - /// - /// Package ID from the package list (BASE64-URL-encoded) - /// AASX Package - /// Included AAS Identifiers - /// - [HttpPut] - [Route("/packages/{packageId}")] - [ValidateModelState] - [SwaggerOperation("PutAASXPackageById")] - public virtual IActionResult PutAASXPackageById([FromRoute][Required] string? packageId, IFormFile file, [FromQuery] string aasIds) + // TODO (jtikekar, 2023-09-04): aasIds + var decodedPackageId = _decoderService.Decode("packageId", packageId); + + if (decodedPackageId == null) { - // TODO (jtikekar, 2023-09-04): aasIds - var decodedPackageId = _decoderService.Decode("packageId", packageId); + throw new NotAllowed($"Cannot proceed as {nameof(decodedPackageId)} is null"); + } - _logger.LogInformation($"Received request to update the AASX Package with package id {decodedPackageId}."); + _logger.LogInformation($"Received request to update the AASX Package with package id {decodedPackageId}."); - var aas = _fileService.GetAssetAdministrationShellByPackageId(decodedPackageId); - var authResult = _authorizationService.AuthorizeAsync(User, aas, "SecurityPolicy").Result; - if (!authResult.Succeeded) + var aas = _fileService.GetAssetAdministrationShellByPackageId(decodedPackageId); + var authResult = _authorizationService.AuthorizeAsync(User, aas, "SecurityPolicy").Result; + if (!authResult.Succeeded) + { + var failedReasons = authResult.Failure.FailureReasons; + var authorizationFailureReasons = failedReasons.ToList(); + if (authorizationFailureReasons.Count != 0) { - var failedReasons = authResult.Failure.FailureReasons; - if (failedReasons != null && failedReasons.Any()) - { - throw new NotAllowed(failedReasons.First().Message); // TODO (jtikekar, 2023-09-04): write AuthResultMiddlewareHandler - } - else if (HttpContext.Response.StatusCode == 307) - { - var url = HttpContext.Response.Headers["redirectInfo"].First(); - return new RedirectResult(url); - } + throw new NotAllowed(authorizationFailureReasons.First().Message); // TODO (jtikekar, 2023-09-04): write AuthResultMiddlewareHandler } - var stream = new MemoryStream(); - file.CopyTo(stream); - var fileName = file.FileName; - _fileService.UpdateAASXPackageById(decodedPackageId, stream.ToArray(), fileName); - - return NoContent(); - + if (HttpContext.Response.StatusCode == 307) + { + var url = HttpContext.Response.Headers["redirectInfo"].First(); + return new RedirectResult(url ?? string.Empty); + } } + var stream = new MemoryStream(); + file.CopyTo(stream); + var fileName = file.FileName; + _fileService.UpdateAASXPackageById(decodedPackageId, stream.ToArray(), fileName); + return NoContent(); } -} +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Controllers/AssetAdministrationShellRepositoryAPIApi.cs b/src/IO.Swagger.Lib.V3/Controllers/AssetAdministrationShellRepositoryAPIApi.cs index 29f5dc774..5a170e3b7 100644 --- a/src/IO.Swagger.Lib.V3/Controllers/AssetAdministrationShellRepositoryAPIApi.cs +++ b/src/IO.Swagger.Lib.V3/Controllers/AssetAdministrationShellRepositoryAPIApi.cs @@ -23,7 +23,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; using Swashbuckle.AspNetCore.Annotations; using System; using System.Collections.Generic; @@ -35,6 +34,8 @@ namespace IO.Swagger.Controllers; +using System.Threading.Tasks; + /// /// /// @@ -143,17 +144,27 @@ public virtual IActionResult DeleteFileByPathAasRepository([FromRoute] [Required var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSmIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSmIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSmIdentifier)} is null"); + } + if (!Program.noSecurity) { var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSmIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -191,6 +202,16 @@ public virtual IActionResult DeleteSubmodelByIdAasRepository([FromRoute] [Requir var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSmIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSmIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSmIdentifier)} is null"); + } + _aasService.DeleteSubmodelById(decodedAasIdentifier, decodedSmIdentifier); return NoContent(); @@ -226,17 +247,27 @@ public virtual IActionResult DeleteSubmodelElementByPathAasRepository([FromRoute var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSmIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSmIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSmIdentifier)} is null"); + } + if (!Program.noSecurity) { var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSmIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -269,11 +300,21 @@ public virtual IActionResult DeleteSubmodelElementByPathAasRepository([FromRoute [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult DeleteSubmodelReferenceByIdAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier) { - var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); - var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + var decodedSmIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSmIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSmIdentifier)} is null"); + } _logger.LogInformation($"Received request to delete submodel reference with id {submodelIdentifier} from the AAS with id {aasIdentifier}."); - _aasService.DeleteSubmodelReferenceById(decodedAasIdentifier, decodedSubmodelIdentifier); + _aasService.DeleteSubmodelReferenceById(decodedAasIdentifier, decodedSmIdentifier); return NoContent(); } @@ -305,6 +346,11 @@ public virtual IActionResult DeleteThumbnailAasRepository([FromRoute] [Required] _logger.LogInformation($"Received request to delete the thumbnail from the AAS with id {decodedAasIdentifier}."); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + _aasService.DeleteThumbnail(decodedAasIdentifier); return NoContent(); @@ -408,25 +454,35 @@ public virtual IActionResult GetAllAssetAdministrationShellsReference([FromQuery [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult GetAllSubmodelElementsAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string? submodelIdentifier, - [FromQuery] int? limit, [FromQuery] string? cursor, [FromQuery] [Required] LevelEnum level, - [FromQuery] [Required] ExtentEnum extent) + public virtual IActionResult GetAllSubmodelElementsAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, + [FromQuery] int? limit, [FromQuery] string? cursor, [FromQuery] LevelEnum level, + [FromQuery] ExtentEnum extent) { - var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); - var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + var decodedSmIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSmIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSmIdentifier)} is null"); + } _logger.LogInformation($"Received request to get all the submodel elements from submodel with id {submodelIdentifier} and the AAS with id {aasIdentifier}."); if (!Program.noSecurity) { - var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); + var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSmIdentifier); var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } - var submodelElements = _aasService.GetAllSubmodelElements(decodedAasIdentifier, decodedSubmodelIdentifier); + var submodelElements = _aasService.GetAllSubmodelElements(decodedAasIdentifier, decodedSmIdentifier); var smePaginated = _paginationService.GetPaginatedList(submodelElements, new PaginationParameters(cursor, limit)); var smeLevelList = _levelExtentModifierService.ApplyLevelExtent(smePaginated.result ?? [], level, extent); @@ -460,12 +516,22 @@ public virtual IActionResult GetAllSubmodelElementsAasRepository([FromRoute] [Re [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult GetAllSubmodelElementsMetadataAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string? submodelIdentifier, - [FromQuery] int? limit, [FromQuery] [Required] string cursor, [FromQuery] [Required] LevelEnum level) + public virtual IActionResult GetAllSubmodelElementsMetadataAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, + [FromQuery] int? limit, [FromQuery] [Required] string cursor, [FromQuery] LevelEnum level) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get metadata of all the submodel elements from the submodel with id {decodedSubmodelIdentifier} and AAS with id {decodedAasIdentifier}"); if (!Program.noSecurity) { @@ -473,7 +539,7 @@ public virtual IActionResult GetAllSubmodelElementsMetadataAasRepository([FromRo var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -513,13 +579,23 @@ public virtual IActionResult GetAllSubmodelElementsMetadataAasRepository([FromRo [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult GetAllSubmodelElementsPathAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string? submodelIdentifier, - [FromQuery] int? limit, [FromQuery] string? cursor, [FromQuery] [Required] LevelEnum level, - [FromQuery] [Required] ExtentEnum extent) + public virtual IActionResult GetAllSubmodelElementsPathAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, + [FromQuery] int? limit, [FromQuery] string? cursor, [FromQuery] LevelEnum level, + [FromQuery] ExtentEnum extent) { var decodedAasIdentifier = _decoderService.Decode($"aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode($"submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received a request to get path for all the submodel elements from the submodel with id {decodedSubmodelIdentifier} and aas with id {decodedAasIdentifier}"); if (!Program.noSecurity) { @@ -527,14 +603,14 @@ public virtual IActionResult GetAllSubmodelElementsPathAasRepository([FromRoute] var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } var submodelElementsList = _aasService.GetAllSubmodelElements(decodedAasIdentifier, decodedSubmodelIdentifier); var smePaginated = _paginationService.GetPaginatedList(submodelElementsList, new PaginationParameters(cursor, limit)); - var smeLevelList = _levelExtentModifierService.ApplyLevelExtent(smePaginated.result??[], level, extent); + var smeLevelList = _levelExtentModifierService.ApplyLevelExtent(smePaginated.result ?? [], level, extent); var smePathList = _pathModifierService.ToIdShortPath(smeLevelList.ConvertAll(sme => (ISubmodelElement)sme)); var output = new PathPagedResult {result = smePathList, paging_metadata = smePaginated.paging_metadata}; return new ObjectResult(output); @@ -568,12 +644,22 @@ public virtual IActionResult GetAllSubmodelElementsPathAasRepository([FromRoute] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult GetAllSubmodelElementsReferenceAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, - [FromQuery] int? limit, [FromQuery] string? cursor, [FromQuery] [Required] LevelEnum level, - [FromQuery] [Required] ExtentEnum extent) + [FromQuery] int? limit, [FromQuery] string? cursor, [FromQuery] LevelEnum level, + [FromQuery] ExtentEnum extent) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get references of all the submodel elements from submodel with id {submodelIdentifier} and the AAS with id {aasIdentifier}."); if (!Program.noSecurity) { @@ -581,7 +667,7 @@ public virtual IActionResult GetAllSubmodelElementsReferenceAasRepository([FromR var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -602,6 +688,7 @@ public virtual IActionResult GetAllSubmodelElementsReferenceAasRepository([FromR /// The maximum number of elements in the response array /// A server-generated identifier retrieved from pagingMetadata that specifies from which position the result listing should continue /// Determines the structural depth of the respective resource content + /// /// List of found submodel elements in their ValueOnly representation /// Bad Request, e.g. the request parameters of the format of the request body is wrong. /// Unauthorized, e.g. the server refused the authorization attempt. @@ -621,12 +708,22 @@ public virtual IActionResult GetAllSubmodelElementsReferenceAasRepository([FromR [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult GetAllSubmodelElementsValueOnlyAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, - [FromQuery] int? limit, [FromQuery] string? cursor, [FromQuery] [Required] LevelEnum level, - [FromQuery] [Required] ExtentEnum extent) + [FromQuery] int? limit, [FromQuery] string? cursor, [FromQuery] LevelEnum level, + [FromQuery] ExtentEnum extent) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get the value of all the submodel elements from the submodel with id {decodedSubmodelIdentifier} and aas with id {decodedAasIdentifier}"); if (!Program.noSecurity) { @@ -634,7 +731,7 @@ public virtual IActionResult GetAllSubmodelElementsValueOnlyAasRepository([FromR var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -675,6 +772,11 @@ public virtual IActionResult GetAllSubmodelReferencesAasRepository([FromRoute] [ { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get all the submodel references from the AAS with id {aasIdentifier}."); var submodels = _aasService.GetAllSubmodelReferencesFromAas(decodedAasIdentifier); @@ -709,6 +811,11 @@ public virtual IActionResult GetAssetAdministrationShellById([FromRoute] [Requir { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get the AAS with id {aasIdentifier}."); var aas = _aasService.GetAssetAdministrationShellById(decodedAasIdentifier); @@ -753,6 +860,11 @@ public virtual IActionResult GetAssetAdministrationShellByIdReferenceAasReposito { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get the reference of AAS with id {aasIdentifier}."); var aas = _aasService.GetAssetAdministrationShellById(decodedAasIdentifier); @@ -788,6 +900,11 @@ public virtual IActionResult GetAssetInformationAasRepository([FromRoute] [Requi { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get the AAS with id {decodedAasIdentifier}."); var output = _aasService.GetAssetInformation(decodedAasIdentifier); @@ -819,40 +936,56 @@ public virtual IActionResult GetAssetInformationAasRepository([FromRoute] [Requi [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult GetFileByPathAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, - [FromRoute] [Required] string idShortPath) + public virtual async Task GetFileByPathAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, + [FromRoute] [Required] string idShortPath) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get file by path at the submodel element {idShortPath} from submodel with id {submodelIdentifier} and the AAS with id {aasIdentifier}."); if (!Program.noSecurity) { var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } var fileName = _aasService.GetFileByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath, out var content, out var fileSize); - //content-disposition so that the aasx file can be doenloaded from the web browser. - ContentDisposition contentDisposition = new() {FileName = fileName, Inline = fileName.ToLower().EndsWith(".pdf") ? true : false}; + //content-disposition so that the aasx file can be downloaded from the web browser. + ContentDisposition contentDisposition = new() {FileName = fileName, Inline = fileName.ToLower().EndsWith(".pdf")}; - HttpContext.Response.Headers.Add("Content-Disposition", contentDisposition.ToString()); + HttpContext.Response.Headers.Append("Content-Disposition", contentDisposition.ToString()); HttpContext.Response.ContentLength = fileSize; if (fileName.ToLower().EndsWith(".svg")) + { HttpContext.Response.ContentType = "image/svg+xml"; + } + if (fileName.ToLower().EndsWith(".pdf")) + { HttpContext.Response.ContentType = "application/pdf"; - HttpContext.Response.Body.WriteAsync(content); + } + + await HttpContext.Response.Body.WriteAsync(content); return new EmptyResult(); } @@ -904,7 +1037,7 @@ public virtual IActionResult GetOperationAsyncResultAasRepository([FromRoute] [R //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... // return StatusCode(0, default(Result)); - return new ObjectResult(JsonConvert.DeserializeObject(string.Empty)); + return new ObjectResult(System.Text.Json.JsonSerializer.Deserialize(string.Empty)); } /// @@ -995,7 +1128,7 @@ public virtual IActionResult GetOperationAsyncStatusAasRepository([FromRoute] [R exampleJson = "\"\""; var example = exampleJson != null - ? JsonConvert.DeserializeObject(exampleJson) + ? System.Text.Json.JsonSerializer.Deserialize(exampleJson) : default(BaseOperationResult); //TODO: Change the data returned return new ObjectResult(example); } @@ -1031,16 +1164,27 @@ public virtual IActionResult GetSubmodelByIdAasRepository([FromRoute] [Required] var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get the submodel with id {submodelIdentifier} from the AAS with id {aasIdentifier}."); var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - var failedReasons = authResult.Failure.FailureReasons; - if (failedReasons != null && failedReasons.Any()) + var failedReasons = authResult.Failure.FailureReasons; + var authorizationFailureReasons = failedReasons.ToList(); + if (authorizationFailureReasons.Count != 0) { - throw new NotAllowed(failedReasons.First().Message); + throw new NotAllowed(authorizationFailureReasons.First().Message); } } @@ -1073,11 +1217,21 @@ public virtual IActionResult GetSubmodelByIdAasRepository([FromRoute] [Required] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult GetSubmodelByIdMetadataAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, - [FromQuery] [Required] LevelEnum level) + [FromQuery] LevelEnum level) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get metadat of the submodel with id {decodedSubmodelIdentifier} from the AAS with id {decodedAasIdentifier}"); var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); @@ -1121,11 +1275,21 @@ public virtual IActionResult GetSubmodelByIdMetadataAasRepository([FromRoute] [R [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult GetSubmodelByIdPathAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, - [FromQuery] [Required] LevelEnum level) + [FromQuery] LevelEnum level) { var decodedAasIdentifier = _decoderService.Decode($"aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode($"submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get path of a submodel with is {decodedSubmodelIdentifier} and AAS with id {decodedAasIdentifier}"); var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); @@ -1172,6 +1336,16 @@ public virtual IActionResult GetSubmodelByIdReferenceAasRepository([FromRoute] [ var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get the submodel with id {submodelIdentifier} from the AAS with id {aasIdentifier}."); var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); @@ -1215,11 +1389,21 @@ public virtual IActionResult GetSubmodelByIdReferenceAasRepository([FromRoute] [ [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult GetSubmodelByIdValueOnlyAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, - [FromQuery] [Required] LevelEnum level, [FromQuery] [Required] ExtentEnum extent) + [FromQuery] LevelEnum level, [FromQuery] ExtentEnum extent) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get the value of submodel with id {decodedSubmodelIdentifier} from the aas with id {decodedAasIdentifier}"); var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); @@ -1265,12 +1449,22 @@ public virtual IActionResult GetSubmodelByIdValueOnlyAasRepository([FromRoute] [ [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult GetSubmodelElementByPathAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, - [FromRoute] [Required] string idShortPath, [FromQuery] [Required] LevelEnum level, - [FromQuery] [Required] ExtentEnum extent) + [FromRoute] [Required] string idShortPath, [FromQuery] LevelEnum level, + [FromQuery] ExtentEnum extent) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get the submodel element at {idShortPath} from the submodel with id {submodelIdentifier} and the AAS with id {aasIdentifier}."); var submodelElement = _aasService.GetSubmodelElementByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath); @@ -1278,14 +1472,14 @@ public virtual IActionResult GetSubmodelElementByPathAasRepository([FromRoute] [ if (!Program.noSecurity) { var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -1319,25 +1513,35 @@ public virtual IActionResult GetSubmodelElementByPathAasRepository([FromRoute] [ [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult GetSubmodelElementByPathMetadataAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, - [FromRoute] [Required] string idShortPath, [FromQuery] [Required] LevelEnum level) + [FromRoute] [Required] string idShortPath, [FromQuery] LevelEnum level) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get metadata of the submodel element at {idShortPath} from the submodel with id {submodelIdentifier} and the AAS with id {aasIdentifier}."); var submodelElement = _aasService.GetSubmodelElementByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath); if (!Program.noSecurity) { var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -1372,25 +1576,35 @@ public virtual IActionResult GetSubmodelElementByPathMetadataAasRepository([From [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult GetSubmodelElementByPathPathAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, - [FromRoute] [Required] string idShortPath, [FromQuery] [Required] LevelEnum level) + [FromRoute] [Required] string idShortPath, [FromQuery] LevelEnum level) { var decodedAasIdentifier = _decoderService.Decode($"aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode($"submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received a request to get a path of a submodel element at {idShortPath} from a submodel with id {decodedSubmodelIdentifier} and aas with id {decodedAasIdentifier}"); var submodelElement = _aasService.GetSubmodelElementByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath); if (!Program.noSecurity) { var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -1425,7 +1639,7 @@ public virtual IActionResult GetSubmodelElementByPathPathAasRepository([FromRout [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult GetSubmodelElementByPathReferenceAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, - [FromRoute] [Required] string idShortPath, [FromQuery] LevelEnum? level) + [FromRoute] [Required] string idShortPath, [FromQuery] LevelEnum level) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); @@ -1436,14 +1650,14 @@ public virtual IActionResult GetSubmodelElementByPathReferenceAasRepository([Fro if (!Program.noSecurity) { var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -1480,26 +1694,36 @@ public virtual IActionResult GetSubmodelElementByPathReferenceAasRepository([Fro [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult GetSubmodelElementByPathValueOnlyAasRepository([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, - [FromRoute] [Required] string idShortPath, [FromQuery] [Required] LevelEnum level, - [FromQuery] [Required] ExtentEnum extent) + [FromRoute] [Required] string idShortPath, [FromQuery] LevelEnum level, + [FromQuery] ExtentEnum extent) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get the value of the submodel element at {idShortPath} from the submodel with id {decodedSubmodelIdentifier} and the aas with id {decodedAasIdentifier}"); var submodelElement = _aasService.GetSubmodelElementByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath); if (!Program.noSecurity) { var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -1530,20 +1754,25 @@ public virtual IActionResult GetSubmodelElementByPathValueOnlyAasRepository([Fro [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult GetThumbnailAasRepository([FromRoute] [Required] string aasIdentifier) + public virtual async Task GetThumbnailAasRepository([FromRoute] [Required] string aasIdentifier) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get the thumbnail of the AAS with Id {aasIdentifier}"); - var fileName = _aasService.GetThumbnail(decodedAasIdentifier, out byte[] content, out long fileSize); + var fileName = _aasService.GetThumbnail(decodedAasIdentifier, out var content, out var fileSize); - //content-disposition so that the aasx file can be doenloaded from the web browser. + //content-disposition so that the aasx file can be downloaded from the web browser. ContentDisposition contentDisposition = new() {FileName = fileName}; HttpContext.Response.Headers.Append("Content-Disposition", contentDisposition.ToString()); HttpContext.Response.ContentLength = fileSize; - HttpContext.Response.Body.WriteAsync(content); + await HttpContext.Response.Body.WriteAsync(content); return new EmptyResult(); } @@ -1599,7 +1828,7 @@ public virtual IActionResult InvokeOperationAasRepository([FromBody] OperationRe exampleJson = "\"\""; var example = exampleJson != null - ? JsonConvert.DeserializeObject(exampleJson) + ? System.Text.Json.JsonSerializer.Deserialize(exampleJson) : default(OperationResult); //TODO: Change the data returned return new ObjectResult(example); } @@ -1760,7 +1989,7 @@ public virtual IActionResult InvokeOperationValueOnlyAasRepository([FromBody] ob exampleJson = "\"\""; var example = exampleJson != null - ? JsonConvert.DeserializeObject(exampleJson) + ? System.Text.Json.JsonSerializer.Deserialize(exampleJson) : default(object); //TODO: Change the data returned return new ObjectResult(example); } @@ -1790,7 +2019,7 @@ public virtual IActionResult InvokeOperationValueOnlyAasRepository([FromBody] ob [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PatchSubmodelAasRepository([FromBody] Submodel? body, [FromRoute] [Required] string aasIdentifier, - [FromRoute] [Required] string submodelIdentifier, [FromQuery] string? level) + [FromRoute] [Required] string submodelIdentifier, [FromQuery] LevelEnum level) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); @@ -1826,16 +2055,37 @@ public virtual IActionResult PatchSubmodelAasRepository([FromBody] Submodel? bod [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PatchSubmodelByIdMetadataAasRepository([FromBody] SubmodelMetadata? body, [FromRoute] [Required] string aasIdentifier, - [FromRoute] [Required] string submodelIdentifier, [FromQuery] string? level) + [FromRoute] [Required] string submodelIdentifier, [FromQuery] LevelEnum level) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received Request to update for submodel with id {decodedSubmodelIdentifier} from the aas with id {decodedAasIdentifier}"); + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } + //Reverse mapping from Metadata to submodel element var submodel = _mappingService.Map(body, "metadata") as ISubmodel; + //Update + if (submodel == null) + { + return BadRequest($"Could not update Submodel as {nameof(submodel)} is null."); + } + _aasService.UpdateSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier, submodel); return NoContent(); @@ -1866,14 +2116,33 @@ public virtual IActionResult PatchSubmodelByIdMetadataAasRepository([FromBody] S [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PatchSubmodelByIdValueOnlyAasRepository([FromBody] SubmodelValue? body, [FromRoute] [Required] string aasIdentifier, - [FromRoute] [Required] string submodelIdentifier, [FromQuery] LevelEnum? level) + [FromRoute] [Required] string submodelIdentifier, [FromQuery] LevelEnum level) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); - _logger.LogInformation($"Received request to update the sumodel with id {decodedSubmodelIdentifier} from the aas with tid {decodedAasIdentifier} by value."); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + + _logger.LogInformation($"Received request to update the submodel with id {decodedSubmodelIdentifier} from the aas with tid {decodedAasIdentifier} by value."); + + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } var submodel = _mappingService.Map(body, "value") as Submodel; + if (submodel == null) + { + return BadRequest($"Could not update Submodel as {nameof(submodel)} is null."); + } _aasService.UpdateSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier, submodel); @@ -1907,12 +2176,27 @@ public virtual IActionResult PatchSubmodelByIdValueOnlyAasRepository([FromBody] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PatchSubmodelElementValueByPathAasRepository([FromBody] ISubmodelElement? body, [FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, [FromRoute] [Required] string idShortPath, - [FromQuery] LevelEnum? level) + [FromQuery] LevelEnum level) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } _logger.LogInformation($"Received request to update the submodel element at {idShortPath} from submodel with id {decodedSubmodelIdentifier} from the AAS with id {decodedAasIdentifier}"); + + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } + _aasService.UpdateSubmodelElementByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath, body); return NoContent(); @@ -1945,15 +2229,32 @@ public virtual IActionResult PatchSubmodelElementValueByPathAasRepository([FromB [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PatchSubmodelElementValueByPathMetadata([FromBody] ISubmodelElementMetadata? body, [FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, [FromRoute] [Required] string idShortPath, - [FromQuery] LevelEnum? level) + [FromQuery] LevelEnum level) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } _logger.LogInformation($"Received request to update the submodel element at {idShortPath} in the submodel with id {decodedSubmodelIdentifier} and the AAS with id {decodedAasIdentifier}"); + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } + //Reverse mapping from Metadata to submodel element - ISubmodelElement submodelElement = _mappingService.Map(body, "metadata") as ISubmodelElement; + if (_mappingService.Map(body, "metadata") is not ISubmodelElement submodelElement) + { + return BadRequest($"Could not update Submodel as {nameof(submodelElement)} is null."); + } //Update _aasService.UpdateSubmodelElementByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath, submodelElement); @@ -1988,17 +2289,35 @@ public virtual IActionResult PatchSubmodelElementValueByPathMetadata([FromBody] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PatchSubmodelElementValueByPathValueOnly([FromBody] ISubmodelElementValue? body, [FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, [FromRoute] [Required] string idShortPath, - [FromQuery] LevelEnum? level) + [FromQuery] LevelEnum level) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } _logger.LogInformation($"Received request to update the submodel element at {idShortPath} in the submodel with id {decodedSubmodelIdentifier} and the AAS with id {decodedAasIdentifier} by value."); + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } //Reverse mapping from Metadata to submodel element - ISubmodelElement submodelElement = _mappingService.Map(body, "value") as ISubmodelElement; + var submodelElement = _mappingService.Map(body, "value") as ISubmodelElement; //Update + if (submodelElement == null) + { + return BadRequest($"Could not update Submodel as {nameof(submodelElement)} is null."); + } + _aasService.UpdateSubmodelElementByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath, submodelElement); return NoContent(); @@ -2030,6 +2349,11 @@ public virtual IActionResult PatchSubmodelElementValueByPathValueOnly([FromBody] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PostAssetAdministrationShell([FromBody] AssetAdministrationShell? body) { + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } + var output = _aasService.CreateAssetAdministrationShell(body); return CreatedAtAction("PostAssetAdministrationShell", output); @@ -2068,22 +2392,36 @@ public virtual IActionResult PostSubmodelElementAasRepository([FromBody] ISubmod { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } _logger.LogInformation($"Received request to create a new submodel element in the submodel {decodedSubmodelIdentifier} and AAS {decodedAasIdentifier}"); if (!Program.noSecurity) { var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + body.IdShort)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + body.IdShort)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{body?.IdShort}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{body?.IdShort}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } + var output = _aasService.CreateSubmodelElement(decodedAasIdentifier, decodedSubmodelIdentifier, first, body); return CreatedAtAction("PostSubmodelElementAasRepository", output); @@ -2119,27 +2457,41 @@ public virtual IActionResult PostSubmodelElementAasRepository([FromBody] ISubmod [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PostSubmodelElementByPathAasRepository([FromBody] ISubmodelElement? body, [FromRoute] [Required] string aasIdentifier, - [FromRoute] [Required] string? submodelIdentifier, [FromRoute] [Required] string idShortPath, + [FromRoute] [Required] string submodelIdentifier, [FromRoute] [Required] string idShortPath, bool first) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } _logger.LogInformation($"Received request to create a new submodel element in the submodel {decodedSubmodelIdentifier} and AAS {decodedAasIdentifier}"); if (!Program.noSecurity) { var submodel = _aasService.GetSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } + var output = _aasService.CreateSubmodelElementByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath, first, body); return CreatedAtAction("PostSubmodelElementByPathAasRepository", output); @@ -2175,9 +2527,18 @@ public virtual IActionResult PostSubmodelElementByPathAasRepository([FromBody] I public virtual IActionResult PostSubmodelReferenceAasRepository([FromBody] Reference? body, [FromRoute] [Required] string aasIdentifier) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } _logger.LogInformation($"Received request to create a submodel reference in the AAS with id {decodedAasIdentifier}"); + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } + var output = _aasService.CreateSubmodelReferenceInAAS(body, decodedAasIdentifier); return CreatedAtAction("PostSubmodelReferenceAasRepository", output); @@ -2208,8 +2569,16 @@ public virtual IActionResult PostSubmodelReferenceAasRepository([FromBody] Refer public virtual IActionResult PutAssetAdministrationShellById([FromBody] AssetAdministrationShell? body, [FromRoute] [Required] string aasIdentifier) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } _logger.LogInformation($"Received request to replace the AAS with id {decodedAasIdentifier}"); + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } _aasService.ReplaceAssetAdministrationShellById(decodedAasIdentifier, body); @@ -2241,8 +2610,16 @@ public virtual IActionResult PutAssetAdministrationShellById([FromBody] AssetAdm public virtual IActionResult PutAssetInformationAasRepository([FromBody] AssetInformation? body, [FromRoute] [Required] string aasIdentifier) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } _logger.LogInformation($"Received request to replace the asset information of the AAS with id {decodedAasIdentifier}"); + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } _aasService.ReplaceAssetInformation(decodedAasIdentifier, body); @@ -2278,8 +2655,21 @@ public virtual IActionResult PutSubmodelByIdAasRepository([FromBody] Submodel? b { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } _logger.LogInformation($"Received request to replace a a submodel {decodedSubmodelIdentifier} from the AAS {decodedAasIdentifier}"); + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } _aasService.ReplaceSubmodelById(decodedAasIdentifier, decodedSubmodelIdentifier, body); @@ -2315,8 +2705,21 @@ public virtual IActionResult PutSubmodelElementByPathAasRepository([FromBody] IS { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } - _logger.LogInformation($"Received request to replace a submodel element at {idShortPath} deom the submodel with id {decodedSubmodelIdentifier} from the AAS {decodedAasIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + + _logger.LogInformation($"Received request to replace a submodel element at {idShortPath} dom the submodel with id {decodedSubmodelIdentifier} from the AAS {decodedAasIdentifier}"); + if (body == null) + { + return BadRequest($"Could not proceed, as {nameof(body)} is null."); + } _aasService.ReplaceSubmodelElementByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath, body); @@ -2345,8 +2748,17 @@ public virtual IActionResult PutSubmodelElementByPathAasRepository([FromBody] IS public virtual IActionResult PutFileByPath([FromRoute] [Required] string aasIdentifier, [FromRoute] [Required] string submodelIdentifier, [FromRoute] string? idShortPath, IFormFile? file) { - var decodedAasId = _decoderService.Decode("aasIdentifier", aasIdentifier); - var decodedSubmodelId = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } var stream = new MemoryStream(); if (file == null) @@ -2355,10 +2767,15 @@ public virtual IActionResult PutFileByPath([FromRoute] [Required] string aasIden } file.CopyTo(stream); - string fileName = file.FileName; - string contentType = file.ContentType; + var fileName = file.FileName; + var contentType = file.ContentType; + + if (idShortPath == null) + { + return BadRequest($"Could not proceed, as {nameof(idShortPath)} is null."); + } - _aasService.ReplaceFileByPath(decodedAasId, decodedSubmodelId, idShortPath, fileName, contentType, stream); + _aasService.ReplaceFileByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath, fileName, contentType, stream); return NoContent(); } @@ -2385,6 +2802,10 @@ public virtual IActionResult PutFileByPath([FromRoute] [Required] string aasIden public virtual IActionResult PutThumbnail([FromRoute] [Required] string aasIdentifier, IFormFile? file) { var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } var stream = new MemoryStream(); if (file == null) @@ -2393,8 +2814,8 @@ public virtual IActionResult PutThumbnail([FromRoute] [Required] string aasIdent } file.CopyTo(stream); - string fileName = file.FileName; - string contentType = file.ContentType; + var fileName = file.FileName; + var contentType = file.ContentType; _aasService.UpdateThumbnail(decodedAasIdentifier, fileName, contentType, stream); diff --git a/src/IO.Swagger.Lib.V3/Controllers/ConceptDescriptionRepositoryAPIApi.cs b/src/IO.Swagger.Lib.V3/Controllers/ConceptDescriptionRepositoryAPIApi.cs index 9b4e0616f..7661b29ac 100644 --- a/src/IO.Swagger.Lib.V3/Controllers/ConceptDescriptionRepositoryAPIApi.cs +++ b/src/IO.Swagger.Lib.V3/Controllers/ConceptDescriptionRepositoryAPIApi.cs @@ -73,7 +73,10 @@ public ConceptDescriptionRepositoryAPIApiController(IAppLogger), description: "Requested Concept Descriptions")] [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] @@ -113,7 +115,9 @@ public virtual IActionResult GetAllConceptDescriptions([FromQuery] string? idSho var cdList = new List(); if (reqDataSpecificationRef != null) + { cdList = _cdService.GetAllConceptDescriptions(idShort, reqIsCaseOf, reqDataSpecificationRef); + } var authResult = _authorizationService.AuthorizeAsync(User, cdList, "SecurityPolicy").Result; if (!authResult.Succeeded) diff --git a/src/IO.Swagger.Lib.V3/Controllers/DescriptionAPIApi.cs b/src/IO.Swagger.Lib.V3/Controllers/DescriptionAPIApi.cs index 0d4253714..c90dfb937 100644 --- a/src/IO.Swagger.Lib.V3/Controllers/DescriptionAPIApi.cs +++ b/src/IO.Swagger.Lib.V3/Controllers/DescriptionAPIApi.cs @@ -23,6 +23,10 @@ namespace IO.Swagger.Controllers; [ApiController] public class DescriptionAPIApiController : ControllerBase { + private readonly IServiceDescription _serviceDescription; + + public DescriptionAPIApiController(IServiceDescription serviceDescription) => _serviceDescription = serviceDescription; + /// /// Returns the self-describing information of a network resource (ServiceDescription) /// @@ -38,18 +42,15 @@ public class DescriptionAPIApiController : ControllerBase [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] public virtual IActionResult GetDescription() { - var output = new ServiceDescription - { - Profiles = new List - { - ProfilesEnum.AasxFileServerServiceSpecificationSSP001Enum, - ProfilesEnum.SubmodelRepositoryServiceSpecificationSSP001Enum, - ProfilesEnum.AssetAdministrationShellRepositoryServiceSpecificationSSP001Enum, - ProfilesEnum.AssetAdministrationShellRegistryServiceSpecificationSSP001Enum, - ProfilesEnum.DiscoveryServiceSpecificationSSP001Enum, - ProfilesEnum.ConceptDescriptionServiceSpecificationSSP001Enum - } - }; - return new ObjectResult(output); + _serviceDescription.Profiles = new List + { + ServiceProfiles.AasxFileServerServiceSpecificationSSP001, + ServiceProfiles.SubmodelRepositoryServiceSpecificationSSP001, + ServiceProfiles.AssetAdministrationShellRepositoryServiceSpecificationSSP001, + ServiceProfiles.AssetAdministrationShellRegistryServiceSpecificationSSP001, + ServiceProfiles.DiscoveryServiceSpecificationSSP001, + ServiceProfiles.ConceptDescriptionServiceSpecificationSSP001 + }; + return new ObjectResult(_serviceDescription.ToJson()); } } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Controllers/SerializationAPIApi.cs b/src/IO.Swagger.Lib.V3/Controllers/SerializationAPIApi.cs index c4c9ab500..523e9d0ef 100644 --- a/src/IO.Swagger.Lib.V3/Controllers/SerializationAPIApi.cs +++ b/src/IO.Swagger.Lib.V3/Controllers/SerializationAPIApi.cs @@ -20,8 +20,8 @@ namespace IO.Swagger.Controllers; -using System.ComponentModel.DataAnnotations; using System.Linq; +using AasSecurity.Exceptions; /// /// @@ -66,11 +66,21 @@ public SerializationAPIApiController(IAppLogger l public virtual IActionResult GenerateSerializationByIds([FromQuery] List? aasIds, [FromQuery] List? submodelIds, [FromQuery] bool includeConceptDescriptions = false) { + if (aasIds == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(aasIds)} is null"); + } + + if (submodelIds == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(submodelIds)} is null"); + } + var decodedAasIds = aasIds.Select(aasId => _decoderService.Decode("aasIdentifier", aasId)).ToList(); var decodedSubmodelIds = submodelIds.Select(submodelId => _decoderService.Decode("submodelIdentifier", submodelId)).ToList(); - var environment = _serializationService.GenerateSerializationByIds(decodedAasIds, decodedSubmodelIds, (bool)includeConceptDescriptions); + var environment = _serializationService.GenerateSerializationByIds(decodedAasIds, decodedSubmodelIds); HttpContext.Request.Headers.TryGetValue("Content-Type", out var contentType); if (!contentType.Equals("application/xml")) @@ -79,7 +89,7 @@ public virtual IActionResult GenerateSerializationByIds([FromQuery] List /// /// @@ -107,8 +110,7 @@ public virtual IActionResult DeleteFileByPathSubmodelRepo([FromRoute] [Required] { var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); - var claimsList = new List(User.Claims); - claimsList.Add(new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; @@ -194,7 +196,7 @@ public virtual IActionResult DeleteSubmodelElementByPathSubmodelRepo([FromRoute] { var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; + var claimsList = new List(User.Claims) {new("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; @@ -217,7 +219,7 @@ public virtual IActionResult DeleteSubmodelElementByPathSubmodelRepo([FromRoute] /// The Submodel’s unique id (UTF8-BASE64-URL-encoded) /// The maximum number of elements in the response array /// A server-generated identifier retrieved from pagingMetadata that specifies from which position the result listing should continue - /// Determines the structural depth of the respective resource content. Default value is deep + /// Determines the structural depth of the respective resource content /// Determines to which extent the resource is being serialized /// Filters response, only elements changed after DateTime /// List of found submodel elements @@ -249,7 +251,7 @@ public virtual IActionResult GetAllSubmodelElements([FromRoute] [Required] strin { throw new NotAllowed($"Decoding {submodelIdentifier} returned null"); } - + _logger.LogInformation($"Received a request to get all the submodel elements from submodel with id {decodedSubmodelIdentifier}"); if (!Program.noSecurity) { @@ -263,12 +265,13 @@ public virtual IActionResult GetAllSubmodelElements([FromRoute] [Required] strin var submodelElements = _submodelService.GetAllSubmodelElements(decodedSubmodelIdentifier); - var filtered = new List(); - if (!string.IsNullOrEmpty(diff)) + var filtered = new List(); + DateTime _diff; + if (diff != null && diff != "") { try { - var _diff = DateTime.Parse(diff).ToUniversalTime(); + _diff = DateTime.Parse(diff).ToUniversalTime(); filtered = filterSubmodelElements(submodelElements, _diff); } catch @@ -287,62 +290,70 @@ public virtual IActionResult GetAllSubmodelElements([FromRoute] [Required] strin return new ObjectResult(output); } - List filterSubmodelElements(List submodelElements, DateTime diff) + List filterSubmodelElements(List submodelElements, DateTime diff) { - var output = new List(); + var output = new List(); - foreach (var sme in submodelElements.Where(sme => sme.TimeStampTree >= diff)) + foreach (var sme in submodelElements.Where(sme => sme != null && sme.TimeStampTree >= diff)) { - List smeDiff; - if (sme is SubmodelElementCollection smc) + List smeDiff; + switch (sme) { - smeDiff = filterSubmodelElements(smc.Value ?? [], diff); - if (smeDiff.Count != 0) + case SubmodelElementCollection smc: { - var smcDiff = new SubmodelElementCollection( - extensions: smc.Extensions, - category: smc.Category, - idShort: smc.IdShort, - displayName: smc.DisplayName, - description: smc.Description, - semanticId: smc.SemanticId, - supplementalSemanticIds: smc.SupplementalSemanticIds, - qualifiers: smc.Qualifiers, - embeddedDataSpecifications: smc.EmbeddedDataSpecifications, - value: smeDiff) {Parent = smc.Parent}; - output.Add(smcDiff); + smeDiff = filterSubmodelElements(smc.Value ?? [], diff); + if (smeDiff.Count != 0) + { + var smcDiff = new SubmodelElementCollection( + extensions: smc.Extensions, + category: smc.Category, + idShort: smc.IdShort, + displayName: smc.DisplayName, + description: smc.Description, + semanticId: smc.SemanticId, + supplementalSemanticIds: smc.SupplementalSemanticIds, + qualifiers: smc.Qualifiers, + embeddedDataSpecifications: smc.EmbeddedDataSpecifications, + value: smeDiff) {Parent = smc.Parent}; + output.Add(smcDiff); + } + else if (smc.TimeStamp >= diff) + { + output.Add(smc); + } + + break; } - else if (smc.TimeStamp >= diff) + case SubmodelElementList sml: { - output.Add(smc); + smeDiff = filterSubmodelElements(sml.Value ?? [], diff); + if (smeDiff.Count != 0) + { + var smlDiff = new SubmodelElementList( + typeValueListElement: sml.TypeValueListElement, + extensions: sml.Extensions, + category: sml.Category, + idShort: sml.IdShort, + displayName: sml.DisplayName, + description: sml.Description, + semanticId: sml.SemanticId, + supplementalSemanticIds: sml.SupplementalSemanticIds, + qualifiers: sml.Qualifiers, + embeddedDataSpecifications: sml.EmbeddedDataSpecifications, + value: smeDiff) {Parent = sml.Parent}; + output.Add(smlDiff); + } + else if (sml.TimeStamp >= diff) + { + output.Add(sml); + } + + break; } + default: + output.Add(sme); + break; } - else if (sme is SubmodelElementList sml) - { - smeDiff = filterSubmodelElements(sml.Value ?? [], diff); - if (smeDiff.Count != 0) - { - var smlDiff = new SubmodelElementList( - typeValueListElement: sml.TypeValueListElement, - extensions: sml.Extensions, - category: sml.Category, - idShort: sml.IdShort, - displayName: sml.DisplayName, - description: sml.Description, - semanticId: sml.SemanticId, - supplementalSemanticIds: sml.SupplementalSemanticIds, - qualifiers: sml.Qualifiers, - embeddedDataSpecifications: sml.EmbeddedDataSpecifications, - value: smeDiff) {Parent = sml.Parent}; - output.Add(smlDiff); - } - else if (sml.TimeStamp >= diff) - { - output.Add(sml); - } - } - else - output.Add(sme); } return output; @@ -380,6 +391,11 @@ public virtual IActionResult GetAllSubmodelElementsMetadataSubmodelRepo([FromRou { var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to get the metadata of all the submodel elements from the submodel with id {decodedSubmodelIdentifier}"); if (!Program.noSecurity) { @@ -387,27 +403,33 @@ public virtual IActionResult GetAllSubmodelElementsMetadataSubmodelRepo([FromRou var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } var smeList = _submodelService.GetAllSubmodelElements(decodedSubmodelIdentifier); - var filtered = new List(); - if (!string.IsNullOrEmpty(diff)) + var filtered = new List(); + DateTime _diff; + if (diff != null && diff != "") { try { - var _diff = DateTime.Parse(diff).ToUniversalTime(); + _diff = DateTime.Parse(diff).ToUniversalTime(); filtered = filterSubmodelElements(smeList, _diff); } - catch { } + catch + { + // ignored + } } else + { filtered = smeList; + } var smePagedList = _paginationService.GetPaginatedList(filtered, new PaginationParameters(cursor, limit)); - var smeListLevel = _levelExtentModifierService.ApplyLevelExtent(smePagedList.result ?? [], level); + var smeListLevel = _levelExtentModifierService.ApplyLevelExtent(smePagedList.result, level); var smeMetadataList = _mappingService.Map(smeListLevel, "metadata"); var output = new MetadataPagedResult() {result = smeMetadataList.ConvertAll(sme => (IMetadataDTO)sme), paging_metadata = smePagedList.paging_metadata}; return new ObjectResult(output); @@ -444,13 +466,13 @@ public virtual IActionResult GetAllSubmodelElementsPathSubmodelRepo([FromRoute] [FromQuery] string? diff) { var decodedSubmodelIdentifier = _decoderService.Decode($"submodelIdentifier", submodelIdentifier); - _logger.LogDebug($"Received request to get all the submodel elements from the submodel with id {decodedSubmodelIdentifier}"); - + if (decodedSubmodelIdentifier == null) { throw new NotAllowed($"Decoding {submodelIdentifier} returned null"); } - + + _logger.LogDebug($"Received request to get all the submodel elements from the submodel with id {decodedSubmodelIdentifier}"); if (!Program.noSecurity) { var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); @@ -463,20 +485,25 @@ public virtual IActionResult GetAllSubmodelElementsPathSubmodelRepo([FromRoute] var submodelElementList = _submodelService.GetAllSubmodelElements(decodedSubmodelIdentifier); - var filtered = new List(); - if (!string.IsNullOrEmpty(diff)) + var filtered = new List(); + DateTime _diff; + if (diff != null && diff != "") { try { - var _diff = DateTime.Parse(diff).ToUniversalTime(); + _diff = DateTime.Parse(diff).ToUniversalTime(); filtered = filterSubmodelElements(submodelElementList, _diff); } - catch { } + catch + { + // ignored + } } else filtered = submodelElementList; - // TODO (jtikekar, 2023-09-04): pagination and modifier not completely implemented + // TODO (jtikekar, 2023-09-04): pagination and modifier + // TODO (jtikekar, 2023-09-04): not complete implemented var output = _pathModifierService.ToIdShortPath(filtered); return new ObjectResult(output); } @@ -487,7 +514,7 @@ public virtual IActionResult GetAllSubmodelElementsPathSubmodelRepo([FromRoute] /// The Submodel’s unique id (UTF8-BASE64-URL-encoded) /// The maximum number of elements in the response array /// A server-generated identifier retrieved from pagingMetadata that specifies from which position the result listing should continue - /// Determines the structural depth of the respective resource content. + /// Determines the structural depth of the respective resource content /// List of found submodel elements /// Bad Request, e.g. the request parameters of the format of the request body is wrong. /// Unauthorized, e.g. the server refused the authorization attempt. @@ -511,6 +538,11 @@ public virtual IActionResult GetAllSubmodelElementsReferenceSubmodelRepo([FromRo { var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Decoding {submodelIdentifier} returned null"); + } + _logger.LogInformation($"Received a request to get all the submodel elements from submodel with id {decodedSubmodelIdentifier}"); if (!Program.noSecurity) { @@ -518,7 +550,7 @@ public virtual IActionResult GetAllSubmodelElementsReferenceSubmodelRepo([FromRo var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -562,6 +594,12 @@ public virtual IActionResult GetAllSubmodelElementsValueOnlySubmodelRepo([FromRo [FromQuery] ExtentEnum extent, [FromQuery] string? diff) { var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Decoding {submodelIdentifier} returned null"); + } + _logger.LogInformation($"Received request to get value of all the submodel elements from the submodel with id {decodedSubmodelIdentifier}"); if (!Program.noSecurity) { @@ -569,24 +607,30 @@ public virtual IActionResult GetAllSubmodelElementsValueOnlySubmodelRepo([FromRo var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } var submodelElements = _submodelService.GetAllSubmodelElements(decodedSubmodelIdentifier); - var filtered = new List(); - if (!string.IsNullOrEmpty(diff)) + var filtered = new List(); + DateTime _diff; + if (diff != null && diff != "") { try { - var _diff = DateTime.Parse(diff).ToUniversalTime(); + _diff = DateTime.Parse(diff).ToUniversalTime(); filtered = filterSubmodelElements(submodelElements, _diff); } - catch { } + catch + { + // ignored + } } else + { filtered = submodelElements; + } var smePagedList = _paginationService.GetPaginatedList(filtered, new PaginationParameters(cursor, limit)); var smeLevelExtent = _levelExtentModifierService.ApplyLevelExtent(smePagedList.result ?? [], level, extent); @@ -628,11 +672,21 @@ public virtual IActionResult GetAllSubmodels([FromQuery] [StringLength(3072, Min var reqSemanticId = _jsonQueryDeserializer.DeserializeReference("semanticId", semanticId); + if (reqSemanticId == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(reqSemanticId)} is null"); + } + + if (idShort == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(idShort)} is null"); + } + var submodelList = _submodelService.GetAllSubmodels(reqSemanticId, idShort); var submodelsPagedList = _paginationService.GetPaginatedList(submodelList, new PaginationParameters(cursor, limit)); var smLevelList = _levelExtentModifierService.ApplyLevelExtent(submodelsPagedList.result, level, extent); - var output = new PagedResult() {result = smLevelList, paging_metadata = submodelsPagedList.paging_metadata}; + var output = new PagedResult {result = smLevelList, paging_metadata = submodelsPagedList.paging_metadata}; return new ObjectResult(output); } @@ -664,7 +718,16 @@ public virtual IActionResult GetAllSubmodelsMetadata([FromQuery] [StringLength(3 [FromQuery] int? limit, [FromQuery] string? cursor, [FromQuery] LevelEnum level) { _logger.LogInformation($"Received request to get the metadata of all the submodels."); + if (idShort == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(idShort)} is null"); + } + var reqSemanticId = _jsonQueryDeserializer.DeserializeReference("semanticId", semanticId); + if (reqSemanticId == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(reqSemanticId)} is null"); + } var submodelList = _submodelService.GetAllSubmodels(reqSemanticId, idShort); @@ -699,16 +762,25 @@ public virtual IActionResult GetAllSubmodelsMetadata([FromQuery] [StringLength(3 [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult GetAllSubmodelsPath([FromQuery] [StringLength(3072, MinimumLength = 1)] string? semanticId, [FromQuery] string? idShort, + public virtual IActionResult GetAllSubmodelsPath([FromQuery] [StringLength(3072, MinimumLength = 1)] string semanticId, [FromQuery] string? idShort, [FromQuery] int? limit, [FromQuery] string? cursor, [FromQuery] LevelEnum level) { _logger.LogInformation($"Received request to get the metadata of all the submodels."); + if (idShort == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(idShort)} is null"); + } + var reqSemanticId = _jsonQueryDeserializer.DeserializeReference("semanticId", semanticId); + if (reqSemanticId == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(reqSemanticId)} is null"); + } var submodelList = _submodelService.GetAllSubmodels(reqSemanticId, idShort); var submodelPagedList = _paginationService.GetPaginatedList(submodelList, new PaginationParameters(cursor, limit)); - var submodelLevelList = _levelExtentModifierService.ApplyLevelExtent(submodelPagedList.result ?? [], level); + var submodelLevelList = _levelExtentModifierService.ApplyLevelExtent(submodelPagedList.result, level); // TODO (jtikekar, 2023-09-04): @Andreas, what if the first element is property, where path is not applicable var submodelsPath = _pathModifierService.ToIdShortPath(submodelLevelList.ConvertAll(sm => (ISubmodel)sm)); var output = new PathPagedResult() {result = submodelsPath, paging_metadata = submodelPagedList.paging_metadata}; @@ -743,8 +815,16 @@ public virtual IActionResult GetAllSubmodelsReference([FromQuery] [StringLength( [FromQuery] int? limit, [FromQuery] string? cursor, [FromQuery] LevelEnum level) { _logger.LogInformation($"Received a request to get all the submodels."); + if (idShort == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(idShort)} is null"); + } var reqSemanticId = _jsonQueryDeserializer.DeserializeReference("semanticId", semanticId); + if (reqSemanticId == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(reqSemanticId)} is null"); + } var submodelList = _submodelService.GetAllSubmodels(reqSemanticId, idShort); @@ -786,15 +866,23 @@ public virtual IActionResult GetAllSubmodelsValueOnly([FromQuery] [StringLength( [FromQuery] ExtentEnum extent) { _logger.LogInformation($"Received a request to get all the submodels."); + if (idShort == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(idShort)} is null"); + } var reqSemanticId = _jsonQueryDeserializer.DeserializeReference("semanticId", semanticId); + if (reqSemanticId == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(reqSemanticId)} is null"); + } var submodelList = _submodelService.GetAllSubmodels(reqSemanticId, idShort); var submodelsPagedList = _paginationService.GetPaginatedList(submodelList, new PaginationParameters(cursor, limit)); - var submodelLevelList = _levelExtentModifierService.ApplyLevelExtent(submodelsPagedList.result ?? [], level, extent); + var submodelLevelList = _levelExtentModifierService.ApplyLevelExtent(submodelsPagedList.result, level, extent); var submodelsValue = _mappingService.Map(submodelLevelList, "value"); - var output = new ValueOnlyPagedResult() {result = submodelsValue.ConvertAll(sme => (IValueDTO)sme), paging_metadata = submodelsPagedList.paging_metadata}; + var output = new ValueOnlyPagedResult {result = submodelsValue.ConvertAll(sme => (IValueDTO)sme), paging_metadata = submodelsPagedList.paging_metadata}; return new ObjectResult(output); } @@ -823,37 +911,52 @@ public virtual IActionResult GetAllSubmodelsValueOnly([FromQuery] [StringLength( [SwaggerResponse(statusCode: 405, type: typeof(Result), description: "Method not allowed - Download only valid for File submodel element")] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult GetFileByPathSubmodelRepo([FromRoute] [Required] string submodelIdentifier, [FromRoute] [Required] string idShortPath) + public virtual async Task GetFileByPathSubmodelRepo([FromRoute] [Required] string submodelIdentifier, [FromRoute] [Required] string idShortPath) { var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received a request to get file at {idShortPath} from submodel with id {decodedSubmodelIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + if (!Program.noSecurity) { var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } var fileName = _submodelService.GetFileByPath(decodedSubmodelIdentifier, idShortPath, out var content, out var fileSize); //content-disposition so that the aasx file can be downloaded from the web browser. - ContentDisposition contentDisposition = new() {FileName = fileName ?? throw new ArgumentNullException(nameof(fileName)), Inline = fileName.ToLower().EndsWith(".pdf")}; + ContentDisposition contentDisposition = new() + { + FileName = fileName ?? throw new NullValueException(nameof(fileName)), + Inline = fileName.EndsWith(".pdf", StringComparison.InvariantCulture) + }; HttpContext.Response.Headers.Append("Content-Disposition", contentDisposition.ToString()); HttpContext.Response.ContentLength = fileSize; - if (fileName.ToLower().EndsWith(".svg")) + if (fileName.EndsWith(".svg", StringComparison.InvariantCulture)) + { HttpContext.Response.ContentType = "image/svg+xml"; - if (fileName.ToLower().EndsWith(".pdf")) + } + + if (fileName.EndsWith(".pdf", StringComparison.InvariantCulture)) + { HttpContext.Response.ContentType = "application/pdf"; - HttpContext.Response.Body.WriteAsync(content); + } + + await HttpContext.Response.Body.WriteAsync(content); return new EmptyResult(); } @@ -908,7 +1011,7 @@ public virtual IActionResult GetOperationAsyncResult([FromRoute] [Required] stri exampleJson = "\"\""; var example = exampleJson != null - ? JsonConvert.DeserializeObject(exampleJson) + ? System.Text.Json.JsonSerializer.Deserialize(exampleJson) : default(OperationResult); //TODO: Change the data returned return new ObjectResult(example); } @@ -994,7 +1097,7 @@ public virtual IActionResult GetOperationAsyncStatus([FromRoute] [Required] stri //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... // return StatusCode(0, default(Result)); - return new ObjectResult(JsonConvert.DeserializeObject(string.Empty)); + return new ObjectResult(System.Text.Json.JsonSerializer.Deserialize(string.Empty)); } //TODO:jtikekar @Andreas the route is same as GetSubmodelById @@ -1025,7 +1128,10 @@ public virtual IActionResult GetSubmodelPolicyHeader([FromRoute] [Required] stri var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received head request to get the submodel policy for id {decodedSubmodelIdentifier}"); - Console.WriteLine($"Received head request to get the submodel policy for id {decodedSubmodelIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); @@ -1070,24 +1176,22 @@ public virtual IActionResult GetSubmodelById([FromRoute] [Required] string submo var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to get the submodel with id {decodedSubmodelIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - var failedReason = authResult.Failure.FailureReasons.FirstOrDefault(); - - if (failedReason != null) + var failedReason = authResult.Failure.FailureReasons.First(); + if (failedReason.Message != "") { - if (failedReason.Message != "") - { - throw new NotAllowed(failedReason.Message); - } - else - { - throw new NotAllowed("Policy incorrect!"); - } + throw new NotAllowed(failedReason.Message); } + + throw new NotAllowed("Policy incorrect!"); } var output = _levelExtentModifierService.ApplyLevelExtent(submodel, level, extent); @@ -1124,6 +1228,10 @@ public virtual IActionResult GetSubmodelByIdMetadata([FromRoute] [Required] stri { var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to get the metadata of the submodel with id {decodedSubmodelIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; @@ -1168,6 +1276,10 @@ public virtual IActionResult GetSubmodelByIdPath([FromRoute] [Required] string s { var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to get the idShortPath of the submodel with id {decodedSubmodelIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; @@ -1212,6 +1324,10 @@ public virtual IActionResult GetSubmodelByIdReference([FromRoute] [Required] str var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to get the submodel with id {decodedSubmodelIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; @@ -1257,6 +1373,10 @@ public virtual IActionResult GetSubmodelByIdValueOnly([FromRoute] [Required] str { var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to get value of submodel with id {decodedSubmodelIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); var authResult = _authorizationService.AuthorizeAsync(User, submodel, "SecurityPolicy").Result; @@ -1303,19 +1423,23 @@ public virtual IActionResult GetSubmodelElementByPathMetadataSubmodelRepo([FromR { var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to get metadata of submodel element at {idShortPath} from the submodel with id {decodedSubmodelIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } var submodelElement = _submodelService.GetSubmodelElementByPath(decodedSubmodelIdentifier, idShortPath); if (!Program.noSecurity) { var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -1354,19 +1478,23 @@ public virtual IActionResult GetSubmodelElementByPathPathSubmodelRepo([FromRoute { var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to path of the submodel element at {idShortPath} from a submodel with id {decodedSubmodelIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } var submodelElement = _submodelService.GetSubmodelElementByPath(decodedSubmodelIdentifier, idShortPath); if (!Program.noSecurity) { var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -1405,17 +1533,23 @@ public virtual IActionResult GetSubmodelElementByPathReferenceSubmodelRepo([From var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to get reference of the submodel element atv{idShortPath} from the submodel with id {decodedSubmodelIdentifier}"); + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + if (!Program.noSecurity) { var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -1456,17 +1590,23 @@ public virtual IActionResult GetSubmodelElementByPathSubmodelRepo([FromRoute] [R var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to get the submodel element at {idShortPath} from the submodel with id {decodedSubmodelIdentifier}"); + + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + if (!Program.noSecurity) { var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -1502,22 +1642,28 @@ public virtual IActionResult GetSubmodelElementByPathSubmodelRepo([FromRoute] [R [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult GetSubmodelElementByPathValueOnlySubmodelRepo([FromRoute] [Required] string submodelIdentifier, - [FromRoute] [Required] string idShortPath, [FromQuery] LevelEnum level, + [FromRoute] [Required] string idShortPath, + [FromQuery] LevelEnum level, [FromQuery] ExtentEnum extent) { var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to get the value of the submodel element at {idShortPath} from the submodel with id {decodedSubmodelIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + if (!Program.noSecurity) { var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -1687,7 +1833,7 @@ public virtual IActionResult InvokeOperationSubmodelRepo([FromBody] OperationReq //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... // return StatusCode(0, default(Result)); - return new ObjectResult(JsonConvert.DeserializeObject(string.Empty)); + return new ObjectResult(System.Text.Json.JsonSerializer.Deserialize(string.Empty)); } /// @@ -1746,9 +1892,19 @@ public virtual IActionResult InvokeOperationValueOnly([FromBody] object? body, [ [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PatchSubmodelById([FromBody] Submodel? body, [FromRoute] [Required] string submodelIdentifier, [FromQuery] LevelEnum level) { + if (body == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to update the submodel with id {decodedSubmodelIdentifier}."); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _submodelService.UpdateSubmodelById(decodedSubmodelIdentifier, body); return NoContent(); @@ -1777,19 +1933,26 @@ public virtual IActionResult PatchSubmodelById([FromBody] Submodel? body, [FromR [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult PatchSubmodelByIdMetadata([FromBody] SubmodelMetadata? body, [FromRoute] [Required] string submodelIdentifier, + public virtual IActionResult PatchSubmodelByIdMetadata([FromBody] SubmodelMetadata? body, [FromRoute] [Required] string? submodelIdentifier, [FromQuery] LevelEnum level) { + if (body == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received Patch Request for submodel with id {decodedSubmodelIdentifier}"); - - //Reverse mapping from Metadata to submodel element - if (body == null) + if (decodedSubmodelIdentifier == null) { - return NoContent(); + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); } var submodel = _mappingService.Map(body, "metadata") as ISubmodel; + if (submodel == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(submodel)} is null"); + } //Update _submodelService.UpdateSubmodelById(decodedSubmodelIdentifier, submodel); @@ -1823,15 +1986,24 @@ public virtual IActionResult PatchSubmodelByIdMetadata([FromBody] SubmodelMetada public virtual IActionResult PatchSubmodelByIdValueOnly([FromBody] SubmodelValue? body, [FromRoute] [Required] string submodelIdentifier, [FromQuery] LevelEnum level) { - var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); - _logger.LogInformation($"Received request to update the submodel with id {decodedSubmodelIdentifier} by value."); - if (body == null) { - return NoContent(); + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } + + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); } + _logger.LogInformation($"Received request to update the submodel with id {decodedSubmodelIdentifier} by value."); + var submodel = _mappingService.Map(body, "value") as Submodel; + if (submodel == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(submodel)} is null"); + } _submodelService.UpdateSubmodelById(decodedSubmodelIdentifier, submodel); @@ -1864,18 +2036,27 @@ public virtual IActionResult PatchSubmodelByIdValueOnly([FromBody] SubmodelValue [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PatchSubmodelElementByPathMetadataSubmodelRepo([FromBody] ISubmodelElementMetadata? body, [FromRoute] [Required] string submodelIdentifier, - [FromRoute] [Required] string idShortPath, [FromQuery] LevelEnum level) + [FromRoute] [Required] string idShortPath, + [FromQuery] LevelEnum level) { + if (body == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to update the submodel element at {idShortPath} in the submodel with id {decodedSubmodelIdentifier}"); - - //Reverse mapping from Metadata to submodel element - if (body == null) + if (decodedSubmodelIdentifier == null) { - return NoContent(); + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); } + //Reverse mapping from Metadata to submodel element var submodelElement = _mappingService.Map(body, "metadata") as ISubmodelElement; + if (submodelElement == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(submodelElement)} is null"); + } //Update _submodelService.UpdateSubmodelElementByPath(decodedSubmodelIdentifier, idShortPath, submodelElement); @@ -1910,7 +2091,16 @@ public virtual IActionResult PatchSubmodelElementByPathMetadataSubmodelRepo([Fro public virtual IActionResult PatchSubmodelElementByPathSubmodelRepo([FromBody] ISubmodelElement? body, [FromRoute] [Required] string submodelIdentifier, [FromRoute] [Required] string idShortPath, [FromQuery] LevelEnum level) { + if (body == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } _logger.LogInformation($"Received request to update the submodel element at {idShortPath} from submodel with id {decodedSubmodelIdentifier}."); _submodelService.UpdateSubmodelElementByPath(decodedSubmodelIdentifier, idShortPath, body); @@ -1942,18 +2132,27 @@ public virtual IActionResult PatchSubmodelElementByPathSubmodelRepo([FromBody] I [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult PatchSubmodelElementByPathValueOnlySubmodelRepo([FromBody] ISubmodelElementValue? body, [FromRoute] [Required] string submodelIdentifier, - [FromRoute] [Required] string idShortPath, [FromQuery] LevelEnum level) + public virtual IActionResult PatchSubmodelElementByPathValueOnlySubmodelRepo([FromBody] ISubmodelElementValue? body, + [FromRoute] [Required] string submodelIdentifier, + [FromRoute] [Required] string idShortPath, + [FromQuery] LevelEnum level) { + if (body == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received an update request for a submodel element at {idShortPath} in the submodel with id {decodedSubmodelIdentifier}."); - - if (body == null) + if (decodedSubmodelIdentifier == null) { - return NoContent(); + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); } - var submodelElement = _mappingService.Map(body, "value") as ISubmodelElement; + if (_mappingService.Map(body, "value") is not ISubmodelElement submodelElement) + { + throw new NotAllowed($"Cannot proceed as {nameof(submodelElement)} is null"); + } //Update _submodelService.UpdateSubmodelElementByPath(decodedSubmodelIdentifier, idShortPath, submodelElement); @@ -1988,10 +2187,20 @@ public virtual IActionResult PatchSubmodelElementByPathValueOnlySubmodelRepo([Fr [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PostSubmodel([FromBody] Submodel? body, [FromQuery] string? aasIdentifier) { + if (body == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } + _logger.LogInformation($"Received request to create a submodel."); var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); - var output = _submodelService.CreateSubmodel(body, decodedAasIdentifier); + if (decodedAasIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedAasIdentifier)} is null"); + } + + var output = _submodelService.CreateSubmodel(body, decodedAasIdentifier); return CreatedAtAction("PostSubmodel", output); } @@ -2025,22 +2234,34 @@ public virtual IActionResult PostSubmodel([FromBody] Submodel? body, [FromQuery] "Conflict, a resource which shall be created exists already. Might be thrown if a Submodel or SubmodelElement with the same ShortId is contained in a POST request.")] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult PostSubmodelElementByPathSubmodelRepo([FromBody] ISubmodelElement? body, [FromRoute] [Required] string submodelIdentifier, - [FromRoute] [Required] string idShortPath, bool first) + public virtual IActionResult PostSubmodelElementByPathSubmodelRepo([FromBody] ISubmodelElement? body, + [FromRoute] [Required] string submodelIdentifier, + [FromRoute] [Required] string idShortPath, + bool first) { + if (body == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _logger.LogInformation($"Received request to create a new submodel element at {idShortPath} in the submodel with id {decodedSubmodelIdentifier}"); if (!Program.noSecurity) { var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); - User.Claims.ToList().Add(new Claim("idShortPath", submodel.IdShort + "." + idShortPath)); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + idShortPath)}; + User.Claims.ToList().Add(new Claim("idShortPath", $"{submodel.IdShort}.{idShortPath}")); + var claimsList = new List(User.Claims) {new("IdShortPath", $"{submodel.IdShort}.{idShortPath}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -2077,20 +2298,32 @@ public virtual IActionResult PostSubmodelElementByPathSubmodelRepo([FromBody] IS "Conflict, a resource which shall be created exists already. Might be thrown if a Submodel or SubmodelElement with the same ShortId is contained in a POST request.")] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult PostSubmodelElementSubmodelRepo([FromBody] ISubmodelElement? body, [FromRoute] [Required] string submodelIdentifier, bool first) + public virtual IActionResult PostSubmodelElementSubmodelRepo([FromBody] ISubmodelElement? body, + [FromRoute] [Required] string submodelIdentifier, + bool first) { + if (body == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to create a new submodel element in the submodel with id {decodedSubmodelIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + if (!Program.noSecurity) { var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + body?.IdShort)}; + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{body.IdShort}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -2124,9 +2357,19 @@ public virtual IActionResult PostSubmodelElementSubmodelRepo([FromBody] ISubmode [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PutSubmodelById([FromBody] Submodel? body, [FromRoute] [Required] string submodelIdentifier) { + if (body == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); _logger.LogInformation($"Received request to replace a submodel {decodedSubmodelIdentifier}"); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + _submodelService.ReplaceSubmodelById(decodedSubmodelIdentifier, body); return NoContent(); @@ -2156,22 +2399,34 @@ public virtual IActionResult PutSubmodelById([FromBody] Submodel? body, [FromRou [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] - public virtual IActionResult PutSubmodelElementByPathSubmodelRepo([FromBody] ISubmodelElement? body, [FromRoute] [Required] string submodelIdentifier, - [FromRoute] [Required] string idShortPath, [FromQuery] LevelEnum level) + public virtual IActionResult PutSubmodelElementByPathSubmodelRepo([FromBody] ISubmodelElement? body, + [FromRoute] [Required] string submodelIdentifier, + [FromRoute] [Required] string idShortPath, + [FromQuery] LevelEnum level) { + if (body == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); - _logger.LogInformation($"Received request to replace a submodel element at {idShortPath} dom-object the submodel with id {decodedSubmodelIdentifier}."); + _logger.LogInformation($"Received request to replace a submodel element at {idShortPath} deom the submodel with id {decodedSubmodelIdentifier}."); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } + if (!Program.noSecurity) { var submodel = _submodelService.GetSubmodelById(decodedSubmodelIdentifier); - var claimsList = new List(User.Claims) {new Claim("IdShortPath", submodel.IdShort + "." + body?.IdShort)}; + var claimsList = new List(User.Claims) {new Claim("IdShortPath", $"{submodel.IdShort}.{body.IdShort}")}; var identity = new ClaimsIdentity(claimsList, "AasSecurityAuth"); var principal = new System.Security.Principal.GenericPrincipal(identity, null); var authResult = _authorizationService.AuthorizeAsync(principal, submodel, "SecurityPolicy").Result; if (!authResult.Succeeded) { - throw new NotAllowed(authResult.Failure.FailureReasons.First().Message); + throw new NotAllowed(authResult.Failure.FailureReasons.FirstOrDefault()?.Message ?? string.Empty); } } @@ -2200,14 +2455,32 @@ public virtual IActionResult PutSubmodelElementByPathSubmodelRepo([FromBody] ISu [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] public virtual IActionResult PutFileByPathSubmodelRepo([FromRoute] [Required] string submodelIdentifier, [FromRoute] string? idShortPath, IFormFile? file) { - var decodedSubmodelId = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (idShortPath == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(idShortPath)} is null"); + } + + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier); + if (decodedSubmodelIdentifier == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null"); + } var stream = new MemoryStream(); file?.CopyTo(stream); var fileName = file?.FileName; var contentType = file?.ContentType; + if (fileName == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(fileName)} is null"); + } + + if (contentType == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(contentType)} is null"); + } - _submodelService.ReplaceFileByPath(decodedSubmodelId, idShortPath, fileName, contentType, stream); + _submodelService.ReplaceFileByPath(decodedSubmodelIdentifier, idShortPath, fileName, contentType, stream); return NoContent(); } diff --git a/src/IO.Swagger.Lib.V3/Formatters/AasRequestFormatter.cs b/src/IO.Swagger.Lib.V3/Formatters/AasRequestFormatter.cs index 3cefac9a6..417ffaa73 100644 --- a/src/IO.Swagger.Lib.V3/Formatters/AasRequestFormatter.cs +++ b/src/IO.Swagger.Lib.V3/Formatters/AasRequestFormatter.cs @@ -8,8 +8,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; using System; using System.Collections.Generic; using System.Linq; @@ -18,6 +16,10 @@ namespace IO.Swagger.Lib.V3.Formatters { + using System.Text.Json; + using System.Text.Json.Serialization; + using AdminShellNS; + public class AasRequestFormatter : InputFormatter { public AasRequestFormatter() @@ -93,17 +95,17 @@ public override Task ReadRequestBodyAsync(InputFormatterCo } else if (typeof(SubmodelValue).IsAssignableFrom(type)) { - var serviceProvider = context.HttpContext.RequestServices; + var serviceProvider = context.HttpContext.RequestServices; var valueOnlyJsonDeserializerService = serviceProvider.GetRequiredService(); - var encodedSubmodelIdentifier = request.RouteValues["submodelIdentifier"] as string; + var encodedSubmodelIdentifier = request.RouteValues["submodelIdentifier"] as string; result = valueOnlyJsonDeserializerService.DeserializeSubmodelValue(node, encodedSubmodelIdentifier); } else if (typeof(IValueDTO).IsAssignableFrom(type)) { - var serviceProvider = context.HttpContext.RequestServices; - var valueOnlyJsonDeserializerService = serviceProvider.GetRequiredService(); - var encodedSubmodelIdentifier = request.RouteValues["submodelIdentifier"] as string; - string idShortPath = (string)request.RouteValues["idShortPath"]; + var serviceProvider = context.HttpContext.RequestServices; + var valueOnlyJsonDeserializerService = serviceProvider.GetRequiredService(); + var encodedSubmodelIdentifier = request.RouteValues["submodelIdentifier"] as string; + string idShortPath = (string)request.RouteValues["idShortPath"]; result = valueOnlyJsonDeserializerService.DeserializeSubmodelElementValue(node, encodedSubmodelIdentifier, idShortPath); } @@ -113,7 +115,6 @@ public override Task ReadRequestBodyAsync(InputFormatterCo SerializationModifiersValidator.Validate(result, level, extent); return InputFormatterResult.SuccessAsync(result); - } private void GetSerializationMidifiersFromRequest(HttpRequest request, out LevelEnum level, out ExtentEnum extent) @@ -142,209 +143,220 @@ private void GetSerializationMidifiersFromRequest(HttpRequest request, out Level private SubmodelMetadata? SubmodelMetadataFrom(JsonNode node) { SubmodelMetadata? output = null; - //Using newtonsoft json because of known "EnumMemberAttribute" issue (https://github.com/dotnet/runtime/issues/74385) in case of ValueType - var serilizerSettings = new JsonSerializerSettings(); - serilizerSettings.Converters.Add(new StringEnumConverter()); - var obj = node as JsonObject; - if (obj == null) + if (node == null) + { + throw new ArgumentNullException(nameof(node)); + } + + if (!(node is JsonNode obj)) { throw new Exception($"Not a JSON object"); } + JsonNode? modelTypeNode = obj["modelType"]; if (modelTypeNode == null) { throw new Exception($"No model type found in the request."); } + JsonValue? modelTypeValue = modelTypeNode as JsonValue; if (modelTypeValue == null) { - throw new Exception( - "Expected JsonValue, " + - $"but got {modelTypeNode.GetType()}"); + throw new Exception($"Expected JsonValue, but got {modelTypeNode.GetType()}"); } + modelTypeValue.TryGetValue(out string? modelType); if (modelType == null) { - throw new Exception( - "Expected a string, " + - $"but the conversion failed from {modelTypeValue}"); + throw new Exception($"Expected a string, but the conversion failed from {modelTypeValue}"); } - if (modelType.Equals("submodel", StringComparison.OrdinalIgnoreCase)) + if (!modelType.Equals("submodel", StringComparison.OrdinalIgnoreCase)) { - var valueMetadata = ISubmodelElementMetadatListFrom(obj["submodelElements"]); + return output; + } - node["submodelElements"] = null; - var submodelMetadata = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); + // Deserialize submodelElements + var valueMetadata = ISubmodelElementMetadatListFrom(obj["submodelElements"]); - if (submodelMetadata != null) - { - output = new SubmodelMetadata(submodelMetadata.id, submodelMetadata.extensions, submodelMetadata.category, submodelMetadata.idShort, - submodelMetadata.displayName, - submodelMetadata.description, submodelMetadata.administration, submodelMetadata.kind, submodelMetadata.semanticId, - submodelMetadata.supplementalSemanticIds, submodelMetadata.qualifiers, submodelMetadata.embeddedDataSpecifications, - valueMetadata); - } + var jsonString = obj.ToString(); + + // Deserialize using System.Text.Json + var options = new JsonSerializerOptions + { + Converters = {new JsonStringEnumConverter()} // Assuming you want to convert enums as strings + }; + + var submodelMetadata = JsonSerializer.Deserialize(jsonString, options); + + if (submodelMetadata != null) + { + output = new SubmodelMetadata( + submodelMetadata.id, + submodelMetadata.extensions, + submodelMetadata.category, + submodelMetadata.idShort, + submodelMetadata.displayName, + submodelMetadata.description, + submodelMetadata.administration, + submodelMetadata.kind, + submodelMetadata.semanticId, + submodelMetadata.supplementalSemanticIds, + submodelMetadata.qualifiers, + submodelMetadata.embeddedDataSpecifications, + valueMetadata); } return output; } - private ISubmodelElementMetadata? ISubmodelElementMetadataFrom(JsonNode node) + public ISubmodelElementMetadata? ISubmodelElementMetadataFrom(JsonNode node) { ISubmodelElementMetadata? output = null; - //Using newtonsoft json because of known "EnumMemberAttribute" issue (https://github.com/dotnet/runtime/issues/74385) in case of ValueType - var serilizerSettings = new JsonSerializerSettings(); - serilizerSettings.Converters.Add(new StringEnumConverter()); - var obj = node as JsonObject; - if (obj == null) + if (node == null) + { + throw new ArgumentNullException(nameof(node)); + } + + // Using System.Text.Json for JSON handling + if (!(node is JsonNode obj)) { throw new Exception($"Not a JSON object"); } + JsonNode? modelTypeNode = obj["modelType"]; if (modelTypeNode == null) { throw new Exception($"No model type found in the request."); } - JsonValue? modelTypeValue = modelTypeNode as JsonValue; - if (modelTypeValue == null) - { - throw new Exception( - "Expected JsonValue, " + - $"but got {modelTypeNode.GetType()}"); - } - modelTypeValue.TryGetValue(out string? modelType); + + string modelType = modelTypeNode.ToJsonString(); if (modelType == null) { - throw new Exception( - "Expected a string, " + - $"but the conversion failed from {modelTypeValue}"); + throw new Exception($"Expected a string, but the conversion failed from {modelTypeNode}"); } + JsonSerializerOptions serializerOptions = new JsonSerializerOptions + { + Converters + = + { + new AdminShellConverters.JsonAasxConverter("modelType", "name") + }, // Assuming JsonAasxConverter is compatible with System.Text.Json + PropertyNameCaseInsensitive = true, + AllowTrailingCommas = true, + ReadCommentHandling = JsonCommentHandling.Skip, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; + switch (modelType.ToLower()) { case "property": - { - //var propertyMetadata = JsonSerializer.Deserialize(node); - output = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); - break; - } + { + //var propertyMetadata = JsonSerializer.Deserialize(node); + output = JsonSerializer.Deserialize(node.ToJsonString(), serializerOptions); + break; + } case "annotatedrelationshipelement": - { - var valueMetadata = ISubmodelElementMetadatListFrom(obj["annotations"]); - - node["annotations"] = null; - var annotatedRelElement = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); - - output = new AnnotatedRelationshipElementMetadata(annotatedRelElement.extensions, annotatedRelElement.category, annotatedRelElement.idShort, - annotatedRelElement.displayName, annotatedRelElement.description, annotatedRelElement.semanticId, - annotatedRelElement.supplementalSemanticIds, annotatedRelElement.qualifiers, - annotatedRelElement.embeddedDataSpecifications, valueMetadata); - break; - } + { + var valueMetadata = ISubmodelElementMetadatListFrom(obj["annotations"]); + + node["annotations"] = null; + var annotatedRelElement = JsonSerializer.Deserialize(node.ToJsonString(), serializerOptions); + + output = new AnnotatedRelationshipElementMetadata(annotatedRelElement.extensions, annotatedRelElement.category, annotatedRelElement.idShort, + annotatedRelElement.displayName, annotatedRelElement.description, annotatedRelElement.semanticId, + annotatedRelElement.supplementalSemanticIds, annotatedRelElement.qualifiers, + annotatedRelElement.embeddedDataSpecifications, valueMetadata); + break; + } case "basiceventelement": - { - output = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); - break; - } + output = JsonSerializer.Deserialize(node.ToString(), serializerOptions); + break; case "blob": - { - output = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); - break; - } + output = JsonSerializer.Deserialize(node.ToString(), serializerOptions); + break; case "entity": - { - var valueMetadata = ISubmodelElementMetadatListFrom(obj["statements"]); + { + var valueMetadata = ISubmodelElementMetadatListFrom(obj["statements"]); - node["statements"] = null; - var entity = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); + node["statements"] = null; + var entity = JsonSerializer.Deserialize(node.ToJsonString(), serializerOptions); - output = new EntityMetadata(entity.entityType, entity.extensions, entity.category, entity.idShort, entity.displayName, entity.description, - entity.semanticId, entity.supplementalSemanticIds, entity.qualifiers, entity.embeddedDataSpecifications, valueMetadata); - break; - } + output = new EntityMetadata(entity.entityType, entity.extensions, entity.category, entity.idShort, entity.displayName, entity.description, + entity.semanticId, entity.supplementalSemanticIds, entity.qualifiers, entity.embeddedDataSpecifications, valueMetadata); + break; + } case "file": - { - output = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); - break; - } + output = JsonSerializer.Deserialize(node.ToString(), serializerOptions); + break; case "multilanguageproperty": - { - output = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); - break; - } + output = JsonSerializer.Deserialize(node.ToString(), serializerOptions); + break; case "operation": - { - output = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); - break; - } + output = JsonSerializer.Deserialize(node.ToString(), serializerOptions); + break; case "range": - { - output = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); - break; - } + output = JsonSerializer.Deserialize(node.ToString(), serializerOptions); + break; case "referenceelement": - { - output = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); - break; - } + output = JsonSerializer.Deserialize(node.ToString(), serializerOptions); + break; case "relationshipelement": - { - output = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); - break; - } + output = JsonSerializer.Deserialize(node.ToString(), serializerOptions); + break; case "submodelelementcollection": - { - - var valueMetadata = ISubmodelElementMetadatListFrom(obj["value"]); + { + var valueMetadata = ISubmodelElementMetadatListFrom(obj["value"]); - node["value"] = null; - var smeColl = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); + node["value"] = null; + var smeColl = JsonSerializer.Deserialize(node.ToJsonString(), serializerOptions); - output = new SubmodelElementCollectionMetadata(smeColl.extensions, smeColl.category, smeColl.idShort, smeColl.displayName, smeColl.description, - smeColl.semanticId, smeColl.supplementalSemanticIds, smeColl.qualifiers, smeColl.embeddedDataSpecifications, - valueMetadata); + output = new SubmodelElementCollectionMetadata(smeColl.extensions, smeColl.category, smeColl.idShort, smeColl.displayName, smeColl.description, + smeColl.semanticId, smeColl.supplementalSemanticIds, smeColl.qualifiers, smeColl.embeddedDataSpecifications, + valueMetadata); - break; - } + break; + } case "submodelelementlist": - { - var valueMetadata = ISubmodelElementMetadatListFrom(obj["value"]); + { + var valueMetadata = ISubmodelElementMetadatListFrom(obj["value"]); - node["value"] = null; - var smeList = JsonConvert.DeserializeObject(node.ToJsonString(), serilizerSettings); + node["value"] = null; + var smeList = JsonSerializer.Deserialize(node.ToJsonString(), serializerOptions); - output = new SubmodelElementListMetadata(smeList.typeValueListElement, smeList.extensions, smeList.category, smeList.idShort, smeList.displayName, - smeList.description, smeList.semanticId, smeList.supplementalSemanticIds, smeList.qualifiers, - smeList.embeddedDataSpecifications, smeList.orderRelevant, smeList.semanticIdListElement, - smeList.valueTypeListElement, valueMetadata); - break; - } + output = new SubmodelElementListMetadata(smeList.typeValueListElement, smeList.extensions, smeList.category, smeList.idShort, smeList.displayName, + smeList.description, smeList.semanticId, smeList.supplementalSemanticIds, smeList.qualifiers, + smeList.embeddedDataSpecifications, smeList.orderRelevant, smeList.semanticIdListElement, + smeList.valueTypeListElement, valueMetadata); + break; + } } return output; } + private List ISubmodelElementMetadatListFrom(JsonNode jsonNode) { - if (jsonNode == null) return null; + if (jsonNode == null) + { + return null; + } - var valueArray = jsonNode as JsonArray; - if (valueArray == null) + if (jsonNode is not JsonArray valueArray) { throw new Exception( - $"Expected a JsonArray, but got {jsonNode.GetType()}"); + $"Expected a JsonArray, but got {jsonNode.GetType()}"); } + var valueMetadata = new List( valueArray.Count); - foreach (JsonNode value in valueArray) - { - valueMetadata.Add(ISubmodelElementMetadataFrom(value)); - } + valueMetadata.AddRange(valueArray.Select(value => ISubmodelElementMetadataFrom(value))); return valueMetadata; } } -} +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs b/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs index 003710905..315bef526 100644 --- a/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs +++ b/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs @@ -100,9 +100,9 @@ public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) else if (IsGenericListOfIClass(context.Object)) { - var jsonArray = new JsonArray(); - IList genericList = (IList)context.Object; - List contextObjectType = new List(); + var jsonArray = new JsonArray(); + IList genericList = (IList)context.Object; + List contextObjectType = new List(); foreach (var generic in genericList) { contextObjectType.Add((IClass)generic); diff --git a/src/IO.Swagger.Lib.V3/IO.Swagger.Lib.V3.csproj b/src/IO.Swagger.Lib.V3/IO.Swagger.Lib.V3.csproj index ecd159c2b..a1a362a23 100644 --- a/src/IO.Swagger.Lib.V3/IO.Swagger.Lib.V3.csproj +++ b/src/IO.Swagger.Lib.V3/IO.Swagger.Lib.V3.csproj @@ -22,7 +22,6 @@ - diff --git a/src/IO.Swagger.Lib.V3/Interfaces/IGenerateSerializationService.cs b/src/IO.Swagger.Lib.V3/Interfaces/IGenerateSerializationService.cs index 12948e7f6..3ae8af08a 100644 --- a/src/IO.Swagger.Lib.V3/Interfaces/IGenerateSerializationService.cs +++ b/src/IO.Swagger.Lib.V3/Interfaces/IGenerateSerializationService.cs @@ -1,9 +1,17 @@ using System.Collections.Generic; -namespace IO.Swagger.Lib.V3.Interfaces +namespace IO.Swagger.Lib.V3.Interfaces; + +/// +/// Service responsible for generating serialized representations of Asset Administration Shells (AAS) and Submodels. +/// +public interface IGenerateSerializationService { - public interface IGenerateSerializationService - { - Environment GenerateSerializationByIds(List? aasIds = null, List? submodelIds = null, bool includeConceptDescriptions = false); - } + /// + /// Generates a serialized environment containing the requested Asset Administration Shells (AAS) and Submodels. + /// + /// Optional list of AAS IDs to include in the serialized output. + /// Optional list of Submodel IDs to include in the serialized output. + /// An object containing the specified AAS and Submodels. + Environment GenerateSerializationByIds(List? aasIds = null, List? submodelIds = null); } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Interfaces/ILevelExtentModifierService.cs b/src/IO.Swagger.Lib.V3/Interfaces/ILevelExtentModifierService.cs index 91bccd4fc..c04a434d3 100644 --- a/src/IO.Swagger.Lib.V3/Interfaces/ILevelExtentModifierService.cs +++ b/src/IO.Swagger.Lib.V3/Interfaces/ILevelExtentModifierService.cs @@ -29,4 +29,4 @@ public interface ILevelExtentModifierService /// The list of transformed IClass instances. /// Thrown if the input list is null. List ApplyLevelExtent(List that, LevelEnum level = LevelEnum.Deep, ExtentEnum extent = ExtentEnum.WithoutBlobValue); -} \ No newline at end of file +} diff --git a/src/IO.Swagger.Lib.V3/Interfaces/IPathModifierService.cs b/src/IO.Swagger.Lib.V3/Interfaces/IPathModifierService.cs index 655ba47a8..774c7f6ac 100644 --- a/src/IO.Swagger.Lib.V3/Interfaces/IPathModifierService.cs +++ b/src/IO.Swagger.Lib.V3/Interfaces/IPathModifierService.cs @@ -27,4 +27,4 @@ public interface IPathModifierService /// The list of submodel elements to transform. /// A list of lists of strings representing the transformed paths. List> ToIdShortPath(List submodelElementList); -} \ No newline at end of file +} diff --git a/src/IO.Swagger.Lib.V3/Interfaces/IReferenceModifierService.cs b/src/IO.Swagger.Lib.V3/Interfaces/IReferenceModifierService.cs index c86a06f02..de0707cee 100644 --- a/src/IO.Swagger.Lib.V3/Interfaces/IReferenceModifierService.cs +++ b/src/IO.Swagger.Lib.V3/Interfaces/IReferenceModifierService.cs @@ -5,6 +5,6 @@ namespace IO.Swagger.Lib.V3.Interfaces public interface IReferenceModifierService { List GetReferenceResult(List referables); - IReference GetReferenceResult(IReferable referable); + IReference? GetReferenceResult(IReferable referable); } } diff --git a/src/IO.Swagger.Lib.V3/Middleware/ExceptionMiddleware.cs b/src/IO.Swagger.Lib.V3/Middleware/ExceptionMiddleware.cs index c88780f48..a7c888194 100644 --- a/src/IO.Swagger.Lib.V3/Middleware/ExceptionMiddleware.cs +++ b/src/IO.Swagger.Lib.V3/Middleware/ExceptionMiddleware.cs @@ -13,14 +13,14 @@ namespace IO.Swagger.Lib.V3.Middleware { + using System.Globalization; + using System.Linq; + public class ExceptionMiddleware { private readonly RequestDelegate _next; - public ExceptionMiddleware(RequestDelegate next) - { - _next = next; - } + public ExceptionMiddleware(RequestDelegate next) => _next = next; public async Task InvokeAsync(HttpContext httpContext, IAppLogger logger) { @@ -38,20 +38,20 @@ public async Task InvokeAsync(HttpContext httpContext, IAppLogger logger) { logger.LogError(exception.Message); - logger.LogDebug(exception.StackTrace); + logger.LogDebug(exception.StackTrace ?? $"No Stacktrace for {exception}"); context.Response.ContentType = "application/json"; var result = new Result(); var message = new Message(); - + var currentDateTime = DateTime.Now.ToString(CultureInfo.InvariantCulture); switch (exception) { case DuplicateException ex: { context.Response.StatusCode = (int)HttpStatusCode.Conflict; - message.Code = HttpStatusCode.Conflict.ToString(); - message.Text = ex.Message; - message.Timestamp = DateTime.Now.ToString(); - message.MessageType = MessageTypeEnum.ErrorEnum; + message.Code = HttpStatusCode.Conflict.ToString(); + message.Text = ex.Message; + message.Timestamp = currentDateTime; + message.MessageType = MessageTypeEnum.Error; break; } case FileNotFoundException: @@ -60,8 +60,8 @@ private async Task HandleExceptionAsync(HttpContext context, Exception exception context.Response.StatusCode = (int)HttpStatusCode.NotFound; message.Code = HttpStatusCode.NotFound.ToString(); message.Text = exception.Message; - message.Timestamp = DateTime.Now.ToString(); - message.MessageType = MessageTypeEnum.ErrorEnum; + message.Timestamp = currentDateTime; + message.MessageType = MessageTypeEnum.Error; break; } case NotAllowed: @@ -69,24 +69,23 @@ private async Task HandleExceptionAsync(HttpContext context, Exception exception context.Response.StatusCode = (int)HttpStatusCode.Forbidden; message.Code = HttpStatusCode.Forbidden.ToString(); message.Text = exception.Message; - message.Timestamp = DateTime.Now.ToString(); - message.MessageType = MessageTypeEnum.ErrorEnum; + message.Timestamp = currentDateTime; + message.MessageType = MessageTypeEnum.Error; break; } case MetamodelVerificationException ex: { //Print the errors in debug level - foreach (var error in ex.ErrorList) + foreach (var errorText in ex.ErrorList.Select(error => $"{Reporting.GenerateJsonPath(error.PathSegments)}:{error.Cause}")) { - var errorText = Reporting.GenerateJsonPath(error.PathSegments) + ":" + error.Cause; logger.LogDebug(errorText); } context.Response.StatusCode = (int)HttpStatusCode.BadRequest; message.Code = HttpStatusCode.BadRequest.ToString(); message.Text = exception.Message; - message.Timestamp = DateTime.Now.ToString(); - message.MessageType = MessageTypeEnum.ErrorEnum; + message.Timestamp = currentDateTime; + message.MessageType = MessageTypeEnum.Error; break; } case InvalidIdShortPathException: @@ -103,8 +102,8 @@ private async Task HandleExceptionAsync(HttpContext context, Exception exception context.Response.StatusCode = (int)HttpStatusCode.BadRequest; message.Code = HttpStatusCode.BadRequest.ToString(); message.Text = exception.Message; - message.Timestamp = DateTime.Now.ToString(); - message.MessageType = MessageTypeEnum.ErrorEnum; + message.Timestamp = currentDateTime; + message.MessageType = MessageTypeEnum.Error; break; } case InvalidSerializationModifierException: @@ -112,8 +111,8 @@ private async Task HandleExceptionAsync(HttpContext context, Exception exception context.Response.StatusCode = (int)HttpStatusCode.MethodNotAllowed; message.Code = HttpStatusCode.MethodNotAllowed.ToString(); message.Text = exception.Message; - message.Timestamp = DateTime.Now.ToString(); - message.MessageType = MessageTypeEnum.ErrorEnum; + message.Timestamp = currentDateTime; + message.MessageType = MessageTypeEnum.Error; break; } case Exceptions.NotImplementedException: @@ -121,8 +120,8 @@ private async Task HandleExceptionAsync(HttpContext context, Exception exception context.Response.StatusCode = (int)HttpStatusCode.NotImplemented; message.Code = HttpStatusCode.NotImplemented.ToString(); message.Text = exception.Message; - message.Timestamp = DateTime.Now.ToString(); - message.MessageType = MessageTypeEnum.ErrorEnum; + message.Timestamp = currentDateTime; + message.MessageType = MessageTypeEnum.Error; break; } case UnprocessableEntityException: @@ -130,8 +129,8 @@ private async Task HandleExceptionAsync(HttpContext context, Exception exception context.Response.StatusCode = (int)HttpStatusCode.UnprocessableEntity; message.Code = HttpStatusCode.UnprocessableEntity.ToString(); message.Text = exception.Message; - message.Timestamp = DateTime.Now.ToString(); - message.MessageType = MessageTypeEnum.ErrorEnum; + message.Timestamp = currentDateTime; + message.MessageType = MessageTypeEnum.Error; break; } default: @@ -139,8 +138,8 @@ private async Task HandleExceptionAsync(HttpContext context, Exception exception context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; message.Code = HttpStatusCode.InternalServerError.ToString(); message.Text = exception.Message; - message.Timestamp = DateTime.Now.ToString(); - message.MessageType = MessageTypeEnum.ErrorEnum; + message.Timestamp = currentDateTime; + message.MessageType = MessageTypeEnum.Error; break; } } diff --git a/src/IO.Swagger.Lib.V3/Models/BaseOperationResult.cs b/src/IO.Swagger.Lib.V3/Models/BaseOperationResult.cs index 08c5dbc2d..ac7285011 100644 --- a/src/IO.Swagger.Lib.V3/Models/BaseOperationResult.cs +++ b/src/IO.Swagger.Lib.V3/Models/BaseOperationResult.cs @@ -9,36 +9,32 @@ */ using System; -using System.Linq; -using System.IO; using System.Text; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; -using Newtonsoft.Json; namespace IO.Swagger.Models { + using System.Text.Json; + using System.Text.Json.Serialization; + /// /// /// - [ DataContract ] + [DataContract] public partial class BaseOperationResult : Result, IEquatable { /// /// Gets or Sets ExecutionState /// - [ DataMember(Name = "executionState") ] + [DataMember(Name = "executionState")] public ExecutionState ExecutionState { get; set; } /// /// Gets or Sets Success /// - [ DataMember(Name = "success") ] + [DataMember(Name = "success")] public bool? Success { get; set; } /// @@ -59,10 +55,9 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public new string ToJson() - { - return JsonConvert.SerializeObject(this, Formatting.Indented); - } + public new string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true, Converters = {new JsonStringEnumConverter()}}; /// /// Returns true if objects are equal @@ -73,7 +68,7 @@ public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((BaseOperationResult) obj); + return obj.GetType() == GetType() && Equals((BaseOperationResult)obj); } /// diff --git a/src/IO.Swagger.Lib.V3/Models/Description.cs b/src/IO.Swagger.Lib.V3/Models/Description.cs index e4ed0b06f..d321d106d 100644 --- a/src/IO.Swagger.Lib.V3/Models/Description.cs +++ b/src/IO.Swagger.Lib.V3/Models/Description.cs @@ -4,205 +4,127 @@ * The entire Repository Service Specification as part of Details of the Asset Administration Shell Part 2 * * OpenAPI spec version: V3.0 - * + * * Generated by: https://github.com/swagger-api/swagger-codegen.git */ + using System; using System.Linq; -using System.IO; using System.Text; -using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; -using Newtonsoft.Json; -namespace IO.Swagger.Models +namespace IO.Swagger.Models; + +using System.Text.Json; +using System.Text.Json.Serialization; + +/// +/// The Description object enables servers to present their capabilities to the clients, in particular which profiles they implement. +/// At least one defined profile is required. Additional, proprietary attributes might be included. Nevertheless, the server must not expect that a regular +/// client understands them. +/// +[DataContract] +public partial class Description : IEquatable { /// - /// The Description object enables servers to present their capabilities to the clients, in particular which profiles they implement. At least one defined profile is required. Additional, proprietary attributes might be included. Nevertheless, the server must not expect that a regular client understands them. + /// Gets or Sets Profiles + /// + + [DataMember(Name = "profiles")] + public List? Profiles { get; set; } + + /// + /// Returns the string presentation of the object /// - [DataContract] - public partial class Description : IEquatable + /// String presentation of the object + public override string ToString() { - /// - /// Gets or Sets Profiles - /// - [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public enum ProfilesEnum - { - /// - /// Enum AssetAdministrationShellServiceSpecificationV30Enum for AssetAdministrationShellServiceSpecification/V3.0 - /// - [EnumMember(Value = "AssetAdministrationShellServiceSpecification/V3.0")] - AssetAdministrationShellServiceSpecificationV30Enum = 0, - /// - /// Enum AssetAdministrationShellServiceSpecificationV30MinimalProfileEnum for AssetAdministrationShellServiceSpecification/V3.0-MinimalProfile - /// - [EnumMember(Value = "AssetAdministrationShellServiceSpecification/V3.0-MinimalProfile")] - AssetAdministrationShellServiceSpecificationV30MinimalProfileEnum = 1, - /// - /// Enum SubmodelServiceSpecificationV30Enum for SubmodelServiceSpecification/V3.0 - /// - [EnumMember(Value = "SubmodelServiceSpecification/V3.0")] - SubmodelServiceSpecificationV30Enum = 2, - /// - /// Enum SubmodelServiceSpecificationV30ValueProfileEnum for SubmodelServiceSpecification/V3.0-ValueProfile - /// - [EnumMember(Value = "SubmodelServiceSpecification/V3.0-ValueProfile")] - SubmodelServiceSpecificationV30ValueProfileEnum = 3, - /// - /// Enum SubmodelServiceSpecificationV30MinimalProfileEnum for SubmodelServiceSpecification/V3.0-MinimalProfile - /// - [EnumMember(Value = "SubmodelServiceSpecification/V3.0-MinimalProfile")] - SubmodelServiceSpecificationV30MinimalProfileEnum = 4, - /// - /// Enum AasxFileServerServiceSpecificationV30Enum for AasxFileServerServiceSpecification/V3.0 - /// - [EnumMember(Value = "AasxFileServerServiceSpecification/V3.0")] - AasxFileServerServiceSpecificationV30Enum = 5, - /// - /// Enum RegistryServiceSpecificationV30Enum for RegistryServiceSpecification/V3.0 - /// - [EnumMember(Value = "RegistryServiceSpecification/V3.0")] - RegistryServiceSpecificationV30Enum = 6, - /// - /// Enum RegistryServiceSpecificationV30AssetAdministrationShellRegistryEnum for RegistryServiceSpecification/V3.0- AssetAdministrationShellRegistry - /// - [EnumMember(Value = "RegistryServiceSpecification/V3.0- AssetAdministrationShellRegistry")] - RegistryServiceSpecificationV30AssetAdministrationShellRegistryEnum = 7, - /// - /// Enum RegistryServiceSpecificationV30SubmodelRegistryEnum for RegistryServiceSpecification/V3.0-SubmodelRegistry - /// - [EnumMember(Value = "RegistryServiceSpecification/V3.0-SubmodelRegistry")] - RegistryServiceSpecificationV30SubmodelRegistryEnum = 8, - /// - /// Enum RepositoryServiceSpecificationV30Enum for RepositoryServiceSpecification/V3.0 - /// - [EnumMember(Value = "RepositoryServiceSpecification/V3.0")] - RepositoryServiceSpecificationV30Enum = 9, - /// - /// Enum RepositoryServiceSpecificationV30MinimalProfileEnum for RepositoryServiceSpecification/V3.0-MinimalProfile - /// - [EnumMember(Value = "RepositoryServiceSpecification/V3.0-MinimalProfile")] - RepositoryServiceSpecificationV30MinimalProfileEnum = 10, - /// - /// Enum AssetAdministrationShellRepositoryServiceSpecificationV30Enum for AssetAdministrationShellRepositoryServiceSpecification/V3.0 - /// - [EnumMember(Value = "AssetAdministrationShellRepositoryServiceSpecification/V3.0")] - AssetAdministrationShellRepositoryServiceSpecificationV30Enum = 11, - /// - /// Enum AssetAdministrationShellRepositoryServiceSpecificationV30MinimalProfileEnum for AssetAdministrationShellRepositoryServiceSpecification/V3.0-MinimalProfile - /// - [EnumMember(Value = "AssetAdministrationShellRepositoryServiceSpecification/V3.0-MinimalProfile")] - AssetAdministrationShellRepositoryServiceSpecificationV30MinimalProfileEnum = 12, - /// - /// Enum SubmodelRepositoryServiceSpecificationV30Enum for SubmodelRepositoryServiceSpecification/V3.0 - /// - [EnumMember(Value = "SubmodelRepositoryServiceSpecification/V3.0")] - SubmodelRepositoryServiceSpecificationV30Enum = 13, - /// - /// Enum SubmodelRepositoryServiceSpecificationV30MinimalProfileEnum for SubmodelRepositoryServiceSpecification/V3.0-MinimalProfile - /// - [EnumMember(Value = "SubmodelRepositoryServiceSpecification/V3.0-MinimalProfile")] - SubmodelRepositoryServiceSpecificationV30MinimalProfileEnum = 14, - /// - /// Enum RegistryAndDiscoveryServiceSpecificationV30Enum for RegistryAndDiscoveryServiceSpecification/V3.0 - /// - [EnumMember(Value = "RegistryAndDiscoveryServiceSpecification/V3.0")] - RegistryAndDiscoveryServiceSpecificationV30Enum = 15 - } + var sb = new StringBuilder(); + sb.Append("class Description {\n"); + sb.Append(" Profiles: ").Append(Profiles).Append('\n'); + sb.Append("}\n"); + return sb.ToString(); + } - /// - /// Gets or Sets Profiles - /// + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public string ToJson() => JsonSerializer.Serialize(this, Options); - [DataMember(Name = "profiles")] - public List? Profiles { get; set; } + private static readonly JsonSerializerOptions Options = new() + { + WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + Converters = {new JsonStringEnumConverter()} + }; - /// - /// Returns the string presentation of the object - /// - /// String presentation of the object - public override string ToString() - { - var sb = new StringBuilder(); - sb.Append("class Description {\n"); - sb.Append(" Profiles: ").Append(Profiles).Append("\n"); - sb.Append("}\n"); - return sb.ToString(); - } + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + return obj.GetType() == GetType() && Equals((Description)obj); + } - /// - /// Returns the JSON string presentation of the object - /// - /// JSON string presentation of the object - public string ToJson() + /// + /// Returns true if Description instances are equal + /// + /// Instance of Description to be compared + /// Boolean + public bool Equals(Description? other) + { + if (ReferenceEquals(null, other)) { - return JsonConvert.SerializeObject(this, Formatting.Indented); + return false; } - /// - /// Returns true if objects are equal - /// - /// Object to be compared - /// Boolean - public override bool Equals(object? obj) + if (ReferenceEquals(this, other)) { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((Description)obj); + return true; } - /// - /// Returns true if Description instances are equal - /// - /// Instance of Description to be compared - /// Boolean - public bool Equals(Description? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - - return - ( - Profiles == other.Profiles || - (Profiles != null && - Profiles.SequenceEqual(other.Profiles)) - ); - } + return + other.Profiles != null && ( + Profiles == other.Profiles || + (Profiles != null && + Profiles.SequenceEqual(other.Profiles)) + ); + } - /// - /// Gets the hash code - /// - /// Hash code - public override int GetHashCode() + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() + { + unchecked // Overflow is fine, just wrap { - unchecked // Overflow is fine, just wrap + var hashCode = 41; + // Suitable nullity checks etc, of course :) + if (Profiles != null) { - var hashCode = 41; - // Suitable nullity checks etc, of course :) - if (Profiles != null) - hashCode = (hashCode * 59) + Profiles.GetHashCode(); - return hashCode; + hashCode = (hashCode * 59) + Profiles.GetHashCode(); } + + return hashCode; } + } + + #region Operators - #region Operators #pragma warning disable 1591 - public static bool operator ==(Description left, Description right) - { - return Equals(left, right); - } + public static bool operator ==(Description left, Description right) => Equals(left, right); - public static bool operator !=(Description left, Description right) - { - return !Equals(left, right); - } + public static bool operator !=(Description left, Description right) => !Equals(left, right); #pragma warning restore 1591 - #endregion Operators - } -} + + #endregion Operators +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Models/ExecutionState.cs b/src/IO.Swagger.Lib.V3/Models/ExecutionState.cs index 0e824e0fd..1bbfc5a86 100644 --- a/src/IO.Swagger.Lib.V3/Models/ExecutionState.cs +++ b/src/IO.Swagger.Lib.V3/Models/ExecutionState.cs @@ -4,57 +4,46 @@ * The entire Repository Service Specification as part of Details of the Asset Administration Shell Part 2 * * OpenAPI spec version: V3.0 - * + * * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using System; -using System.Linq; -using System.IO; -using System.Text; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel.DataAnnotations; + using System.Runtime.Serialization; -using Newtonsoft.Json; -namespace IO.Swagger.Models +namespace IO.Swagger.Models; + +/// +/// Gets or Sets ExecutionState +/// +public enum ExecutionState { /// - /// Gets or Sets ExecutionState + /// Enum Initiated for Initiated + /// + [EnumMember(Value = "Initiated")] Initiated = 0, + + /// + /// Enum Running for Running + /// + [EnumMember(Value = "Running")] Running = 1, + + /// + /// Enum Completed for Completed + /// + [EnumMember(Value = "Completed")] Completed = 2, + + /// + /// Enum Canceled for Canceled + /// + [EnumMember(Value = "Canceled")] Canceled = 3, + + /// + /// Enum Failed for Failed + /// + [EnumMember(Value = "Failed")] Failed = 4, + + /// + /// Enum Timeout for Timeout /// - [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public enum ExecutionState - { - /// - /// Enum InitiatedEnum for Initiated - /// - [EnumMember(Value = "Initiated")] - InitiatedEnum = 0, - /// - /// Enum RunningEnum for Running - /// - [EnumMember(Value = "Running")] - RunningEnum = 1, - /// - /// Enum CompletedEnum for Completed - /// - [EnumMember(Value = "Completed")] - CompletedEnum = 2, - /// - /// Enum CanceledEnum for Canceled - /// - [EnumMember(Value = "Canceled")] - CanceledEnum = 3, - /// - /// Enum FailedEnum for Failed - /// - [EnumMember(Value = "Failed")] - FailedEnum = 4, - /// - /// Enum TimeoutEnum for Timeout - /// - [EnumMember(Value = "Timeout")] - TimeoutEnum = 5 - } -} + [EnumMember(Value = "Timeout")] Timeout = 5 +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Models/GetPathItemsResult.cs b/src/IO.Swagger.Lib.V3/Models/GetPathItemsResult.cs index 11c8b898d..832a183d4 100644 --- a/src/IO.Swagger.Lib.V3/Models/GetPathItemsResult.cs +++ b/src/IO.Swagger.Lib.V3/Models/GetPathItemsResult.cs @@ -7,7 +7,6 @@ * Contact: info@idtwin.org * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; @@ -16,6 +15,9 @@ namespace IO.Swagger.Models { + using System.Text.Json; + using System.Text.Json.Serialization; + /// /// /// @@ -46,7 +48,9 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public string ToJson() => JsonConvert.SerializeObject(this, Formatting.Indented); + public string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true, Converters = {new JsonStringEnumConverter()}}; /// /// Returns true if objects are equal diff --git a/src/IO.Swagger.Lib.V3/Models/GetReferencesResult.cs b/src/IO.Swagger.Lib.V3/Models/GetReferencesResult.cs index 7808650f2..b35a895fe 100644 --- a/src/IO.Swagger.Lib.V3/Models/GetReferencesResult.cs +++ b/src/IO.Swagger.Lib.V3/Models/GetReferencesResult.cs @@ -7,7 +7,6 @@ * Contact: info@idtwin.org * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; @@ -16,6 +15,8 @@ namespace IO.Swagger.Models { + using System.Text.Json; + /// /// /// @@ -46,8 +47,10 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public string ToJson() => JsonConvert.SerializeObject(this, Formatting.Indented); + public string ToJson() => JsonSerializer.Serialize(this, options); + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true}; + /// /// Returns true if objects are equal /// diff --git a/src/IO.Swagger.Lib.V3/Models/GetSubmodelElementsResult.cs b/src/IO.Swagger.Lib.V3/Models/GetSubmodelElementsResult.cs index 947a3a6d9..68e8ff6b0 100644 --- a/src/IO.Swagger.Lib.V3/Models/GetSubmodelElementsResult.cs +++ b/src/IO.Swagger.Lib.V3/Models/GetSubmodelElementsResult.cs @@ -7,7 +7,6 @@ * Contact: info@idtwin.org * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; @@ -16,6 +15,8 @@ namespace IO.Swagger.Models { + using System.Text.Json; + /// /// /// @@ -46,7 +47,9 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public string ToJson() => JsonConvert.SerializeObject(this, Formatting.Indented); + public string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true}; /// /// Returns true if objects are equal diff --git a/src/IO.Swagger.Lib.V3/Models/IServiceDescription.cs b/src/IO.Swagger.Lib.V3/Models/IServiceDescription.cs new file mode 100644 index 000000000..42066a531 --- /dev/null +++ b/src/IO.Swagger.Lib.V3/Models/IServiceDescription.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; + +namespace IO.Swagger.Models; + +/// +/// The Description object enables servers to present their capabilities to the clients, in particular which profiles they implement. At least one defined profile is required. Additional, proprietary attributes might be included. Nevertheless, the server must not expect that a regular client understands them. +/// +public interface IServiceDescription +{ + /// + /// Gets or Sets Profiles + /// + List? Profiles { get; set; } + + /// + /// Returns the string presentation of the object + /// + /// String presentation of the object + string ToString(); + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + string ToJson(); + + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + bool Equals(object? obj); + + /// + /// Returns true if ServiceDescription instances are equal + /// + /// Instance of ServiceDescription to be compared + /// Boolean + bool Equals(ServiceDescription? other); + + /// + /// Gets the hash code + /// + /// Hash code + int GetHashCode(); +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Models/Message.cs b/src/IO.Swagger.Lib.V3/Models/Message.cs index 4e9356478..3925f980c 100644 --- a/src/IO.Swagger.Lib.V3/Models/Message.cs +++ b/src/IO.Swagger.Lib.V3/Models/Message.cs @@ -13,199 +13,228 @@ using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; -namespace IO.Swagger.Models +namespace IO.Swagger.Models; + +using System.Text.Json; +using System.Text.Json.Serialization; + +/// +/// Enum for Message Types +/// +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum MessageTypeEnum +{ + /// + /// Undefined MessageType + /// + [EnumMember(Value = "Undefined")] Undefined = 0, + + /// + /// Info MessageType + /// + [EnumMember(Value = "Info")] Info = 1, + + /// + /// Warning MessageType + /// + [EnumMember(Value = "Warning")] Warning = 2, + + /// + /// Error MessageType + /// + [EnumMember(Value = "Error")] Error = 3, + + /// + /// Exception MessageType + /// + [EnumMember(Value = "Exception")] Exception = 4 +} + +/// +/// +/// +[DataContract] +public partial class Message : IEquatable { - using System.Text.Json; - using System.Text.Json.Serialization; + private readonly JsonSerializerOptions options = new(); /// - /// Enum for Message Types + /// Gets or Sets Code /// - [Newtonsoft.Json.JsonConverter(typeof(JsonStringEnumConverter))] - public enum MessageTypeEnum + [StringLength(32, MinimumLength = 1)] + [DataMember(Name = "code")] + public string? Code { get; set; } + + /// + /// Gets or Sets CorrelationId + /// + [StringLength(128, MinimumLength = 1)] + [DataMember(Name = "correlationId")] + public string? CorrelationId { get; set; } + + /// + /// Gets or Sets MessageType + /// + + [DataMember(Name = "messageType")] + public MessageTypeEnum? MessageType { get; set; } + + /// + /// Gets or Sets Text + /// + + [DataMember(Name = "text")] + public string? Text { get; set; } + + /// + /// Gets or Sets Timestamp + /// + [RegularExpression( + @"/^-?(([1-9][0-9][0-9][0-9]+)|(0[0-9][0-9][0-9]))-((0[1-9])|(1[0-2]))-((0[1-9])|([12][0-9])|(3[01]))T(((([01][0-9])|(2[0-3])):[0-5][0-9]:([0-5][0-9])(\.[0-9]+)?)|24:00:00(\.0+)?)(Z|\+00:00|-00:00)$/")] + [DataMember(Name = "timestamp")] + public string? Timestamp { get; set; } + + /// + /// Returns the string presentation of the object + /// + /// String presentation of the object + public override string ToString() + { + var sb = new StringBuilder(); + sb.Append("class Message {\n"); + sb.Append(" Code: ").Append(Code).Append('\n'); + sb.Append(" CorrelationId: ").Append(CorrelationId).Append('\n'); + sb.Append(" MessageType: ").Append(MessageType).Append('\n'); + sb.Append(" Text: ").Append(Text).Append('\n'); + sb.Append(" Timestamp: ").Append(Timestamp).Append('\n'); + sb.Append("}\n"); + return sb.ToString(); + } + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public string ToJson() { - /// - /// Undefined MessageType - /// - [EnumMember(Value = "Undefined")] UndefinedEnum = 0, - - /// - /// Info MessageType - /// - [EnumMember(Value = "Info")] InfoEnum = 1, - - /// - /// Warning MessageType - /// - [EnumMember(Value = "Warning")] WarningEnum = 2, - - /// - /// Error MessageType - /// - [EnumMember(Value = "Error")] ErrorEnum = 3, - - /// - /// Exception MessageType - /// - [EnumMember(Value = "Exception")] ExceptionEnum = 4 + options.WriteIndented = true; + options.Converters.Add(new JsonStringEnumConverter()); + return JsonSerializer.Serialize(this, options); } /// - /// + /// Returns true if objects are equal /// - [DataContract] - public partial class Message : IEquatable + /// Object to be compared + /// Boolean + public override bool Equals(object? obj) { - private JsonSerializerOptions options = new(); - - /// - /// Gets or Sets Code - /// - [StringLength(32, MinimumLength = 1)] - [DataMember(Name = "code")] - public string? Code { get; set; } - - /// - /// Gets or Sets CorrelationId - /// - [StringLength(128, MinimumLength = 1)] - [DataMember(Name = "correlationId")] - public string? CorrelationId { get; set; } - - /// - /// Gets or Sets MessageType - /// - - [DataMember(Name = "messageType")] - public MessageTypeEnum? MessageType { get; set; } - - /// - /// Gets or Sets Text - /// - - [DataMember(Name = "text")] - public string? Text { get; set; } - - /// - /// Gets or Sets Timestamp - /// - [RegularExpression( - @"/^-?(([1-9][0-9][0-9][0-9]+)|(0[0-9][0-9][0-9]))-((0[1-9])|(1[0-2]))-((0[1-9])|([12][0-9])|(3[01]))T(((([01][0-9])|(2[0-3])):[0-5][0-9]:([0-5][0-9])(\.[0-9]+)?)|24:00:00(\.0+)?)(Z|\+00:00|-00:00)$/")] - [DataMember(Name = "timestamp")] - public string? Timestamp { get; set; } - - /// - /// Returns the string presentation of the object - /// - /// String presentation of the object - public override string ToString() + if (ReferenceEquals(null, obj)) { - var sb = new StringBuilder(); - sb.Append("class Message {\n"); - sb.Append(" Code: ").Append(Code).Append('\n'); - sb.Append(" CorrelationId: ").Append(CorrelationId).Append('\n'); - sb.Append(" MessageType: ").Append(MessageType).Append('\n'); - sb.Append(" Text: ").Append(Text).Append('\n'); - sb.Append(" Timestamp: ").Append(Timestamp).Append('\n'); - sb.Append("}\n"); - return sb.ToString(); + return false; } - /// - /// Returns the JSON string presentation of the object - /// - /// JSON string presentation of the object - public string ToJson() + if (ReferenceEquals(this, obj)) { - options.WriteIndented = true; - options.Converters.Add(new JsonStringEnumConverter()); - return JsonSerializer.Serialize(this, options); + return true; } - /// - /// Returns true if objects are equal - /// - /// Object to be compared - /// Boolean - public override bool Equals(object? obj) + return obj.GetType() == GetType() && Equals((Message)obj); + } + + /// + /// Returns true if Message instances are equal + /// + /// Instance of Message to be compared + /// Boolean + public bool Equals(Message? other) + { + if (ReferenceEquals(null, other)) { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((Message)obj); + return false; } - /// - /// Returns true if Message instances are equal - /// - /// Instance of Message to be compared - /// Boolean - public bool Equals(Message? other) + if (ReferenceEquals(this, other)) { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - - return - ( - Code == other.Code || - (Code != null && - Code.Equals(other.Code, StringComparison.Ordinal)) - ) && - ( - CorrelationId == other.CorrelationId || - (CorrelationId != null && - CorrelationId.Equals(other.CorrelationId, StringComparison.Ordinal)) - ) && - ( - MessageType == other.MessageType || - (MessageType != null && - MessageType.Equals(other.MessageType)) - ) && - ( - Text == other.Text || - (Text != null && - Text.Equals(other.Text, StringComparison.Ordinal)) - ) && - ( - Timestamp == other.Timestamp || - (Timestamp != null && - Timestamp.Equals(other.Timestamp, StringComparison.Ordinal)) - ); + return true; } - /// - /// Gets the hash code - /// - /// Hash code - public override int GetHashCode() + return + ( + Code == other.Code || + (Code != null && + Code.Equals(other.Code, StringComparison.Ordinal)) + ) && + ( + CorrelationId == other.CorrelationId || + (CorrelationId != null && + CorrelationId.Equals(other.CorrelationId, StringComparison.Ordinal)) + ) && + ( + MessageType == other.MessageType || + (MessageType != null && + MessageType.Equals(other.MessageType)) + ) && + ( + Text == other.Text || + (Text != null && + Text.Equals(other.Text, StringComparison.Ordinal)) + ) && + ( + Timestamp == other.Timestamp || + (Timestamp != null && + Timestamp.Equals(other.Timestamp, StringComparison.Ordinal)) + ); + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() + { + unchecked // Overflow is fine, just wrap { - unchecked // Overflow is fine, just wrap + var hashCode = 41; + // Suitable nullity checks etc., of course :) + if (Code != null) { - var hashCode = 41; - // Suitable nullity checks etc, of course :) - if (Code != null) - hashCode = (hashCode * 59) + Code.GetHashCode(); - if (CorrelationId != null) - hashCode = (hashCode * 59) + CorrelationId.GetHashCode(); - if (MessageType != null) - hashCode = (hashCode * 59) + MessageType.GetHashCode(); - if (Text != null) - hashCode = (hashCode * 59) + Text.GetHashCode(); - if (Timestamp != null) - hashCode = (hashCode * 59) + Timestamp.GetHashCode(); - return hashCode; + hashCode = (hashCode * 59) + Code.GetHashCode(); } + + if (CorrelationId != null) + { + hashCode = (hashCode * 59) + CorrelationId.GetHashCode(); + } + + if (MessageType != null) + { + hashCode = (hashCode * 59) + MessageType.GetHashCode(); + } + + if (Text != null) + { + hashCode = (hashCode * 59) + Text.GetHashCode(); + } + + if (Timestamp != null) + { + hashCode = (hashCode * 59) + Timestamp.GetHashCode(); + } + + return hashCode; } - - #region Operators + } + + #region Operators #pragma warning disable 1591 - public static bool operator ==(Message left, Message right) => Equals(left, right); + public static bool operator ==(Message left, Message right) => Equals(left, right); - public static bool operator !=(Message left, Message right) => !Equals(left, right); + public static bool operator !=(Message left, Message right) => !Equals(left, right); #pragma warning restore 1591 - #endregion Operators - } + #endregion Operators } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Models/OperationRequest.cs b/src/IO.Swagger.Lib.V3/Models/OperationRequest.cs index 0b41b731d..b75bc63bd 100644 --- a/src/IO.Swagger.Lib.V3/Models/OperationRequest.cs +++ b/src/IO.Swagger.Lib.V3/Models/OperationRequest.cs @@ -8,7 +8,6 @@ * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -18,6 +17,8 @@ namespace IO.Swagger.Models { + using System.Text.Json; + /// /// /// @@ -73,10 +74,10 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public string ToJson() - { - return JsonConvert.SerializeObject(this, Formatting.Indented); - } + public string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true}; + /// /// Returns true if objects are equal diff --git a/src/IO.Swagger.Lib.V3/Models/OperationResult.cs b/src/IO.Swagger.Lib.V3/Models/OperationResult.cs index 6422f1023..0ffe1174b 100644 --- a/src/IO.Swagger.Lib.V3/Models/OperationResult.cs +++ b/src/IO.Swagger.Lib.V3/Models/OperationResult.cs @@ -8,7 +8,6 @@ * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -18,6 +17,8 @@ namespace IO.Swagger.Models { + using System.Text.Json; + /// /// /// @@ -81,10 +82,10 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public string ToJson() - { - return JsonConvert.SerializeObject(this, Formatting.Indented); - } + public string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true}; + /// /// Returns true if objects are equal diff --git a/src/IO.Swagger.Lib.V3/Models/Result.cs b/src/IO.Swagger.Lib.V3/Models/Result.cs index b1af01fc9..a165a4011 100644 --- a/src/IO.Swagger.Lib.V3/Models/Result.cs +++ b/src/IO.Swagger.Lib.V3/Models/Result.cs @@ -13,21 +13,22 @@ using System.Text; using System.Collections.Generic; using System.Runtime.Serialization; -using Newtonsoft.Json; namespace IO.Swagger.Models { + using System.Text.Json; + /// /// /// - [ DataContract ] + [DataContract] public partial class Result : IEquatable { /// /// Gets or Sets Messages /// - [ DataMember(Name = "messages") ] + [DataMember(Name = "messages")] public List? Messages { get; set; } /// @@ -43,14 +44,13 @@ public override string ToString() return sb.ToString(); } + private JsonSerializerOptions? serializerOptions = new() {WriteIndented = true}; + /// /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public string ToJson() - { - return JsonConvert.SerializeObject(this, Formatting.Indented); - } + public string ToJson() => JsonSerializer.Serialize(this, serializerOptions); /// /// Returns true if objects are equal @@ -61,7 +61,7 @@ public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((Result) obj); + return obj.GetType() == GetType() && Equals((Result)obj); } /// @@ -75,9 +75,9 @@ public bool Equals(Result? other) if (ReferenceEquals(this, other)) return true; return - Messages == other.Messages || - (Messages != null && - Messages.SequenceEqual(other.Messages)); + Messages == other.Messages || + (Messages != null && + Messages.SequenceEqual(other.Messages)); } /// diff --git a/src/IO.Swagger.Lib.V3/Models/ServerDescriptionProfiles.cs b/src/IO.Swagger.Lib.V3/Models/ServerDescriptionProfiles.cs new file mode 100644 index 000000000..516ad966b --- /dev/null +++ b/src/IO.Swagger.Lib.V3/Models/ServerDescriptionProfiles.cs @@ -0,0 +1,108 @@ +namespace IO.Swagger.Models; + +using System.Runtime.Serialization; + +public partial class Description +{ + /// + /// Gets or Sets Profiles + /// + public enum ServerDescriptionProfiles + { + /// + /// Enum AssetAdministrationShellServiceSpecificationV30 for AssetAdministrationShellServiceSpecification/V3.0 + /// + [EnumMember(Value = "AssetAdministrationShellServiceSpecification/V3.0")] + AssetAdministrationShellServiceSpecificationV30 = 0, + + /// + /// Enum AssetAdministrationShellServiceSpecificationV30MinimalProfile for AssetAdministrationShellServiceSpecification/V3.0-MinimalProfile + /// + [EnumMember(Value = "AssetAdministrationShellServiceSpecification/V3.0-MinimalProfile")] + AssetAdministrationShellServiceSpecificationV30MinimalProfile = 1, + + /// + /// Enum SubmodelServiceSpecificationV30 for SubmodelServiceSpecification/V3.0 + /// + [EnumMember(Value = "SubmodelServiceSpecification/V3.0")] + SubmodelServiceSpecificationV30 = 2, + + /// + /// Enum SubmodelServiceSpecificationV30ValueProfile for SubmodelServiceSpecification/V3.0-ValueProfile + /// + [EnumMember(Value = "SubmodelServiceSpecification/V3.0-ValueProfile")] + SubmodelServiceSpecificationV30ValueProfile = 3, + + /// + /// Enum SubmodelServiceSpecificationV30MinimalProfile for SubmodelServiceSpecification/V3.0-MinimalProfile + /// + [EnumMember(Value = "SubmodelServiceSpecification/V3.0-MinimalProfile")] + SubmodelServiceSpecificationV30MinimalProfile = 4, + + /// + /// Enum AasxFileServerServiceSpecificationV30 for AasxFileServerServiceSpecification/V3.0 + /// + [EnumMember(Value = "AasxFileServerServiceSpecification/V3.0")] + AasxFileServerServiceSpecificationV30 = 5, + + /// + /// Enum RegistryServiceSpecificationV30 for RegistryServiceSpecification/V3.0 + /// + [EnumMember(Value = "RegistryServiceSpecification/V3.0")] + RegistryServiceSpecificationV30 = 6, + + /// + /// Enum RegistryServiceSpecificationV30AssetAdministrationShellRegistry for RegistryServiceSpecification/V3.0- AssetAdministrationShellRegistry + /// + [EnumMember(Value = "RegistryServiceSpecification/V3.0- AssetAdministrationShellRegistry")] + RegistryServiceSpecificationV30AssetAdministrationShellRegistry = 7, + + /// + /// Enum RegistryServiceSpecificationV30SubmodelRegistry for RegistryServiceSpecification/V3.0-SubmodelRegistry + /// + [EnumMember(Value = "RegistryServiceSpecification/V3.0-SubmodelRegistry")] + RegistryServiceSpecificationV30SubmodelRegistry = 8, + + /// + /// Enum RepositoryServiceSpecificationV30 for RepositoryServiceSpecification/V3.0 + /// + [EnumMember(Value = "RepositoryServiceSpecification/V3.0")] + RepositoryServiceSpecificationV30 = 9, + + /// + /// Enum RepositoryServiceSpecificationV30MinimalProfile for RepositoryServiceSpecification/V3.0-MinimalProfile + /// + [EnumMember(Value = "RepositoryServiceSpecification/V3.0-MinimalProfile")] + RepositoryServiceSpecificationV30MinimalProfile = 10, + + /// + /// Enum AssetAdministrationShellRepositoryServiceSpecificationV30 for AssetAdministrationShellRepositoryServiceSpecification/V3.0 + /// + [EnumMember(Value = "AssetAdministrationShellRepositoryServiceSpecification/V3.0")] + AssetAdministrationShellRepositoryServiceSpecificationV30 = 11, + + /// + /// Enum AssetAdministrationShellRepositoryServiceSpecificationV30MinimalProfile for AssetAdministrationShellRepositoryServiceSpecification/V3.0-MinimalProfile + /// + [EnumMember(Value = "AssetAdministrationShellRepositoryServiceSpecification/V3.0-MinimalProfile")] + AssetAdministrationShellRepositoryServiceSpecificationV30MinimalProfile = 12, + + /// + /// Enum SubmodelRepositoryServiceSpecificationV30 for SubmodelRepositoryServiceSpecification/V3.0 + /// + [EnumMember(Value = "SubmodelRepositoryServiceSpecification/V3.0")] + SubmodelRepositoryServiceSpecificationV30 = 13, + + /// + /// Enum SubmodelRepositoryServiceSpecificationV30MinimalProfile for SubmodelRepositoryServiceSpecification/V3.0-MinimalProfile + /// + [EnumMember(Value = "SubmodelRepositoryServiceSpecification/V3.0-MinimalProfile")] + SubmodelRepositoryServiceSpecificationV30MinimalProfile = 14, + + /// + /// Enum RegistryAndDiscoveryServiceSpecificationV30 for RegistryAndDiscoveryServiceSpecification/V3.0 + /// + [EnumMember(Value = "RegistryAndDiscoveryServiceSpecification/V3.0")] + RegistryAndDiscoveryServiceSpecificationV30 = 15 + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Models/ServiceDescription.cs b/src/IO.Swagger.Lib.V3/Models/ServiceDescription.cs index d3ec92805..5ac11acff 100644 --- a/src/IO.Swagger.Lib.V3/Models/ServiceDescription.cs +++ b/src/IO.Swagger.Lib.V3/Models/ServiceDescription.cs @@ -1,214 +1,116 @@ /* * DotAAS Part 2 | HTTP/REST | Asset Administration Shell Registry Service Specification * - * The Full Profile of the Asset Administration Shell Registry Service Specification as part of the [Specification of the Asset Administration Shell: Part 2](http://industrialdigitaltwin.org/en/content-hub). Publisher: Industrial Digital Twin Association (IDTA) 2023 + * The Full Profile of the Asset Administration Shell Registry Service Specification as part of the [Specification of the Asset Administration Shell: Part 2](http://industrialdigitaltwin.org/en/content-hub). + * Publisher: Industrial Digital Twin Association (IDTA) 2023 * * OpenAPI spec version: V3.0.1_SSP-001 * Contact: info@idtwin.org * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; + using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace IO.Swagger.Models; -namespace IO.Swagger.Models +/// +[DataContract] +public partial class ServiceDescription : IEquatable, IServiceDescription { - /// - /// The Description object enables servers to present their capabilities to the clients, in particular which profiles they implement. At least one defined profile is required. Additional, proprietary attributes might be included. Nevertheless, the server must not expect that a regular client understands them. - /// - [DataContract] - public partial class ServiceDescription : IEquatable + /// + [DataMember(Name = "profiles")] + public List? Profiles { get; set; } + + /// + public override string ToString() { - /// - /// Gets or Sets Profiles - /// - [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public enum ProfilesEnum - { - /// - /// Enum AssetAdministrationShellServiceSpecificationSSP001Enum for https://admin-shell.io/aas/API/3/0/AssetAdministrationShellServiceSpecification/SSP-001 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellServiceSpecification/SSP-001")] - AssetAdministrationShellServiceSpecificationSSP001Enum = 0, - /// - /// Enum AssetAdministrationShellServiceSpecificationSSP002Enum for https://admin-shell.io/aas/API/3/0/AssetAdministrationShellServiceSpecification/SSP-002 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellServiceSpecification/SSP-002")] - AssetAdministrationShellServiceSpecificationSSP002Enum = 1, - /// - /// Enum SubmodelServiceSpecificationSSP001Enum for https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-001 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-001")] - SubmodelServiceSpecificationSSP001Enum = 2, - /// - /// Enum SubmodelServiceSpecificationSSP002Enum for https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-002 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-002")] - SubmodelServiceSpecificationSSP002Enum = 3, - /// - /// Enum SubmodelServiceSpecificationSSP003Enum for https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-003 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-003")] - SubmodelServiceSpecificationSSP003Enum = 4, - /// - /// Enum AasxFileServerServiceSpecificationSSP001Enum for https://admin-shell.io/aas/API/3/0/AasxFileServerServiceSpecification/SSP-001 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AasxFileServerServiceSpecification/SSP-001")] - AasxFileServerServiceSpecificationSSP001Enum = 5, - /// - /// Enum AssetAdministrationShellRegistryServiceSpecificationSSP001Enum for https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRegistryServiceSpecification/SSP-001 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRegistryServiceSpecification/SSP-001")] - AssetAdministrationShellRegistryServiceSpecificationSSP001Enum = 6, - /// - /// Enum AssetAdministrationShellRegistryServiceSpecificationSSP002Enum for https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRegistryServiceSpecification/SSP-002 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRegistryServiceSpecification/SSP-002")] - AssetAdministrationShellRegistryServiceSpecificationSSP002Enum = 7, - /// - /// Enum SubmodelRegistryServiceSpecificationSSP001Enum for https://admin-shell.io/aas/API/3/0/SubmodelRegistryServiceSpecification/SSP-001 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelRegistryServiceSpecification/SSP-001")] - SubmodelRegistryServiceSpecificationSSP001Enum = 8, - /// - /// Enum SubmodelRegistryServiceSpecificationSSP002Enum for https://admin-shell.io/aas/API/3/0/SubmodelRegistryServiceSpecification/SSP-002 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelRegistryServiceSpecification/SSP-002")] - SubmodelRegistryServiceSpecificationSSP002Enum = 9, - /// - /// Enum DiscoveryServiceSpecificationSSP001Enum for https://admin-shell.io/aas/API/3/0/DiscoveryServiceSpecification/SSP-001 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/DiscoveryServiceSpecification/SSP-001")] - DiscoveryServiceSpecificationSSP001Enum = 10, - /// - /// Enum AssetAdministrationShellRepositoryServiceSpecificationSSP001Enum for https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRepositoryServiceSpecification/SSP-001 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRepositoryServiceSpecification/SSP-001")] - AssetAdministrationShellRepositoryServiceSpecificationSSP001Enum = 11, - /// - /// Enum AssetAdministrationShellRepositoryServiceSpecificationSSP002Enum for https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRepositoryServiceSpecification/SSP-002 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRepositoryServiceSpecification/SSP-002")] - AssetAdministrationShellRepositoryServiceSpecificationSSP002Enum = 12, - /// - /// Enum SubmodelRepositoryServiceSpecificationSSP001Enum for https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-001 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-001")] - SubmodelRepositoryServiceSpecificationSSP001Enum = 13, - /// - /// Enum SubmodelRepositoryServiceSpecificationSSP002Enum for https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-002 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-002")] - SubmodelRepositoryServiceSpecificationSSP002Enum = 14, - /// - /// Enum SubmodelRepositoryServiceSpecificationSSP003Enum for https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-003 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-003")] - SubmodelRepositoryServiceSpecificationSSP003Enum = 15, - /// - /// Enum SubmodelRepositoryServiceSpecificationSSP004Enum for https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-004 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-004")] - SubmodelRepositoryServiceSpecificationSSP004Enum = 16, - /// - /// Enum ConceptDescriptionServiceSpecificationSSP001Enum for https://admin-shell.io/aas/API/3/0/ConceptDescriptionServiceSpecification/SSP-001 - /// - [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/ConceptDescriptionServiceSpecification/SSP-001")] - ConceptDescriptionServiceSpecificationSSP001Enum = 17 - } + var sb = new StringBuilder(); + sb.Append("class ServiceDescription {\n"); + sb.Append(" Profiles: ").Append(Profiles).Append('\n'); + sb.Append("}\n"); + return sb.ToString(); + } + + + /// + public string ToJson() => JsonSerializer.Serialize(this, Options); - /// - /// Gets or Sets Profiles - /// + private static readonly JsonSerializerOptions Options = new() + { + WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + Converters = {new JsonStringEnumConverter()} + }; - [DataMember(Name = "profiles")] - public List? Profiles { get; set; } - /// - /// Returns the string presentation of the object - /// - /// String presentation of the object - public override string ToString() + /// + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) { - var sb = new StringBuilder(); - sb.Append("class ServiceDescription {\n"); - sb.Append(" Profiles: ").Append(Profiles).Append("\n"); - sb.Append("}\n"); - return sb.ToString(); + return false; } - /// - /// Returns the JSON string presentation of the object - /// - /// JSON string presentation of the object - public string ToJson() + if (ReferenceEquals(this, obj)) { - return JsonConvert.SerializeObject(this, Formatting.Indented); + return true; } - /// - /// Returns true if objects are equal - /// - /// Object to be compared - /// Boolean - public override bool Equals(object? obj) + return obj.GetType() == GetType() && Equals((ServiceDescription)obj); + } + + + /// + public bool Equals(ServiceDescription? other) + { + if (ReferenceEquals(null, other)) { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((ServiceDescription)obj); + return false; } - /// - /// Returns true if ServiceDescription instances are equal - /// - /// Instance of ServiceDescription to be compared - /// Boolean - public bool Equals(ServiceDescription? other) + if (ReferenceEquals(this, other)) { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; + return true; + } - return + return + other.Profiles != null && (Profiles == other.Profiles || + (Profiles != null && + Profiles.SequenceEqual(other.Profiles))); + } - Profiles == other.Profiles || - (Profiles != null && - Profiles.SequenceEqual(other.Profiles)) - ; - } - /// - /// Gets the hash code - /// - /// Hash code - public override int GetHashCode() + /// + public override int GetHashCode() + { + unchecked // Overflow is fine, just wrap { - unchecked // Overflow is fine, just wrap + var hashCode = 41; + // Suitable nullity checks etc., of course :) + if (Profiles != null) { - var hashCode = 41; - // Suitable nullity checks etc., of course :) - if (Profiles != null) - hashCode = (hashCode * 59) + Profiles.GetHashCode(); - return hashCode; + hashCode = (hashCode * 59) + Profiles.GetHashCode(); } + + return hashCode; } + } + + #region Operators - #region Operators #pragma warning disable 1591 - public static bool operator ==(ServiceDescription left, ServiceDescription right) - { - return Equals(left, right); - } + public static bool operator ==(ServiceDescription left, ServiceDescription right) => Equals(left, right); - public static bool operator !=(ServiceDescription left, ServiceDescription right) - { - return !Equals(left, right); - } + public static bool operator !=(ServiceDescription left, ServiceDescription right) => !Equals(left, right); #pragma warning restore 1591 - #endregion Operators - } -} + + #endregion Operators +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Models/ServiceProfiles.cs b/src/IO.Swagger.Lib.V3/Models/ServiceProfiles.cs new file mode 100644 index 000000000..9def6e1e9 --- /dev/null +++ b/src/IO.Swagger.Lib.V3/Models/ServiceProfiles.cs @@ -0,0 +1,120 @@ +namespace IO.Swagger.Models; + +using System.Runtime.Serialization; + +public partial class ServiceDescription +{ + /// + /// Gets or Sets Profiles + /// + public enum ServiceProfiles + { + /// + /// Enum AssetAdministrationShellServiceSpecificationSSP001 for https://admin-shell.io/aas/API/3/0/AssetAdministrationShellServiceSpecification/SSP-001 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellServiceSpecification/SSP-001")] + AssetAdministrationShellServiceSpecificationSSP001 = 0, + + /// + /// Enum AssetAdministrationShellServiceSpecificationSSP002 for https://admin-shell.io/aas/API/3/0/AssetAdministrationShellServiceSpecification/SSP-002 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellServiceSpecification/SSP-002")] + AssetAdministrationShellServiceSpecificationSSP002 = 1, + + /// + /// Enum SubmodelServiceSpecificationSSP001 for https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-001 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-001")] + SubmodelServiceSpecificationSSP001 = 2, + + /// + /// Enum SubmodelServiceSpecificationSSP002 for https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-002 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-002")] + SubmodelServiceSpecificationSSP002 = 3, + + /// + /// Enum SubmodelServiceSpecificationSSP003 for https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-003 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-003")] + SubmodelServiceSpecificationSSP003 = 4, + + /// + /// Enum AasxFileServerServiceSpecificationSSP001 for https://admin-shell.io/aas/API/3/0/AasxFileServerServiceSpecification/SSP-001 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AasxFileServerServiceSpecification/SSP-001")] + AasxFileServerServiceSpecificationSSP001 = 5, + + /// + /// Enum AssetAdministrationShellRegistryServiceSpecificationSSP001 for https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRegistryServiceSpecification/SSP-001 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRegistryServiceSpecification/SSP-001")] + AssetAdministrationShellRegistryServiceSpecificationSSP001 = 6, + + /// + /// Enum AssetAdministrationShellRegistryServiceSpecificationSSP002 for https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRegistryServiceSpecification/SSP-002 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRegistryServiceSpecification/SSP-002")] + AssetAdministrationShellRegistryServiceSpecificationSSP002 = 7, + + /// + /// Enum SubmodelRegistryServiceSpecificationSSP001 for https://admin-shell.io/aas/API/3/0/SubmodelRegistryServiceSpecification/SSP-001 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelRegistryServiceSpecification/SSP-001")] + SubmodelRegistryServiceSpecificationSSP001 = 8, + + /// + /// Enum SubmodelRegistryServiceSpecificationSSP002 for https://admin-shell.io/aas/API/3/0/SubmodelRegistryServiceSpecification/SSP-002 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelRegistryServiceSpecification/SSP-002")] + SubmodelRegistryServiceSpecificationSSP002 = 9, + + /// + /// Enum DiscoveryServiceSpecificationSSP001 for https://admin-shell.io/aas/API/3/0/DiscoveryServiceSpecification/SSP-001 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/DiscoveryServiceSpecification/SSP-001")] + DiscoveryServiceSpecificationSSP001 = 10, + + /// + /// Enum AssetAdministrationShellRepositoryServiceSpecificationSSP001 for https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRepositoryServiceSpecification/SSP-001 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRepositoryServiceSpecification/SSP-001")] + AssetAdministrationShellRepositoryServiceSpecificationSSP001 = 11, + + /// + /// Enum AssetAdministrationShellRepositoryServiceSpecificationSSP002 for https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRepositoryServiceSpecification/SSP-002 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRepositoryServiceSpecification/SSP-002")] + AssetAdministrationShellRepositoryServiceSpecificationSSP002 = 12, + + /// + /// Enum SubmodelRepositoryServiceSpecificationSSP001 for https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-001 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-001")] + SubmodelRepositoryServiceSpecificationSSP001 = 13, + + /// + /// Enum SubmodelRepositoryServiceSpecificationSSP002 for https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-002 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-002")] + SubmodelRepositoryServiceSpecificationSSP002 = 14, + + /// + /// Enum SubmodelRepositoryServiceSpecificationSSP003 for https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-003 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-003")] + SubmodelRepositoryServiceSpecificationSSP003 = 15, + + /// + /// Enum SubmodelRepositoryServiceSpecificationSSP004 for https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-004 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-004")] + SubmodelRepositoryServiceSpecificationSSP004 = 16, + + /// + /// Enum ConceptDescriptionServiceSpecificationSSP001 for https://admin-shell.io/aas/API/3/0/ConceptDescriptionServiceSpecification/SSP-001 + /// + [EnumMember(Value = "https://admin-shell.io/aas/API/3/0/ConceptDescriptionServiceSpecification/SSP-001")] + ConceptDescriptionServiceSpecificationSSP001 = 17 + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/IMappingService.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/IMappingService.cs index 7a696fd00..d80008ce7 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/IMappingService.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/IMappingService.cs @@ -5,8 +5,8 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers { public interface IMappingService { - IDTO? Map(IClass source, string mappingResolverKey); - List Map(List sourceList, string mappingResolverKey); + IDTO? Map(IClass? source, string mappingResolverKey); + List Map(List sourceList, string mappingResolverKey); IClass? Map(IDTO dto, string mappingResolverKey); } } diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs index 08b252e1e..0758bbebc 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs @@ -10,7 +10,7 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers { public class MappingService : IMappingService { - public IDTO? Map(IClass source, string mappingResolverKey) + public IDTO? Map(IClass? source, string mappingResolverKey) { if (mappingResolverKey == null) { @@ -31,7 +31,7 @@ public class MappingService : IMappingService } } - public List Map(List sourceList, string mappingResolverKey) + public List Map(List sourceList, string mappingResolverKey) { if (mappingResolverKey == null) { diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/RequestMetadataMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/RequestMetadataMapper.cs index 033591d89..6d7f661fc 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/RequestMetadataMapper.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/RequestMetadataMapper.cs @@ -207,7 +207,7 @@ private static List TransformReferenceList(List refere return references.Select(reference => TransformReference(reference)).ToList(); } - private static IReference TransformReference(ReferenceDTO referenceDTO) + private static IReference? TransformReference(ReferenceDTO referenceDTO) { var transformedKeys = TransformKeys(referenceDTO.keys); var transformedSemanticId = referenceDTO.referredSemanticId != null ? diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/ResponseMetadataMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/ResponseMetadataMapper.cs index 1541bd81a..805171a3b 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/ResponseMetadataMapper.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/ResponseMetadataMapper.cs @@ -5,5 +5,5 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers; public class ResponseMetadataMapper { private static ResponseMetadataTransformer Transformer = new(); - public static IDTO Map(IClass source) => Transformer.Transform(source); + public static IDTO Map(IClass? source) => Transformer.Transform(source); } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/ResponseMetadataTransformer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/ResponseMetadataTransformer.cs index f850588e5..6231de3df 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/ResponseMetadataTransformer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/ResponseMetadataTransformer.cs @@ -11,7 +11,7 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers internal class ResponseMetadataTransformer : ITransformer { - public IDTO Transform(IClass that) => that.Transform(this); + public IDTO Transform(IClass? that) => that.Transform(this); public IDTO TransformAdministrativeInformation(IAdministrativeInformation that) => new AdministrativeInformationDTO(TransformEmbeddedDataSpecList(that.EmbeddedDataSpecifications), that.Version, that.Revision, (ReferenceDTO)Transform(that.Creator), @@ -61,7 +61,7 @@ public IDTO TransformAnnotatedRelationshipElement(IAnnotatedRelationshipElement public IDTO TransformDataSpecificationIec61360(IDataSpecificationIec61360 that) => throw new System.NotImplementedException(); - internal List? TransformEmbeddedDataSpecList(List that) + internal List? TransformEmbeddedDataSpecList(List that) { List? output = null; if (!that.IsNullOrEmpty()) @@ -100,7 +100,7 @@ public IDTO TransformEntity(IEntity that) public IDTO TransformEventPayload(IEventPayload that) => throw new System.NotImplementedException(); - public List TransformExtensionList(List that) + public List TransformExtensionList(List that) { List extensions = null; if (that != null) @@ -125,7 +125,7 @@ public IDTO TransformFile(IFile that) TransformEmbeddedDataSpecList(that.EmbeddedDataSpecifications)); } - internal List? TransformKeyList(List? keyList) + internal List? TransformKeyList(List? keyList) { List? output = null; @@ -145,7 +145,7 @@ public IDTO TransformFile(IFile that) public IDTO TransformLangStringDefinitionTypeIec61360(ILangStringDefinitionTypeIec61360 that) => throw new System.NotImplementedException(); - public List TransformLangStringNameTypeList(List that) + public List TransformLangStringNameTypeList(List that) { List langStrings = null; if (that != null) @@ -164,7 +164,7 @@ public List TransformLangStringNameTypeList(List throw new System.NotImplementedException(); - public List TransformLangStringTextTypeList(List that) + public List TransformLangStringTextTypeList(List that) { List langStrings = null; @@ -223,7 +223,7 @@ public IDTO TransformProperty(IProperty that) => TransformReferenceList(that.SupplementalSemanticIds), TransformQualifierList(that.Qualifiers), TransformEmbeddedDataSpecList(that.EmbeddedDataSpecifications)); - internal List TransformQualifierList(List qualifierList) + internal List TransformQualifierList(List qualifierList) { List output = null; return (qualifierList.IsNullOrEmpty() ? output : qualifierList.Select(qualifier => (QualifierDTO)Transform(qualifier)).ToList()) ?? []; @@ -239,7 +239,7 @@ public IDTO TransformRange(IRange that) => TransformReferenceList(that.SupplementalSemanticIds), TransformQualifierList(that.Qualifiers), TransformEmbeddedDataSpecList(that.EmbeddedDataSpecifications)); - internal List TransformReferenceList(List that) + internal List TransformReferenceList(List that) { List output = null; if (!that.IsNullOrEmpty()) diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapper.cs index f1a3f0dac..684038faf 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapper.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapper.cs @@ -6,7 +6,7 @@ public class ResponseValueMapper { private static ResponseValueTransformer Transformer = new ResponseValueTransformer(); - public static IValueDTO? Map(IClass source) + public static IValueDTO? Map(IClass? source) { var transformed = Transformer.Transform(source); return transformed as IValueDTO; diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs index fcb573788..6c7d88ad1 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs @@ -106,7 +106,7 @@ public IDTO TransformFile(IFile that) return new FileValue(that.IdShort, that.ContentType, that.Value); } - internal List? TransformKeyList(List? keyList) + internal List? TransformKeyList(List? keyList) { List? output = null; diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializer.cs index 88ca6dcd0..7706f4d80 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializer.cs @@ -3,18 +3,20 @@ using DataTransferObjects.ValueDTOs; using IO.Swagger.Lib.V3.Exceptions; using IO.Swagger.Lib.V3.Interfaces; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Text.Json.Nodes; namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers { + using System.Text.Json; + public interface IValueOnlyJsonDeserializer { IValueDTO? DeserializeSubmodelElementValue(JsonNode node, string? encodedSubmodelIdentifier = null, string? idShortPath = null); SubmodelValue? DeserializeSubmodelValue(JsonNode node, string? encodedSubmodelIdentifier); } + public class ValueOnlyJsonDeserializer : IValueOnlyJsonDeserializer { private readonly ISubmodelService _submodelService; @@ -23,8 +25,9 @@ public class ValueOnlyJsonDeserializer : IValueOnlyJsonDeserializer public ValueOnlyJsonDeserializer(ISubmodelService submodelService, IBase64UrlDecoderService decoderService) { _submodelService = submodelService ?? throw new ArgumentNullException(nameof(submodelService)); - _decoderService = decoderService ?? throw new ArgumentNullException(nameof(decoderService)); + _decoderService = decoderService ?? throw new ArgumentNullException(nameof(decoderService)); } + public IValueDTO? DeserializeSubmodelElementValue(JsonNode node, string? encodedSubmodelIdentifier = null, string idShortPath = null) { if (node == null) throw new ArgumentNullException(nameof(node)); @@ -36,7 +39,7 @@ public ValueOnlyJsonDeserializer(ISubmodelService submodelService, IBase64UrlDec foreach (var keyValue in jsonObject) { string idShort = keyValue.Key; - var value = keyValue.Value; + var value = keyValue.Value; output = Deserialize(idShort, value, encodedSubmodelIdentifier, idShortPath); } } @@ -50,26 +53,26 @@ public ValueOnlyJsonDeserializer(ISubmodelService submodelService, IBase64UrlDec switch (value) { case JsonValue jsonValue: - { - //Property - jsonValue.TryGetValue(out string propertyValue); - output = new PropertyValue(idShort, propertyValue); - break; - } + { + //Property + jsonValue.TryGetValue(out string propertyValue); + output = new PropertyValue(idShort, propertyValue); + break; + } case JsonObject valueObject: - { - output = ParseJsonValueObject(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); - break; - } + { + output = ParseJsonValueObject(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); + break; + } case JsonArray valueArray: - { - output = ParseJsonValueArray(idShort, valueArray, encodedSubmodelIdentifier, idShortPath); - break; - } + { + output = ParseJsonValueArray(idShort, valueArray, encodedSubmodelIdentifier, idShortPath); + break; + } default: - { - throw new InvalidOperationException(); - } + { + throw new InvalidOperationException(); + } } return output; @@ -79,7 +82,7 @@ public ValueOnlyJsonDeserializer(ISubmodelService submodelService, IBase64UrlDec { //This is Multilingual Property or SMEList var decodedSubmodelId = _decoderService.Decode("submodelId", encodedSubmodelIdentifier); - var element = _submodelService.GetSubmodelElementByPath(decodedSubmodelId, idShortPath); + var element = _submodelService.GetSubmodelElementByPath(decodedSubmodelId, idShortPath); if (element != null) { if (element is MultiLanguageProperty) @@ -95,6 +98,7 @@ public ValueOnlyJsonDeserializer(ISubmodelService submodelService, IBase64UrlDec throw new JsonDeserializationException(idShort, "Element is neither MutlilanguageProperty nor SubmodelElementList"); } } + return null; } @@ -128,7 +132,8 @@ private IValueDTO CreateMultilanguagePropertyValue(string idShort, JsonArray val private void GetPropertyFromJsonObject(JsonObject jsonObject, out string? propertyName, out string? propertyValue) { - propertyName = null; propertyValue = null; + propertyName = null; + propertyValue = null; foreach (var item in jsonObject) { propertyName = item.Key; @@ -203,10 +208,10 @@ private IValueDTO CreateSubmodelElementCollectionValue(string idShort, JsonObjec foreach (var item in valueObject) { - var newNode = new JsonObject(new[] { KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString())) }); + var newNode = new JsonObject(new[] {KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString()))}); if (idShortPath == null) idShortPath = idShort; - var newIdShortPath = idShortPath + "." + item.Key; + var newIdShortPath = idShortPath + "." + item.Key; var submodelElement = DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier, newIdShortPath); submodelElements.Add((ISubmodelElementValue)submodelElement); } @@ -219,16 +224,17 @@ private IValueDTO CreateBasicEventElement(string idShort, JsonObject valueObject ReferenceDTO? observed = null; if (valueObject["observed"] is not null) { - observed = JsonConvert.DeserializeObject(valueObject.ToString()); + observed = JsonSerializer.Deserialize(valueObject.ToString()); } + return new BasicEventElementValue(idShort, observed); } private IValueDTO CreateEntityValue(string idShort, JsonObject valueObject, string? encodedSubmodelIdentifier, string idShortPath) { - string? entityType = null; - string globalAssetId = null; - List statements = null; + string? entityType = null; + string globalAssetId = null; + List statements = null; JsonValue entityTypeNode = valueObject["entityType"] as JsonValue; entityTypeNode?.TryGetValue(out entityType); @@ -242,33 +248,35 @@ private IValueDTO CreateEntityValue(string idShort, JsonObject valueObject, stri statements = new List(); foreach (var item in statementsNode) { - var newNode = new JsonObject(new[] { KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString())) }); - var newIdShortPath = idShortPath + "." + item.Key; + var newNode = new JsonObject(new[] {KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString()))}); + var newIdShortPath = idShortPath + "." + item.Key; var statement = DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier, newIdShortPath); statements.Add((ISubmodelElementValue)statement); } } + return new EntityValue(idShort, (EntityType)Stringification.EntityTypeFromString(entityType), statements, globalAssetId); } private IValueDTO CreateReferenceElementValue(string idShort, JsonObject valueObject) { - ReferenceDTO referenceDTO = JsonConvert.DeserializeObject(valueObject.ToString()); + ReferenceDTO referenceDTO = JsonSerializer.Deserialize(valueObject.ToString()); return new ReferenceElementValue(idShort, referenceDTO); } private IValueDTO CreateRelationshipElementValue(string idShort, JsonObject valueObject) { - ReferenceDTO firstDTO = null, secondDTO = null; - JsonNode firstNode = valueObject["first"]; + ReferenceDTO firstDTO = null, secondDTO = null; + JsonNode firstNode = valueObject["first"]; if (firstNode != null) { - firstDTO = JsonConvert.DeserializeObject(firstNode.ToString()); + firstDTO = JsonSerializer.Deserialize(firstNode.ToString()); } + JsonNode secondNode = valueObject["second"]; if (secondNode != null) { - secondDTO = JsonConvert.DeserializeObject(firstNode.ToString()); + secondDTO = JsonSerializer.Deserialize(firstNode.ToString()); } return new RelationshipElementValue(idShort, firstDTO, secondDTO); @@ -276,16 +284,17 @@ private IValueDTO CreateRelationshipElementValue(string idShort, JsonObject valu private IValueDTO CreateAnnotedRelationshipElementValue(string idShort, JsonObject valueObject, string? encodedSubmodelIdentifier, string idShortPath) { - ReferenceDTO firstDTO = null, secondDTO = null; - JsonNode firstNode = valueObject["first"]; + ReferenceDTO firstDTO = null, secondDTO = null; + JsonNode firstNode = valueObject["first"]; if (firstNode != null) { - firstDTO = JsonConvert.DeserializeObject(firstNode.ToString()); + firstDTO = JsonSerializer.Deserialize(firstNode.ToString()); } + JsonNode secondNode = valueObject["second"]; if (secondNode != null) { - secondDTO = JsonConvert.DeserializeObject(firstNode.ToString()); + secondDTO = JsonSerializer.Deserialize(firstNode.ToString()); } JsonArray annotationsNode = valueObject["annotations"] as JsonArray; @@ -297,6 +306,7 @@ private IValueDTO CreateAnnotedRelationshipElementValue(string idShort, JsonObje var annotation = DeserializeSubmodelElementValue(annotationNode, encodedSubmodelIdentifier, idShortPath); annotations.Add((ISubmodelElementValue)annotation); } + return new AnnotatedRelationshipElementValue(idShort, firstDTO, secondDTO, annotations); } @@ -305,8 +315,8 @@ private IValueDTO CreateAnnotedRelationshipElementValue(string idShort, JsonObje private IValueDTO CreateBlobValue(string idShort, JsonObject valueObject) { - string? contentType = null; - var contentTypeNode = valueObject["contentType"] as JsonValue; + string? contentType = null; + var contentTypeNode = valueObject["contentType"] as JsonValue; contentTypeNode?.TryGetValue(out contentType); var valueNode = valueObject["value"] as JsonValue; @@ -322,8 +332,8 @@ private IValueDTO CreateBlobValue(string idShort, JsonObject valueObject) private IValueDTO CreateFileValue(string idShort, JsonObject valueObject) { string? contentType = null; - string value = null; - var contentTypeNode = valueObject["contentType"] as JsonValue; + string value = null; + var contentTypeNode = valueObject["contentType"] as JsonValue; contentTypeNode?.TryGetValue(out contentType); var valueNode = valueObject["value"] as JsonValue; valueNode?.TryGetValue(out value); @@ -332,8 +342,8 @@ private IValueDTO CreateFileValue(string idShort, JsonObject valueObject) private static IValueDTO CreateRangeValue(string idShort, JsonObject valueObject) { - string min = null, max = null; - var minNode = valueObject["min"] as JsonValue; + string min = null, max = null; + var minNode = valueObject["min"] as JsonValue; minNode?.TryGetValue(out min); var maxNode = valueObject["max"] as JsonValue; maxNode?.TryGetValue(out max); @@ -344,10 +354,10 @@ private static IValueDTO CreateRangeValue(string idShort, JsonObject valueObject public SubmodelValue DeserializeSubmodelValue(JsonNode node, string? encodedSubmodelIdentifier) { var submodelElements = new List(); - var jsonObject = node as JsonObject; + var jsonObject = node as JsonObject; foreach (var item in jsonObject) { - var newNode = new JsonObject(new[] { KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString())) }); + var newNode = new JsonObject(new[] {KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString()))}); var submodelElement = DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier); submodelElements.Add((ISubmodelElementValue)submodelElement); } @@ -355,4 +365,4 @@ public SubmodelValue DeserializeSubmodelValue(JsonNode node, string? encodedSubm return new SubmodelValue(submodelElements); } } -} +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/PathModifier/PathTransformer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/PathModifier/PathTransformer.cs index 0b6b5a8ce..0456fbb2b 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/PathModifier/PathTransformer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/PathModifier/PathTransformer.cs @@ -2,227 +2,354 @@ using System.Collections.Generic; using static AasCore.Aas3_0.Visitation; -namespace IO.Swagger.Lib.V3.SerializationModifiers.PathModifier; - -/// -public class PathTransformer : ITransformerWithContext> +namespace IO.Swagger.Lib.V3.SerializationModifiers.PathModifier { - /// - public List Transform(IClass that, PathModifierContext context) => that.Transform(this, context); - - /// - public List TransformAdministrativeInformation(IAdministrativeInformation that, PathModifierContext context) => throw new System.NotImplementedException(); - - /// - public List TransformAssetAdministrationShell(IAssetAdministrationShell that, PathModifierContext context) => throw new System.NotImplementedException(); - - /// - public List TransformAssetInformation(IAssetInformation that, PathModifierContext context) => throw new System.NotImplementedException(); - - /// - public List TransformConceptDescription(IConceptDescription that, PathModifierContext context) => throw new System.NotImplementedException(); - - /// - public List TransformDataSpecificationIec61360(IDataSpecificationIec61360 that, PathModifierContext context) => throw new System.NotImplementedException(); - - /// - public List TransformEmbeddedDataSpecification(IEmbeddedDataSpecification that, PathModifierContext context) => throw new System.NotImplementedException(); + public class PathTransformer : ITransformerWithContext> + { + public List Transform(IClass? that, PathModifierContext context) + { + return that.Transform(this, context); + } - /// - public List TransformEnvironment(IEnvironment that, PathModifierContext context) => throw new System.NotImplementedException(); + public List TransformAdministrativeInformation(IAdministrativeInformation that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformEventPayload(IEventPayload that, PathModifierContext context) => throw new System.NotImplementedException(); + public List TransformAnnotatedRelationshipElement(IAnnotatedRelationshipElement that, PathModifierContext context) + { + if (context.IdShortPaths.Count == 0) + { + context.IdShortPaths.Add(that.IdShort); + } + else + { + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}"); + } + + if (that.Annotations != null) + { + var currentParentPath = string.IsNullOrEmpty(context.ParentPath) ? that.IdShort : $"{context.ParentPath}.{that.IdShort}"; + foreach (ISubmodelElement? item in that.Annotations) + { + context.ParentPath = currentParentPath; + Transform(item, context); + } + } - /// - public List TransformExtension(IExtension that, PathModifierContext context) => throw new System.NotImplementedException(); + return context.IdShortPaths; + } - /// - public List TransformKey(IKey that, PathModifierContext context) => throw new System.NotImplementedException(); + public List TransformAssetAdministrationShell(IAssetAdministrationShell that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformLangStringDefinitionTypeIec61360(ILangStringDefinitionTypeIec61360 that, PathModifierContext context) => - throw new System.NotImplementedException(); + public List TransformAssetInformation(IAssetInformation that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformLangStringNameType(ILangStringNameType that, PathModifierContext context) => throw new System.NotImplementedException(); + public List TransformBasicEventElement(IBasicEventElement that, PathModifierContext context) + { + if (context.ParentPath == null) + throw new InvalidSerializationModifierException("Path", that.GetType().Name); - /// - public List TransformLangStringPreferredNameTypeIec61360(ILangStringPreferredNameTypeIec61360 that, PathModifierContext context) => - throw new System.NotImplementedException(); + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}"); + return context.IdShortPaths; + } + public List TransformBlob(IBlob that, PathModifierContext context) + { + if (context.ParentPath == null) + throw new InvalidSerializationModifierException("Path", that.GetType().Name); - /// - public List TransformLangStringShortNameTypeIec61360(ILangStringShortNameTypeIec61360 that, PathModifierContext context) => throw new System.NotImplementedException(); + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}"); + return context.IdShortPaths; + } - /// - public List TransformLangStringTextType(ILangStringTextType that, PathModifierContext context) => throw new System.NotImplementedException(); + public List TransformCapability(ICapability that, PathModifierContext context) + { + if (context.ParentPath == null) + throw new InvalidSerializationModifierException("Path", that.GetType().Name); - /// - public List TransformLevelType(ILevelType that, PathModifierContext context) => throw new System.NotImplementedException(); + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}"); + return context.IdShortPaths; + } - /// - public List TransformQualifier(IQualifier that, PathModifierContext context) => throw new System.NotImplementedException(); + public List TransformConceptDescription(IConceptDescription that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformReference(IReference that, PathModifierContext context) => throw new System.NotImplementedException(); + public List TransformDataSpecificationIec61360(IDataSpecificationIec61360 that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformResource(IResource that, PathModifierContext context) => throw new System.NotImplementedException(); + public List TransformEmbeddedDataSpecification(IEmbeddedDataSpecification that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformSpecificAssetId(ISpecificAssetId that, PathModifierContext context) => throw new System.NotImplementedException(); + public List TransformEntity(IEntity that, PathModifierContext context) + { + if (context.IdShortPaths.Count == 0) + { + context.IdShortPaths.Add(that.IdShort ?? string.Empty); + } + else + { + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}"); + } + + if (that.Statements != null) + { + var currentParentPath = string.IsNullOrEmpty(context.ParentPath) ? that.IdShort : $"{context.ParentPath}.{that.IdShort}"; + foreach (var item in that.Statements) + { + context.ParentPath = currentParentPath; + Transform(item, context); + } + } - /// - public List TransformValueList(IValueList that, PathModifierContext context) => throw new System.NotImplementedException(); + return context.IdShortPaths; + } - /// - public List TransformValueReferencePair(IValueReferencePair that, PathModifierContext context) => throw new System.NotImplementedException(); + public List TransformEnvironment(IEnvironment that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformAnnotatedRelationshipElement(IAnnotatedRelationshipElement that, PathModifierContext context) => - TransformWithChildren(context, that.IdShort, that.Annotations); + public List TransformEventPayload(IEventPayload that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformBasicEventElement(IBasicEventElement that, PathModifierContext context) => TransformWithPath(that, context, that.IdShort); + public List TransformExtension(IExtension that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformBlob(IBlob that, PathModifierContext context) => TransformWithPath(that, context, that.IdShort); + public List TransformFile(IFile that, PathModifierContext context) + { + if (context.ParentPath == null) + throw new InvalidSerializationModifierException("Path", that.GetType().Name); - /// - public List TransformCapability(ICapability that, PathModifierContext context) => TransformWithPath(that, context, that.IdShort); + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}"); + return context.IdShortPaths; + } - /// - public List TransformEntity(IEntity that, PathModifierContext context) => TransformWithChildren(context, that.IdShort, that.Statements); + public List TransformKey(IKey that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformFile(IFile that, PathModifierContext context) => TransformWithPath(that, context, that.IdShort); + public List TransformLangStringDefinitionTypeIec61360(ILangStringDefinitionTypeIec61360 that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformMultiLanguageProperty(IMultiLanguageProperty that, PathModifierContext context) => TransformWithPath(that, context, that.IdShort); + public List TransformLangStringNameType(ILangStringNameType that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformOperation(IOperation that, PathModifierContext context) - { - if (that.IdShort != null) + public List TransformLangStringPreferredNameTypeIec61360(ILangStringPreferredNameTypeIec61360 that, PathModifierContext context) { - context.IdShortPaths?.Add(that.IdShort); + throw new System.NotImplementedException(); } - TransformOperationVariables(that.InputVariables, context, that.IdShort); - TransformOperationVariables(that.OutputVariables, context, that.IdShort); - TransformOperationVariables(that.InoutputVariables, context, that.IdShort); + public List TransformLangStringShortNameTypeIec61360(ILangStringShortNameTypeIec61360 that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - return context.IdShortPaths ?? []; - } + public List TransformLangStringTextType(ILangStringTextType that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformOperationVariable(IOperationVariable that, PathModifierContext context) => TransformWithPath(that, context, that.Value.IdShort); + public List TransformLevelType(ILevelType that, PathModifierContext context) + { + throw new System.NotImplementedException(); + } - /// - public List TransformProperty(IProperty that, PathModifierContext context) => TransformWithPath(that, context, that.IdShort); + public List TransformMultiLanguageProperty(IMultiLanguageProperty that, PathModifierContext context) + { + if (context.ParentPath == null) + throw new InvalidSerializationModifierException("Path", that.GetType().Name); - /// - public List TransformRange(IRange that, PathModifierContext context) => TransformWithPath(that, context, that.IdShort); + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}"); + return context.IdShortPaths; + } - /// - public List TransformReferenceElement(IReferenceElement that, PathModifierContext context) => TransformWithPath(that, context, that.IdShort); + public List TransformOperation(IOperation that, PathModifierContext context) + { + context.IdShortPaths.Add(that.IdShort); + + if (that.InputVariables != null) + { + foreach (var element in that.InputVariables) + { + context.ParentPath = that.IdShort; + Transform(element, context); + } + } + + if (that.OutputVariables != null) + { + foreach (var element in that.OutputVariables) + { + context.ParentPath = that.IdShort; + Transform(element, context); + } + } + + if (that.InoutputVariables != null) + { + foreach (var element in that.InoutputVariables) + { + context.ParentPath = that.IdShort; + Transform(element, context); + } + } - /// - public List TransformRelationshipElement(IRelationshipElement that, PathModifierContext context) => TransformWithPath(that, context, that.IdShort); + return context.IdShortPaths; + } - /// - public List TransformSubmodel(ISubmodel? that, PathModifierContext context) - { - context.IdShortPaths?.Add(that?.IdShort ?? string.Empty); + public List TransformOperationVariable(IOperationVariable that, PathModifierContext context) + { + if (context.ParentPath == null) + throw new InvalidSerializationModifierException("Path", that.GetType().Name); + context.IdShortPaths.Add(context.ParentPath + "." + that.Value.IdShort); + return context.IdShortPaths; + } - if (that?.SubmodelElements == null) + public List TransformProperty(IProperty that, PathModifierContext context) { - return context.IdShortPaths ?? []; + if (context.ParentPath == null) + throw new InvalidSerializationModifierException("Path", that.GetType().Name); + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}"); + return context.IdShortPaths; } - foreach (var element in that.SubmodelElements) + public List TransformQualifier(IQualifier that, PathModifierContext context) { - context.ParentPath = that.IdShort ?? string.Empty; - Transform(element, context); + throw new System.NotImplementedException(); } - return context.IdShortPaths ?? []; - } + public List TransformRange(IRange that, PathModifierContext context) + { + if (context.ParentPath == null) + throw new InvalidSerializationModifierException("Path", that.GetType().Name); - /// - public List TransformSubmodelElementCollection(ISubmodelElementCollection that, PathModifierContext context) => - TransformWithChildren(context, that.IdShort, that.Value); + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}"); + return context.IdShortPaths; + } - /// - public List TransformSubmodelElementList(ISubmodelElementList that, PathModifierContext context) - { - if (that.Value == null) + public List TransformReference(IReference that, PathModifierContext context) { - return context.IdShortPaths ?? []; + throw new System.NotImplementedException(); } - for (var i = 0; i < that.Value.Count; i++) + public List TransformReferenceElement(IReferenceElement that, PathModifierContext context) { - context.IdShortPaths?.Add(string.IsNullOrEmpty(context.ParentPath) ? $"{that.IdShort}[{i}]" : $"{context.ParentPath}.{that.IdShort}[{i}]"); - } + if (context.ParentPath == null) + throw new InvalidSerializationModifierException("Path", that.GetType().Name); - return context.IdShortPaths ?? []; - } + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}"); + return context.IdShortPaths; + } - private List TransformWithChildren(PathModifierContext context, string? idShort, IEnumerable? children) - { - if (context.IdShortPaths == null) + public List TransformRelationshipElement(IRelationshipElement that, PathModifierContext context) { - return [string.Empty]; + if (context.ParentPath == null) + throw new InvalidSerializationModifierException("Path", that.GetType().Name); + + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}"); + return context.IdShortPaths; } - if (context.IdShortPaths.Count == 0) + public List TransformResource(IResource that, PathModifierContext context) { - context.IdShortPaths.Add(idShort ?? string.Empty); + throw new System.NotImplementedException(); } - else + + public List TransformSpecificAssetId(ISpecificAssetId that, PathModifierContext context) { - context.IdShortPaths.Add($"{context.ParentPath}.{idShort}"); + throw new System.NotImplementedException(); } - if (children == null) + public List TransformSubmodel(ISubmodel? that, PathModifierContext context) { + context.IdShortPaths.Add(that.IdShort); + + if (that.SubmodelElements != null) + { + foreach (var element in that.SubmodelElements) + { + context.ParentPath = that.IdShort; + Transform(element, context); + } + } + return context.IdShortPaths; } - var currentParentPath = string.IsNullOrEmpty(context.ParentPath) ? idShort : $"{context.ParentPath}.{idShort}"; - foreach (var item in children) + public List TransformSubmodelElementCollection(ISubmodelElementCollection that, PathModifierContext context) { - context.ParentPath = currentParentPath; - Transform(item, context); - } + if (context.IdShortPaths.Count == 0) + { + context.IdShortPaths.Add(that.IdShort); + } + else + { + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}"); + } + + if (that.Value != null) + { + var currentParentPath = string.IsNullOrEmpty(context.ParentPath) ? that.IdShort : $"{context.ParentPath}.{that.IdShort}"; + foreach (var item in that.Value) + { + context.ParentPath = currentParentPath; + Transform(item, context); + } + } - return context.IdShortPaths; - } + return context.IdShortPaths; + } - private static List TransformWithPath(T that, PathModifierContext context, string? idShort) - { - if (context.ParentPath == null) + public List TransformSubmodelElementList(ISubmodelElementList that, PathModifierContext context) { - throw new InvalidSerializationModifierException("Path", that.GetType().Name); - } + if (that.Value != null) + { + for (var i = 0; i < that.Value.Count; i++) + { + if (string.IsNullOrEmpty(context.ParentPath)) + { + //No need of prefix + context.IdShortPaths.Add(that.IdShort + $"[{i}]"); + } + else + { + context.IdShortPaths.Add($"{context.ParentPath}.{that.IdShort}" + $"[{i}]"); + } + } + } - context.IdShortPaths?.Add($"{context.ParentPath}.{idShort}"); - return context.IdShortPaths ?? []; - } + return context.IdShortPaths; + } - private void TransformOperationVariables(IEnumerable? variables, PathModifierContext context, string? parentPath) - { - if (variables == null) + public List TransformValueList(IValueList that, PathModifierContext context) { - return; + throw new System.NotImplementedException(); } - foreach (var element in variables) + public List TransformValueReferencePair(IValueReferencePair that, PathModifierContext context) { - context.ParentPath = parentPath; - Transform(element, context); + throw new System.NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/IO.Swagger.Lib.V3/Services/AasRepositoryApiHelperService.cs b/src/IO.Swagger.Lib.V3/Services/AasRepositoryApiHelperService.cs index 3dbfc9650..7e75930b4 100644 --- a/src/IO.Swagger.Lib.V3/Services/AasRepositoryApiHelperService.cs +++ b/src/IO.Swagger.Lib.V3/Services/AasRepositoryApiHelperService.cs @@ -24,7 +24,7 @@ public AasRepositoryApiHelperService(IAppLogger l return null; } - var result = new List(); + var result = new List(); foreach (var aas in aasList) { result.Add(aas.GetReference()); diff --git a/src/IO.Swagger.Lib.V3/Services/GenerateSerializationService.cs b/src/IO.Swagger.Lib.V3/Services/GenerateSerializationService.cs index 8eb8ec235..0a7d5e565 100644 --- a/src/IO.Swagger.Lib.V3/Services/GenerateSerializationService.cs +++ b/src/IO.Swagger.Lib.V3/Services/GenerateSerializationService.cs @@ -5,50 +5,61 @@ using System.Collections.Generic; using System.Linq; -namespace IO.Swagger.Lib.V3.Services +namespace IO.Swagger.Lib.V3.Services; + +using Environment = AasCore.Aas3_0.Environment; + +/// +public class GenerateSerializationService : IGenerateSerializationService { - public class GenerateSerializationService : IGenerateSerializationService + private readonly IAppLogger _logger; + private readonly IAssetAdministrationShellService _aasService; + private readonly ISubmodelService _submodelService; + + /// + /// Initializes a new instance of the class. + /// + /// Logger instance for logging activities. + /// Service for accessing Asset Administration Shells. + /// Service for accessing Submodels. + /// + /// Thrown when any of the required services (logger, aasService, submodelService) are null. + /// + public GenerateSerializationService(IAppLogger logger, IAssetAdministrationShellService aasService, ISubmodelService submodelService) { - private readonly IAppLogger _logger; - private readonly IAssetAdministrationShellService _aasService; - private readonly ISubmodelService _submodelService; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _aasService = aasService ?? throw new ArgumentNullException(nameof(aasService)); + _submodelService = submodelService ?? throw new ArgumentNullException(nameof(submodelService)); + } - public GenerateSerializationService(IAppLogger logger, IAssetAdministrationShellService aasService, ISubmodelService submodelService) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _aasService = aasService ?? throw new ArgumentNullException(nameof(aasService)); - _submodelService = submodelService ?? throw new ArgumentNullException(nameof(submodelService)); - } + /// + public Environment GenerateSerializationByIds(List? aasIds = null, List? submodelIds = null) + { + var outputEnv = new Environment {AssetAdministrationShells = new List(), Submodels = new List()}; - public AasCore.Aas3_0.Environment GenerateSerializationByIds(List? aasIds = null, List? submodelIds = null, bool includeConceptDescriptions = false) + //Fetch AASs for the requested aasIds + var aasList = _aasService.GetAllAssetAdministrationShells(); + if (aasIds != null) { - var outputEnv = new AasCore.Aas3_0.Environment(); - outputEnv.AssetAdministrationShells = new List(); - outputEnv.Submodels = new List(); - - //Fetch AASs for the requested aasIds - var aasList = _aasService.GetAllAssetAdministrationShells(); - foreach (var aasId in aasIds) + foreach (var foundAas in aasIds.Select(aasId => aasList.Where(a => a.Id != null && a.Id.Equals(aasId, StringComparison.Ordinal))).Where(foundAas => foundAas.Any())) { - var foundAas = aasList.Where(a => a.Id.Equals(aasId)); - if (foundAas.Any()) - { - outputEnv.AssetAdministrationShells.Add(foundAas.First()); - } - } - - //Fetch Submodels for the requested submodelIds - var submodelList = _submodelService.GetAllSubmodels(); - foreach (var submodelId in submodelIds) - { - var foundSubmodel = submodelList.Where(s => s.Id.Equals(submodelId)); - if (foundSubmodel.Any()) - { - outputEnv.Submodels.Add(foundSubmodel.First()); - } + outputEnv.AssetAdministrationShells.Add(foundAas.First()); } + } + //Fetch Submodels for the requested submodelIds + var submodelList = _submodelService.GetAllSubmodels(); + if (submodelIds == null) + { return outputEnv; } + + foreach (var foundSubmodel in submodelIds.Select(submodelId => submodelList.Where(s => s.Id != null && s.Id.Equals(submodelId, StringComparison.Ordinal))) + .Where(foundSubmodel => foundSubmodel.Any())) + { + outputEnv.Submodels.Add(foundSubmodel.First()); + } + + return outputEnv; } -} +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Services/LevelExtentModifierService.cs b/src/IO.Swagger.Lib.V3/Services/LevelExtentModifierService.cs index 3a097bec0..dec3d6654 100644 --- a/src/IO.Swagger.Lib.V3/Services/LevelExtentModifierService.cs +++ b/src/IO.Swagger.Lib.V3/Services/LevelExtentModifierService.cs @@ -1,12 +1,14 @@ -using IO.Swagger.Lib.V3.Interfaces; +using AasxServerStandardBib.Logging; +using IO.Swagger.Lib.V3.Interfaces; using IO.Swagger.Lib.V3.SerializationModifiers.LevelExtent; using IO.Swagger.Models; using System; using System.Collections.Generic; -using System.Linq; namespace IO.Swagger.Lib.V3.Services; +using System.Linq; + /// public class LevelExtentModifierService : ILevelExtentModifierService { @@ -20,14 +22,13 @@ public IClass ApplyLevelExtent(IClass that, LevelEnum level = LevelEnum.Deep, Ex var context = new LevelExtentModifierContext(level, extent); return _transformer.Transform(that, context); } - + /// public List ApplyLevelExtent(List that, LevelEnum level = LevelEnum.Deep, ExtentEnum extent = ExtentEnum.WithoutBlobValue) { ArgumentNullException.ThrowIfNull(that); var context = new LevelExtentModifierContext(level, extent); - return that.Select(source => source != null ? _transformer.Transform(source, context) : null).ToList(); } } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Services/PaginationService.cs b/src/IO.Swagger.Lib.V3/Services/PaginationService.cs index bca460bd9..c2560faff 100644 --- a/src/IO.Swagger.Lib.V3/Services/PaginationService.cs +++ b/src/IO.Swagger.Lib.V3/Services/PaginationService.cs @@ -6,79 +6,101 @@ using System; using System.Collections.Generic; -namespace IO.Swagger.Lib.V3.Services; - -using System.Linq; - -/// -public class PaginationService : IPaginationService +namespace IO.Swagger.Lib.V3.Services { - private readonly IAppLogger _logger; - - /// - /// Constructor for PaginationService. - /// - /// Logger instance for logging. - public PaginationService(IAppLogger logger) => _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - - /// - public PagedResult GetPaginatedList(List sourceList, PaginationParameters paginationParameters) + public class PaginationService : IPaginationService { - var startIndex = paginationParameters.Cursor; - var endIndex = startIndex + paginationParameters.Limit - 1; - - CapEndIndex(sourceList, ref endIndex); - - LogErrorIfStartIndexOutOfBounds(sourceList, startIndex, endIndex); - - var outputList = GetPaginationList(sourceList, startIndex, endIndex); - var pagingMetadata = CreatePagingMetadata(sourceList, endIndex); - - return new PagedResult {result = outputList.ConvertAll(r => r as IClass), paging_metadata = pagingMetadata}; - } - - /// - public PackageDescriptionPagedResult GetPaginatedPackageDescriptionList(List sourceList, PaginationParameters paginationParameters) - { - var startIndex = paginationParameters.Cursor; - var endIndex = startIndex + paginationParameters.Limit - 1; - - CapEndIndex(sourceList, ref endIndex); - - LogErrorIfStartIndexOutOfBounds(sourceList, startIndex, endIndex); + private readonly IAppLogger _logger; - var outputList = GetPaginationList(sourceList, startIndex, endIndex); - var pagingMetadata = CreatePagingMetadata(sourceList, endIndex); - - return new PackageDescriptionPagedResult {result = outputList, paging_metadata = pagingMetadata}; - } - - private static void CapEndIndex(List sourceList, ref int endIndex) - { - if (endIndex > sourceList.Count - 1) + public PaginationService(IAppLogger logger) { - endIndex = sourceList.Count - 1; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } - } - - private void LogErrorIfStartIndexOutOfBounds(List sourceList, int startIndex, int endIndex) - { - if (startIndex > sourceList.Count - 1) + public PagedResult GetPaginatedList(List sourceList, PaginationParameters paginationParameters) { - _logger.LogError($"There are fewer elements in the retrieved list than requested for pagination - (from: {startIndex}, size: {endIndex})"); + var outputList = new List(); + var startIndex = paginationParameters.Cursor; + var endIndex = startIndex + paginationParameters.Limit - 1; + + //cap the endIndex + if (endIndex > sourceList.Count - 1) + { + endIndex = sourceList.Count - 1; + } + + //If there are less elements in the sourceList than "from" + if (startIndex > sourceList.Count - 1) + { + _logger.LogError($"There are less elements in the retrieved list than requested pagination - (from: {startIndex}, size:{endIndex})"); + } + + for (var i = startIndex; i <= endIndex; i++) + { + outputList.Add(sourceList[i]); + } + + //Creating pagination result + var pagingMetadata = new PagedResultPagingMetadata(); + if (endIndex < sourceList.Count - 1) + { + pagingMetadata.cursor = Convert.ToString(endIndex + 1); + } + + var paginationResult = new PagedResult() + { + result = outputList.ConvertAll(r => r as IClass), + paging_metadata = pagingMetadata + }; + + //return paginationResult; + return paginationResult; } - } - - private static List GetPaginationList(List sourceList, int startIndex, int endIndex) => sourceList.Skip(startIndex).Take(endIndex - startIndex + 1).ToList(); - private static PagedResultPagingMetadata CreatePagingMetadata(List sourceList, int endIndex) - { - var pagingMetadata = new PagedResultPagingMetadata(); - if (endIndex < sourceList.Count - 1) + public PackageDescriptionPagedResult GetPaginatedPackageDescriptionList(List sourceList, PaginationParameters paginationParameters) { - pagingMetadata.cursor = Convert.ToString(endIndex + 1); + var startIndex = paginationParameters.Cursor; + var endIndex = startIndex + paginationParameters.Limit - 1; + var outputList = GetPaginationList(sourceList, startIndex, endIndex); + + //Creating pagination result + var pagingMetadata = new PagedResultPagingMetadata(); + if (endIndex < sourceList.Count - 1) + { + pagingMetadata.cursor = Convert.ToString(endIndex + 1); + } + + var paginationResult = new PackageDescriptionPagedResult() + { + result = outputList, + paging_metadata = pagingMetadata + }; + + //return paginationResult; + return paginationResult; } - return pagingMetadata; + private List GetPaginationList(List sourceList, int startIndex, int endIndex) + { + var outputList = new List(); + + //cap the endIndex + if (endIndex > sourceList.Count - 1) + { + endIndex = sourceList.Count - 1; + } + + //If there are less elements in the sourceList than "from" + if (startIndex > sourceList.Count - 1) + { + _logger.LogError($"There are less elements in the retrieved list than requested pagination - (from: {startIndex}, size:{endIndex})"); + } + + for (var i = startIndex; i <= endIndex; i++) + { + outputList.Add(sourceList[i]); + } + + return outputList; + } } -} \ No newline at end of file +} diff --git a/src/IO.Swagger.Lib.V3/Services/PathModifierService.cs b/src/IO.Swagger.Lib.V3/Services/PathModifierService.cs index a6e4ceac7..f89cdff01 100644 --- a/src/IO.Swagger.Lib.V3/Services/PathModifierService.cs +++ b/src/IO.Swagger.Lib.V3/Services/PathModifierService.cs @@ -2,27 +2,47 @@ using IO.Swagger.Lib.V3.SerializationModifiers.PathModifier; using System.Collections.Generic; -namespace IO.Swagger.Lib.V3.Services; +namespace IO.Swagger.Lib.V3.Services +{ + public class PathModifierService : IPathModifierService + { + private static readonly PathTransformer _pathTransformer = new PathTransformer(); -using System.Linq; + /// + /// Serialize an instance of the meta-model into a JSON object. + /// + public List ToIdShortPath(IClass? that) + { + var context = new PathModifierContext(); + return _pathTransformer.Transform(that, context); + } -/// -public class PathModifierService : IPathModifierService -{ - private static readonly PathTransformer PathTransformer = new(); + public List> ToIdShortPath(List submodelList) + { + var output = new List>(); - /// - public List ToIdShortPath(IClass that) - { - var context = new PathModifierContext(); - return PathTransformer.Transform(that, context); - } + foreach (var submodel in submodelList) + { + var context = new PathModifierContext(); + var path = _pathTransformer.Transform(submodel, context); + output.Add(path); + } + + return output; + } - /// - public List> ToIdShortPath(List submodelList) => - (from submodel in submodelList let context = new PathModifierContext() select PathTransformer.Transform(submodel, context)).ToList(); + public List> ToIdShortPath(List submodelElementList) + { + var output = new List>(); - /// - public List> ToIdShortPath(List submodelElementList) => - (from submodelElement in submodelElementList let context = new PathModifierContext() select PathTransformer.Transform(submodelElement, context)).ToList(); -} \ No newline at end of file + foreach (var submodelElement in submodelElementList) + { + var context = new PathModifierContext(); + var path = _pathTransformer.Transform(submodelElement, context); + output.Add(path); + } + + return output; + } + } +} diff --git a/src/IO.Swagger.Lib.V3/Services/ReferenceModifierService.cs b/src/IO.Swagger.Lib.V3/Services/ReferenceModifierService.cs index aebd4e4e7..245b8db65 100644 --- a/src/IO.Swagger.Lib.V3/Services/ReferenceModifierService.cs +++ b/src/IO.Swagger.Lib.V3/Services/ReferenceModifierService.cs @@ -29,7 +29,7 @@ public List GetReferenceResult(List referables) return output; } - public IReference GetReferenceResult(IReferable referable) + public IReference? GetReferenceResult(IReferable referable) { return referable.GetReference(); } diff --git a/src/IO.Swagger.Lib.V3/Startup.cs b/src/IO.Swagger.Lib.V3/Startup.cs index 840d02f31..c067f8eda 100644 --- a/src/IO.Swagger.Lib.V3/Startup.cs +++ b/src/IO.Swagger.Lib.V3/Startup.cs @@ -4,9 +4,10 @@ * The entire Repository Service Specification as part of Details of the Asset Administration Shell Part 2 * * OpenAPI spec version: V3.0 - * + * * Generated by: https://github.com/swagger-api/swagger-codegen.git */ + using System; using System.IO; using Microsoft.AspNetCore.Builder; @@ -16,14 +17,17 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Serialization; using IO.Swagger.Filters; namespace IO.Swagger; using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.OpenApi.Any; using Models; @@ -54,59 +58,63 @@ public Startup(IWebHostEnvironment env, IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { // Add framework services. - services - .AddMvc(options => - { - options.InputFormatters.RemoveType(); - options.OutputFormatters.RemoveType(); - }) - .AddNewtonsoftJson(opts => - { - opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - opts.SerializerSettings.Converters.Add(new StringEnumConverter(new CamelCaseNamingStrategy())); - }) - .AddXmlSerializerFormatters(); - + services.AddMvc(options => + { + options.InputFormatters.RemoveType(); + options.OutputFormatters.RemoveType(); + }) + .AddJsonOptions(options => + { + options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve; + }) + .AddXmlSerializerFormatters(); + + services.Configure(options => + { + options.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()); + }); + services.Configure(options => + { + options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + }); services.AddSwaggerGen(c => { - // Other Swagger configuration... + c.SwaggerDoc("V3.0", + new OpenApiInfo + { + Version = "V3.0", + Title = "DotAAS Part 2 | HTTP/REST | Repository Service Specification", + Description = "DotAAS Part 2 | HTTP/REST | Repository Service Specification (ASP.NET Core 3.1)", + Contact = new OpenApiContact + { + Name + = "Constantin Ziesche, Andreas Orzelski, Florian Krebs, Bastian Rössl, Manuel Sauer, Jens Vialkowitsch, Michael Hoffmeister, Torben Miny, Sebastian Bader, Marko Ristin, Nico Braunisch", + Url = new Uri("https://github.com/swagger-api/swagger-codegen"), + Email = "" + }, + TermsOfService = new Uri("https://github.com/admin-shell-io/aas-specs") + }); + + c.CustomSchemaIds(type => type.FullName); + c.IncludeXmlComments($"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{_hostingEnv.ApplicationName}.xml"); + + c.OperationFilter(); c.MapType(() => new OpenApiSchema - { - Type = "string", - Enum = new List - { - new OpenApiString(MessageTypeEnum.UndefinedEnum.ToString()), - new OpenApiString(MessageTypeEnum.InfoEnum.ToString()), - new OpenApiString(MessageTypeEnum.WarningEnum.ToString()), - new OpenApiString(MessageTypeEnum.ErrorEnum.ToString()), - new OpenApiString(MessageTypeEnum.ExceptionEnum.ToString()) - } - }); + { + Type = "string", + Enum = Enum.GetNames(typeof(MessageTypeEnum)) + .Select(enumName => new OpenApiString(enumName)) + .Cast() + .ToList(), + Nullable = false + }); }); - services - .AddSwaggerGen(c => - { - c.SwaggerDoc("V3.0", new OpenApiInfo - { - Version = "V3.0", - Title = "DotAAS Part 2 | HTTP/REST | Repository Service Specification", - Description = "DotAAS Part 2 | HTTP/REST | Repository Service Specification (ASP.NET Core 3.1)", - Contact = new OpenApiContact() - { - Name = "Constantin Ziesche, Andreas Orzelski, Florian Krebs, Bastian Rössl, Manuel Sauer, Jens Vialkowitsch, Michael Hoffmeister, Torben Miny, Sebastian Bader, Marko Ristin, Nico Braunisch", - Url = new Uri("https://github.com/swagger-api/swagger-codegen"), - Email = "" - }, - TermsOfService = new Uri("https://github.com/admin-shell-io/aas-specs") - }); - c.CustomSchemaIds(type => type.FullName); - c.IncludeXmlComments($"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{_hostingEnv.ApplicationName}.xml"); - - // Include DataAnnotation attributes on Controller Action parameters as Swagger validation rules (e.g required, pattern, ..) - // Use [ValidateModelState] on Actions to actually validate it in C# as well! - c.OperationFilter(); - }); } /// diff --git a/src/IO.Swagger.Registry.Lib.V3.Tests/Extensions/ReferenceElementExtensionsTests.cs b/src/IO.Swagger.Registry.Lib.V3.Tests/Extensions/ReferenceElementExtensionsTests.cs new file mode 100644 index 000000000..371277166 --- /dev/null +++ b/src/IO.Swagger.Registry.Lib.V3.Tests/Extensions/ReferenceElementExtensionsTests.cs @@ -0,0 +1,100 @@ +namespace IO.Swagger.Registry.Lib.V3.Tests.Extensions; + +using AasCore.Aas3_0; +using V3.Extensions; + +public class ReferenceElementExtensionsTests +{ + private readonly IFixture _fixture; + + public ReferenceElementExtensionsTests() + { + _fixture = new Fixture().Customize(new AutoMoqCustomization()); + } + + [Fact] + public void ReverseReferenceKeys_NullReferenceElement_DoesNothing() + { + // Arrange + ReferenceElement referenceElement = null; + + // Act + referenceElement.ReverseReferenceKeys(); + + // Assert + referenceElement.Should().BeNull(); + } + + [Fact] + public void ReverseReferenceKeys_NullValueProperty_DoesNothing() + { + // Arrange + var referenceElement = _fixture.Build() + .With(x => x.Value, (Reference?)null) + .Create(); + + // Act + referenceElement.ReverseReferenceKeys(); + + // Assert + referenceElement.Value.Should().BeNull(); + } + + [Fact] + public void ReverseReferenceKeys_NullKeysProperty_DoesNothing() + { + // Arrange + var reference = _fixture.Build() + .With(x => x.Keys, (List?)null) + .Create(); + var referenceElement = _fixture.Build() + .With(x => x.Value, reference) + .Create(); + + // Act + referenceElement.ReverseReferenceKeys(); + + // Assert + referenceElement.Value.Keys.Should().BeNull(); + } + + [Fact] + public void ReverseReferenceKeys_EmptyKeysList_DoesNothing() + { + // Arrange + var reference = _fixture.Build() + .With(x => x.Keys, new List()) + .Create(); + var referenceElement = _fixture.Build() + .With(x => x.Value, reference) + .Create(); + + // Act + referenceElement.ReverseReferenceKeys(); + + // Assert + referenceElement.Value.Keys.Should().BeEmpty(); + } + + [Fact] + public void ReverseReferenceKeys_NonEmptyKeysList_ReversesKeys() + { + // Arrange + var keys = new List {new Key(KeyTypes.ReferenceElement, "key1"), new Key(KeyTypes.ReferenceElement, "key2"), new Key(KeyTypes.ReferenceElement, "key3")}; + var reference = _fixture.Build() + .With(x => x.Keys, keys) + .Create(); + var referenceElement = _fixture.Build() + .With(x => x.Value, reference) + .Create(); + + // Act + referenceElement.ReverseReferenceKeys(); + + // Assert + referenceElement.Value.Keys.Should().HaveCount(3); + referenceElement.Value.Keys[0].Value.Should().Be("key3"); + referenceElement.Value.Keys[1].Value.Should().Be("key2"); + referenceElement.Value.Keys[2].Value.Should().Be("key1"); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Registry.Lib.V3.Tests/Services/AasDescriptorPaginationServiceTests.cs b/src/IO.Swagger.Registry.Lib.V3.Tests/Services/AasDescriptorPaginationServiceTests.cs index 49fd2b43e..1b06c8137 100644 --- a/src/IO.Swagger.Registry.Lib.V3.Tests/Services/AasDescriptorPaginationServiceTests.cs +++ b/src/IO.Swagger.Registry.Lib.V3.Tests/Services/AasDescriptorPaginationServiceTests.cs @@ -5,6 +5,8 @@ namespace IO.Swagger.Registry.Lib.V3.Tests.Services; +using Microsoft.OpenApi.Any; + public class AasDescriptorPaginationServiceTests { private readonly IFixture _fixture; @@ -17,7 +19,7 @@ public AasDescriptorPaginationServiceTests() _mockLogger = _fixture.Freeze>>(); _service = _fixture.Create(); } - + [Fact] public void Constructor_WithNullLogger_ThrowsArgumentNullException() { diff --git a/src/IO.Swagger.Registry.Lib.V3.Tests/Services/SubmodelPropertyExtractionServiceTests.cs b/src/IO.Swagger.Registry.Lib.V3.Tests/Services/SubmodelPropertyExtractionServiceTests.cs new file mode 100644 index 000000000..d3e586362 --- /dev/null +++ b/src/IO.Swagger.Registry.Lib.V3.Tests/Services/SubmodelPropertyExtractionServiceTests.cs @@ -0,0 +1,134 @@ +namespace IO.Swagger.Registry.Lib.V3.Tests.Services; + +using AasCore.Aas3_0; +using JetBrains.Annotations; +using V3.Services; + +[TestSubject(typeof(SubmodelPropertyExtractionService))] +public class SubmodelPropertyExtractionServiceTests +{ + private readonly IFixture _fixture; + private SubmodelPropertyExtractionService _submodelPropertyExtractionService; + + public SubmodelPropertyExtractionServiceTests() + { + _fixture = new Fixture().Customize(new AutoMoqCustomization()); + _submodelPropertyExtractionService = new SubmodelPropertyExtractionService(); + } + + [Fact] + public void FindMatchingProperties_ElementCollectionWithNullValue_ReturnsZeroAndNulls() + { + // Arrange + var elementCollection = _fixture.Build() + .With(x => x.Value, (List?)null) + .Create(); + + // Act + var result = _submodelPropertyExtractionService.FindMatchingProperties(elementCollection, null, null); + + // Assert + result.found.Should().Be(0); + result.jsonProperty.Should().BeNull(); + result.endpointProperty.Should().BeNull(); + } + + [Fact] + public void FindMatchingProperties_NoMatchingProperties_ReturnsZeroAndNulls() + { + // Arrange + var properties = new List + { + _fixture.Build().With(x => x.IdShort, "someId").With(x => x.Value, "someValue").Create(), + _fixture.Build().With(x => x.IdShort, "anotherId").With(x => x.Value, "anotherValue").Create() + }; + var elementCollection = _fixture.Build() + .With(x => x.Value, properties) + .Create(); + + // Act + var result = _submodelPropertyExtractionService.FindMatchingProperties(elementCollection, "nonexistentAasID", "nonexistentAssetID"); + + // Assert + result.found.Should().Be(0); + result.jsonProperty.Should().BeNull(); + result.endpointProperty.Should().BeNull(); + } + + [Fact] + public void FindMatchingProperties_WithMatchingProperties_ReturnsCorrectValues() + { + // Arrange + var properties = new List + { + _fixture.Build().With(x => x.IdShort, "aasID").With(x => x.Value, "expectedAasID").Create(), + _fixture.Build().With(x => x.IdShort, "assetID").With(x => x.Value, "expectedAssetID").Create(), + _fixture.Build().With(x => x.IdShort, "descriptorJSON").With(x => x.Value, "jsonValue").Create(), + _fixture.Build().With(x => x.IdShort, "endpoint").With(x => x.Value, "endpointValue").Create() + }; + var elementCollection = _fixture.Build() + .With(x => x.Value, properties) + .Create(); + + // Act + var result = _submodelPropertyExtractionService.FindMatchingProperties(elementCollection, "expectedAasID", "expectedAssetID"); + + // Assert + result.found.Should().Be(2); + result.jsonProperty.Should().NotBeNull(); + result.jsonProperty.Value.Should().Be("jsonValue"); + result.endpointProperty.Should().NotBeNull(); + result.endpointProperty.Value.Should().Be("endpointValue"); + } + + [Fact] + public void AddPropertyToCollection_CheckEmptyTrueAndEmptyValue_DoesNotAddProperty() + { + // Arrange + var collection = _fixture.Create(); + int initialCount = collection.Value.Count; + + // Act + _submodelPropertyExtractionService.AddPropertyToCollection(collection, "testId", "", DateTime.UtcNow, checkEmpty: true); + + // Assert + collection.Value.Count.Should().Be(initialCount); + } + + [Fact] + public void AddPropertyToCollection_ValidValue_AddsProperty() + { + // Arrange + var collection = _fixture.Create(); + int initialCount = collection.Value.Count; + + // Act + _submodelPropertyExtractionService.AddPropertyToCollection(collection, "testId", "testValue", DateTime.UtcNow); + + // Assert + collection.Value.Count.Should().Be(initialCount + 1); + var addedProperty = collection.Value.Last() as Property; + addedProperty.Should().NotBeNull(); + addedProperty.IdShort.Should().Be("testId"); + addedProperty.Value.Should().Be("testValue"); + } + + [Fact] + public void CreateSubmodelElementCollection_ValidInputs_CreatesCollection() + { + // Arrange + var idShort = "testCollection"; + var timestamp = DateTime.UtcNow; + + // Act + var collection = _submodelPropertyExtractionService.CreateSubmodelElementCollection(idShort, timestamp); + + // Assert + collection.Should().NotBeNull(); + collection.IdShort.Should().Be(idShort); + collection.TimeStampCreate.Should().Be(timestamp); + collection.TimeStamp.Should().Be(timestamp); + collection.Value.Should().NotBeNull().And.BeEmpty(); + } + +} \ No newline at end of file diff --git a/src/IO.Swagger.Registry.Lib.V3/Controllers/AssetAdministrationShellRegistryAPIApi.cs b/src/IO.Swagger.Registry.Lib.V3/Controllers/AssetAdministrationShellRegistryAPIApi.cs index fe1246947..aaf2d04b1 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Controllers/AssetAdministrationShellRegistryAPIApi.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Controllers/AssetAdministrationShellRegistryAPIApi.cs @@ -15,588 +15,566 @@ using IO.Swagger.Registry.Lib.V3.Attributes; using IO.Swagger.Registry.Lib.V3.Interfaces; using IO.Swagger.Registry.Lib.V3.Models; -using IO.Swagger.Registry.Lib.V3.Serializers; using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; using Swashbuckle.AspNetCore.Annotations; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; -namespace IO.Swagger.Controllers +namespace IO.Swagger.Controllers; + +using AasSecurity.Exceptions; + +/// +/// +/// +[ApiController] +public class AssetAdministrationShellRegistryAPIApiController : ControllerBase { + private readonly IAppLogger _logger; + private readonly IBase64UrlDecoderService _decoderService; + private readonly IAasRegistryService _aasRegistryService; + private readonly IRegistryInitializerService _registryInitializerService; + private readonly IAasDescriptorPaginationService _paginationService; + + public AssetAdministrationShellRegistryAPIApiController(IAppLogger logger, IBase64UrlDecoderService decoderService, + IAasRegistryService aasRegistryService, IRegistryInitializerService registryInitializerService, + IAasDescriptorPaginationService paginationService) + { + _logger = logger; + _decoderService = decoderService; + _aasRegistryService = aasRegistryService; + _registryInitializerService = registryInitializerService; + _paginationService = paginationService; + } + /// - /// + /// Deletes an Asset Administration Shell Descriptor, i.e. de-registers an AAS /// - [ ApiController ] - public class AssetAdministrationShellRegistryAPIApiController : ControllerBase + /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) + /// Asset Administration Shell Descriptor deleted successfully + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Not Found + /// Internal Server Error + /// Default error handling for unmentioned status codes + [HttpDelete] + [Route("/shell-descriptors/{aasIdentifier}")] + [ValidateModelState] + [SwaggerOperation("DeleteAssetAdministrationShellDescriptorById")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual IActionResult DeleteAssetAdministrationShellDescriptorById([FromRoute] [Required] byte[] aasIdentifier) { - private readonly IAppLogger _logger; - private readonly IBase64UrlDecoderService _decoderService; - private readonly IAasRegistryService _aasRegistryService; - private readonly IRegistryInitializerService _registryInitializerService; - private readonly IAasDescriptorPaginationService _paginationService; - - public AssetAdministrationShellRegistryAPIApiController(IAppLogger logger, IBase64UrlDecoderService decoderService, - IAasRegistryService aasRegistryService, IRegistryInitializerService registryInitializerService, IAasDescriptorPaginationService paginationService) - { - _logger = logger; - _decoderService = decoderService; - _aasRegistryService = aasRegistryService; - _registryInitializerService = registryInitializerService; - _paginationService = paginationService; - } + //TODO: Uncomment the next line to return response 204 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(204); - /// - /// Deletes an Asset Administration Shell Descriptor, i.e. de-registers an AAS - /// - /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) - /// Asset Administration Shell Descriptor deleted successfully - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Not Found - /// Internal Server Error - /// Default error handling for unmentioned status codes - [ HttpDelete ] - [ Route("/shell-descriptors/{aasIdentifier}") ] - [ ValidateModelState ] - [ SwaggerOperation("DeleteAssetAdministrationShellDescriptorById") ] - [ SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.") ] - [ SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found") ] - [ SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error") ] - [ SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes") ] - public virtual IActionResult DeleteAssetAdministrationShellDescriptorById([ FromRoute ] [ Required ] byte[] aasIdentifier) - { - //TODO: Uncomment the next line to return response 204 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(204); + //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(400, default(Result)); - //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(400, default(Result)); + //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(404, default(Result)); - //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(404, default(Result)); + //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(500, default(Result)); - //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(500, default(Result)); + //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(0, default(Result)); - //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(0, default(Result)); + throw new NotImplementedException(); + } - throw new NotImplementedException(); - } + /// + /// Deletes a Submodel Descriptor, i.e. de-registers a submodel + /// + /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) + /// The Submodel’s unique id (UTF8-BASE64-URL-encoded) + /// Submodel Descriptor deleted successfully + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Not Found + /// Internal Server Error + /// Default error handling for unmentioned status codes + [HttpDelete] + [Route("/shell-descriptors/{aasIdentifier}/submodel-descriptors/{submodelIdentifier}")] + [ValidateModelState] + [SwaggerOperation("DeleteSubmodelDescriptorByIdThroughSuperpath")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual IActionResult DeleteSubmodelDescriptorByIdThroughSuperpath([FromRoute] [Required] string aasIdentifier, + [FromRoute] [Required] string submodelIdentifier) + { + //TODO: Uncomment the next line to return response 204 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(204); - /// - /// Deletes a Submodel Descriptor, i.e. de-registers a submodel - /// - /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) - /// The Submodel’s unique id (UTF8-BASE64-URL-encoded) - /// Submodel Descriptor deleted successfully - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Not Found - /// Internal Server Error - /// Default error handling for unmentioned status codes - [ HttpDelete ] - [ Route("/shell-descriptors/{aasIdentifier}/submodel-descriptors/{submodelIdentifier}") ] - [ ValidateModelState ] - [ SwaggerOperation("DeleteSubmodelDescriptorByIdThroughSuperpath") ] - [ SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.") ] - [ SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found") ] - [ SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error") ] - [ SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes") ] - public virtual IActionResult DeleteSubmodelDescriptorByIdThroughSuperpath([ FromRoute ] [ Required ] string aasIdentifier, - [ FromRoute ] [ Required ] string submodelIdentifier) - { - //TODO: Uncomment the next line to return response 204 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(204); + //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(400, default(Result)); - //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(400, default(Result)); + //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(404, default(Result)); - //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(404, default(Result)); + //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(500, default(Result)); - //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(500, default(Result)); + //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(0, default(Result)); - //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(0, default(Result)); + throw new NotImplementedException(); + } - throw new NotImplementedException(); + /// + /// Returns all Asset Administration Shell Descriptors + /// + /// The maximum number of elements in the response array + /// A server-generated identifier retrieved from pagingMetadata that specifies from which position the result listing should continue + /// The Asset's kind (Instance or Type) + /// The Asset's type (UTF8-BASE64-URL-encoded) + /// Requested Asset Administration Shell Descriptors + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Forbidden + /// Internal Server Error + /// Default error handling for unmentioned status codes + [HttpGet] + [Route("/shell-descriptors")] + [ValidateModelState] + [SwaggerOperation("GetAllAssetAdministrationShellDescriptors")] + [SwaggerResponse(statusCode: 200, type: typeof(List), description: "Requested Asset Administration Shell Descriptors")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual IActionResult GetAllAssetAdministrationShellDescriptors([FromQuery] int? limit, + [FromQuery] string? cursor, + [FromQuery] string? assetKind, + [FromQuery] string? assetType) + { + // TODO (jtikekar, 2023-09-04): AssetType resembles GlobalAssetId from old Implementation + var assetList = new List(); + if (!string.IsNullOrEmpty(assetType)) + { + var decodedAssetType = _decoderService.Decode("assetType", assetType); + assetList = [decodedAssetType]; } - /// - /// Returns all Asset Administration Shell Descriptors - /// - /// The maximum number of elements in the response array - /// A server-generated identifier retrieved from pagingMetadata that specifies from which position the result listing should continue - /// The Asset's kind (Instance or Type) - /// The Asset's type (UTF8-BASE64-URL-encoded) - /// Requested Asset Administration Shell Descriptors - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Forbidden - /// Internal Server Error - /// Default error handling for unmentioned status codes - [ HttpGet ] - [ Route("/shell-descriptors") ] - [ ValidateModelState ] - [ SwaggerOperation("GetAllAssetAdministrationShellDescriptors") ] - [ SwaggerResponse(statusCode: 200, type: typeof(List), description: "Requested Asset Administration Shell Descriptors") ] - [ SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.") ] - [ SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden") ] - [ SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error") ] - [ SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes") ] - public virtual IActionResult GetAllAssetAdministrationShellDescriptors([ FromQuery ] int? limit, [ FromQuery ] string? cursor, [ FromQuery ] string? assetKind, - [ FromQuery ] string? assetType) + List aasDescriptors; + if (!Program.withDb) { - // TODO (jtikekar, 2023-09-04): AssetType resembles GlobalAssetId from old Implementation - List? assetList = new List(); - if (!string.IsNullOrEmpty(assetType)) - { - var decodedAssetType = _decoderService.Decode("assetType", assetType); - assetList = new List() - { - decodedAssetType - }; - } - - List aasDescriptors; - if (!Program.withDb) - { - // from AAS memory - aasDescriptors = _aasRegistryService.GetAllAssetAdministrationShellDescriptors(assetKind, assetList); - } - else - { - //From DB - aasDescriptors = new List(); - using (AasContext db = new AasContext()) - { - foreach (var aasDB in db.AASSets) - { - if (assetList.Count == 0 || assetList.Contains(aasDB.GlobalAssetId)) - { - var aasDesc = _aasRegistryService.CreateAasDescriptorFromDB(aasDB); - aasDescriptors.Add(aasDesc); - } - } - } - } - - var output = _paginationService.GetPaginatedList(aasDescriptors, new Models.PaginationParameters(cursor, limit)); - return new ObjectResult(output); + // from AAS memory + aasDescriptors = _aasRegistryService.GetAllAssetAdministrationShellDescriptors(assetKind, assetList); } - - /// - /// Returns all Submodel Descriptors - /// - /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) - /// The maximum number of elements in the response array - /// A server-generated identifier retrieved from pagingMetadata that specifies from which position the result listing should continue - /// Requested Submodel Descriptors - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Forbidden - /// Not Found - /// Internal Server Error - /// Default error handling for unmentioned status codes - [ HttpGet ] - [ Route("/shell-descriptors/{aasIdentifier}/submodel-descriptors") ] - [ ValidateModelState ] - [ SwaggerOperation("GetAllSubmodelDescriptorsThroughSuperpath") ] - [ SwaggerResponse(statusCode: 200, type: typeof(List), description: "Requested Submodel Descriptors") ] - [ SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.") ] - [ SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden") ] - [ SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found") ] - [ SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error") ] - [ SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes") ] - public virtual IActionResult GetAllSubmodelDescriptorsThroughSuperpath([ FromRoute ] [ Required ] string aasIdentifier, [ FromQuery ] int? limit, - [ FromQuery ] string cursor) + else { - //TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(200, default(GetSubmodelDescriptorsResult)); + //From DB + aasDescriptors = []; + using var db = new AasContext(); + aasDescriptors.AddRange(from aasDB in db.AASSets + where assetList.Count == 0 || assetList.Contains(aasDB.GlobalAssetId) + select _aasRegistryService.CreateAasDescriptorFromDB(aasDB)); + } - //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(400, default(Result)); + var output = _paginationService.GetPaginatedList(aasDescriptors, new Models.PaginationParameters(cursor, limit)); + return new ObjectResult(output); + } - //TODO: Uncomment the next line to return response 403 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(403, default(Result)); + /// + /// Returns all Submodel Descriptors + /// + /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) + /// The maximum number of elements in the response array + /// A server-generated identifier retrieved from pagingMetadata that specifies from which position the result listing should continue + /// Requested Submodel Descriptors + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Forbidden + /// Not Found + /// Internal Server Error + /// Default error handling for unmentioned status codes + [HttpGet] + [Route("/shell-descriptors/{aasIdentifier}/submodel-descriptors")] + [ValidateModelState] + [SwaggerOperation("GetAllSubmodelDescriptorsThroughSuperpath")] + [SwaggerResponse(statusCode: 200, type: typeof(List), description: "Requested Submodel Descriptors")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] + [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual IActionResult GetAllSubmodelDescriptorsThroughSuperpath([FromRoute] [Required] string aasIdentifier, + [FromQuery] int? limit, + [FromQuery] string cursor) + { + //TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(200, default(GetSubmodelDescriptorsResult)); - //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(404, default(Result)); + //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(400, default(Result)); - //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(500, default(Result)); + //TODO: Uncomment the next line to return response 403 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(403, default(Result)); - //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(0, default(Result)); - string exampleJson = null; - exampleJson = "\"\""; + //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(404, default(Result)); - throw new NotImplementedException(); - } + //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(500, default(Result)); + + //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(0, default(Result)); + string exampleJson = null; + exampleJson = "\"\""; + + throw new NotImplementedException(); + } - /// - /// Returns a specific Asset Administration Shell Descriptor - /// - /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) - /// Requested Asset Administration Shell Descriptor - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Forbidden - /// Not Found - /// Internal Server Error - /// Default error handling for unmentioned status codes - [ HttpGet ] - [ Route("/shell-descriptors/{aasIdentifier}") ] - [ ValidateModelState ] - [ SwaggerOperation("GetAssetAdministrationShellDescriptorById") ] - [ SwaggerResponse(statusCode: 200, type: typeof(AssetAdministrationShellDescriptor), description: "Requested Asset Administration Shell Descriptor") ] - [ SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.") ] - [ SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden") ] - [ SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found") ] - [ SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error") ] - [ SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes") ] - public virtual IActionResult GetAssetAdministrationShellDescriptorById([ FromRoute ] [ Required ] string aasIdentifier) + /// + /// Returns a specific Asset Administration Shell Descriptor + /// + /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) + /// Requested Asset Administration Shell Descriptor + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Forbidden + /// Not Found + /// Internal Server Error + /// Default error handling for unmentioned status codes + [HttpGet] + [Route("/shell-descriptors/{aasIdentifier}")] + [ValidateModelState] + [SwaggerOperation("GetAssetAdministrationShellDescriptorById")] + [SwaggerResponse(statusCode: 200, type: typeof(AssetAdministrationShellDescriptor), description: "Requested Asset Administration Shell Descriptor")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] + [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual IActionResult GetAssetAdministrationShellDescriptorById([FromRoute] [Required] string aasIdentifier) + { + var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); + _logger.LogInformation($"Received request to get the AAS Descriptor by Id"); + if (!Program.withDb) { - var decodedAasIdentifier = _decoderService.Decode("aasIdentifier", aasIdentifier); - _logger.LogInformation($"Received request to get the AAS Descriptor by Id"); - if (!Program.withDb) + var aasList = _aasRegistryService.GetAllAssetAdministrationShellDescriptors(aasIdentifier: decodedAasIdentifier); + if (aasList.Count != 0) { - var aasList = _aasRegistryService.GetAllAssetAdministrationShellDescriptors(aasIdentifier: decodedAasIdentifier); - if (aasList.Any()) - { - return new ObjectResult(aasList.First()); - } + return new ObjectResult(aasList.First()); } - else + } + else + { + // from database + using var db = new AasContext(); + foreach (var aasDB in db.AASSets) { - // from database - using (AasContext db = new AasContext()) + if (decodedAasIdentifier == null || !decodedAasIdentifier.Equals(aasDB.Identifier, StringComparison.Ordinal)) { - foreach (var aasDB in db.AASSets) - { - if (decodedAasIdentifier.Equals(aasDB.Identifier)) - { - var aasDesc = _aasRegistryService.CreateAasDescriptorFromDB(aasDB); - return new ObjectResult(aasDesc); - } - } + continue; } - } - return NotFound(); + var aasDesc = _aasRegistryService.CreateAasDescriptorFromDB(aasDB); + return new ObjectResult(aasDesc); + } } - /// - /// Returns a specific Submodel Descriptor - /// - /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) - /// The Submodel’s unique id (UTF8-BASE64-URL-encoded) - /// Requested Submodel Descriptor - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Forbidden - /// Not Found - /// Internal Server Error - /// Default error handling for unmentioned status codes - [ HttpGet ] - [ Route("/shell-descriptors/{aasIdentifier}/submodel-descriptors/{submodelIdentifier}") ] - [ ValidateModelState ] - [ SwaggerOperation("GetSubmodelDescriptorByIdThroughSuperpath") ] - [ SwaggerResponse(statusCode: 200, type: typeof(SubmodelDescriptor), description: "Requested Submodel Descriptor") ] - [ SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.") ] - [ SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden") ] - [ SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found") ] - [ SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error") ] - [ SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes") ] - public virtual IActionResult GetSubmodelDescriptorByIdThroughSuperpath([ FromRoute ] [ Required ] string aasIdentifier, - [ FromRoute ] [ Required ] string submodelIdentifier) - { - //TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(200, default(SubmodelDescriptor)); + return NotFound(); + } - //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(400, default(Result)); + /// + /// Returns a specific Submodel Descriptor + /// + /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) + /// The Submodel’s unique id (UTF8-BASE64-URL-encoded) + /// Requested Submodel Descriptor + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Forbidden + /// Not Found + /// Internal Server Error + /// Default error handling for unmentioned status codes + [HttpGet] + [Route("/shell-descriptors/{aasIdentifier}/submodel-descriptors/{submodelIdentifier}")] + [ValidateModelState] + [SwaggerOperation("GetSubmodelDescriptorByIdThroughSuperpath")] + [SwaggerResponse(statusCode: 200, type: typeof(SubmodelDescriptor), description: "Requested Submodel Descriptor")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] + [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual IActionResult GetSubmodelDescriptorByIdThroughSuperpath([FromRoute] [Required] string aasIdentifier, + [FromRoute] [Required] string submodelIdentifier) + { + //TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(200, default(SubmodelDescriptor)); - //TODO: Uncomment the next line to return response 403 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(403, default(Result)); + //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(400, default(Result)); - //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(404, default(Result)); + //TODO: Uncomment the next line to return response 403 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(403, default(Result)); - //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(500, default(Result)); + //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(404, default(Result)); - //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(0, default(Result)); - throw new NotImplementedException(); - } + //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(500, default(Result)); - /// - /// Creates a new Asset Administration Shell Descriptor, i.e. registers an AAS - /// - /// Asset Administration Shell Descriptor object - /// Asset Administration Shell Descriptor created successfully - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Forbidden - /// Conflict, a resource which shall be created exists already. Might be thrown if a Submodel or SubmodelElement with the same ShortId is contained in a POST request. - /// Internal Server Error - /// Default error handling for unmentioned status codes - //TODO (jtikekar, 2023-09-04): Routes are different than old impl - [ HttpPost ] - [ Route("/shell-descriptors") ] - [ ValidateModelState ] - [ SwaggerOperation("PostAssetAdministrationShellDescriptor") ] - [ SwaggerResponse(statusCode: 201, type: typeof(AssetAdministrationShellDescriptor), description: "Asset Administration Shell Descriptor created successfully") ] - [ SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.") ] - [ SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden") ] - [ SwaggerResponse(statusCode: 409, type: typeof(Result), - description: - "Conflict, a resource which shall be created exists already. Might be thrown if a Submodel or SubmodelElement with the same ShortId is contained in a POST request.") ] - [ SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error") ] - [ SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes") ] - public virtual IActionResult PostAssetAdministrationShellDescriptor([ FromBody ] AssetAdministrationShellDescriptor body) - { - var timestamp = DateTime.UtcNow; + //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(0, default(Result)); + throw new NotImplementedException(); + } - _logger.LogInformation($"Received request to create a new AAS Descriptor"); + /// + /// Creates a new Asset Administration Shell Descriptor, i.e. registers an AAS + /// + /// Asset Administration Shell Descriptor object + /// Asset Administration Shell Descriptor created successfully + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Forbidden + /// Conflict, a resource which shall be created exists already. Might be thrown if a Submodel or SubmodelElement with the same ShortId is contained in a POST request. + /// Internal Server Error + /// Default error handling for unmentioned status codes + //TODO (jtikekar, 2023-09-04): Routes are different than old impl + [HttpPost] + [Route("/shell-descriptors")] + [ValidateModelState] + [SwaggerOperation("PostAssetAdministrationShellDescriptor")] + [SwaggerResponse(statusCode: 201, type: typeof(AssetAdministrationShellDescriptor), description: "Asset Administration Shell Descriptor created successfully")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] + [SwaggerResponse(statusCode: 409, type: typeof(Result), + description: + "Conflict, a resource which shall be created exists already. Might be thrown if a Submodel or SubmodelElement with the same ShortId is contained in a POST request.")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual IActionResult PostAssetAdministrationShellDescriptor([FromBody] AssetAdministrationShellDescriptor? body) + { + var timestamp = DateTime.UtcNow; - // TODO (jtikekar, 2023-09-04): Just for testing purpose. Remove during refactoring - bool test = false; - if (test) - { - string jsonAd = DescriptorSerializer.ToJsonObject(body).ToJsonString(); - _logger.LogDebug(jsonAd); - } + if (body == null) + { + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } - lock (Program.changeAasxFile) - { - _registryInitializerService.CreateAssetAdministrationShellDescriptor(body, timestamp); - } + _logger.LogInformation($"Received request to create a new AAS Descriptor"); - return CreatedAtAction("PostAssetAdministrationShellDescriptor", body); + lock (Program.changeAasxFile) + { + _registryInitializerService.CreateAssetAdministrationShellDescriptor(body, timestamp); } - /// - /// Creates a new Submodel Descriptor, i.e. registers a submodel - /// - /// Submodel Descriptor object - /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) - /// Submodel Descriptor created successfully - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Forbidden - /// Not Found - /// Conflict, a resource which shall be created exists already. Might be thrown if a Submodel or SubmodelElement with the same ShortId is contained in a POST request. - /// Internal Server Error - /// Default error handling for unmentioned status codes - [ HttpPost ] - [ Route("/shell-descriptors/{aasIdentifier}/submodel-descriptors") ] - [ ValidateModelState ] - [ SwaggerOperation("PostSubmodelDescriptorThroughSuperpath") ] - [ SwaggerResponse(statusCode: 201, type: typeof(SubmodelDescriptor), description: "Submodel Descriptor created successfully") ] - [ SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.") ] - [ SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden") ] - [ SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found") ] - [ SwaggerResponse(statusCode: 409, type: typeof(Result), - description: - "Conflict, a resource which shall be created exists already. Might be thrown if a Submodel or SubmodelElement with the same ShortId is contained in a POST request.") ] - [ SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error") ] - [ SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes") ] - public virtual IActionResult PostSubmodelDescriptorThroughSuperpath([ FromBody ] SubmodelDescriptor body, [ FromRoute ] [ Required ] string aasIdentifier) - { - //TODO: Uncomment the next line to return response 201 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(201, default(SubmodelDescriptor)); + return CreatedAtAction("PostAssetAdministrationShellDescriptor", body); + } - //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(400, default(Result)); + /// + /// Creates a new Submodel Descriptor, i.e. registers a submodel + /// + /// Submodel Descriptor object + /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) + /// Submodel Descriptor created successfully + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Forbidden + /// Not Found + /// Conflict, a resource which shall be created exists already. Might be thrown if a Submodel or SubmodelElement with the same ShortId is contained in a POST request. + /// Internal Server Error + /// Default error handling for unmentioned status codes + [HttpPost] + [Route("/shell-descriptors/{aasIdentifier}/submodel-descriptors")] + [ValidateModelState] + [SwaggerOperation("PostSubmodelDescriptorThroughSuperpath")] + [SwaggerResponse(statusCode: 201, type: typeof(SubmodelDescriptor), description: "Submodel Descriptor created successfully")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] + [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] + [SwaggerResponse(statusCode: 409, type: typeof(Result), + description: + "Conflict, a resource which shall be created exists already. Might be thrown if a Submodel or SubmodelElement with the same ShortId is contained in a POST request.")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual IActionResult PostSubmodelDescriptorThroughSuperpath([FromBody] SubmodelDescriptor body, [FromRoute] [Required] string aasIdentifier) + { + //TODO: Uncomment the next line to return response 201 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(201, default(SubmodelDescriptor)); - //TODO: Uncomment the next line to return response 403 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(403, default(Result)); + //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(400, default(Result)); - //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(404, default(Result)); + //TODO: Uncomment the next line to return response 403 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(403, default(Result)); - //TODO: Uncomment the next line to return response 409 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(409, default(Result)); + //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(404, default(Result)); - //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(500, default(Result)); + //TODO: Uncomment the next line to return response 409 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(409, default(Result)); - //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(0, default(Result)); - throw new NotImplementedException(); - } + //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(500, default(Result)); - /// - /// Updates an existing Asset Administration Shell Descriptor - /// - /// Asset Administration Shell Descriptor object - /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) - /// Asset Administration Shell Descriptor updated successfully - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Forbidden - /// Not Found - /// Internal Server Error - /// Default error handling for unmentioned status codes - [ HttpPut ] - [ Route("/shell-descriptors/{aasIdentifier}") ] - [ ValidateModelState ] - [ SwaggerOperation("PutAssetAdministrationShellDescriptorById") ] - [ SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.") ] - [ SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden") ] - [ SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found") ] - [ SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error") ] - [ SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes") ] - public virtual IActionResult PutAssetAdministrationShellDescriptorById([ FromBody ] AssetAdministrationShellDescriptor body, - [ FromRoute ] [ Required ] byte[] aasIdentifier) - { - //TODO: Uncomment the next line to return response 204 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(204); + //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(0, default(Result)); + throw new NotImplementedException(); + } - //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(400, default(Result)); + /// + /// Updates an existing Asset Administration Shell Descriptor + /// + /// Asset Administration Shell Descriptor object + /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) + /// Asset Administration Shell Descriptor updated successfully + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Forbidden + /// Not Found + /// Internal Server Error + /// Default error handling for unmentioned status codes + [HttpPut] + [Route("/shell-descriptors/{aasIdentifier}")] + [ValidateModelState] + [SwaggerOperation("PutAssetAdministrationShellDescriptorById")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] + [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual IActionResult PutAssetAdministrationShellDescriptorById([FromBody] AssetAdministrationShellDescriptor? body, + [FromRoute] [Required] byte[] aasIdentifier) + { + //TODO: Uncomment the next line to return response 204 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(204); - //TODO: Uncomment the next line to return response 403 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(403, default(Result)); + //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(400, default(Result)); - //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(404, default(Result)); + //TODO: Uncomment the next line to return response 403 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(403, default(Result)); - //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(500, default(Result)); + //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(404, default(Result)); - //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(0, default(Result)); + //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(500, default(Result)); - throw new NotImplementedException(); - } + //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(0, default(Result)); - /// - /// Updates an existing Submodel Descriptor - /// - /// Submodel Descriptor object - /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) - /// The Submodel’s unique id (UTF8-BASE64-URL-encoded) - /// Submodel Descriptor updated successfully - /// Bad Request, e.g. the request parameters of the format of the request body is wrong. - /// Forbidden - /// Not Found - /// Internal Server Error - /// Default error handling for unmentioned status codes - [ HttpPut ] - [ Route("/shell-descriptors/{aasIdentifier}/submodel-descriptors/{submodelIdentifier}") ] - [ ValidateModelState ] - [ SwaggerOperation("PutSubmodelDescriptorByIdThroughSuperpath") ] - [ SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.") ] - [ SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden") ] - [ SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found") ] - [ SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error") ] - [ SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes") ] - public virtual IActionResult PutSubmodelDescriptorByIdThroughSuperpath([ FromBody ] SubmodelDescriptor body, [ FromRoute ] [ Required ] string aasIdentifier, - [ FromRoute ] [ Required ] string submodelIdentifier) - { - //TODO: Uncomment the next line to return response 204 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(204); + throw new NotImplementedException(); + } - //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(400, default(Result)); + /// + /// Updates an existing Submodel Descriptor + /// + /// Submodel Descriptor object + /// The Asset Administration Shell’s unique id (UTF8-BASE64-URL-encoded) + /// The Submodel’s unique id (UTF8-BASE64-URL-encoded) + /// Submodel Descriptor updated successfully + /// Bad Request, e.g. the request parameters of the format of the request body is wrong. + /// Forbidden + /// Not Found + /// Internal Server Error + /// Default error handling for unmentioned status codes + [HttpPut] + [Route("/shell-descriptors/{aasIdentifier}/submodel-descriptors/{submodelIdentifier}")] + [ValidateModelState] + [SwaggerOperation("PutSubmodelDescriptorByIdThroughSuperpath")] + [SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")] + [SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")] + [SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")] + [SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")] + [SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")] + public virtual IActionResult PutSubmodelDescriptorByIdThroughSuperpath([FromBody] SubmodelDescriptor? body, [FromRoute] [Required] string aasIdentifier, + [FromRoute] [Required] string submodelIdentifier) + { + //TODO: Uncomment the next line to return response 204 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(204); - //TODO: Uncomment the next line to return response 403 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(403, default(Result)); + //TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(400, default(Result)); - //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(404, default(Result)); + //TODO: Uncomment the next line to return response 403 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(403, default(Result)); - //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(500, default(Result)); + //TODO: Uncomment the next line to return response 404 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(404, default(Result)); - //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... - // return StatusCode(0, default(Result)); + //TODO: Uncomment the next line to return response 500 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(500, default(Result)); - throw new NotImplementedException(); - } + //TODO: Uncomment the next line to return response 0 or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode(0, default(Result)); - [ HttpPost ] - [ Route("/overwrite-shell-descriptors") ] - [ ValidateModelState ] - [ SwaggerOperation("PostMultipleAssetAdministrationShellDescriptors") ] - [ SwaggerResponse(statusCode: 201, type: typeof(List), description: "Asset Administration Shell Descriptors created successfully") ] - public virtual IActionResult PostMultipleAssetAdministrationShellDescriptor([ FromBody ] List body) + throw new NotImplementedException(); + } + + [HttpPost] + [Route("/overwrite-shell-descriptors")] + [ValidateModelState] + [SwaggerOperation("PostMultipleAssetAdministrationShellDescriptors")] + [SwaggerResponse(statusCode: 201, type: typeof(List), description: "Asset Administration Shell Descriptors created successfully")] + public virtual IActionResult PostMultipleAssetAdministrationShellDescriptor([FromBody] List? body) + { + if (body == null) { - var timestamp = DateTime.UtcNow; + throw new NotAllowed($"Cannot proceed as {nameof(body)} is null"); + } - _logger.LogDebug($"Received request to create multiple shell descriptors"); + var timestamp = DateTime.UtcNow; - _registryInitializerService.CreateMultipleAssetAdministrationShellDescriptor(body, timestamp); + _logger.LogDebug($"Received request to create multiple shell descriptors"); - return new ObjectResult("ok"); + lock (Program.changeAasxFile) + { + _registryInitializerService.CreateMultipleAssetAdministrationShellDescriptor(body, timestamp); } - /// - /// Returns a list of Asset Administration Shell ids based on Asset identifier key-value-pairs - /// - /// The key-value-pair of an Asset identifier (BASE64-URL-encoded JSON-serialized key-value-pairs) - /// An Asset identifier (BASE64-URL-encoded identifier) - /// Requested Asset Administration Shell ids - [ HttpGet ] - [ Route("/lookup/shells") ] - [ ValidateModelState ] - [ SwaggerOperation("GetAllAssetAdministrationShellIdsByAssetLink") ] - [ SwaggerResponse(statusCode: 200, type: typeof(List), description: "Requested Asset Administration Shell ids") ] - public virtual IActionResult GetAllAssetAdministrationShellIdsByAssetLink( - [ FromQuery ] List assetIds, - [ FromQuery ] string? assetId) + return new ObjectResult("ok"); + } + + /// + /// Returns a list of Asset Administration Shell ids based on Asset identifier key-value-pairs + /// + /// The key-value-pair of an Asset identifier (BASE64-URL-encoded JSON-serialized key-value-pairs) + /// An Asset identifier (BASE64-URL-encoded identifier) + /// Requested Asset Administration Shell ids + [HttpGet] + [Route("/lookup/shells")] + [ValidateModelState] + [SwaggerOperation("GetAllAssetAdministrationShellIdsByAssetLink")] + [SwaggerResponse(statusCode: 200, type: typeof(List), description: "Requested Asset Administration Shell ids")] + public virtual IActionResult GetAllAssetAdministrationShellIdsByAssetLink( + [FromQuery] List? assetIds, + [FromQuery] string? assetId) + { + try { - try - { - //collect aasetIds from list - var assetList = new List(); - foreach (var kv in assetIds) - { - if (kv.Value != "") - { - var decodedAssetId = _decoderService.Decode("assetId", kv.Value); - assetList.Add(decodedAssetId); - } - } + //collect assetIds from list + var assetList = (from kv in assetIds where kv.Value != "" select _decoderService.Decode("assetId", kv.Value)).ToList(); - // single assetId - if (assetId != null && assetId != "") - { - var decodedAssetId = _decoderService.Decode("assetId", assetId); - assetList.Add(decodedAssetId); - } + // single assetId + if (assetId != null && assetId != "") + { + var decodedAssetId = _decoderService.Decode("assetId", assetId); + assetList.Add(decodedAssetId); + } - var aasList = new List(); + var aasList = new List(); - if (!Program.withDb) - { - var aasDecsriptorList = _aasRegistryService.GetAllAssetAdministrationShellDescriptors(assetList: assetList); - - foreach (var ad in aasDecsriptorList) - { - if (ad != null) - { - aasList.Add(ad.Id); - } - } - } - else - { - // from database - using (AasContext db = new AasContext()) - { - foreach (var aasDB in db.AASSets) - { - if (assetList.Contains(aasDB.GlobalAssetId)) - aasList.Add(aasDB.Identifier); - } - } - } + if (!Program.withDb) + { + var aasDescriptorList = _aasRegistryService.GetAllAssetAdministrationShellDescriptors(assetList: assetList); - return new ObjectResult(aasList); + aasList.AddRange(aasDescriptorList.OfType().Select(ad => ad.Id)); } - catch (Exception ex) + else { - return BadRequest(ex.Message); + // from database + using var db = new AasContext(); + aasList.AddRange(from aasDB in db.AASSets where assetList.Contains(aasDB.GlobalAssetId) select aasDB.Identifier); } + + return new ObjectResult(aasList); + } + catch (Exception ex) + { + return BadRequest(ex.Message); } } } \ No newline at end of file diff --git a/src/IO.Swagger.Registry.Lib.V3/Extensions/ReferenceElementExtensions.cs b/src/IO.Swagger.Registry.Lib.V3/Extensions/ReferenceElementExtensions.cs new file mode 100644 index 000000000..351350160 --- /dev/null +++ b/src/IO.Swagger.Registry.Lib.V3/Extensions/ReferenceElementExtensions.cs @@ -0,0 +1,20 @@ +namespace IO.Swagger.Registry.Lib.V3.Extensions; + +using System.Linq; + +public static class ReferenceElementExtensions +{ + /// + /// Reverses the keys in the Value property of the ReferenceElement. + /// + /// The reference element whose keys are to be reversed. + public static void ReverseReferenceKeys(this ReferenceElement referenceElement) + { + if (referenceElement?.Value?.Keys == null) return; + + var keys = referenceElement.Value.Keys.ToList(); + keys.Reverse(); + + referenceElement.Value.Keys = keys; + } +} diff --git a/src/IO.Swagger.Registry.Lib.V3/IO.Swagger.Registry.Lib.V3.csproj b/src/IO.Swagger.Registry.Lib.V3/IO.Swagger.Registry.Lib.V3.csproj index 230f780ee..b858897ad 100644 --- a/src/IO.Swagger.Registry.Lib.V3/IO.Swagger.Registry.Lib.V3.csproj +++ b/src/IO.Swagger.Registry.Lib.V3/IO.Swagger.Registry.Lib.V3.csproj @@ -19,7 +19,6 @@ - diff --git a/src/IO.Swagger.Registry.Lib.V3/Interfaces/IRegistryInitializerService.cs b/src/IO.Swagger.Registry.Lib.V3/Interfaces/IRegistryInitializerService.cs index 2cb681f27..6ea8b694c 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Interfaces/IRegistryInitializerService.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Interfaces/IRegistryInitializerService.cs @@ -5,6 +5,8 @@ namespace IO.Swagger.Registry.Lib.V3.Interfaces { + using System.Threading.Tasks; + public interface IRegistryInitializerService { void CreateAssetAdministrationShellDescriptor(AssetAdministrationShellDescriptor newAasDesc, DateTime timestamp, bool initial = false); @@ -12,7 +14,7 @@ public interface IRegistryInitializerService ISubmodel? GetAasRegistry(); List GetAasDescriptorsForSubmodelView(); - List GetRegistryList(); - void InitRegistry(List cList, DateTime timestamp, bool initAgain = false); + List GetRegistryList(); + Task InitRegistry(List cList, DateTime timestamp, bool initAgain = false); } } \ No newline at end of file diff --git a/src/IO.Swagger.Registry.Lib.V3/Models/AssetAdministrationShellDescriptor.cs b/src/IO.Swagger.Registry.Lib.V3/Models/AssetAdministrationShellDescriptor.cs index eed8a2472..c89c01357 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Models/AssetAdministrationShellDescriptor.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Models/AssetAdministrationShellDescriptor.cs @@ -8,7 +8,6 @@ * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -18,6 +17,8 @@ namespace IO.Swagger.Registry.Lib.V3.Models { + using System.Text.Json; + /// /// /// @@ -132,10 +133,9 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public new string ToJson() - { - return JsonConvert.SerializeObject(this, Formatting.Indented); - } + public new string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true}; /// /// Returns true if objects are equal @@ -243,12 +243,12 @@ public override int GetHashCode() #pragma warning disable 1591 - public static bool operator ==(AssetAdministrationShellDescriptor left, AssetAdministrationShellDescriptor right) + public static bool operator ==(AssetAdministrationShellDescriptor? left, AssetAdministrationShellDescriptor? right) { return Equals(left, right); } - public static bool operator !=(AssetAdministrationShellDescriptor left, AssetAdministrationShellDescriptor right) + public static bool operator !=(AssetAdministrationShellDescriptor? left, AssetAdministrationShellDescriptor right) { return !Equals(left, right); } diff --git a/src/IO.Swagger.Registry.Lib.V3/Models/Descriptor.cs b/src/IO.Swagger.Registry.Lib.V3/Models/Descriptor.cs index eff699e1c..45e38095d 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Models/Descriptor.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Models/Descriptor.cs @@ -8,7 +8,6 @@ * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; @@ -17,6 +16,8 @@ namespace IO.Swagger.Registry.Lib.V3.Models { + using System.Text.Json; + /// /// /// @@ -63,10 +64,9 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public string ToJson() - { - return JsonConvert.SerializeObject(this, Formatting.Indented); - } + public string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true}; /// /// Returns true if objects are equal diff --git a/src/IO.Swagger.Registry.Lib.V3/Models/Endpoint.cs b/src/IO.Swagger.Registry.Lib.V3/Models/Endpoint.cs index e099a4484..1191c22fa 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Models/Endpoint.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Models/Endpoint.cs @@ -8,7 +8,6 @@ * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; @@ -16,6 +15,8 @@ namespace IO.Swagger.Registry.Lib.V3.Models { + using System.Text.Json; + /// /// /// @@ -61,10 +62,9 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public string ToJson() - { - return JsonConvert.SerializeObject(this, Formatting.Indented); - } + public string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true}; /// /// Returns true if objects are equal diff --git a/src/IO.Swagger.Registry.Lib.V3/Models/Message.cs b/src/IO.Swagger.Registry.Lib.V3/Models/Message.cs index f18a7c4ad..be96c128f 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Models/Message.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Models/Message.cs @@ -8,7 +8,6 @@ * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; @@ -16,9 +15,10 @@ namespace IO.Swagger.Registry.Lib.V3.Models; -/// -/// -/// +using System.Text.Json; +using System.Text.Json.Serialization; +using Swagger.Models; + [DataContract] public class Message : IEquatable { @@ -38,38 +38,7 @@ public class Message : IEquatable [DataMember(Name = "correlationId")] public string? CorrelationId { get; set; } - /// - /// Gets or Sets MessageType - /// - [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public enum MessageTypeEnum - { - /// - /// Enum UndefinedEnum for Undefined - /// - [EnumMember(Value = "Undefined")] UndefinedEnum = 0, - - /// - /// Enum InfoEnum for Info - /// - [EnumMember(Value = "Info")] InfoEnum = 1, - - /// - /// Enum WarningEnum for Warning - /// - [EnumMember(Value = "Warning")] WarningEnum = 2, - - /// - /// Enum ErrorEnum for Error - /// - [EnumMember(Value = "Error")] ErrorEnum = 3, - - /// - /// Enum ExceptionEnum for Exception - /// - [EnumMember(Value = "Exception")] ExceptionEnum = 4 - } - + /// /// Gets or Sets MessageType /// @@ -112,7 +81,9 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public string ToJson() => JsonConvert.SerializeObject(this, Formatting.Indented); + public string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true, Converters = {new JsonStringEnumConverter()}}; /// /// Returns true if objects are equal diff --git a/src/IO.Swagger.Registry.Lib.V3/Models/ProtocolInformation.cs b/src/IO.Swagger.Registry.Lib.V3/Models/ProtocolInformation.cs index aedef4cb4..58288cbc0 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Models/ProtocolInformation.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Models/ProtocolInformation.cs @@ -8,7 +8,6 @@ * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -18,76 +17,78 @@ namespace IO.Swagger.Registry.Lib.V3.Models { + using System.Text.Json; + /// /// /// - [ DataContract ] + [DataContract] public partial class ProtocolInformation : IEquatable { /// /// Gets or Sets Href /// - [ Required ] - [ MaxLength(2048) ] - [ DataMember(Name = "href") ] + [Required] + [MaxLength(2048)] + [DataMember(Name = "href")] public string? Href { get; set; } /// /// Gets or Sets EndpointProtocol /// - [ MaxLength(128) ] - [ DataMember(Name = "endpointProtocol") ] + [MaxLength(128)] + [DataMember(Name = "endpointProtocol")] public string? EndpointProtocol { get; set; } /// /// Gets or Sets EndpointProtocolVersion /// - [ DataMember(Name = "endpointProtocolVersion") ] + [DataMember(Name = "endpointProtocolVersion")] public List? EndpointProtocolVersion { get; set; } /// /// Gets or Sets Subprotocol /// - [ MaxLength(128) ] - [ DataMember(Name = "subprotocol") ] + [MaxLength(128)] + [DataMember(Name = "subprotocol")] public string? Subprotocol { get; set; } /// /// Gets or Sets SubprotocolBody /// - [ MaxLength(128) ] - [ DataMember(Name = "subprotocolBody") ] + [MaxLength(128)] + [DataMember(Name = "subprotocolBody")] public string? SubprotocolBody { get; set; } /// /// Gets or Sets SubprotocolBodyEncoding /// - [ MaxLength(128) ] - [ DataMember(Name = "subprotocolBodyEncoding") ] + [MaxLength(128)] + [DataMember(Name = "subprotocolBodyEncoding")] public string? SubprotocolBodyEncoding { get; set; } /// /// Gets or Sets SecurityAttributes /// - [ DataMember(Name = "securityAttributes") ] + [DataMember(Name = "securityAttributes")] public List? SecurityAttributes { get; set; } public ProtocolInformation(string? href = null, string? endpointProtocol = null, List? endpointProtocolVersion = null, string? subprotocol = null, - string? subprotocolBody = null, string? subprotocolBodyEncoding = null, List? securityAttributes = null) + string? subprotocolBody = null, string? subprotocolBodyEncoding = null, List? securityAttributes = null) { - Href = href; - EndpointProtocol = endpointProtocol; + Href = href; + EndpointProtocol = endpointProtocol; EndpointProtocolVersion = endpointProtocolVersion; - Subprotocol = subprotocol; - SubprotocolBody = subprotocolBody; + Subprotocol = subprotocol; + SubprotocolBody = subprotocolBody; SubprotocolBodyEncoding = subprotocolBodyEncoding; - SecurityAttributes = securityAttributes; + SecurityAttributes = securityAttributes; } /// @@ -113,10 +114,9 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public string ToJson() - { - return JsonConvert.SerializeObject(this, Formatting.Indented); - } + public string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true}; /// /// Returns true if objects are equal @@ -127,7 +127,7 @@ public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((ProtocolInformation) obj); + return obj.GetType() == GetType() && Equals((ProtocolInformation)obj); } /// diff --git a/src/IO.Swagger.Registry.Lib.V3/Models/ProtocolInformationSecurityAttributes.cs b/src/IO.Swagger.Registry.Lib.V3/Models/ProtocolInformationSecurityAttributes.cs index fbd4fa1d6..ba162a165 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Models/ProtocolInformationSecurityAttributes.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Models/ProtocolInformationSecurityAttributes.cs @@ -8,7 +8,6 @@ * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; @@ -16,59 +15,61 @@ namespace IO.Swagger.Registry.Lib.V3.Models { + using System.Text.Json; + using System.Text.Json.Serialization; + /// /// /// - [ DataContract ] + [DataContract] public partial class ProtocolInformationSecurityAttributes : IEquatable { /// /// Gets or Sets Type /// - [ JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter)) ] public enum TypeEnum { /// - /// Enum NONEEnum for NONE + /// Enum NONE for NONE /// - [ EnumMember(Value = "NONE") ] NONEEnum = 0, + [EnumMember(Value = "NONE")] NONE = 0, /// - /// Enum RFCTLSAEnum for RFC_TLSA + /// Enum RFCTLSA for RFC_TLSA /// - [ EnumMember(Value = "RFC_TLSA") ] RFCTLSAEnum = 1, + [EnumMember(Value = "RFC_TLSA")] RFCTLSA = 1, /// - /// Enum W3CDIDEnum for W3C_DID + /// Enum W3CDID for W3C_DID /// - [ EnumMember(Value = "W3C_DID") ] W3CDIDEnum = 2 + [EnumMember(Value = "W3C_DID")] W3CDID = 2 } /// /// Gets or Sets Type /// - [ Required ] - [ DataMember(Name = "type") ] + [Required] + [DataMember(Name = "type")] public TypeEnum? Type { get; set; } /// /// Gets or Sets Key /// - [ Required ] - [ DataMember(Name = "key") ] + [Required] + [DataMember(Name = "key")] public string? Key { get; set; } /// /// Gets or Sets Value /// - [ Required ] - [ DataMember(Name = "value") ] + [Required] + [DataMember(Name = "value")] public string Value { get; set; } public ProtocolInformationSecurityAttributes(TypeEnum type, string? key, string value) { - Type = type; - Key = key; + Type = type; + Key = key; Value = value; } @@ -91,10 +92,9 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public string ToJson() - { - return JsonConvert.SerializeObject(this, Formatting.Indented); - } + public string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true, Converters = {new JsonStringEnumConverter()}}; /// /// Returns true if objects are equal @@ -105,7 +105,7 @@ public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((ProtocolInformationSecurityAttributes) obj); + return obj.GetType() == GetType() && Equals((ProtocolInformationSecurityAttributes)obj); } /// diff --git a/src/IO.Swagger.Registry.Lib.V3/Models/Result.cs b/src/IO.Swagger.Registry.Lib.V3/Models/Result.cs index 25b31ab5d..dfc07fbe5 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Models/Result.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Models/Result.cs @@ -8,7 +8,6 @@ * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; @@ -17,6 +16,8 @@ namespace IO.Swagger.Registry.Lib.V3.Models { + using System.Text.Json; + /// /// /// @@ -47,10 +48,9 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public string ToJson() - { - return JsonConvert.SerializeObject(this, Formatting.Indented); - } + public string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true}; /// /// Returns true if objects are equal diff --git a/src/IO.Swagger.Registry.Lib.V3/Models/SubmodelDescriptor.cs b/src/IO.Swagger.Registry.Lib.V3/Models/SubmodelDescriptor.cs index 89a679ca1..8365d44eb 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Models/SubmodelDescriptor.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Models/SubmodelDescriptor.cs @@ -8,7 +8,6 @@ * Generated by: https://github.com/swagger-api/swagger-codegen.git */ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -18,6 +17,8 @@ namespace IO.Swagger.Registry.Lib.V3.Models { + using System.Text.Json; + /// /// /// @@ -111,10 +112,9 @@ public override string ToString() /// Returns the JSON string presentation of the object /// /// JSON string presentation of the object - public new string ToJson() - { - return JsonConvert.SerializeObject(this, Formatting.Indented); - } + public new string ToJson() => JsonSerializer.Serialize(this, options); + + private static readonly JsonSerializerOptions options = new() {WriteIndented = true, IgnoreNullValues = true}; /// /// Returns true if objects are equal diff --git a/src/IO.Swagger.Registry.Lib.V3/Serializers/DescriptorDeserializeImplementation.cs b/src/IO.Swagger.Registry.Lib.V3/Serializers/DescriptorDeserializeImplementation.cs index 8307de399..63634c419 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Serializers/DescriptorDeserializeImplementation.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Serializers/DescriptorDeserializeImplementation.cs @@ -792,7 +792,7 @@ public static class DescriptorDeserializeImplementation return null; } - ProtocolInformationSecurityAttributes.TypeEnum type = ProtocolInformationSecurityAttributes.TypeEnum.NONEEnum; + ProtocolInformationSecurityAttributes.TypeEnum type = ProtocolInformationSecurityAttributes.TypeEnum.NONE; string? key = null; string value = null; diff --git a/src/IO.Swagger.Registry.Lib.V3/Services/AasDescriptorPaginationService.cs b/src/IO.Swagger.Registry.Lib.V3/Services/AasDescriptorPaginationService.cs index 6c5f6e2ab..e214c3b59 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Services/AasDescriptorPaginationService.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Services/AasDescriptorPaginationService.cs @@ -52,7 +52,7 @@ private List GetPaginationList(List sourceList, int startIndex, int end //If there are less elements in the sourceList than "from" if (startIndex > sourceList.Count - 1) { - _logger.LogError($"There are less elements in the retrived list than requested pagination - (from: {startIndex}, size:{endIndex})"); + _logger.LogError($"There are less elements in the retrieved list than requested pagination - (from: {startIndex}, size:{endIndex})"); } for (int i = startIndex; i <= endIndex; i++) diff --git a/src/IO.Swagger.Registry.Lib.V3/Services/AasDescriptorWritingService.cs b/src/IO.Swagger.Registry.Lib.V3/Services/AasDescriptorWritingService.cs new file mode 100644 index 000000000..d63b233f2 --- /dev/null +++ b/src/IO.Swagger.Registry.Lib.V3/Services/AasDescriptorWritingService.cs @@ -0,0 +1,195 @@ +namespace IO.Swagger.Registry.Lib.V3.Services; + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.Json.Nodes; +using Extensions; +using global::Extensions; +using Models; +using Serializers; + +public class AasDescriptorWritingService : IAasDescriptorWritingService +{ + private static int submodelRegistryCount; + private readonly ISubmodelPropertyExtractionService _submodelPropertyExtractionService; + + /// + /// Initializes a new instance of the class. + /// + /// The service for extracting properties from submodel elements. + public AasDescriptorWritingService(ISubmodelPropertyExtractionService submodelPropertyExtractionService) + { + _submodelPropertyExtractionService = submodelPropertyExtractionService; + } + + /// + public void AddNewEntry(AssetAdministrationShellDescriptor ad, ISubmodel aasRegistry, ISubmodel submodelRegistry, DateTime timestamp, string? aasID, string? assetID, + string? endpoint) + { + if (aasRegistry is not {SubmodelElements: not null}) + { + return; + } + + var collection = _submodelPropertyExtractionService.CreateSubmodelElementCollection($"ShellDescriptor_{aasRegistry.SubmodelElements.Count}", timestamp); + + _submodelPropertyExtractionService.AddPropertyToCollection(collection, "idShort", ad.IdShort ?? string.Empty, timestamp); + _submodelPropertyExtractionService.AddPropertyToCollection(collection, "aasID", aasID ?? string.Empty, timestamp); + _submodelPropertyExtractionService.AddPropertyToCollection(collection, "assetID", assetID ?? string.Empty, timestamp, checkEmpty: true); + _submodelPropertyExtractionService.AddPropertyToCollection(collection, "endpoint", endpoint ?? string.Empty, timestamp); + _submodelPropertyExtractionService.AddPropertyToCollection(collection, "descriptorJSON", DescriptorSerializer.ToJsonObject(ad)?.ToJsonString() ?? string.Empty, + timestamp); + + aasRegistry?.SubmodelElements.Add(collection); + + if (ad.SubmodelDescriptors == null) + { + return; + } + + foreach (var sd in ad.SubmodelDescriptors) + { + if (collection.Value != null && submodelRegistry != null) + { + ProcessSubmodelDescriptor(sd, timestamp, collection.Value, submodelRegistry); + } + } + } + + /// + public bool OverwriteExistingEntryForEdenticalIds(AssetAdministrationShellDescriptor ad, ISubmodel aasRegistry, DateTime timestamp, bool initial, string? aasID, + string? assetID, + string? endpoint) + { + if (initial || aasRegistry?.SubmodelElements is null) + { + return false; + } + + foreach (var element in aasRegistry.SubmodelElements) + { + if (element is not SubmodelElementCollection elementCollection) + { + continue; + } + + var (found, jsonProperty, endpointProperty) = _submodelPropertyExtractionService.FindMatchingProperties(elementCollection, aasID, assetID); + + if (found != 2 || jsonProperty == null) + { + continue; + } + + UpdateProperties(jsonProperty, endpointProperty, ad, timestamp, endpoint); + return true; + } + + return false; + } + + /// + /// Updates properties of an existing AAS descriptor. + /// + /// The JSON property to update. + /// The endpoint property to update. + /// The AAS descriptor. + /// The timestamp for the update. + /// The endpoint for the AAS. + private static void UpdateProperties(Property jsonProperty, Property? endpointProperty, AssetAdministrationShellDescriptor ad, DateTime timestamp, string? endpoint) + { + var jsonString = DescriptorSerializer.ToJsonObject(ad)?.ToJsonString(); + + jsonProperty.TimeStampCreate = timestamp; + jsonProperty.TimeStamp = timestamp; + jsonProperty.Value = jsonString; + + if (endpointProperty != null) + { + endpointProperty.TimeStampCreate = timestamp; + endpointProperty.TimeStamp = timestamp; + endpointProperty.Value = endpoint; + } + + Console.WriteLine("Replace Descriptor:"); + Console.WriteLine(jsonString); + } + + /// + public void ProcessSubmodelDescriptor(SubmodelDescriptor sd, DateTime timestamp, List parentCollection, + ISubmodel submodelRegistry) + { + var submodelCollection = _submodelPropertyExtractionService.CreateSubmodelElementCollection($"SubmodelDescriptor_{submodelRegistryCount++}", timestamp); + + _submodelPropertyExtractionService.AddPropertyToCollection(submodelCollection, "idShort", sd.IdShort ?? string.Empty, timestamp); + _submodelPropertyExtractionService.AddPropertyToCollection(submodelCollection, "submodelID", sd.Id ?? string.Empty, timestamp); + _submodelPropertyExtractionService.AddPropertyToCollection(submodelCollection, "semanticID", sd.SemanticId?.GetAsExactlyOneKey()?.Value ?? string.Empty, timestamp, + checkEmpty: true); + + if (sd.Endpoints?.Count > 0) + { + var endpoint = sd.Endpoints[0].ProtocolInformation?.Href; + _submodelPropertyExtractionService.AddPropertyToCollection(submodelCollection, "endpoint", endpoint ?? string.Empty, timestamp); + } + + _submodelPropertyExtractionService.AddPropertyToCollection(submodelCollection, "descriptorJSON", DescriptorSerializer.ToJsonObject(sd)?.ToJsonString() ?? string.Empty, + timestamp); + + var federatedCollection = _submodelPropertyExtractionService.CreateSubmodelElementCollection("federatedElements", timestamp); + submodelCollection.Value?.Add(federatedCollection); + + submodelRegistry.SubmodelElements?.Add(submodelCollection); + submodelRegistry.SetAllParents(timestamp); + + var referenceElement = new ReferenceElement(idShort: $"ref_Submodel_{submodelRegistryCount}") + { + TimeStampCreate = timestamp, TimeStamp = timestamp, Value = submodelCollection.GetModelReference(true) + }; + + referenceElement.ReverseReferenceKeys(); + parentCollection?.Add(referenceElement); + + if (sd.IdShort == "NameplateVC" && sd.Endpoints?.Count > 0) + { + var ep = sd.Endpoints[0].ProtocolInformation?.Href; + _submodelPropertyExtractionService.AddPropertyToCollection(submodelCollection, "NameplateVC", ep ?? string.Empty, timestamp); + } + + if (sd.FederatedElements != null) + { + ProcessFederatedElements(sd.FederatedElements, federatedCollection, timestamp); + } + } + + /// + /// Processes federated elements and adds them to a federated collection. + /// + /// The federated elements to process. + /// The collection to which the elements will be added. + /// The timestamp for the processing. + private static void ProcessFederatedElements(IEnumerable federatedElements, SubmodelElementCollection federatedCollection, DateTime timestamp) + { + foreach (var fe in federatedElements) + { + try + { + var node = System.Text.Json.JsonSerializer.Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(fe))); + var sme = Jsonization.Deserialize.ISubmodelElementFrom(node); + + if (sme == null) + { + continue; + } + + sme.TimeStampCreate = timestamp; + sme.TimeStamp = timestamp; + federatedCollection.Value?.Add(sme); + } + catch + { + // ignored + } + } + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Registry.Lib.V3/Services/IAasDescriptorWritingService.cs b/src/IO.Swagger.Registry.Lib.V3/Services/IAasDescriptorWritingService.cs new file mode 100644 index 000000000..c594048a7 --- /dev/null +++ b/src/IO.Swagger.Registry.Lib.V3/Services/IAasDescriptorWritingService.cs @@ -0,0 +1,49 @@ +namespace IO.Swagger.Registry.Lib.V3.Services; + +using System; +using System.Collections.Generic; +using Models; + +/// +/// Provides services to manage Asset Administration Shell (AAS) descriptors and their properties within submodel registries. +/// +public interface IAasDescriptorWritingService +{ + /// + /// Adds a new entry to the AAS registry. + /// + /// The AAS descriptor to add. + /// The AAS registry submodel. + /// The submodel registry. + /// The timestamp for when the entry is added. + /// The ID of the AAS. + /// The ID of the asset. + /// The endpoint for the AAS. + void AddNewEntry(AssetAdministrationShellDescriptor ad, ISubmodel aasRegistry, ISubmodel submodelRegistry, DateTime timestamp, string? aasID, string? assetID, + string? endpoint); + + /// + /// Overwrites an existing entry in the AAS registry if the IDs match. + /// + /// The AAS descriptor to overwrite. + /// The AAS registry submodel. + /// The timestamp for when the entry is overwritten. + /// Indicates if this is the initial entry. + /// The ID of the AAS. + /// The ID of the asset. + /// The endpoint for the AAS. + /// True if the entry was overwritten, otherwise false. + bool OverwriteExistingEntryForEdenticalIds(AssetAdministrationShellDescriptor ad, ISubmodel aasRegistry, DateTime timestamp, bool initial, string? aasID, + string? assetID, + string? endpoint); + + /// + /// Processes a submodel descriptor and adds it to the submodel registry. + /// + /// The submodel descriptor to process. + /// The timestamp for the processing. + /// The parent collection to which the descriptor will be added. + /// The submodel registry. + void ProcessSubmodelDescriptor(SubmodelDescriptor sd, DateTime timestamp, List parentCollection, + ISubmodel submodelRegistry); +} \ No newline at end of file diff --git a/src/IO.Swagger.Registry.Lib.V3/Services/ISubmodelPropertyExtractionService.cs b/src/IO.Swagger.Registry.Lib.V3/Services/ISubmodelPropertyExtractionService.cs new file mode 100644 index 000000000..ecdfcfa5b --- /dev/null +++ b/src/IO.Swagger.Registry.Lib.V3/Services/ISubmodelPropertyExtractionService.cs @@ -0,0 +1,52 @@ +namespace IO.Swagger.Registry.Lib.V3.Services; + +using System; + +/// +/// Provides methods for extracting and manipulating properties within a submodel element collection. +/// +public interface ISubmodelPropertyExtractionService +{ + /// + /// Finds and returns properties from a submodel element collection that match specific criteria. + /// + /// The collection of submodel elements to search through. + /// The ID of the Asset Administration Shell to match against. + /// The ID of the asset to match against. + /// + /// A tuple containing: + /// - The count of found properties matching the criteria. + /// - The property with IdShort "descriptorJSON", if found. + /// - The property with IdShort "endpoint", if found. + /// + (int found, Property? jsonProperty, Property? endpointProperty) FindMatchingProperties(SubmodelElementCollection elementCollection, string? aasID, string? assetID); + + /// + /// Adds a new property to a submodel element collection. + /// + /// The collection to which the property will be added. + /// The IdShort of the property. + /// The value of the property. + /// The timestamp for when the property is created. + /// If true, the property is only added if the value is not empty. + /// + /// + /// var collection = new SubmodelElementCollection(); + /// SubmodelPropertyExtractionService.AddPropertyToCollection(collection, "exampleID", "exampleValue", DateTime.UtcNow); + /// + /// + void AddPropertyToCollection(SubmodelElementCollection collection, string idShort, string value, DateTime timestamp, bool checkEmpty = false); + + /// + /// Creates a new submodel element collection with a specified IdShort and timestamp. + /// + /// The IdShort of the collection. + /// The timestamp for when the collection is created. + /// A new instance of . + /// + /// + /// var collection = SubmodelPropertyExtractionService.CreateSubmodelElementCollection("exampleID", DateTime.UtcNow); + /// + /// + SubmodelElementCollection CreateSubmodelElementCollection(string idShort, DateTime timestamp); +} \ No newline at end of file diff --git a/src/IO.Swagger.Registry.Lib.V3/Services/RegistryInitializerService.cs b/src/IO.Swagger.Registry.Lib.V3/Services/RegistryInitializerService.cs index 8347e6611..0100743d3 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Services/RegistryInitializerService.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Services/RegistryInitializerService.cs @@ -1,12 +1,10 @@ using AasxServer; -using AasxServerDB; using Extensions; using IdentityModel; using IdentityModel.Client; using IO.Swagger.Registry.Lib.V3.Interfaces; using IO.Swagger.Registry.Lib.V3.Models; using IO.Swagger.Registry.Lib.V3.Serializers; -using IO.Swagger.Registry.Lib.V3.Services; using Microsoft.IdentityModel.Tokens; using System; using System.Collections.Generic; @@ -18,278 +16,276 @@ using System.Net.Http.Headers; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; -using System.Security.Policy; using System.Text; using System.Text.Json.Nodes; using System.Threading.Tasks; -using static AasxServer.Program; -namespace IO.Swagger.Registry.Lib.V3.Services +namespace IO.Swagger.Registry.Lib.V3.Services; + +using System.Globalization; +using AasxServerDB; +using AdminShellNS; + +public class RegistryInitializerService : IRegistryInitializerService { - public class RegistryInitializerService : IRegistryInitializerService + private const string AasxFilesChainPfx = "/aasx/files/Andreas_Orzelski_Chain.pfx"; + private static bool init; + private static ISubmodel? aasRegistry; + private static ISubmodel? submodelRegistry; + private static int initiallyEmpty; + private static List getRegistry = []; + private static List postRegistry = []; + private static List federatedElemensSemanticId = []; + private static List aasDescriptorsForSubmodelView = []; + + public RegistryInitializerService(IAasDescriptorWritingService aasDescriptorWritingService) { - static bool init; - static ISubmodel? aasRegistry; - static ISubmodel? submodelRegistry; - static int initiallyEmpty = 0; - static AasCore.Aas3_0.Environment envRegistry; - static List getRegistry = []; - static List postRegistry = []; - static List federatedElemensSemanticId = []; - static int submodelRegistryCount; - static List aasDescriptorsForSubmodelView = new List(); - - public List GetRegistryList() - { - return getRegistry; - } + _aasDescriptorWritingService = aasDescriptorWritingService; + } - public ISubmodel? GetAasRegistry() - { - return aasRegistry; - } + public List GetRegistryList() => getRegistry; + + public ISubmodel? GetAasRegistry() => aasRegistry; + + public List GetAasDescriptorsForSubmodelView() => aasDescriptorsForSubmodelView; - public List GetAasDescriptorsForSubmodelView() + public static X509Certificate2? Certificate; + private readonly IAasDescriptorWritingService _aasDescriptorWritingService; + + public async Task InitRegistry(List cList, DateTime timestamp, bool initAgain = false) + { + if (!initAgain && init) { - return aasDescriptorsForSubmodelView; + Program.signalNewData(2); + return; } - public static X509Certificate2 certificate = null; + Program.initializingRegistry = true; - public void InitRegistry(List cList, DateTime timestamp, bool initAgain = false) + init = true; + if (initAgain) { - if (!initAgain && init) + aasRegistry = null; + submodelRegistry = null; + + var i = initiallyEmpty; + while (i < Program.env.Length) { - AasxServer.Program.signalNewData(2); - return; + Program.env[i] = null; + i++; } + } - AasxServer.Program.initializingRegistry = true; - - init = true; - if (initAgain) + if (aasRegistry == null || submodelRegistry == null) + { + foreach (AdminShellNS.AdminShellPackageEnv env in Program.env) { - aasRegistry = null; - submodelRegistry = null; + var aas = env.AasEnv.AssetAdministrationShells[0]; + if (aas.IdShort != "REGISTRY") + { + continue; + } - int i = initiallyEmpty; - while (i < AasxServer.Program.env.Length) + if (aas.Submodels == null || aas.Submodels.Count <= 0) { - AasxServer.Program.env[ i ] = null; - i++; + continue; } - } - if (aasRegistry == null || submodelRegistry == null) - { - foreach (AdminShellNS.AdminShellPackageEnv env in AasxServer.Program.env) + foreach (var sm in aas.Submodels.Select(smr => env.AasEnv.FindSubmodel(smr))) { - if (env != null) + if (sm is not {IdShort: not null}) { - var aas = env.AasEnv.AssetAdministrationShells[ 0 ]; - if (aas.IdShort == "REGISTRY") - { - envRegistry = env.AasEnv; - if (aas.Submodels != null && aas.Submodels.Count > 0) - { - foreach (var smr in aas.Submodels) - { - var sm = env.AasEnv.FindSubmodel(smr); - if (sm != null && sm.IdShort != null) - { - if (sm.IdShort == "AASREGISTRY") - { - aasRegistry = sm; - if (aasRegistry.SubmodelElements == null) - aasRegistry.SubmodelElements = new List(); - } + continue; + } - if (sm.IdShort == "SUBMODELREGISTRY") - { - submodelRegistry = sm; - if (submodelRegistry.SubmodelElements == null) - submodelRegistry.SubmodelElements = new List(); - } - } - } - } - } + switch (sm.IdShort) + { + case "AASREGISTRY": + aasRegistry = sm; + aasRegistry.SubmodelElements ??= []; + break; + case "SUBMODELREGISTRY": + submodelRegistry = sm; + submodelRegistry.SubmodelElements ??= []; + break; } } + } - if (aasRegistry != null) + if (aasRegistry != null) + { + getRegistry.Clear(); + if (aasRegistry.SubmodelElements != null) { - getRegistry.Clear(); foreach (var sme in aasRegistry.SubmodelElements) { - if (sme is Property p) + switch (sme) { - if (p.IdShort.ToLower() == "postregistry") + case Property p: { - string registryURL = TranslateURL(p.Value); - Console.WriteLine("POST to Registry: " + registryURL); - if (registryURL != "") + if (p.IdShort?.ToLower(CultureInfo.InvariantCulture) == "postregistry") { - postRegistry.Add(registryURL); + if (p.Value != null) + { + var registryURL = TranslateURL(p.Value); + Console.WriteLine("POST to Registry: " + registryURL); + if (registryURL != "") + { + postRegistry.Add(registryURL); + } + } } - } - if (p.IdShort.ToLower() == "getregistry") - { - string registryURL = TranslateURL(p.Value); - Console.WriteLine("GET from Registry: " + registryURL); - if (registryURL != "") + if (p.IdShort?.ToLower(CultureInfo.InvariantCulture) == "getregistry") { - getRegistry.Add(registryURL); + if (p.Value != null) + { + var registryURL = TranslateURL(p.Value); + Console.WriteLine("GET from Registry: " + registryURL); + if (registryURL != "") + { + getRegistry.Add(registryURL); + } + } } - } - } - if (sme is SubmodelElementCollection smc) - { - if (smc.IdShort == "federatedElements") + break; + } + case SubmodelElementCollection smc: { - foreach (var sme2 in smc.Value) + if (smc.IdShort == "federatedElements") { - if (sme2 is Property p2) + foreach (var sme2 in smc.Value) { - if (p2.IdShort.Contains("semanticId")) + if (sme2 is not Property p2) + { + continue; + } + + if (p2.IdShort != null && p2.IdShort.Contains("semanticId")) + { federatedElemensSemanticId.Add(p2.Value); + } } } + + break; } } } + } - if (Program.withDb) + if (Program.withDb) + { + using (AasContext db = new AasContext()) { - using (AasContext db = new AasContext()) + foreach (var aasDB in db.AASSets) { - foreach (var aasDB in db.AASSets) + if (aasDB.IdShort == "REGISTRY" || aasDB.IdShort == "myAASwithGlobalSecurityMetaModel") { - if (aasDB.IdShort != "REGISTRY" && aasDB.IdShort != "myAASwithGlobalSecurityMetaModel") - { - var aasDesc = AasRegistryService.GlobalCreateAasDescriptorFromDB(aasDB); - AddAasToRegistry(null, aasDesc, timestamp); - } + continue; } + + var aasDesc = AasRegistryService.GlobalCreateAasDescriptorFromDB(aasDB); + AddAasToRegistry(null, timestamp, aasDesc); } } - else + + foreach (var env in Program.env) { - foreach (AdminShellNS.AdminShellPackageEnv env in AasxServer.Program.env) + var aas = env.AasEnv?.AssetAdministrationShells?[0]; + if (aas?.IdShort != null && aas.IdShort.Equals("REGISTRY", StringComparison.Ordinal) && + (bool)aas.IdShort.Equals("myAASwithGlobalSecurityMetaModel", StringComparison.InvariantCulture)) { - if (env != null) - { - if (env != null) - { - var aas = env.AasEnv.AssetAdministrationShells[0]; - if (aas.IdShort != "REGISTRY" && aas.IdShort != "myAASwithGlobalSecurityMetaModel") - { - AddAasToRegistry(env, null, timestamp); - } + AddAasToRegistry(env, timestamp); + } - if (aas.IdShort == "PcfViewTask") - { - string certificatePassword = "i40"; - Stream s2 = null; - try - { - s2 = env.GetLocalStreamFromPackage("/aasx/files/Andreas_Orzelski_Chain.pfx", access: FileAccess.Read); - } - catch - { - } + if (aas?.IdShort != "PcfViewTask") + { + continue; + } - if (s2 == null) - { - Console.WriteLine("Stream error!"); - continue; - } + const string certificatePassword = "i40"; + Stream? s2 = null; + try + { + s2 = env.GetLocalStreamFromPackage(AasxFilesChainPfx, access: FileAccess.Read); + } + catch + { + // Well? It seems like an Orzelski problem... + } - X509Certificate2Collection xc = new X509Certificate2Collection(); - using (var m = new System.IO.MemoryStream()) - { - s2.CopyTo(m); - var b = m.GetBuffer(); - xc.Import(b, certificatePassword, X509KeyStorageFlags.PersistKeySet); - certificate = new X509Certificate2(b, certificatePassword); - Console.WriteLine("Client certificate: " + "/aasx/files/Andreas_Orzelski_Chain.pfx"); - s2.Close(); - } - } - } - } + if (s2 == null) + { + Console.WriteLine("Stream error!"); + continue; } + + var xc = new X509Certificate2Collection(); + using var m = new MemoryStream(); + s2.CopyTo(m); + var b = m.GetBuffer(); + xc.Import(b, certificatePassword, X509KeyStorageFlags.PersistKeySet); + Certificate = new X509Certificate2(b, certificatePassword); + Console.WriteLine($"Client certificate: {AasxFilesChainPfx}"); + s2.Close(); } } if (getRegistry.Count != 0) { - var submodelDescriptors = new List(); - string submodelRegistryUrl = System.Environment.GetEnvironmentVariable("SUBMODELREGISTRY"); + var submodelDescriptors = new List(); + var submodelRegistryUrl = System.Environment.GetEnvironmentVariable("SUBMODELREGISTRY"); if (submodelRegistryUrl != null) { - string json = null; - string accessToken = null; + string? accessToken = null; submodelRegistryUrl = submodelRegistryUrl.Replace("\r", ""); submodelRegistryUrl = submodelRegistryUrl.Replace("\n", ""); // basyx with Submodel Registry: read submodel descriptors - string requestPath = submodelRegistryUrl + "/submodel-descriptors"; - string queryPara = ""; - string userPW = ""; - string urlEdcWrapper = ""; - string replace = ""; + var requestPath = $"{submodelRegistryUrl}/submodel-descriptors"; - if (AasxCredentials.get(cs.credentials, requestPath, out queryPara, out userPW, out urlEdcWrapper, out replace)) + if (AasxCredentials.get(cs.credentials, requestPath, out _, out _, out _, out var replace) && !string.IsNullOrEmpty(replace)) { - if (replace != "") - requestPath = replace; + requestPath = replace; } var handler = new HttpClientHandler() {ServerCertificateCustomValidationCallback = delegate { return true; }}; if (!requestPath.Contains("localhost")) { - if (AasxServer.AasxTask.proxy != null) - handler.Proxy = AasxServer.AasxTask.proxy; - else - handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; + handler.Proxy = AasxTask.proxy; } var client = new HttpClient(handler); client.Timeout = TimeSpan.FromSeconds(10); if (accessToken != null) + { client.SetBearerToken(accessToken); + } - bool error = false; - HttpResponseMessage response = new HttpResponseMessage(); + var error = false; + var response = new HttpResponseMessage(); try { - Console.WriteLine("GET " + requestPath); + Console.WriteLine($"GET {requestPath}"); var task = Task.Run(async () => { response = await client.GetAsync(requestPath); }); task.Wait(); - json = response.Content.ReadAsStringAsync().Result; - // TODO (jtikekar, 2023-09-04): check this call flow - // aasDescriptors = JsonConvert.DeserializeObject>(json); + var json = response.Content.ReadAsStringAsync().Result; if (!string.IsNullOrEmpty(json)) { - MemoryStream mStrm = new MemoryStream(Encoding.UTF8.GetBytes(json)); - JsonNode node = System.Text.Json.JsonSerializer.DeserializeAsync(mStrm).Result; + var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + var node = await System.Text.Json.JsonSerializer.DeserializeAsync(memoryStream); if (node is JsonObject jo) { if (jo.ContainsKey("result")) { - node = (JsonNode) jo[ "result" ]; + node = jo["result"]; if (node is JsonArray a) { - foreach (JsonNode n in a) - { - if (n != null) - submodelDescriptors.Add(DescriptorDeserializer.SubmodelDescriptorFrom(n)); - } + submodelDescriptors.AddRange(a.OfType().Select(jsonNode => DescriptorDeserializer.SubmodelDescriptorFrom(jsonNode))); } } } @@ -304,44 +300,41 @@ public void InitRegistry(List cList, DateTime timestamp, b if (error) { - string r = "ERROR GET; " + response.StatusCode.ToString(); - r += " ; " + requestPath; - if (response.Content != null) - r += " ; " + response.Content.ReadAsStringAsync().Result; + var r = $"ERROR GET; {response.StatusCode}"; + r += $" ; {requestPath}"; + r += $" ; {response.Content.ReadAsStringAsync().Result}"; Console.WriteLine(r); } - else // OK - { - } } foreach (var greg in getRegistry) { - List aasDescriptors = new List(); - - string json = null; - string accessToken = null; - //string requestPath = greg + "/" + "registry/shell-descriptors"; - string? requestPath = greg + "/shell-descriptors"; - string? queryPara = ""; - string userPW = ""; - string? urlEdcWrapper = ""; - string? replace = ""; - - if (AasxCredentials.get(cs.credentials, requestPath, out queryPara, out userPW, out urlEdcWrapper, out replace)) + var aasDescriptors = new List(); + + string? json = null; + string? accessToken = null; + var requestPath = $"{greg}/shell-descriptors"; + string userPW; + string urlEdcWrapper; + string replace; + + if (AasxCredentials.get(cs.credentials, requestPath, out var queryPara, out userPW, out urlEdcWrapper, out replace) && !string.IsNullOrEmpty(replace)) { - if (replace != "") - requestPath = replace; + requestPath = replace; } - var handler = new HttpClientHandler() {ServerCertificateCustomValidationCallback = delegate { return true; }}; + var handler = new HttpClientHandler {ServerCertificateCustomValidationCallback = delegate { return true; }}; if (!requestPath.Contains("localhost")) { - if (AasxServer.AasxTask.proxy != null) - handler.Proxy = AasxServer.AasxTask.proxy; + if (AasxTask.proxy != null) + { + handler.Proxy = AasxTask.proxy; + } else + { handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; + } } var client = new HttpClient(handler); @@ -349,62 +342,60 @@ public void InitRegistry(List cList, DateTime timestamp, b if (accessToken != null) client.SetBearerToken(accessToken); - bool error = false; - HttpResponseMessage response = new HttpResponseMessage(); + var error = false; + var response = new HttpResponseMessage(); try { - Console.WriteLine("GET " + requestPath); - var task = Task.Run(async () => { response = await client.GetAsync(requestPath); }); + Console.WriteLine($"GET {requestPath}"); + var path = requestPath; + var task = Task.Run(async () => { response = await client.GetAsync(path); }); task.Wait(); json = response.Content.ReadAsStringAsync().Result; - // TODO (jtikekar, 2023-09-04): check this call flow - // aasDescriptors = JsonConvert.DeserializeObject>(json); if (!string.IsNullOrEmpty(json)) { - MemoryStream mStrm = new MemoryStream(Encoding.UTF8.GetBytes(json)); - JsonNode node = System.Text.Json.JsonSerializer.DeserializeAsync(mStrm).Result; + var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + var node = await System.Text.Json.JsonSerializer.DeserializeAsync(memoryStream); if (node is JsonObject jo) { if (jo.ContainsKey("result")) { - node = (JsonNode) jo[ "result" ]; + node = jo["result"]; if (node is JsonArray a) { - foreach (JsonNode n in a) + foreach (var jsonNode in a) { - if (n != null) + if (jsonNode == null) { - var ad = DescriptorDeserializer.AssetAdministrationShellDescriptorFrom(n); - aasDescriptors.Add(ad); - if (ad.SubmodelDescriptors == null) - ad.SubmodelDescriptors = new List(); - if (ad.SubmodelDescriptors.Count == 0) - { - requestPath = ad.Endpoints[ 0 ].ProtocolInformation.Href; - Console.WriteLine("GET " + requestPath); - task = Task.Run(async () => { response = await client.GetAsync(requestPath); }); - task.Wait(); - json = response.Content.ReadAsStringAsync().Result; - mStrm = new MemoryStream(Encoding.UTF8.GetBytes(json)); - node = System.Text.Json.JsonSerializer.DeserializeAsync(mStrm).Result; - var aas = Jsonization.Deserialize.AssetAdministrationShellFrom(node); + continue; + } - var ids = new List(); - foreach (var s in aas.Submodels) - { - var id = s.Keys[ 0 ].Value; - ids.Add(id); - } + var ad = DescriptorDeserializer.AssetAdministrationShellDescriptorFrom(jsonNode); + aasDescriptors.Add(ad); + ad.SubmodelDescriptors ??= []; - foreach (var sd in submodelDescriptors) - { - if (ids.Contains(sd.Id)) - ad.SubmodelDescriptors.Add(sd); - } + if (ad.SubmodelDescriptors.Count != 0) + { + continue; + } - aasDescriptorsForSubmodelView.Add(ad); - } + requestPath = ad.Endpoints?[0].ProtocolInformation?.Href; + Console.WriteLine($"GET {requestPath}"); + var path1 = requestPath; + task = Task.Run(async () => { response = await client.GetAsync(path1); }); + task.Wait(); + json = response.Content.ReadAsStringAsync().Result; + memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + node = await System.Text.Json.JsonSerializer.DeserializeAsync(memoryStream); + var aas = Jsonization.Deserialize.AssetAdministrationShellFrom(node); + + var ids = (from s in aas?.Submodels select s.Keys[0].Value).ToList(); + + foreach (var sd in submodelDescriptors.Where(sd => ids.Contains(sd.Id))) + { + ad.SubmodelDescriptors.Add(sd); } + + aasDescriptorsForSubmodelView.Add(ad); } } } @@ -420,22 +411,15 @@ public void InitRegistry(List cList, DateTime timestamp, b if (error) { - string r = "ERROR GET; " + response.StatusCode.ToString(); - r += " ; " + requestPath; - if (response.Content != null) - r += " ; " + response.Content.ReadAsStringAsync().Result; + var r = $"ERROR GET; {response.StatusCode} ; {requestPath} ; {response.Content.ReadAsStringAsync().Result}"; Console.WriteLine(r); } else { - int i = 0; - while (i < AasxServer.Program.env.Length) + var i = 0; + while (i < Program.env.Length) { - var env = AasxServer.Program.env[ i ]; - if (env == null) - { - break; - } + var env = Program.env[i]; i++; } @@ -443,225 +427,265 @@ public void InitRegistry(List cList, DateTime timestamp, b initiallyEmpty = i; foreach (var ad in aasDescriptors) { - if (ad == null || ad.IdShort == "REGISTRY" || ad.IdShort == "myAASwithGlobalSecurityMetaModel") + if (ad.IdShort != null && (ad.IdShort.Equals("REGISTRY", StringComparison.Ordinal) || + ad.IdShort.Equals("myAASwithGlobalSecurityMetaModel", StringComparison.Ordinal))) + { continue; + } var watch = System.Diagnostics.Stopwatch.StartNew(); - // check, if AAS is exisiting and must be replaced - var extensions = new List {new Extension("endpoint", value: ad.Endpoints[ 0 ].ProtocolInformation.Href)}; + // check, if AAS is existing and must be replaced + var extensions = new List {new Extension("endpoint", value: ad.Endpoints?[0].ProtocolInformation?.Href)}; var aas = new AssetAdministrationShell(ad.Id, new AssetInformation(AssetKind.Instance, ad.GlobalAssetId), extensions, - idShort: ad.IdShort + " - EXTERNAL"); + idShort: $"{ad.IdShort} - EXTERNAL"); aas.TimeStamp = timestamp; aas.TimeStampCreate = timestamp; var newEnv = new AdminShellNS.AdminShellPackageEnv(); - newEnv.AasEnv.AssetAdministrationShells.Add(aas); + newEnv.AasEnv?.AssetAdministrationShells?.Add(aas); - foreach (var sd in ad.SubmodelDescriptors) + if (ad.SubmodelDescriptors != null) { - if (sd.IdShort == "NameplateVC") - continue; - - bool success = false; - bool external = false; - string idEncoded = ""; - string? endpoint = sd.Endpoints[ 0 ].ProtocolInformation.Href; - var s1 = endpoint.Split("/shells/"); - if (s1.Length == 2) + foreach (var sd in ad.SubmodelDescriptors) { - var s2 = s1[ 1 ].Split("/submodels/"); - if (s2.Length == 2) + if (sd.IdShort != null && sd.IdShort.Equals("NameplateVC", StringComparison.Ordinal)) { - idEncoded = s2[ 1 ].Replace("/submodel/", ""); - ; - endpoint = s1[ 0 ] + "/submodels/" + idEncoded; + continue; } - } - requestPath = endpoint; - queryPara = ""; - userPW = ""; - urlEdcWrapper = ""; - replace = ""; - client.DefaultRequestHeaders.Clear(); - if (AasxCredentials.get(cList, requestPath, out queryPara, out userPW, out urlEdcWrapper, out replace)) - { - if (replace != "") - requestPath = replace; - if (queryPara != "") - queryPara = "?" + queryPara; - if (userPW != "") - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", userPW); - if (urlEdcWrapper != "") - requestPath = urlEdcWrapper; - } + var success = false; + var external = false; + string idEncoded; + var endpoint = sd.Endpoints?[0].ProtocolInformation?.Href; + var s1 = endpoint?.Split("/shells/"); + if (s1 != null && s1.Length == 2) + { + var s2 = s1[1].Split("/submodels/"); + if (s2.Length == 2) + { + idEncoded = s2[1].Replace("/submodel/", ""); + endpoint = s1[0] + "/submodels/" + idEncoded; + } + } + + requestPath = endpoint; + client.DefaultRequestHeaders.Clear(); + if (requestPath != null && AasxCredentials.get(cList, requestPath, out queryPara, out userPW, out urlEdcWrapper, out replace)) + { + if (replace != "") + { + requestPath = replace; + } - AasxServer.Program.submodelAPIcount++; - string clientToken = ""; + if (queryPara != "") + { + queryPara = "?" + queryPara; + } - switch (sd.IdShort) - { - case "BillOfMaterial": - case "ProductCarbonFootprint": - case "CarbonFootprint": - case "TechnicalData": - case "Nameplate": - case "WeightInformation": - // copy specific submodels locally - try + if (userPW != "") { - requestPath += queryPara; - // HEAD to get policy for submodel - if (Program.withPolicy) + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", userPW); + } + + if (urlEdcWrapper != "") + { + requestPath = urlEdcWrapper; + } + } + + Program.submodelAPIcount++; + string clientToken = null; + + switch (sd.IdShort) + { + case "BillOfMaterial": + case "ProductCarbonFootprint": + case "CarbonFootprint": + case "TechnicalData": + case "Nameplate": + case "WeightInformation": + // copy specific submodels locally + try { - // requestPath += queryPara; - Console.WriteLine("HEAD Submodel " + requestPath); - var task = Task.Run(async () => { response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, requestPath)); }); - task.Wait(); - - string userName = "aorzelski@phoenixcontact.com"; - string policy = ""; - string policyRequestedResource = ""; - foreach (var kvp in response.Headers) + requestPath += queryPara; + // HEAD to get policy for submodel + if (Program.withPolicy) { - if (kvp.Key == "policy") - policy = kvp.Value.FirstOrDefault(); - if (kvp.Key == "policyRequestedResource") - policyRequestedResource = kvp.Value.FirstOrDefault(); - } + // requestPath += queryPara; + Console.WriteLine($"HEAD Submodel {requestPath}"); + var path = requestPath; + var task = Task.Run(async () => + { + response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, path)); + }); + task.Wait(); - if (policy != "") - { - var credential = new X509SigningCredentials(certificate); - string clientId = "client.jwt"; - string subject = certificate.Subject; - var now = DateTime.UtcNow; - var claimList = - new List() + const string userName = "aorzelski@phoenixcontact.com"; + var policy = string.Empty; + var policyRequestedResource = string.Empty; + foreach (var kvp in response.Headers) + { + if (kvp.Key == "policy") { - new Claim(JwtClaimTypes.JwtId, Guid.NewGuid().ToString()), - new Claim(JwtClaimTypes.Subject, clientId), - new Claim(JwtClaimTypes.IssuedAt, now.ToEpochTime().ToString(), ClaimValueTypes.Integer64), - new Claim("userName", userName) - }; + policy = kvp.Value.FirstOrDefault(); + } + + if (kvp.Key == "policyRequestedResource") + { + policyRequestedResource = kvp.Value.FirstOrDefault() ?? string.Empty; + } + } + if (policy != "") - claimList.Add(new Claim("policy", policy, ClaimValueTypes.String)); - if (policyRequestedResource != "") - claimList.Add(new Claim("policyRequestedResource", policyRequestedResource, ClaimValueTypes.String)); - var token = new JwtSecurityToken( - clientId, - policyRequestedResource, - claimList, - now, - now.AddDays(1), - credential) - ; - var tokenHandler = new JwtSecurityTokenHandler(); - clientToken = tokenHandler.WriteToken(token); - client.SetBearerToken(clientToken); + { + var credential = new X509SigningCredentials(Certificate); + const string clientId = "client.jwt"; + var now = DateTime.UtcNow; + var claimList = + new List() + { + new(JwtClaimTypes.JwtId, Guid.NewGuid().ToString()), + new(JwtClaimTypes.Subject, clientId), + new(JwtClaimTypes.IssuedAt, now.ToEpochTime().ToString(CultureInfo.InvariantCulture), + ClaimValueTypes.Integer64), + new("userName", userName) + }; + if (policy != "") + if (policy != null) + { + claimList.Add(new Claim("policy", policy, ClaimValueTypes.String)); + } + + if (policyRequestedResource != "") + claimList.Add(new Claim("policyRequestedResource", policyRequestedResource, ClaimValueTypes.String)); + var token = new JwtSecurityToken( + clientId, + policyRequestedResource, + claimList, + now, + now.AddDays(1), + credential) + ; + var tokenHandler = new JwtSecurityTokenHandler(); + clientToken = tokenHandler.WriteToken(token); + client.SetBearerToken(clientToken); + } } - } - Console.WriteLine("GET Submodel " + requestPath); - var task1 = Task.Run(async () => { response = await client.GetAsync(requestPath); }); - task1.Wait(); - if (response.IsSuccessStatusCode) - { - json = response.Content.ReadAsStringAsync().Result; - var sm = new Submodel(""); - try + Console.WriteLine("GET Submodel " + requestPath); + var task1 = Task.Run(async () => { response = await client.GetAsync(requestPath); }); + task1.Wait(); + if (response.IsSuccessStatusCode) { - MemoryStream mStrm = new MemoryStream(Encoding.UTF8.GetBytes(json)); - JsonNode node = System.Text.Json.JsonSerializer.DeserializeAsync(mStrm).Result; - sm = Jsonization.Deserialize.SubmodelFrom(node); - - sm.IdShort += " - COPY"; - sm.Extensions = new List - { - new Extension("endpoint", value: sd.Endpoints[ 0 ].ProtocolInformation.Href), - new Extension("clientToken", value: clientToken) - }; - sm.SetAllParentsAndTimestamps(null, timestamp, timestamp); - aas.AddSubmodelReference(sm.GetReference()); - newEnv.AasEnv.Submodels.Add(sm); - success = true; - } - catch (Exception ex) - { - Console.WriteLine("ERROR Deserialization " + requestPath + " " + ex.Message); + json = response.Content.ReadAsStringAsync().Result; + Submodel sm; + try + { + var mStrm = new MemoryStream(Encoding.UTF8.GetBytes(json)); + var node = await System.Text.Json.JsonSerializer.DeserializeAsync(mStrm); + sm = Jsonization.Deserialize.SubmodelFrom(node); - success = false; + if (sm != null) + { + sm.IdShort += " - COPY"; + } + + if (sm != null) + { + sm.Extensions = new List + { + new Extension("endpoint", value: sd.Endpoints?[0].ProtocolInformation?.Href), + new Extension("clientToken", value: clientToken) + }; + sm.SetAllParentsAndTimestamps(null, timestamp, timestamp); + aas.AddSubmodelReference(sm.GetReference()); + newEnv.AasEnv?.Submodels.Add(sm); + } + + success = true; + } + catch (Exception ex) + { + Console.WriteLine($"ERROR Deserialization {requestPath} {ex.Message}"); + + success = false; + } } } - } - catch - { - success = false; - } + catch + { + success = false; + } - break; - default: - // test if submodel is accessible - try - { - if (urlEdcWrapper == "") + break; + default: + // test if submodel is accessible + try { - if (queryPara == "") + if (urlEdcWrapper == "") { - queryPara = "?level=core"; + if (queryPara == "") + { + queryPara = "?level=core"; + } + else + { + queryPara += "&level=core"; + } } - else + + requestPath += queryPara; + Console.WriteLine("GET Submodel Core " + requestPath); + var path = requestPath; + var task2 = Task.Run(async () => { response = await client.GetAsync(path); }); + task2.Wait(); + if (response.IsSuccessStatusCode) { - queryPara += "&level=core"; + success = true; + external = true; } } - - requestPath += queryPara; - Console.WriteLine("GET Submodel Core " + requestPath); - var task2 = Task.Run(async () => { response = await client.GetAsync(requestPath); }); - task2.Wait(); - if (response.IsSuccessStatusCode) + catch { - success = true; - external = true; + success = false; } - } - catch - { - success = false; - } - break; - } + break; + } - if (!success || external) - { - var sm = new Submodel(sd.Id); - if (!success) + if (success && !external) { - sm.IdShort = sd.IdShort + " - NO ACCESS"; + continue; } - else + { - if (external) - sm.IdShort = sd.IdShort + " - EXTERNAL"; - } + var sm = new Submodel(sd.Id); + if (!success) + { + sm.IdShort = $"{sd.IdShort} - NO ACCESS"; + } + else + { + if (external) + sm.IdShort = $"{sd.IdShort} - EXTERNAL"; + } - sm.Extensions = new List - { - new Extension("endpoint", value: sd.Endpoints[ 0 ].ProtocolInformation.Href), - new Extension("clientToken", value: clientToken) - }; - sm.SetAllParentsAndTimestamps(null, timestamp, timestamp); - aas.AddSubmodelReference(sm.GetReference()); - newEnv.AasEnv.Submodels.Add(sm); + sm.Extensions = new List + { + new Extension("endpoint", value: sd.Endpoints?[0].ProtocolInformation.Href), + new Extension("clientToken", value: clientToken) + }; + sm.SetAllParentsAndTimestamps(null, timestamp, timestamp); + aas.AddSubmodelReference(sm.GetReference()); + newEnv.AasEnv.Submodels?.Add(sm); + } } } watch.Stop(); - Console.WriteLine(watch.ElapsedMilliseconds + " ms"); + Console.WriteLine($"{watch.ElapsedMilliseconds} ms"); - AasxServer.Program.env[ i ] = newEnv; + Program.env[i] = newEnv; i++; } } @@ -669,9 +693,9 @@ public void InitRegistry(List cList, DateTime timestamp, b } } - AasxServer.Program.signalNewData(2); + Program.signalNewData(2); - AasxServer.Program.initializingRegistry = false; + Program.initializingRegistry = false; if (aasRegistry != null && aasRegistry.SubmodelElements != null) { @@ -682,479 +706,243 @@ public void InitRegistry(List cList, DateTime timestamp, b Console.WriteLine($"Registry is empty"); } } + } - #region PrivateMethods + #region PrivateMethods - static string TranslateURL(string url) + private static string TranslateURL(string? url) + { + // get from environment + if (url?[..1] != "$") { - // get from environment - if (url.Substring(0, 1) == "$") - { - string envVar = url.Substring(1); - url = System.Environment.GetEnvironmentVariable(envVar); - if (url == null) - { - url = ""; - } - url = url.Replace("\r", ""); - url = url.Replace("\n", ""); - } - - return url; + return url ?? string.Empty; } - static void AddAasToRegistry(AdminShellNS.AdminShellPackageEnv? env, AssetAdministrationShellDescriptor? aasDesc, DateTime timestamp) -#pragma warning restore IDE1006 // Benennungsstile + var envVar = url[1..]; + url = System.Environment.GetEnvironmentVariable(envVar); + if (url == null) { - AssetAdministrationShellDescriptor ad = new AssetAdministrationShellDescriptor(); - - if (aasDesc != null) - { - ad = aasDesc; - } - else - { - var aas = env.AasEnv.AssetAdministrationShells[0]; - - string? globalAssetId = aas.AssetInformation.GlobalAssetId!; - - // ad.Administration.Version = aas.administration.version; - // ad.Administration.Revision = aas.administration.revision; - ad.IdShort = aas.IdShort!; - ad.Id = aas.Id; - var e = new Endpoint(); - e.ProtocolInformation = new ProtocolInformation(); - e.ProtocolInformation.Href = - Program.externalRepository + "/shells/" + - Base64UrlEncoder.Encode(ad.Id); - Console.WriteLine("AAS " + ad.IdShort + " " + e.ProtocolInformation.Href); - e.Interface = "AAS-1.0"; - ad.Endpoints = new List(); - ad.Endpoints.Add(e); - ad.GlobalAssetId = globalAssetId; - // - var extSubjId = new Reference(ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, "assetKind") }); - var specificAssetId = new SpecificAssetId("assetKind", aas.AssetInformation.AssetKind.ToString(), externalSubjectId: extSubjId); - ad.SpecificAssetIds = new List { specificAssetId }; - - // Submodels - if (aas.Submodels != null && aas.Submodels.Count > 0) - { - ad.SubmodelDescriptors = new List(); - foreach (var smr in aas.Submodels) - { - var sm = env.AasEnv.FindSubmodel(smr); - if (sm != null && sm.IdShort != null) - { - SubmodelDescriptor sd = new SubmodelDescriptor(); - sd.IdShort = sm.IdShort; - sd.Id = sm.Id; - var esm = new Models.Endpoint(); - esm.ProtocolInformation = new ProtocolInformation(); - esm.ProtocolInformation.Href = - AasxServer.Program.externalRepository + "/shells/" + - Base64UrlEncoder.Encode(ad.Id) + "/submodels/" + - Base64UrlEncoder.Encode(sd.Id); - // Console.WriteLine("SM " + sd.IdShort + " " + esm.ProtocolInformation.EndpointAddress); - esm.Interface = "SUBMODEL-1.0"; - sd.Endpoints = new List(); - sd.Endpoints.Add(esm); - if (sm.SemanticId != null) - { - var sid = sm.SemanticId.GetAsExactlyOneKey(); - if (sid != null) - { - var semanticId = new Reference(ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, sid.Value) }); - sd.SemanticId = semanticId; - } - } + url = ""; + } - // add searchData for registry - if (sm.SubmodelElements != null) - foreach (var se in sm.SubmodelElements) - { - var sme = se; - bool federate = false; - if (sme.SemanticId != null && sme.SemanticId.Keys != null && sme.SemanticId.Keys.Count != 0 && sme.SemanticId.Keys[0] != null) - { - if (federatedElemensSemanticId.Contains(sme.SemanticId.Keys[0].Value)) - federate = true; - } + url = url.Replace("\r", ""); + url = url.Replace("\n", ""); - if (sme.Qualifiers != null && sme.Qualifiers.Count != 0) - { - if (sme.Qualifiers[0].Type == "federatedElement") - federate = true; - } - } + return url; + } - ad.SubmodelDescriptors.Add(sd); - if (sm.IdShort.ToLower() == "nameplate") - { - // Add special entry for verifiable credentials - sd = new SubmodelDescriptor(); - sd.IdShort = "NameplateVC"; - sd.Id = sm.Id + "_VC"; - esm = new Models.Endpoint(); - esm.ProtocolInformation = new ProtocolInformation(); - // TODO (jtikekar, 2023-09-04): @Andreas why hardcoded=> Verifiable creditentials - esm.ProtocolInformation.Href = - "https://nameplate.h2894164.stratoserver.net/demo/selfdescriptiononthefly/" + - "aHR0cHM6Ly9yZWdpc3RyeS5oMjg5NDE2NC5zdHJhdG9zZXJ2ZXIubmV0/" + - Base64UrlEncoder.Encode(ad.Id); - esm.Interface = "VC-1.0"; - sd.Endpoints = new List(); - sd.Endpoints.Add(esm); - if (sm.SemanticId != null) - { - var sid = sm.SemanticId.GetAsExactlyOneKey(); - if (sid != null) - { - var semanticId = new Reference(ReferenceTypes.ExternalReference, new List() { new Key(KeyTypes.GlobalReference, sid.Value) }); - sd.SemanticId = semanticId; - } - } + void AddAasToRegistry(AdminShellPackageEnv? env, DateTime timestamp, AssetAdministrationShellDescriptor? aasDesc = null) + { + var aas = env?.AasEnv?.AssetAdministrationShells?[0]; - ad.SubmodelDescriptors.Add(sd); - } - } - } - } - } + var ad = new AssetAdministrationShellDescriptor(); - // add to internal registry - if (postRegistry.Contains("this")) - AddAasDescriptorToRegistry(ad, timestamp, true); - - // Test serialize + deserialize; - // TODO (jtikekar, 2023-09-04): @Andreas why? Gives an exception due to interface IReference Needs to extend Jsonization class - //bool test = true; - //if (test) - //{ - // string json = JsonConvert.SerializeObject(ad); - // Console.WriteLine(json); - // var adTest = JsonConvert.DeserializeObject(json); - //} - - // POST Descriptor to Registry - foreach (var pr in postRegistry) + if (aasDesc != null) + { + ad = aasDesc; + } + else + { + var globalAssetId = aas?.AssetInformation?.GlobalAssetId!; + + ad.IdShort = aas?.IdShort; + ad.Id = aas?.Id; + var e = new Endpoint(); + e.ProtocolInformation = new ProtocolInformation(); + e.ProtocolInformation.Href = + $"{Program.externalRepository}/shells/{Base64UrlEncoder.Encode(ad.Id)}"; + Console.WriteLine($"AAS {ad.IdShort} {e.ProtocolInformation.Href}"); + e.Interface = "AAS-1.0"; + ad.Endpoints = new List(); + ad.Endpoints.Add(e); + ad.GlobalAssetId = globalAssetId; + // + var extSubjId = new Reference(ReferenceTypes.ExternalReference, new List {new Key(KeyTypes.GlobalReference, "assetKind")}); + var specificAssetId = new SpecificAssetId("assetKind", aas?.AssetInformation?.AssetKind.ToString(CultureInfo.InvariantCulture), externalSubjectId: extSubjId); + ad.SpecificAssetIds = new List {specificAssetId}; + + // Submodels + if (aas?.Submodels != null && aas.Submodels.Count > 0) { - if (pr == "this") + ad.SubmodelDescriptors = new List(); + foreach (var sm in aas.Submodels.Select(smr => env.AasEnv.FindSubmodel(smr))) { - continue; - } - - var watch = System.Diagnostics.Stopwatch.StartNew(); - string accessToken = null; - string requestPath = pr; - if (!requestPath.Contains("?")) - { - //requestPath = requestPath + "/registry/shell-descriptors"; - requestPath = requestPath + "/shell-descriptors"; - } - - //string json = JsonConvert.SerializeObject(ad); - string json = DescriptorSerializer.ToJsonObject(ad).ToJsonString(); - - var handler = new HttpClientHandler() {ServerCertificateCustomValidationCallback = delegate { return true; }}; - - if (!requestPath.Contains("localhost")) - { - if (AasxTask.proxy != null) + if (sm.IdShort == null) { - handler.Proxy = AasxTask.proxy; + continue; } - else - { - handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; - } - } - var client = new HttpClient(handler); - if (accessToken != null) - client.SetBearerToken(accessToken); - client.Timeout = TimeSpan.FromSeconds(20); - - if (json != "") - { - bool error = false; - HttpResponseMessage response = new HttpResponseMessage(); - try + var sd = new SubmodelDescriptor(); + sd.IdShort = sm.IdShort; + sd.Id = sm.Id; + var esm = new Models.Endpoint(); + esm.ProtocolInformation = new ProtocolInformation(); + esm.ProtocolInformation.Href = + $"{Program.externalRepository}/shells/{Base64UrlEncoder.Encode(ad.Id)}/submodels/{Base64UrlEncoder.Encode(sd.Id)}"; + + esm.Interface = "SUBMODEL-1.0"; + sd.Endpoints = new List(); + sd.Endpoints.Add(esm); + if (sm.SemanticId != null) { - Console.WriteLine("POST " + requestPath); - var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"); - var task = Task.Run(async () => - { - response = await client.PostAsync( - requestPath, content); - }); - task.Wait(); - error = !response.IsSuccessStatusCode; + var sid = sm.SemanticId.GetAsExactlyOneKey(); + { + var semanticId = new Reference(ReferenceTypes.ExternalReference, new List {new Key(KeyTypes.GlobalReference, sid.Value)}); + sd.SemanticId = semanticId; + } } - catch + + ad.SubmodelDescriptors.Add(sd); + if (!sm.IdShort.Equals("nameplate", StringComparison.CurrentCultureIgnoreCase)) { - error = true; + continue; } - if (error) + // Add special entry for verifiable credentials + sd = new SubmodelDescriptor(); + sd.IdShort = "NameplateVC"; + sd.Id = $"{sm.Id}_VC"; + esm = new Endpoint(); + esm.ProtocolInformation = new ProtocolInformation(); + // TODO (jtikekar, 2023-09-04): @Andreas why hardcoded=> Verifiable credentials + esm.ProtocolInformation.Href = $"https://nameplate.h2894164.stratoserver.net/demo/selfdescriptiononthefly/" + + $"aHR0cHM6Ly9yZWdpc3RyeS5oMjg5NDE2NC5zdHJhdG9zZXJ2ZXIubmV0/{Base64UrlEncoder.Encode(ad.Id)}"; + esm.Interface = "VC-1.0"; + sd.Endpoints = new List(); + sd.Endpoints.Add(esm); + if (sm.SemanticId != null) { - string r = "ERROR POST; " + response.StatusCode.ToString(); - r += " ; " + requestPath; - if (response.Content != null) - r += " ; " + response.Content.ReadAsStringAsync().Result; - Console.WriteLine(r); + var sid = sm.SemanticId.GetAsExactlyOneKey(); + var semanticId = new Reference(ReferenceTypes.ExternalReference, new List() {new Key(KeyTypes.GlobalReference, sid.Value)}); + sd.SemanticId = semanticId; } - } - watch.Stop(); - Console.WriteLine(watch.ElapsedMilliseconds + " ms"); + ad.SubmodelDescriptors.Add(sd); + } } } - public void CreateAssetAdministrationShellDescriptor(AssetAdministrationShellDescriptor newAasDesc, DateTime timestamp, bool initial = false) + // add to internal registry + if (postRegistry.Contains("this")) { - AddAasDescriptorToRegistry(newAasDesc, timestamp, initial); - Program.signalNewData(2); + CreateAssetAdministrationShellDescriptor(ad, timestamp, true); } - static void AddAasDescriptorToRegistry(AssetAdministrationShellDescriptor ad, DateTime timestamp, bool initial = false) + // POST Descriptor to Registry + foreach (var pr in postRegistry) { - string? aasID = ad.Id; - string? assetID = ad.GlobalAssetId; - string? endpoint = ""; - if (ad.Endpoints != null && ad.Endpoints.Count != 0) + if (pr == "this") { - endpoint = ad.Endpoints[ 0 ].ProtocolInformation.Href; + continue; } - // overwrite existing entry, if assetID AND aasID are identical - if (!initial) + var watch = System.Diagnostics.Stopwatch.StartNew(); + string? accessToken = null; + var requestPath = pr; + if (!requestPath.Contains("?", StringComparison.InvariantCulture)) { - foreach (var e in aasRegistry?.SubmodelElements) - { - if (e is SubmodelElementCollection ec) - { - int found = 0; - Property pjson = null; - Property pep = null; - foreach (var e2 in ec.Value) - { - if (e2 is Property ep) - { - if (ep.IdShort == "aasID" && ep.Value == aasID) - found++; - if (ep.IdShort == "assetID" && ep.Value == assetID) - found++; - if (ep.IdShort == "descriptorJSON") - pjson = ep; - if (ep.IdShort == "endpoint") - pep = ep; - } - } - - if (found == 2 && pjson != null) - { - //string s = JsonConvert.SerializeObject(ad); - string s = DescriptorSerializer.ToJsonObject(ad).ToJsonString(); - // if (s != pjson.Value) - { - pjson.TimeStampCreate = timestamp; - pjson.TimeStamp = timestamp; - pjson.Value = s; - pep.TimeStampCreate = timestamp; - pep.TimeStamp = timestamp; - pep.Value = endpoint; - Console.WriteLine("Replace Descriptor:"); - Console.WriteLine(s); - } - return; - } - } - } + //requestPath = requestPath + "/registry/shell-descriptors"; + requestPath += "/shell-descriptors"; } - // add new entry - SubmodelElementCollection c = new SubmodelElementCollection( - idShort: "ShellDescriptor_" + aasRegistry.SubmodelElements.Count, - value: new List()); - c.TimeStampCreate = timestamp; - c.TimeStamp = timestamp; - var p = new Property(DataTypeDefXsd.String, idShort: "idShort"); - p.TimeStampCreate = timestamp; - p.TimeStamp = timestamp; - p.Value = ad.IdShort; - c.Value.Add(p); - p = new Property(DataTypeDefXsd.String, idShort: "aasID"); - p.TimeStampCreate = timestamp; - p.TimeStamp = timestamp; - p.Value = aasID; - c.Value.Add(p); - p = new Property(DataTypeDefXsd.String, idShort: "assetID"); - p.TimeStampCreate = timestamp; - p.TimeStamp = timestamp; - if (assetID != "") - { - p.Value = assetID; - } + //string json = JsonConvert.SerializeObject(ad); + var json = DescriptorSerializer.ToJsonObject(ad)?.ToJsonString(); - c.Value.Add(p); - p = new Property(DataTypeDefXsd.String, idShort: "endpoint"); - p.TimeStampCreate = timestamp; - p.TimeStamp = timestamp; - p.Value = endpoint; - c.Value.Add(p); - p = new Property(DataTypeDefXsd.String, idShort: "descriptorJSON"); - p.TimeStampCreate = timestamp; - p.TimeStamp = timestamp; - p.Value = DescriptorSerializer.ToJsonObject(ad).ToJsonString(); - c.Value.Add(p); - aasRegistry?.SubmodelElements.Add(c); - /* - int federatedElementsCount = 0; - var smc = new SubmodelElementCollection( - idShort: "federatedElements", - value: new List()); - smc.TimeStampCreate = timestamp; - smc.TimeStamp = timestamp; - c.Value.Add(smc); - */ - // iterate submodels - int iSubmodel = 0; - foreach (var sd in ad.SubmodelDescriptors) + var handler = new HttpClientHandler {ServerCertificateCustomValidationCallback = delegate { return true; }}; + + if (!requestPath.Contains("localhost")) { - // add new entry - SubmodelElementCollection cs = new SubmodelElementCollection( - idShort: "SubmodelDescriptor_" + submodelRegistryCount++, - value: new List()); - cs.TimeStampCreate = timestamp; - cs.TimeStamp = timestamp; - var ps = new Property(DataTypeDefXsd.String, idShort: "idShort"); - ps.TimeStampCreate = timestamp; - ps.TimeStamp = timestamp; - ps.Value = sd.IdShort; - cs.Value.Add(ps); - ps = new Property(DataTypeDefXsd.String, idShort: "submodelID"); - ps.TimeStampCreate = timestamp; - ps.TimeStamp = timestamp; - ps.Value = sd.Id; - cs.Value.Add(ps); - ps = new Property(DataTypeDefXsd.String, idShort: "semanticID"); - ps.TimeStampCreate = timestamp; - ps.TimeStamp = timestamp; - if (sd.SemanticId != null && sd.SemanticId.GetAsExactlyOneKey().Value != null) - ps.Value = sd.SemanticId.GetAsExactlyOneKey().Value; - cs.Value.Add(ps); - if (sd.Endpoints != null && sd.Endpoints.Count != 0) + if (AasxTask.proxy != null) { - endpoint = sd.Endpoints[ 0 ].ProtocolInformation.Href; + handler.Proxy = AasxTask.proxy; } - - ps = new Property(DataTypeDefXsd.String, idShort: "endpoint"); - ps.TimeStampCreate = timestamp; - ps.TimeStamp = timestamp; - ps.Value = endpoint; - cs.Value.Add(ps); - ps = new Property(DataTypeDefXsd.String, idShort: "descriptorJSON"); - ps.TimeStampCreate = timestamp; - ps.TimeStamp = timestamp; - //ps.Value = JsonConvert.SerializeObject(sd); - ps.Value = DescriptorSerializer.ToJsonObject(sd).ToJsonString(); - cs.Value.Add(ps); - // iterate submodels - int federatedElementsCount = 0; - var smc = new SubmodelElementCollection( - idShort: "federatedElements", - value: new List()); - smc.TimeStampCreate = timestamp; - smc.TimeStamp = timestamp; - cs.Value.Add(smc); - if (submodelRegistry.SubmodelElements == null) - submodelRegistry.SubmodelElements = new List(); - submodelRegistry?.SubmodelElements.Add(cs); - submodelRegistry?.SetAllParents(timestamp); - var r = new ReferenceElement(idShort: "ref_Submodel_" + iSubmodel++); - r.TimeStampCreate = timestamp; - r.TimeStamp = timestamp; - var mr = cs.GetModelReference(true); - r.Value = mr; - // revert order in references - int first = 0; - int last = r.Value.Keys.Count - 1; - while (first < last) + else { - var temp = r.Value.Keys[ first ]; - r.Value.Keys[ first ] = r.Value.Keys[ last ]; - r.Value.Keys[ last ] = temp; - first++; - last--; + handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; } + } - c.Value.Add(r); + var client = new HttpClient(handler); + if (accessToken != null) + client.SetBearerToken(accessToken); + client.Timeout = TimeSpan.FromSeconds(20); - if (sd.IdShort == "NameplateVC") + if (json != "") + { + var error = false; + var response = new HttpResponseMessage(); + try { - if (sd.Endpoints != null && sd.Endpoints.Count > 0) + Console.WriteLine($"POST {requestPath}"); + if (json != null) { - var ep = sd.Endpoints[ 0 ].ProtocolInformation.Href; - p = new Property(DataTypeDefXsd.String, idShort: "NameplateVC"); - p.TimeStampCreate = timestamp; - p.TimeStamp = timestamp; - p.Value = ep; - cs.Value.Add(p); + var content = new StringContent(json, Encoding.UTF8, "application/json"); + var task = Task.Run(async () => + { + response = await client.PostAsync( + requestPath, content); + }); + task.Wait(); } + + error = !response.IsSuccessStatusCode; + } + catch + { + error = true; } - // TODO (jtikekar, 2023-09-04): @Andreas - if (sd.FederatedElements != null && sd.FederatedElements.Count != 0) + if (error) { - foreach (var fe in sd.FederatedElements) - { - try - { - federatedElementsCount++; - /* - var sme = Newtonsoft.Json.JsonConvert.DeserializeObject( - fe, new AdminShellConverters.JsonAasxConverter("modelType", "name")); - */ - MemoryStream mStrm = new MemoryStream(Encoding.UTF8.GetBytes(fe)); - JsonNode node = System.Text.Json.JsonSerializer.DeserializeAsync(mStrm).Result; - var sme = Jsonization.Deserialize.ISubmodelElementFrom(node); - - // p = AdminShell.Property.CreateNew("federatedElement" + federatedElementsCount); - sme.TimeStampCreate = timestamp; - sme.TimeStamp = timestamp; - // p.value = fe; - smc.Value.Add(sme); - } - catch - { - } - } + var r = $"ERROR POST; {response.StatusCode} ; {requestPath} ; {response.Content}"; + Console.WriteLine(r); } } - aasRegistry?.SetAllParents(); + watch.Stop(); + Console.WriteLine($"{watch.ElapsedMilliseconds} ms"); } + } - public void CreateMultipleAssetAdministrationShellDescriptor(List body, DateTime timestamp) + public void CreateAssetAdministrationShellDescriptor(AssetAdministrationShellDescriptor newAasDesc, DateTime timestamp, bool initial = false) + { + var aasID = newAasDesc.Id; + var assetID = newAasDesc.GlobalAssetId; + var endpoint = string.Empty; + if (newAasDesc.Endpoints != null && newAasDesc.Endpoints.Count != 0) { - if (aasRegistry != null) - aasRegistry.SubmodelElements.Clear(); - if (submodelRegistry != null) - submodelRegistry.SubmodelElements.Clear(); - foreach (var ad in body) + endpoint = newAasDesc.Endpoints[0].ProtocolInformation?.Href; + } + + if (aasRegistry != null && _aasDescriptorWritingService.OverwriteExistingEntryForEdenticalIds(newAasDesc, aasRegistry, timestamp, initial, aasID, assetID, endpoint)) + { + return; + } + + if (aasRegistry != null && submodelRegistry != null) + { + _aasDescriptorWritingService.AddNewEntry(newAasDesc, aasRegistry, submodelRegistry, timestamp, aasID, assetID, endpoint); + + aasRegistry.SetAllParents(); + } + + Program.signalNewData(2); + } + + public void CreateMultipleAssetAdministrationShellDescriptor(List body, DateTime timestamp) + { + aasRegistry?.SubmodelElements?.Clear(); + submodelRegistry?.SubmodelElements?.Clear(); + foreach (var ad in body.OfType()) + { + lock (Program.changeAasxFile) { - if (ad == null) - continue; - lock (Program.changeAasxFile) - { - AddAasDescriptorToRegistry(ad, timestamp); - } + CreateAssetAdministrationShellDescriptor(ad, timestamp); } - - Program.signalNewData(2); } - #endregion + Program.signalNewData(2); } + + #endregion } \ No newline at end of file diff --git a/src/IO.Swagger.Registry.Lib.V3/Services/SubmodelPropertyExtractionService.cs b/src/IO.Swagger.Registry.Lib.V3/Services/SubmodelPropertyExtractionService.cs new file mode 100644 index 000000000..7174507e8 --- /dev/null +++ b/src/IO.Swagger.Registry.Lib.V3/Services/SubmodelPropertyExtractionService.cs @@ -0,0 +1,62 @@ +namespace IO.Swagger.Registry.Lib.V3.Services; + +using System; +using System.Collections.Generic; + +/// +public class SubmodelPropertyExtractionService : ISubmodelPropertyExtractionService +{ + /// + public (int found, Property? jsonProperty, Property? endpointProperty) FindMatchingProperties(SubmodelElementCollection elementCollection, string? aasID, + string? assetID) + { + var found = 0; + Property? jsonProperty = null; + Property? endpointProperty = null; + + if (elementCollection.Value == null) + { + return (found, jsonProperty, endpointProperty); + } + + foreach (var subElement in elementCollection.Value) + { + if (subElement is Property property) + { + switch (property.IdShort) + { + case "aasID" when property.Value == aasID: + case "assetID" when property.Value == assetID: + found++; + break; + case "descriptorJSON": + jsonProperty = property; + break; + case "endpoint": + endpointProperty = property; + break; + } + } + } + + return (found, jsonProperty, endpointProperty); + } + + /// + public void AddPropertyToCollection(SubmodelElementCollection collection, string idShort, string value, DateTime timestamp, bool checkEmpty = false) + { + if (checkEmpty && string.IsNullOrEmpty(value)) + { + return; + } + + var property = new Property(DataTypeDefXsd.String, idShort: idShort) {TimeStampCreate = timestamp, TimeStamp = timestamp, Value = value}; + + collection.Value?.Add(property); + } + + + /// + public SubmodelElementCollection CreateSubmodelElementCollection(string idShort, DateTime timestamp) => + new(idShort: idShort, value: new List()) {TimeStampCreate = timestamp, TimeStamp = timestamp}; +} \ No newline at end of file diff --git a/src/IO.Swagger.Registry.Lib.V3/Startup.cs b/src/IO.Swagger.Registry.Lib.V3/Startup.cs index 8603ab428..dbdf93200 100644 --- a/src/IO.Swagger.Registry.Lib.V3/Startup.cs +++ b/src/IO.Swagger.Registry.Lib.V3/Startup.cs @@ -17,15 +17,19 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Serialization; using IO.Swagger.Registry.Lib.V3.Filters; using System.Collections.Generic; using Microsoft.OpenApi.Any; namespace IO.Swagger; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Formatters; using Models; +using Registry.Lib.V3.Models; /// /// Startup @@ -57,35 +61,31 @@ public void ConfigureServices(IServiceCollection services) services .AddMvc(options => { - options.InputFormatters.RemoveType(); - options.OutputFormatters.RemoveType(); + // Remove System.Text.Json formatters + options.InputFormatters.RemoveType(); + options.OutputFormatters.RemoveType(); }) - .AddNewtonsoftJson(opts => - { - opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - opts.SerializerSettings.Converters.Add(new StringEnumConverter(new CamelCaseNamingStrategy())); - }) + .AddJsonOptions(options => + { + options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve; + }) .AddXmlSerializerFormatters(); - - services.AddSwaggerGen(c => - { - // Other Swagger configuration... - - c.MapType(() => new OpenApiSchema - { - Type = "string", - Enum = new List - { - new OpenApiString(MessageTypeEnum.UndefinedEnum.ToString()), - new OpenApiString(MessageTypeEnum.InfoEnum.ToString()), - new OpenApiString(MessageTypeEnum.WarningEnum.ToString()), - new OpenApiString(MessageTypeEnum.ErrorEnum.ToString()), - new OpenApiString(MessageTypeEnum.ExceptionEnum.ToString()) - } - }); - }); - + services.Configure(o => o.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter())); + services.Configure(options => + { + options.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()); + }); + + services.Configure(options => + { + options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + }); services .AddSwaggerGen(c => { @@ -106,9 +106,18 @@ public void ConfigureServices(IServiceCollection services) c.CustomSchemaIds(type => type.FullName); c.IncludeXmlComments($"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{_hostingEnv.ApplicationName}.xml"); - // Include DataAnnotation attributes on Controller Action parameters as Swagger validation rules (e.g required, pattern, ..) + // Include DataAnnotation attributes on Controller Action parameters as Swagger validation rules (e.g. required, pattern, ..) // Use [ValidateModelState] on Actions to actually validate it in C# as well! c.OperationFilter(); + + c.MapType(() => new OpenApiSchema + { + Type = "string", + Enum = Enum.GetNames(typeof(MessageTypeEnum)) + .Select(enumName => new OpenApiString(enumName)) + .Cast() + .ToList() + }); }); }