diff --git a/.build/BuildToolkit.ps1 b/.build/BuildToolkit.ps1 deleted file mode 100644 index 26d22dbf7..000000000 --- a/.build/BuildToolkit.ps1 +++ /dev/null @@ -1,680 +0,0 @@ -# Tool Versions -$NunitVersion = "3.12.0"; -$OpenCoverVersion = "4.7.1221"; -$DocFxVersion = "2.58.4"; -$ReportGeneratorVersion = "4.8.13"; -$OpenCoverToCoberturaVersion = "0.3.4"; - -# Folder Pathes -$RootPath = $MyInvocation.PSScriptRoot; -$BuildTools = "$RootPath\packages"; - -# Artifacts -$ArtifactsDir = "$RootPath\artifacts"; - -# Documentation -$DocumentationDir = "$RootPath\docs"; -$DocumentationArtifcacts = "$ArtifactsDir\Documentation"; - -# Tests -$NunitReportsDir = "$ArtifactsDir\Tests"; -$OpenCoverReportsDir = "$ArtifactsDir\Tests" -$CoberturaReportsDir = "$ArtifactsDir\Tests" - -# Nuget -$NugetConfig = "$RootPath\NuGet.Config"; -$NugetPackageArtifacts = "$ArtifactsDir\Packages"; - -# Load partial scripts -. "$PSScriptRoot\Output.ps1"; - -# Define Tools -$global:DotNetCli = "dotnet.exe"; -$global:NugetCli = "nuget.exe"; -$global:GitCli = ""; -$global:OpenCoverCli = "$BuildTools\OpenCover.$OpenCoverVersion\tools\OpenCover.Console.exe"; -$global:NunitCli = "$BuildTools\NUnit.ConsoleRunner.$NunitVersion\tools\nunit3-console.exe"; -$global:ReportGeneratorCli = "$BuildTools\ReportGenerator.$ReportGeneratorVersion\tools\net47\ReportGenerator.exe"; -$global:DocFxCli = "$BuildTools\docfx.console.$DocFxVersion\tools\docfx.exe"; -$global:OpenCoverToCoberturaCli = "$BuildTools\OpenCoverToCoberturaConverter.$OpenCoverToCoberturaVersion\tools\OpenCoverToCoberturaConverter.exe"; - -# Git -$global:GitCommitHash = ""; - -# Functions -function Invoke-Initialize([string]$Version = "1.0.0", [bool]$Cleanup = $False) { - Write-Step "Initializing BuildToolkit" - - # First check the powershell version - if ($PSVersionTable.PSVersion.Major -lt 5) { - Write-Host ("The needed major powershell version for this script is 5. Your version: " + ($PSVersionTable.PSVersion.ToString())) - exit 1; - } - - # Assign git.exe - $gitCommand = (Get-Command "git.exe" -ErrorAction SilentlyContinue); - if ($null -eq $gitCommand) { - Write-Host "Unable to find git.exe in your PATH. Download from https://git-scm.com"; - exit 1; - } - - $global:GitCli = $gitCommand.Path; - - # Load Hash - $global:GitCommitHash = (& $global:GitCli rev-parse HEAD); - Invoke-ExitCodeCheck $LastExitCode; - - # Initialize Folders - CreateFolderIfNotExists $BuildTools; - CreateFolderIfNotExists $ArtifactsDir; - - # Environment Variable Defaults - if (-not $env:MORYX_BUILDNUMBER) { - $env:MORYX_BUILDNUMBER = 0; - } - - if (-not $env:MORYX_BUILD_CONFIG) { - $env:MORYX_BUILD_CONFIG = "Debug"; - } - - if (-not $env:MORYX_BUILD_VERBOSITY) { - $env:MORYX_BUILD_VERBOSITY = "minimal" - } - - if (-not $env:MORYX_TEST_VERBOSITY) { - $env:MORYX_TEST_VERBOSITY = "normal" - } - - if (-not $env:MORYX_NUGET_VERBOSITY) { - $env:MORYX_NUGET_VERBOSITY = "normal" - } - - if (-not $env:MORYX_OPTIMIZE_CODE) { - $env:MORYX_OPTIMIZE_CODE = $True; - } - else { - if (-not [bool]::TryParse($env:MORYX_OPTIMIZE_CODE, [ref]$env:MORYX_OPTIMIZE_CODE)) { - $env:MORYX_OPTIMIZE_CODE = $True; - } - } - - if (-not $env:MORYX_PACKAGE_TARGET) { - $env:MORYX_PACKAGE_TARGET = ""; - } - - if (-not $env:MORYX_PACKAGE_TARGET_V3) { - $env:MORYX_PACKAGE_TARGET_V3 = ""; - } - - if (-not $env:MORYX_ASSEMBLY_VERSION) { - $env:MORYX_ASSEMBLY_VERSION = $Version; - } - - if (-not $env:MORYX_FILE_VERSION) { - $env:MORYX_FILE_VERSION = $Version; - } - - if (-not $env:MORYX_INFORMATIONAL_VERSION) { - $env:MORYX_INFORMATIONAL_VERSION = $Version; - } - - if (-not $env:MORYX_PACKAGE_VERSION) { - $env:MORYX_PACKAGE_VERSION = $Version; - } - - Set-Version $Version; - - # Printing Variables - Write-Step "Printing global variables" - Write-Variable "RootPath" $RootPath; - Write-Variable "DocumentationDir" $DocumentationDir; - Write-Variable "NunitReportsDir" $NunitReportsDir; - - Write-Step "Printing global scope" - Write-Variable "OpenCoverCli" $global:OpenCoverCli; - Write-Variable "NUnitCli" $global:NUnitCli; - Write-Variable "ReportGeneratorCli" $global:ReportGeneratorCli; - Write-Variable "DocFxCli" $global:DocFxCli; - Write-Variable "OpenCoverToCoberturaCli" $global:OpenCoverToCoberturaCli; - Write-Variable "GitCli" $global:GitCli; - Write-Variable "GitCommitHash" $global:GitCommitHash; - - Write-Step "Printing environment variables" - Write-Variable "MORYX_OPTIMIZE_CODE" $env:MORYX_OPTIMIZE_CODE; - Write-Variable "MORYX_BUILDNUMBER" $env:MORYX_BUILDNUMBER; - Write-Variable "MORYX_BUILD_CONFIG" $env:MORYX_BUILD_CONFIG; - Write-Variable "MORYX_BUILD_VERBOSITY" $env:MORYX_BUILD_VERBOSITY; - Write-Variable "MORYX_TEST_VERBOSITY" $env:MORYX_TEST_VERBOSITY; - Write-Variable "MORYX_NUGET_VERBOSITY" $env:MORYX_NUGET_VERBOSITY; - Write-Variable "MORYX_PACKAGE_TARGET" $env:MORYX_PACKAGE_TARGET; - Write-Variable "MORYX_PACKAGE_TARGET_V3" $env:MORYX_PACKAGE_TARGET_V3; - - Write-Variable "MORYX_ASSEMBLY_VERSION" $env:MORYX_ASSEMBLY_VERSION; - Write-Variable "MORYX_FILE_VERSION" $env:MORYX_FILE_VERSION; - Write-Variable "MORYX_INFORMATIONAL_VERSION" $env:MORYX_INFORMATIONAL_VERSION; - Write-Variable "MORYX_PACKAGE_VERSION" $env:MORYX_PACKAGE_VERSION; - - - # Cleanp - if ($Cleanup) { - Write-Step "Cleanup" - - Write-Host "Cleaning up repository ..." -ForegroundColor Red; - & $global:GitCli clean -f -d -x - Invoke-ExitCodeCheck $LastExitCode; - - & $global:GitCli checkout . - Invoke-ExitCodeCheck $LastExitCode; - } -} - -function Invoke-Cleanup { - # Clean up - Write-Step "Cleaning up repository ..."; - & $global:GitCli clean -f -d -x - Invoke-ExitCodeCheck $LastExitCode; -} - -function Install-Tool([string]$PackageName, [string]$Version, [string]$TargetExecutable, [string]$OutputDirectory = $BuildTools) { - if (-not (Test-Path $TargetExecutable)) { - & $global:NugetCli install $PackageName -version $Version -outputdirectory $OutputDirectory -configfile $NugetConfig - Invoke-ExitCodeCheck $LastExitCode; - } - else { - Write-Host "$PackageName ($Version) already exists. Do not need to install." - } -} - -function Invoke-Build([string]$ProjectFile, [string]$Options = "") { - Write-Step "Building $ProjectFile" - - # TODO: maybe we find a better way: currently all packages of all solutions are restored. - ForEach ($solution in (Get-ChildItem $RootPath -Filter "*.sln")) { - Write-Host "Restoring Nuget packages of $solution"; - - & $global:DotNetCli restore $solution --verbosity $env:MORYX_NUGET_VERBOSITY --configfile $NugetConfig; - Invoke-ExitCodeCheck $LastExitCode; - } - - $additonalOptions = ""; - if (-not [string]::IsNullOrEmpty($Options)) { - $additonalOptions = ",$Options"; - } - - $msbuildParams = "Optimize=" + (&{If($env:MORYX_OPTIMIZE_CODE -eq $True) {"true"} Else {"false"}}) + ",DebugSymbols=true$additonalOptions"; - $buildArgs = "--configuration", "$env:MORYX_BUILD_CONFIG"; - $buildArgs += "--verbosity", $env:MORYX_BUILD_VERBOSITY; - $buildArgs += "-p:$msbuildParams" - - & $global:DotNetCli build $ProjectFile @buildArgs - Invoke-ExitCodeCheck $LastExitCode; -} - -function Invoke-Nunit([string]$SearchPath = $RootPath, [string]$SearchFilter = "*.csproj") { - $randomIncrement = Get-Random -Minimum 2000 -Maximum 2100 - Write-Step "Running $Name Tests: $SearchPath" - - $testProjects = Get-ChildItem $SearchPath -Recurse -Include $SearchFilter - if ($testProjects.Length -eq 0) { - Write-Host-Warning "No test projects found!" - return; - } - - $env:PORT_INCREMENT = $randomIncrement; - - if (-not (Test-Path $global:NUnitCli)) { - Install-Tool "NUnit.Console" $NunitVersion $global:NunitCli; - } - - CreateFolderIfNotExists $NunitReportsDir; - - ForEach($testProject in $testProjects ) { - $projectName = ([System.IO.Path]::GetFileNameWithoutExtension($testProject.Name)); - $testAssembly = [System.IO.Path]::Combine($testProject.DirectoryName, "bin", $env:MORYX_BUILD_CONFIG, "$projectName.dll"); - - # If assembly does not exists, the project will be build - if (-not (Test-Path $testAssembly)) { - Invoke-Build $testProject - } - - & $global:NUnitCli $testProject /config:"$env:MORYX_BUILD_CONFIG" - } - - Invoke-ExitCodeCheck $LastExitCode; -} - -function Invoke-SmokeTest([string]$RuntimePath, [int]$ModulesCount, [int]$InterruptTime) { - $randomIncrement = Get-Random -Minimum 2000 -Maximum 2100 - Write-Step "Invoking Runtime SmokeTest Modules: $ModulesCount, Interrupt Time: $InterruptTime, Port Increment: $randomIncrement." - - & "$RuntimePath" @("smokeTest", "-e $ModulesCount", "-i $InterruptTime", "-p $randomIncrement") - Invoke-ExitCodeCheck $LastExitCode; -} - -function Invoke-CoverTests($SearchPath = $RootPath, $SearchFilter = "*.csproj", $FilterFile = "$RootPath\OpenCoverFilter.txt") { - Write-Step "Starting cover tests from $SearchPath with filter $FilterFile." - - if (-not (Test-Path $SearchPath)) { - Write-Host-Warning "$SearchPath does not exists, ignoring!"; - return; - } - - $testProjects = Get-ChildItem $SearchPath -Recurse -Include $SearchFilter - if ($testProjects.Length -eq 0) { - Write-Host-Warning "No test projects found!" - return; - } - - if (-not (Test-Path $global:NUnitCli)) { - Install-Tool "NUnit.Console" $NunitVersion $global:NunitCli; - } - - if (-not (Test-Path $global:OpenCoverCli)) { - Install-Tool "OpenCover" $OpenCoverVersion $global:OpenCoverCli; - } - - if (-not (Test-Path $global:OpenCoverToCoberturaCli)) { - Install-Tool "OpenCoverToCoberturaConverter" $OpenCoverToCoberturaVersion $global:OpenCoverToCoberturaCli; - } - - CreateFolderIfNotExists $OpenCoverReportsDir; - CreateFolderIfNotExists $NunitReportsDir; - - $includeFilter = "+[Moryx*]*"; - $excludeFilter = "-[*nunit*]* -[*Tests]* -[*Model*]*"; - - if (Test-Path $FilterFile) { - $ignoreContent = Get-Content $FilterFile; - - foreach ($line in $ignoreContent) { - $parts = $line.Split(":"); - if ($parts.Count -lt 2) { - continue - } - - $filterType = $parts[0]; - $filterValue = $parts[1]; - - if ($filterType.StartsWith("INCLUDE")) { - $includeFilter += " $filterValue"; - } - - if ($filterType.StartsWith("EXCLUDE")) { - $excludeFilter += " $filterValue"; - } - } - - Write-Host "Active Filter: `r`n Include: $includeFilter `r`n Exclude: $excludeFilter"; - } - - ForEach($testProject in $testProjects ) { - $projectName = ([System.IO.Path]::GetFileNameWithoutExtension($testProject.Name)); - $testAssembly = [System.IO.Path]::Combine($testProject.DirectoryName, "bin", $env:MORYX_BUILD_CONFIG, "$projectName.dll"); - $isNetCore = Get-CsprojIsNetCore($testProject); - - Write-Host "OpenCover Test: ${projectName}:"; - - $nunitXml = ($NunitReportsDir + "\$projectName.TestResult.xml"); - $openCoverXml = ($OpenCoverReportsDir + "\$projectName.OpenCover.xml"); - $coberturaXml = ($CoberturaReportsDir + "\$projectName.Cobertura.xml"); - - if ($isNetCore) { - $targetArgs = '"test -v ' + $env:MORYX_TEST_VERBOSITY + ' -c ' + $env:MORYX_BUILD_CONFIG + ' ' + $testProject + '"'; - $openCoverAgs = "-target:$global:DotNetCli", "-targetargs:$targetArgs" - } - else { - # If assembly does not exists, the project will be build - if (-not (Test-Path $testAssembly)) { - Invoke-Build $testProject - } - - $openCoverAgs = "-target:$global:NunitCli", "-targetargs:/config:$env:MORYX_BUILD_CONFIG /result:$nunitXml $testAssembly" - } - - $openCoverAgs += "-log:Debug", "-register:administrator", "-output:$openCoverXml", "-hideskipped:all", "-skipautoprops"; - $openCoverAgs += "-returntargetcode" # We need the nunit return code - $openCoverAgs += "-filter:$includeFilter $excludeFilter" - - & $global:OpenCoverCli $openCoverAgs - - $exitCode = [int]::Parse($LastExitCode); - if ($exitCode -ne 0) { - $errorText = ""; - switch ($exitCode) { - -1 { $errorText = "INVALID_ARG"; } - -2 { $errorText = "INVALID_ASSEMBLY"; } - -4 { $errorText = "INVALID_TEST_FIXTURE"; } - -5 { $errorText = "UNLOAD_ERROR"; } - Default { $errorText = "UNEXPECTED_ERROR"; } - } - - if ($exitCode -gt 0) { - $errorText = "FAILED_TESTS ($exitCode)"; - } - - Write-Host-Error "Nunit exited with $errorText for $projectName"; - Invoke-ExitCodeCheck $exitCode; - } - - & $global:OpenCoverToCoberturaCli -input:$openCoverXml -output:$coberturaXml -sources:$rootPath - Invoke-ExitCodeCheck $LastExitCode; - } -} - -function Get-CsprojIsNetCore($CsprojItem) { - [xml]$csprojContent = Get-Content $CsprojItem.FullName - $sdkProject = $csprojContent.Project.Sdk; - if ($null -ne $sdkProject) { - # Read Target Framework - $targetFramework = $csprojContent.Project.PropertyGroup.TargetFramework; - if ($targetFramework -Match "netcoreapp" -or $targetFramework -Match "net5.") { - # NETCore - return $true; - } - } - return $false; -} - -function Get-CsprojIsSdkProject($CsprojItem) { - [xml]$csprojContent = Get-Content $CsprojItem.FullName - $sdkProject = $csprojContent.Project.Sdk; - if ($null -ne $sdkProject) { - return $true; - } - return $false; -} - -function Invoke-CoverReport { - Write-Step "Creating cover report. Searching for OpenCover.xml files in $OpenCoverReportsDir." - - if (-not (Test-Path $OpenCoverReportsDir)) { - Write-Host-Error "$OpenCoverReportsDir was not found!"; - Invoke-ExitCodeCheck 1; - } - - if (-not (Test-Path $global:ReportGeneratorCli)) { - Install-Tool "ReportGenerator" $ReportGeneratorVersion $global:ReportGeneratorCli; - } - - $reports = (Get-ChildItem $OpenCoverReportsDir -Recurse -Include '*.OpenCover.xml'); - $asArgument = [string]::Join(";",$reports); - - CreateFolderIfNotExists $DocumentationArtifcacts; - - & $global:ReportGeneratorCli -reports:"$asArgument" -targetDir:"$DocumentationArtifcacts/OpenCover" - Invoke-ExitCodeCheck $LastExitCode; -} - -function Invoke-DocFx($Metadata = [System.IO.Path]::Combine($DocumentationDir, "docfx.json")) { - Write-Step "Generating documentation using DocFx" - - if (-not (Test-Path $Metadata)) { - Write-Host-Error "Metadata was not found at: $Metadata!" - Invoke-ExitCodeCheck 1; - } - - if (-not (Test-Path $global:DocFxCli)) { - Install-Tool "docfx.console" $DocFxVersion $global:DocFxCli; - } - - $docFxObj = (Get-Content $Metadata) | ConvertFrom-Json; - $metadataFolder = [System.IO.Path]::GetDirectoryName($Metadata); - $docFxDest = [System.IO.Path]::Combine($metadataFolder, $docFxObj.build.dest); - - & $global:DocFxCli $Metadata; - Invoke-ExitCodeCheck $LastExitCode; - - CreateFolderIfNotExists $DocumentationArtifcacts; - CopyAndReplaceFolder $docFxDest "$DocumentationArtifcacts\DocFx"; -} - -function Invoke-PackSdkProject($CsprojItem, [bool]$IncludeSymbols = $False) { - Write-Host "Try to pack .NET SDK project: $($CsprojItem.Name) ..."; - - # Check if the project should be packed - $csprojFullName = $CsprojItem.FullName; - [xml]$csprojContent = Get-Content $csprojFullName - $createPackage = $csprojContent.Project.PropertyGroup.CreatePackage; -; - if ($null -eq $createPackage -or "false" -eq $createPackage) { - Write-Host-Warning "... csproj not flagged with true: $($CsprojItem.Name)"; - return; - } - - $packargs = "--output", "$NugetPackageArtifacts"; - $packargs += "--configuration", "$env:MORYX_BUILD_CONFIG"; - $packargs += "--verbosity", "$env:MORYX_NUGET_VERBOSITY"; - $packargs += "--no-build"; - - if ($IncludeSymbols) { - $packargs += "--include-symbols"; - $packargs += "--include-source"; - } - - & $global:DotNetCli pack "$csprojFullName" @packargs - Invoke-ExitCodeCheck $LastExitCode; -} - -function Invoke-PackFrameworkProject($CsprojItem, [bool]$IsTool = $False, [bool]$IncludeSymbols = $False) { - Write-Host "Try to pack .NET Framework project: $CsprojItem.Name ..."; - - # Check if there is a matching nuspec for the proj - $csprojFullName = $CsprojItem.FullName; - $nuspecPath = [IO.Path]::ChangeExtension($csprojFullName, "nuspec") - if(-not (Test-Path $nuspecPath)) { - Write-Host-Warning "Nuspec for project not found: $CsprojItem.Name"; - return; - } - - $packargs = "-outputdirectory", "$NugetPackageArtifacts"; - $packargs += "-includereferencedprojects"; - $packargs += "-Version", "$env:MORYX_PACKAGE_VERSION"; - $packargs += "-Prop", "Configuration=$env:MORYX_BUILD_CONFIG"; - $packargs += "-Verbosity", "$env:MORYX_NUGET_VERBOSITY"; - - if ($IncludeSymbols) { - $packargs += "-Symbols"; - } - - if ($IsTool) { - $packargs += "-Tool"; - } - - # Call nuget with default arguments plus optional - & $global:NugetCli pack "$csprojFullName" @packargs - Invoke-ExitCodeCheck $LastExitCode; -} - -function Invoke-Pack($ProjectItem, [bool]$IsTool = $False, [bool]$IncludeSymbols = $False) { - CreateFolderIfNotExists $NugetPackageArtifacts; - - if (Get-CsprojIsSdkProject($ProjectItem)) { - Invoke-PackSdkProject $ProjectItem $IncludeSymbols; - } - else { - Invoke-PackFrameworkProject $ProjectItem $IsTool $IncludeSymbols; - } -} - -function Invoke-PackAll([switch]$Symbols = $False) { - Write-Host "Looking for .csproj files..." - # Look for csproj in this directory - foreach ($csprojItem in Get-ChildItem $RootPath -Recurse -Filter *.csproj) { - Invoke-Pack -ProjectItem $csprojItem -IncludeSymbols $Symbols - } -} - -function Invoke-Publish { - Write-Host "Pushing packages from $NugetPackageArtifacts to $env:MORYX_PACKAGE_TARGET" - - $packages = Get-ChildItem $NugetPackageArtifacts -Recurse -Include *.nupkg - if ($packages.Length -gt 0 -and [string]::IsNullOrEmpty($env:MORYX_PACKAGE_TARGET)) { - Write-Host-Error "There is no package target given. Set the environment varialble MORYX_PACKAGE_TARGET to publish packages."; - Invoke-ExitCodeCheck 1; - } - - foreach ($package in $packages) { - Write-Host "Pushing package $package" - & $global:DotNetCli nuget push $package --api-key $env:MORYX_NUGET_APIKEY --no-symbols --skip-duplicate --source $env:MORYX_PACKAGE_TARGET - Invoke-ExitCodeCheck $LastExitCode; - } - - $symbolPackages = Get-ChildItem $NugetPackageArtifacts -Recurse -Include *.snupkg - if ($symbolPackages.Length -gt 0 -and [string]::IsNullOrEmpty($env:MORYX_PACKAGE_TARGET_V3)) { - Write-Host-Error "There is no package (v3) target given. Set the environment varialble MORYX_PACKAGE_TARGET_V3 to publish snupkg symbol packages."; - Invoke-ExitCodeCheck 1; - } - - foreach ($symbolPackage in $symbolPackages) { - Write-Host "Pushing symbol (snupkg) $symbolPackage" - & $global:DotNetCli nuget push $symbolPackage --api-key $env:MORYX_NUGET_APIKEY --skip-duplicate --source $env:MORYX_PACKAGE_TARGET_V3 - Invoke-ExitCodeCheck $LastExitCode; - } -} - -function Set-Version ([string]$MajorMinorPatch) { - $semVer2Regex = "^(?0|[1-9]\d*)\.(?0|[1-9]\d*)\.(?0|[1-9]\d*)(?:-(?(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"; - - $version = Read-VersionFromRef($MajorMinorPatch); - Write-Host "Setting environment version to $version"; - - # Match semVer2 regex - $regexMatch = [regex]::Match($version, $semVer2Regex); - - if (-not $regexMatch.Success) { - Write-Host "Could not parse version: $version"; - Invoke-ExitCodeCheck 1; - } - - # Extract groups - $matchgroups = $regexMatch.captures.groups; - $majorGroup = $matchgroups[1]; - $minorGroup = $matchgroups[2]; - $patchGroup = $matchgroups[3]; - $preReleaseGroup = $matchgroups[4]; - - # Compose Major.Minor.Patch - $mmp = $majorGroup.Value + "." + $minorGroup.Value + "." + $patchGroup.Value; - - # Check if it is a pre release - $env:MORYX_ASSEMBLY_VERSION = $majorGroup.Value + ".0.0.0" # 3.0.0.0 - $env:MORYX_FILE_VERSION = $mmp + "." + $env:MORYX_BUILDNUMBER; # 3.1.2.42 - - if ($preReleaseGroup.Success) { - $env:MORYX_INFORMATIONAL_VERSION = $mmp + "-" + $preReleaseGroup.Value + "+" + $global:GitCommitHash; # 3.1.2-beta.1+d95a996ed5ba14a1421dafeb844a56ab08211ead - $env:MORYX_PACKAGE_VERSION = $mmp + "-" + $preReleaseGroup.Value; - } else { - $env:MORYX_INFORMATIONAL_VERSION = $mmp + "+" + $global:GitCommitHash; # 3.1.2+d95a996ed5ba14a1421dafeb844a56ab08211ead - $env:MORYX_PACKAGE_VERSION = $mmp; - } -} - -function Read-VersionFromRef([string]$MajorMinorPatch) { - function preReleaseVersion ([string] $name) - { - $name = $name.Replace("/","").ToLower(); - return "$MajorMinorPatch-$name.$env:MORYX_BUILDNUMBER";; - } - - $ref = ""; - if ($env:GITHUB_WORKFLOW) { # GitHub Workflow - Write-Host "Reading version from 'GitHub Workflow'"; - $ref = $env:GITHUB_REF; - - if ($ref.StartsWith("refs/tags/")) { - if ($ref.StartsWith("refs/tags/v")) { - # Its a version tag - $version = $ref.Replace("refs/tags/v","") - } - else { - # Just a tag - $name = $ref.Replace("refs/tags/",""); - $version = = preReleaseVersion($name); - } - } - elseif ($ref.StartsWith("refs/heads/")) { - # Its a branch - $name = $ref.Replace("refs/heads/",""); - $version = preReleaseVersion($name); - } - else { - $version = preReleaseVersion($ref); - } - } - else { # Local build - Write-Host "Reading version from 'local'"; - $ref = (& $global:GitCli rev-parse --abbrev-ref HEAD); - $version = preReleaseVersion($ref); - } - - return $version; -} - -function Set-AssemblyVersion([string]$InputFile) { - $file = Get-Childitem -Path $inputFile; - - if (-Not $file) { - Write-Host "AssemblyInfo: $inputFile was not found!"; - exit 1; - } - - Write-Host "Applying assembly info of $($file.FullName) -> $env:MORYX_ASSEMBLY_VERSION "; - - $assemblyVersionPattern = 'AssemblyVersion\("[0-9]+(\.([0-9]+)){3}"\)'; - $assemblyVersion = 'AssemblyVersion("' + $env:MORYX_ASSEMBLY_VERSION + '")'; - - $assemblyFileVersionPattern = 'AssemblyFileVersion\("[0-9]+(\.([0-9]+)){3}"\)'; - $assemblyFileVersion = 'AssemblyFileVersion("' + $env:MORYX_FILE_VERSION + '")'; - - $assemblyInformationalVersionPattern = 'AssemblyInformationalVersion\("[0-9]+(\.([0-9]+)){3}"\)'; - $assemblyInformationalVersion = 'AssemblyInformationalVersion("' + $env:MORYX_INFORMATIONAL_VERSION + '")'; - - $assemblyConfigurationPattern = 'AssemblyConfiguration\("\w+"\)'; - $assemblyConfiguration = 'AssemblyConfiguration("' + $env:MORYX_BUILD_CONFIG + '")'; - - $content = (Get-Content $file.FullName) | ForEach-Object { - ForEach-Object {$_ -replace $assemblyVersionPattern, $assemblyVersion } | - ForEach-Object {$_ -replace $assemblyFileVersionPattern, $assemblyFileVersion } | - ForEach-Object {$_ -replace $assemblyInformationalVersionPattern, $assemblyInformationalVersion } | - ForEach-Object {$_ -replace $assemblyConfigurationPattern, $assemblyConfiguration } - } - - Out-File -InputObject $content -FilePath $file.FullName -Encoding utf8; -} - -function Set-AssemblyVersions([string[]]$Ignored = $(), [string]$SearchPath = $RootPath) { - $Ignored = $Ignored + "\\.build\\" + "\\Tests\\" + "\\IntegrationTests\\" + "\\SystemTests\\"; - - $assemblyInfos = Get-ChildItem -Path $RootPath -include "*AssemblyInfo.cs" -Recurse | Where-Object { - $fullName = $_.FullName; - return -not ($Ignored.Where({ $fullName -match $_ }).Count -gt 0); - } - - if ($assemblyInfos) - { - Write-Host "Will apply version to $($assemblyInfos.Count) AssemblyInfos."; - foreach ($file in $assemblyInfos) { - Set-AssemblyVersion -InputFile $file; - } - } -} - -function CreateFolderIfNotExists([string]$Folder) { - if (-not (Test-Path $Folder)) { - Write-Host "Creating missing directory '$Folder'" - New-Item $Folder -Type Directory | Out-Null - } -} - -function CopyAndReplaceFolder($SourceDir, $TargetDir) { - Write-Host-Info "Copy $SourceDir to $TargetDir!" - # Remove old folder if exists - if (Test-Path $TargetDir) { - Write-Host "Target path already exists, removing ..." -ForegroundColor Yellow - Remove-Item -Recurse -Force $TargetDir - } - - # Copy to target path - Write-Host "Copy from $SourceDir to $TargetDir ..." -ForegroundColor Green - Copy-Item -Path $SourceDir -Recurse -Destination $TargetDir -Container -} diff --git a/.build/Output.ps1 b/.build/Output.ps1 deleted file mode 100644 index 913f5577b..000000000 --- a/.build/Output.ps1 +++ /dev/null @@ -1,36 +0,0 @@ -################################ -# Functions for Console Output # -################################ - -function Write-Step([string]$step) { - Write-Host "########################################################################################################" -foreground Magenta; - Write-Host "#### $step" -foreground Magenta; - Write-Host "########################################################################################################" -foreground Magenta -} - -function Write-Variable ([string]$variableName, [string]$variableValue) { - Write-Host ($variableName + " = " + $variableValue) -} - -function Invoke-ExitCodeCheck([string]$exitCode) { - if ([int]::Parse($exitCode) -gt 0) { - Write-Host "This is the end, you know (ExitCode: $exitCode) - Lady, the plans we had went all wrong - We ain't nothing but fight and shout and tears." -ForegroundColor Red - exit $exitCode; - } -} - -function Write-Host-Info([string]$message) { - Write-Host $message -} - -function Write-Host-Success([string]$message) { - Write-Host $message -ForegroundColor Green -} - -function Write-Host-Warning([string]$message) { - Write-Host $message -ForegroundColor Yellow -} - -function Write-Host-Error([string]$message) { - Write-Host $message -ForegroundColor Red -} \ No newline at end of file diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index a6f81c1c2..fde8ac4b0 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -12,94 +12,87 @@ on: branches: - dev - future - + env: - MORYX_OPTIMIZE_CODE: "false" - MORYX_BUILD_CONFIG: "Release" - MORYX_BUILDNUMBER: ${{github.run_number}} - dotnet_sdk_version: '7.x' - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + dotnet_sdk_version: '8.0.100' REPOSITORY_NAME: ${{ github.event.repository.name }} + MORYX_PACKAGE_TARGET_DEV: 'https://www.myget.org/F/moryx-oss-ci/api/v2/package' + MORYX_PACKAGE_TARGET_V3_DEV: 'https://www.myget.org/F/moryx-oss-ci/api/v3/index.json' + MORYX_PACKAGE_TARGET_FUTURE: 'https://www.myget.org/F/moryx-oss-ci/api/v2/package' + MORYX_PACKAGE_TARGET_V3_FUTURE: 'https://www.myget.org/F/moryx-oss-ci/api/v3/index.json' + MORYX_PACKAGE_TARGET_RELEASE: 'https://api.nuget.org/v3/index.json' + MORYX_PACKAGE_TARGET_V3_RELEASE: 'https://api.nuget.org/v3/index.json' jobs: + EnvVar: + runs-on: ubuntu-latest + steps: + - run: echo "" + outputs: + dotnet_sdk_version: ${{ env.dotnet_sdk_version }} + REPOSITORY_NAME: ${{ env.REPOSITORY_NAME }} + MORYX_PACKAGE_TARGET_DEV: ${{ env.MORYX_PACKAGE_TARGET_DEV }} + MORYX_PACKAGE_TARGET_V3_DEV: ${{ env.MORYX_PACKAGE_TARGET_V3_DEV }} + MORYX_PACKAGE_TARGET_FUTURE: ${{ env.MORYX_PACKAGE_TARGET_FUTURE }} + MORYX_PACKAGE_TARGET_V3_FUTURE: ${{ env.MORYX_PACKAGE_TARGET_V3_FUTURE }} + MORYX_PACKAGE_TARGET_RELEASE: ${{ env.MORYX_PACKAGE_TARGET_RELEASE }} + MORYX_PACKAGE_TARGET_V3_RELEASE: ${{ env.MORYX_PACKAGE_TARGET_V3_RELEASE }} + Build: - uses: PHOENIXCONTACT/tools/.github/workflows/build-tool.yml@release-6 + needs: [EnvVar] + uses: phoenixcontact/tools/.github/workflows/build-tool.yml@main with: - MORYX_OPTIMIZE_CODE: "false" - MORYX_BUILD_CONFIG: "Release" - MORYX_BUILDNUMBER: ${{github.run_number}} - dotnet_sdk_version: '7.x' - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - REPOSITORY_NAME: ${{ github.event.repository.name }} + dotnet_sdk_version: ${{ needs.EnvVar.outputs.dotnet_sdk_version }} + REPOSITORY_NAME: ${{ needs.EnvVar.outputs.REPOSITORY_NAME }} UnitTests: - needs: [Build] - uses: PHOENIXCONTACT/tools/.github/workflows/unittest-tool.yml@release-6 + needs: [EnvVar, Build] + uses: phoenixcontact/tools/.github/workflows/unittest-tool.yml@main with: - MORYX_OPTIMIZE_CODE: "false" - MORYX_BUILD_CONFIG: "Release" - MORYX_BUILDNUMBER: ${{github.run_number}} - dotnet_sdk_version: '7.x' - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - REPOSITORY_NAME: ${{ github.event.repository.name }} + dotnet_sdk_version: ${{ needs.EnvVar.outputs.dotnet_sdk_version }} + REPOSITORY_NAME: ${{ needs.EnvVar.outputs.REPOSITORY_NAME }} IntegrationTests: - needs: [Build] - uses: PHOENIXCONTACT/tools/.github/workflows/integrationtest-tool.yml@release-6 + needs: [EnvVar, Build] + uses: phoenixcontact/tools/.github/workflows/integrationtest-tool.yml@main with: - MORYX_OPTIMIZE_CODE: "false" - MORYX_BUILD_CONFIG: "Release" - MORYX_BUILDNUMBER: ${{github.run_number}} - dotnet_sdk_version: '7.x' - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - REPOSITORY_NAME: ${{ github.event.repository.name }} + dotnet_sdk_version: ${{ needs.EnvVar.outputs.dotnet_sdk_version }} + REPOSITORY_NAME: ${{ needs.EnvVar.outputs.REPOSITORY_NAME }} ReportGenerator: - needs: [UnitTests, IntegrationTests] - uses: PHOENIXCONTACT/tools/.github/workflows/reportgenerator-tool.yml@release-6 + needs: [EnvVar, UnitTests, IntegrationTests] + uses: phoenixcontact/tools/.github/workflows/reportgenerator-tool.yml@main with: - MORYX_OPTIMIZE_CODE: "false" - MORYX_BUILD_CONFIG: "Release" - MORYX_BUILDNUMBER: ${{github.run_number}} - dotnet_sdk_version: '7.x' - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - REPOSITORY_NAME: ${{ github.event.repository.name }} + REPOSITORY_NAME: ${{ needs.EnvVar.outputs.REPOSITORY_NAME }} Publish-Test-Coverage: - needs: [ReportGenerator] - uses: PHOENIXCONTACT/tools/.github/workflows/publish-test-coverage-tool.yml@release-6 + needs: [EnvVar, ReportGenerator] + uses: phoenixcontact/tools/.github/workflows/publish-test-coverage-tool.yml@main with: - MORYX_OPTIMIZE_CODE: "false" - MORYX_BUILD_CONFIG: "Release" - MORYX_BUILDNUMBER: ${{github.run_number}} - dotnet_sdk_version: '7.x' - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - REPOSITORY_NAME: ${{ github.event.repository.name }} + REPOSITORY_NAME: ${{ needs.EnvVar.outputs.REPOSITORY_NAME }} secrets: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - Documentation: - needs: [UnitTests] - uses: PHOENIXCONTACT/tools/.github/workflows/documentation-tool.yml@release-6 - with: - MORYX_OPTIMIZE_CODE: "false" - MORYX_BUILD_CONFIG: "Release" - MORYX_BUILDNUMBER: ${{github.run_number}} - dotnet_sdk_version: '7.x' - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - REPOSITORY_NAME: ${{ github.event.repository.name }} + # currently not working + # Documentation: + # needs: [EnvVar, UnitTests] + # uses: phoenixcontact/tools/.github/workflows/documentation-tool.yml@main + # with: + # REPOSITORY_NAME: ${{ needs.EnvVar.outputs.REPOSITORY_NAME }} Publish: - needs: [UnitTests] - uses: PHOENIXCONTACT/tools/.github/workflows/publish-tool.yml@release-6 + needs: [EnvVar, UnitTests] + uses: phoenixcontact/tools/.github/workflows/publish-tool.yml@main with: - MORYX_OPTIMIZE_CODE: "false" - MORYX_BUILD_CONFIG: "Release" - MORYX_BUILDNUMBER: ${{github.run_number}} - dotnet_sdk_version: '7.x' - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - REPOSITORY_NAME: ${{ github.event.repository.name }} + dotnet_sdk_version: ${{ needs.EnvVar.outputs.dotnet_sdk_version }} + REPOSITORY_NAME: ${{ needs.EnvVar.outputs.REPOSITORY_NAME }} + MORYX_PACKAGE_TARGET_DEV: ${{ needs.EnvVar.outputs.MORYX_PACKAGE_TARGET_DEV }} + MORYX_PACKAGE_TARGET_V3_DEV: ${{ needs.EnvVar.outputs.MORYX_PACKAGE_TARGET_V3_DEV }} + MORYX_PACKAGE_TARGET_FUTURE: ${{ needs.EnvVar.outputs.MORYX_PACKAGE_TARGET_FUTURE }} + MORYX_PACKAGE_TARGET_V3_FUTURE: ${{ needs.EnvVar.outputs.MORYX_PACKAGE_TARGET_V3_FUTURE }} + MORYX_PACKAGE_TARGET_RELEASE: ${{ needs.EnvVar.outputs.MORYX_PACKAGE_TARGET_RELEASE }} + MORYX_PACKAGE_TARGET_V3_RELEASE: ${{ needs.EnvVar.outputs.MORYX_PACKAGE_TARGET_V3_RELEASE }} secrets: MYGET_TOKEN: ${{secrets.MYGET_TOKEN}} NUGET_TOKEN: ${{secrets.NUGET_TOKEN}} diff --git a/Build.ps1 b/Build.ps1 deleted file mode 100644 index 4b65211d1..000000000 --- a/Build.ps1 +++ /dev/null @@ -1,63 +0,0 @@ -param ( - [switch]$SetAssemblyVersion, - [switch]$Build, - - [switch]$SmokeTests, - [switch]$UnitTests, - [switch]$IntegrationTests, - [switch]$SystemTests, - - [switch]$CoverReport, - [switch]$GenerateDocs, - - [switch]$Pack, - [switch]$Publish -) - -# Load Toolkit -. ".build\BuildToolkit.ps1" - -# Set MSBuild to latest version -$MsBuildVersion = "latest"; - -# Initialize Toolkit -Invoke-Initialize -Version (Get-Content "VERSION"); - -if ($Build) { - Invoke-Build ".\MORYX-Framework.sln" -} - -if ($SmokeTests) { - $runtimePath = "$RootPath\src\StartProject\bin\$env:MORYX_BUILD_CONFIG\StartProject.exe"; - Invoke-SmokeTest $runtimePath 3 6000 -} - -if ($UnitTests) { - Invoke-CoverTests -SearchFilter "*.Tests.csproj" -} - -if ($IntegrationTests) { - Invoke-CoverTests -SearchFilter "*.IntegrationTests.csproj" -} - -if ($SystemTests) { - Invoke-CoverTests -SearchFilter "*.SystemTests.csproj" -} - -if ($CoverReport) { - Invoke-CoverReport -} - -if ($GenerateDocs) { - Invoke-DocFx -} - -if ($Pack) { - Invoke-PackAll -Symbols -} - -if ($Publish) { - Invoke-Publish -} - -Write-Host "Success!" \ No newline at end of file diff --git a/Directory.build.props b/Directory.Build.props similarity index 91% rename from Directory.build.props rename to Directory.Build.props index c735b57d6..a5baa5c61 100644 --- a/Directory.build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 10.0 + latest diff --git a/Directory.Build.targets b/Directory.Build.targets index 1d84decb3..d12d3f6bd 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,27 +1,28 @@ - + - 6.0.0 - 6.0.0 + 8.0.0 + 8.0.0 + latest - - - + + + - - - + + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -43,12 +44,10 @@ - + - - - + diff --git a/LICENSE b/LICENSE index f433b1a53..33f844f2c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION diff --git a/VERSION b/VERSION index dc0208aba..fbb9ea12d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.3.1 +8.2.0 diff --git a/docs/migrations/v6_to_v8.md b/docs/migrations/v6_to_v8.md new file mode 100644 index 000000000..7212ddae1 --- /dev/null +++ b/docs/migrations/v6_to_v8.md @@ -0,0 +1,29 @@ +# Migration from MORYX Framework v6 to v8 + + +## Local Container Refactoring +The DI container within modules based on Castle Windsor was refactored and simplified. The most changes are caused by removing the historic split between local and global container, which was obsolete after switching the global container to ServiceCollection. We also removed the concept of installers and registrators and replaced everything with API on `IContainer` and extensions inspired by the `IServiceCollection`. + +- **Attribute changes:** The base attributes for registration were removed, use `ComponentAttribute`, `PluginAttribute` and `PluginFactory` instead. +- **Installers removed** The concept of installes was removed and with it their implementations `AutoInstaller` and `DependencyInstaller`. They were replaced by the extensions `LoadFromAssembly` with different signature options for `DependencyRegistrationAttribute` and `Predicate` +- **LoadComponents** was removed as a dedicate feature and is now an extension on `IContainer`. It has also been restricted to public/exported types. +- **IContainerHost** was removed. The seperate interface for accessing a modules container just caused unnecessary casts and the risk of invalid type. The property `Container` was added to `IServerModule` instead. +- **Extend** The flexible method for passing facilities to Castle was removed as it was only added and used by WCF. +- **MoryxFacility** All MORYX specific behavior like strategies and `Named` import overrides were refactored to follow Castle best practises and are now isolated in the `MoryxFacility`. This enables everyone to achieve the MORYX DI behavior with a Castle Container without the MORYX wrapper. +- **Installers** As previously mentioned installers were removed, but since the API on `IContainer` now supports everything previously reserved for installers and registrators, just migrate the registration onto the container like the [DbContextContainerExtension](https://github.com/PHOENIXCONTACT/MORYX-Framework/blob/future/src/Moryx.Model/DbContextContainerExtension.cs) or the [BasicInterceptorInstaller](https://github.com/PHOENIXCONTACT/MORYX-Framework/blob/future/src/Moryx.TestTools.UnitTest/BasicInterceptorInstaller.cs) + +## ServerModuleBase + +To simplify development and prepare easier integration of the Moryx.Cli we merged the `ServerModuleFacadeControllerBase` into the `ServerModuleBase`. Just replace the base type if your module is affected by this. + +## GetObjectData(SerializationInfo info, StreamingContext context) + +Removed all overrides of the obsolete method `Exception.GetObjectData(SerializationInfo info, StreamingContext context)` as well as all constructors which were calling the base class constructor `Exception(SerializationInfo info, StreamingContext context)` +The following classes are affected by this change +- MissingFacadeException +- HealthStateException +- InvalidConfigException + +## Merged IPublicResource into IResource + +`IPublicResource` and `IResource` were merged into `IResource`, since the differentiaten between those was hard to understand for some and barely had any real world advantages. Now literally "Everything is a resource". \ No newline at end of file diff --git a/docs/tutorials/HowToCreateAProduct.md b/docs/tutorials/HowToCreateAProduct.md index c62cb9f8e..2a00fdc6f 100644 --- a/docs/tutorials/HowToCreateAProduct.md +++ b/docs/tutorials/HowToCreateAProduct.md @@ -1,11 +1,11 @@ --- uid: HowToCreateAProduct --- -# How to create a resource +# How to create a product This tutorial shows how [Products](../../src/Moryx.AbstractionLayer/Products/ProductType.cs) should be implemented. Look [here](../articles/Products/Concept.md) if you are not firm with the concept of a `Product`. -For products we differentiate between [ProductType](../../src/Moryx.AbstractionLayer/Products/ProductType.cs) and [ProductInstance](../../src/Moryx.AbstractionLayer/Products/ProductInstance.cs). The `ProductType` is what you can order in a catalog, while the `ProductInstance` is what you received after ordering: an instance of the product with its unique serialnumber. So that a `ProductType` can be producted it needs a corresponding `ProductInstance`. If your application isn't used for production, you can skip the `ProductInstances`. +For products we differentiate between [ProductType](../../src/Moryx.AbstractionLayer/Products/ProductType.cs) and [ProductInstance](../../src/Moryx.AbstractionLayer/Products/ProductInstance.cs). The `ProductType` is what you can order in a catalog, while the `ProductInstance` is what you received after ordering: an instance of the product with its unique serialnumber. So that a `ProductType` can be produced it needs a corresponding `ProductInstance`. If your application isn't used for production, you can skip the `ProductInstances`. ## Create a basic ProductType and ProductInstance All ProductTypes are derived from `ProductType`. The methode `Instantiate()` returns an object of the correspoding `ProductInstance`. diff --git a/docs/tutorials/HowToTestAModule.md b/docs/tutorials/HowToTestAModule.md index 2796eecf6..0ee512088 100644 --- a/docs/tutorials/HowToTestAModule.md +++ b/docs/tutorials/HowToTestAModule.md @@ -3,7 +3,7 @@ In order to test a module in its lifecycle with its respective facade we offer the `Moryx.TestTools.IntegrationTest`. The package brings a `MoryxTestEnvironment`. With this class you can first create mocks for all module facades your module dependents on using the static `CreateModuleMock` method. -Afterwards you can create the environment using an implementation of the `ServerModuleFacadeControllerBase`, an instance of the `ConfigBase` and the set of dependency mocks. +Afterwards you can create the environment using an implementation of the `ServerModuleBase` class, an instance of the `ConfigBase` and the set of dependency mocks. The first two parameters are usually your `ModuleController` and your `ModuleConfig`. The following example shows a setup for the `IShiftManagement` facade interface. The module depends on the `IResourceManagement` and `IOperatorManagement` facades. diff --git a/src/Moryx.AbstractionLayer.Products.Endpoints/Moryx.AbstractionLayer.Products.Endpoints.csproj b/src/Moryx.AbstractionLayer.Products.Endpoints/Moryx.AbstractionLayer.Products.Endpoints.csproj index 82b4823b5..6c7673222 100644 --- a/src/Moryx.AbstractionLayer.Products.Endpoints/Moryx.AbstractionLayer.Products.Endpoints.csproj +++ b/src/Moryx.AbstractionLayer.Products.Endpoints/Moryx.AbstractionLayer.Products.Endpoints.csproj @@ -1,10 +1,9 @@  - net6.0 + net8.0 Endpoints for the Product Facade true - true MORYX;IIoT;IoT; diff --git a/src/Moryx.AbstractionLayer.Products.Endpoints/ProductManagementController.cs b/src/Moryx.AbstractionLayer.Products.Endpoints/ProductManagementController.cs index 71654e272..516876d7e 100644 --- a/src/Moryx.AbstractionLayer.Products.Endpoints/ProductManagementController.cs +++ b/src/Moryx.AbstractionLayer.Products.Endpoints/ProductManagementController.cs @@ -18,7 +18,6 @@ using Moryx.AbstractionLayer.Resources; using Moryx.Runtime.Modules; using System.ComponentModel; -using Moryx.Runtime.Container; namespace Moryx.AbstractionLayer.Products.Endpoints { @@ -38,9 +37,8 @@ public ProductManagementController(IProductManagement productManagement, { _productManagement = productManagement; - var module = moduleManager.AllModules.FirstOrDefault(module => module is IFacadeContainer); - var host = (IContainerHost)module; - _productConverter = new ProductConverter(_productManagement, host.Container, serviceProvider); + var module = moduleManager.AllModules.FirstOrDefault(module => module is IFacadeContainer); + _productConverter = new ProductConverter(_productManagement, module.Container, serviceProvider); } #region importers @@ -188,7 +186,7 @@ public ActionResult GetTypeById(long id) { productType = _productManagement.LoadType(id); } - catch (ProductNotFoundException e) + catch (ProductNotFoundException) { } if (productType == null) diff --git a/src/Moryx.AbstractionLayer.Products.Endpoints/ProductPermissions.cs b/src/Moryx.AbstractionLayer.Products.Endpoints/ProductPermissions.cs index d9399c4d9..df0e1b110 100644 --- a/src/Moryx.AbstractionLayer.Products.Endpoints/ProductPermissions.cs +++ b/src/Moryx.AbstractionLayer.Products.Endpoints/ProductPermissions.cs @@ -1,15 +1,53 @@ namespace Moryx.AbstractionLayer.Products.Endpoints { + /// + /// Permissions used to authorize for the + /// public static class ProductPermissions { + /// + /// Prefix used for all permissions of the controller + /// private const string _prefix = "Moryx.Products."; + + /// + /// Permission for all actions related to viewing one or multiple product types + /// public const string CanViewTypes = _prefix + "CanViewTypes"; + + /// + /// Permission for all actions related to creating and editing recipes + /// public const string CanCreateAndEditRecipes = _prefix + "CanCreateAndEditRecipes"; + + /// + /// Permission for all actions related to editing one or multiple product types + /// public const string CanEditType = _prefix + "CanEditType"; + + /// + /// Permission for all actions related to duplicating one or multiple product types + /// public const string CanDuplicateType = _prefix + "CanDuplicateType"; + + /// + /// Permission for all actions related to see and execute a product importer + /// public const string CanImport = _prefix + "CanImport"; + + /// + /// Permission for all actions related to deleting one or multiple product types + /// public const string CanDeleteType = _prefix + "CanDeleteType"; + + /// + /// Permission for all actions related to viewing one or multiple product instances + /// public const string CanViewInstances = _prefix + "CanViewInstances"; + + /// + /// Permission for all actions related to creating one or multiple product instances + /// public const string CanCreateInstances = _prefix + "CanCreateInstances"; } } diff --git a/src/Moryx.AbstractionLayer.Products.Endpoints/WorkplanPermissions.cs b/src/Moryx.AbstractionLayer.Products.Endpoints/WorkplanPermissions.cs index d09a886fe..4ae545160 100644 --- a/src/Moryx.AbstractionLayer.Products.Endpoints/WorkplanPermissions.cs +++ b/src/Moryx.AbstractionLayer.Products.Endpoints/WorkplanPermissions.cs @@ -1,10 +1,28 @@ namespace Moryx.AbstractionLayer.Products.Endpoints { + /// + /// Permissions used to authorize for the + /// public static class WorkplanPermissions { + /// + /// Prefix used for all permissions of the controller + /// private const string _prefix = "Moryx.Workplans."; + + /// + /// Permission for all actions related to viewing one or multiple workplans + /// public const string CanView = _prefix + "CanView"; + + /// + /// Permission for all actions related to editing or creating one or multiple workplans + /// public const string CanEdit = _prefix + "CanEdit"; + + /// + /// Permission for all actions related to deleting one or multiple workplans + /// public const string CanDelete = _prefix + "CanDelete"; } } diff --git a/src/Moryx.AbstractionLayer.Resources.Endpoints/Moryx.AbstractionLayer.Resources.Endpoints.csproj b/src/Moryx.AbstractionLayer.Resources.Endpoints/Moryx.AbstractionLayer.Resources.Endpoints.csproj index 8c981b0b2..21907fa30 100644 --- a/src/Moryx.AbstractionLayer.Resources.Endpoints/Moryx.AbstractionLayer.Resources.Endpoints.csproj +++ b/src/Moryx.AbstractionLayer.Resources.Endpoints/Moryx.AbstractionLayer.Resources.Endpoints.csproj @@ -1,10 +1,9 @@ - + - net6.0 + net8.0 true REST Api in order to interact with the resource management - true MORYX;IIoT;IoT;Resource diff --git a/src/Moryx.AbstractionLayer.Resources.Endpoints/ResourceManagementController.cs b/src/Moryx.AbstractionLayer.Resources.Endpoints/ResourceManagementController.cs index 29b106227..15aca8484 100644 --- a/src/Moryx.AbstractionLayer.Resources.Endpoints/ResourceManagementController.cs +++ b/src/Moryx.AbstractionLayer.Resources.Endpoints/ResourceManagementController.cs @@ -15,7 +15,6 @@ using Moryx.Tools; using Moryx.AbstractionLayer.Properties; using Moryx.Runtime.Modules; -using Moryx.Runtime.Container; using Moryx.Configuration; namespace Moryx.AbstractionLayer.Resources.Endpoints @@ -40,8 +39,7 @@ public ResourceModificationController(IResourceManagement resourceManagement, _resourceManagement = resourceManagement ?? throw new ArgumentNullException(nameof(resourceManagement)); _resourceTypeTree = resourceTypeTree ?? throw new ArgumentNullException(nameof(resourceTypeTree)); var module = moduleManager.AllModules.FirstOrDefault(module => module is IFacadeContainer); - var containerHost = (IContainerHost)module; - _serialization = new ResourceSerialization(containerHost.Container, serviceProvider); + _serialization = new ResourceSerialization(module.Container, serviceProvider); } [HttpGet] @@ -64,7 +62,7 @@ public ActionResult GetDetailsBatch([FromQuery] long[] ids) var converter = new ResourceToModelConverter(_resourceTypeTree, _serialization); if (ids is null || ids.Length == 0) - ids = _resourceManagement.GetResources().Select(r => r.Id).ToArray(); + ids = _resourceManagement.GetResources().Select(r => r.Id).ToArray(); return ids.Select(id => _resourceManagement.Read(id, r => converter.GetDetails(r))) .Where(details => details != null).ToArray(); diff --git a/src/Moryx.AbstractionLayer.Resources.Endpoints/ResourcePermissions.cs b/src/Moryx.AbstractionLayer.Resources.Endpoints/ResourcePermissions.cs index 926f7dc64..4abe04817 100644 --- a/src/Moryx.AbstractionLayer.Resources.Endpoints/ResourcePermissions.cs +++ b/src/Moryx.AbstractionLayer.Resources.Endpoints/ResourcePermissions.cs @@ -1,14 +1,49 @@ namespace Moryx.AbstractionLayer.Resources.Endpoints { + /// + /// Permissions used to authorize for the + /// public static class ResourcePermissions { + /// + /// Prefix used for all permissions of the controller + /// private const string _prefix = "Moryx.Resources."; + + /// + /// Permission for all actions related to viewing the resource instance tree + /// public const string CanViewTree = _prefix + "CanViewTree"; + + /// + /// Permission for all actions related to viewing the instance information of a resource + /// public const string CanViewDetails = _prefix + "CanViewDetails"; + + /// + /// Permission for all actions related to editing the resource graph and its members + /// public const string CanEdit = _prefix + "CanEdit"; + + // ToDo: Rename permission to CanViewTypeTree + /// + /// Permission for all actions related to viewing the resource type tree + /// public const string CanViewTypeTree = _prefix + "CanAddResource"; + + /// + /// Permission for all actions related to adding one or multiple resources + /// public const string CanAdd = _prefix + "CanAdd"; + + /// + /// Permission for all actions related to adding one or multiple resources + /// public const string CanDelete = _prefix + "CanDelete"; + + /// + /// Permission for all actions related to invoking a method on a resource + /// public const string CanInvokeMethod = _prefix + "CanInvokeMethod"; } } diff --git a/src/Moryx.AbstractionLayer.TestTools/DummyProductPartLink.cs b/src/Moryx.AbstractionLayer.TestTools/DummyProductPartLink.cs index 1c7cc4098..f700d5988 100644 --- a/src/Moryx.AbstractionLayer.TestTools/DummyProductPartLink.cs +++ b/src/Moryx.AbstractionLayer.TestTools/DummyProductPartLink.cs @@ -11,6 +11,7 @@ namespace Moryx.AbstractionLayer.TestTools /// public class DummyProductPartLink : ProductPartLink { + /// public override bool Equals(object obj) { var toCompareWith = obj as DummyProductPartLink; diff --git a/src/Moryx.AbstractionLayer.TestTools/DummyProductRecipe.cs b/src/Moryx.AbstractionLayer.TestTools/DummyProductRecipe.cs index 41ce23945..0ee5ca41b 100644 --- a/src/Moryx.AbstractionLayer.TestTools/DummyProductRecipe.cs +++ b/src/Moryx.AbstractionLayer.TestTools/DummyProductRecipe.cs @@ -13,6 +13,7 @@ namespace Moryx.AbstractionLayer.TestTools /// public class DummyProductRecipe : ProductRecipe { + /// public override bool Equals(object obj) { var toCompareWith = obj as DummyProductRecipe; @@ -27,12 +28,18 @@ public override bool Equals(object obj) } } + /// + /// Dummy implementation of a workplan recipe. + /// public class DummyProductWorkplanRecipe : DummyProductRecipe, IWorkplanRecipe { + /// public IWorkplan Workplan { get; set; } + /// public ICollection DisabledSteps { get; set; } + /// public override bool Equals(object obj) { var toCompareWith = obj as DummyProductWorkplanRecipe; diff --git a/src/Moryx.AbstractionLayer.TestTools/DummyProductType.cs b/src/Moryx.AbstractionLayer.TestTools/DummyProductType.cs index 8ffecfaf1..54e9e029e 100644 --- a/src/Moryx.AbstractionLayer.TestTools/DummyProductType.cs +++ b/src/Moryx.AbstractionLayer.TestTools/DummyProductType.cs @@ -17,6 +17,7 @@ protected override ProductInstance Instantiate() { return new DummyProductInstance(); } +/// public override bool Equals(object obj) { @@ -51,6 +52,7 @@ protected override ProductInstance Instantiate() /// public IEnumerable ProductPartLinkEnumerable { get; set; } + /// public override bool Equals(object obj) { var toCompareWith = obj as DummyProductTypeWithParts; @@ -86,7 +88,8 @@ protected override ProductInstance Instantiate() /// Second dummy ProductFile /// public ProductFile SecondProductFile { get; set; } - + + /// public override bool Equals(object obj) { var toCompareWith = obj as DummyProductTypeWithFiles; diff --git a/src/Moryx.AbstractionLayer.TestTools/DummyWorkplan.cs b/src/Moryx.AbstractionLayer.TestTools/DummyWorkplan.cs index 0e131f0ab..db255b711 100644 --- a/src/Moryx.AbstractionLayer.TestTools/DummyWorkplan.cs +++ b/src/Moryx.AbstractionLayer.TestTools/DummyWorkplan.cs @@ -6,8 +6,12 @@ namespace Moryx.AbstractionLayer.TestTools { + /// + /// Dummy implementation of with overridden method for testing purposes. + /// public class DummyWorkplan : Workplan { + /// public override bool Equals(object obj) { var toCompareWith = obj as DummyWorkplan; diff --git a/src/Moryx.AbstractionLayer.TestTools/Moryx.AbstractionLayer.TestTools.csproj b/src/Moryx.AbstractionLayer.TestTools/Moryx.AbstractionLayer.TestTools.csproj index bde0a3899..d261b6e64 100644 --- a/src/Moryx.AbstractionLayer.TestTools/Moryx.AbstractionLayer.TestTools.csproj +++ b/src/Moryx.AbstractionLayer.TestTools/Moryx.AbstractionLayer.TestTools.csproj @@ -1,21 +1,15 @@  - net6.0 + net8.0 true Additional AbstractionLayer implementations for Tests - true MORYX;IIoT;IoT;Abstraction;Tests - - - - - diff --git a/src/Moryx.AbstractionLayer.TestTools/Resources/ResourceGraphMock.cs b/src/Moryx.AbstractionLayer.TestTools/Resources/ResourceGraphMock.cs index 895b3f867..8eb4b45e5 100644 --- a/src/Moryx.AbstractionLayer.TestTools/Resources/ResourceGraphMock.cs +++ b/src/Moryx.AbstractionLayer.TestTools/Resources/ResourceGraphMock.cs @@ -16,38 +16,48 @@ public class ResourceGraphMock : IResourceGraph { private IDictionary _typeMap; + /// + /// The list of resources in this graph + /// public List Graph { get; set; } + /// public Resource Get(long id) { return Graph.FirstOrDefault(r => r.Id == id); } + /// public TResource GetResource() where TResource : class, IResource { throw new NotImplementedException(); } + /// public TResource GetResource(long id) where TResource : class, IResource { throw new NotImplementedException(); } + /// public TResource GetResource(string name) where TResource : class, IResource { throw new NotImplementedException(); } + /// public TResource GetResource(Func predicate) where TResource : class, IResource { throw new NotImplementedException(); } + /// public IEnumerable GetResources() where TResource : class, IResource { throw new NotImplementedException(); } + /// public IEnumerable GetResources(Func predicate) where TResource : class, IResource { throw new NotImplementedException(); @@ -101,6 +111,7 @@ public bool Destroy(IResource resource, bool permanent) return Destroy(resource); } + /// public void Save(IResource resource) { } diff --git a/src/Moryx.AbstractionLayer/Moryx.AbstractionLayer.csproj b/src/Moryx.AbstractionLayer/Moryx.AbstractionLayer.csproj index 6ce2a84f3..f3779fc05 100644 --- a/src/Moryx.AbstractionLayer/Moryx.AbstractionLayer.csproj +++ b/src/Moryx.AbstractionLayer/Moryx.AbstractionLayer.csproj @@ -1,10 +1,9 @@  - netstandard2.0;net6.0 + netstandard2.0;net8.0 true Domain model types and definitions of Cyber-physical systems in IIoT projects. - true MORYX;IIoT;IoT;Hardware;Communication;Manufacturing;Industrial;Abstraction;Realtime diff --git a/src/Moryx.AbstractionLayer/Process/ProcessBindingResolverFactory.cs b/src/Moryx.AbstractionLayer/Process/ProcessBindingResolverFactory.cs index 85ad9684a..2359bdbd7 100644 --- a/src/Moryx.AbstractionLayer/Process/ProcessBindingResolverFactory.cs +++ b/src/Moryx.AbstractionLayer/Process/ProcessBindingResolverFactory.cs @@ -127,6 +127,10 @@ public class ProductResolver : BindingResolverBase { private readonly string _fallbackProperty; + /// + /// Creates a new + /// + /// public ProductResolver(string fallbackProperty) { _fallbackProperty = fallbackProperty; diff --git a/src/Moryx.AbstractionLayer/Resources/IPublicResource.cs b/src/Moryx.AbstractionLayer/Resources/IPublicResource.cs deleted file mode 100644 index 0abe142e8..000000000 --- a/src/Moryx.AbstractionLayer/Resources/IPublicResource.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; -using Moryx.AbstractionLayer.Capabilities; - -namespace Moryx.AbstractionLayer.Resources -{ - /// - /// Interface for resources that are visible outside of the abstraction layer - /// - public interface IPublicResource : IResource - { - /// - /// The resource's capabilities - /// - ICapabilities Capabilities { get; } - - /// - /// Raised when the capabilities have changed. - /// - event EventHandler CapabilitiesChanged; - } -} diff --git a/src/Moryx.AbstractionLayer/Resources/IResource.cs b/src/Moryx.AbstractionLayer/Resources/IResource.cs index 60bad43ec..112617ebe 100644 --- a/src/Moryx.AbstractionLayer/Resources/IResource.cs +++ b/src/Moryx.AbstractionLayer/Resources/IResource.cs @@ -1,6 +1,9 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +using Moryx.AbstractionLayer.Capabilities; +using System; + namespace Moryx.AbstractionLayer.Resources { /// @@ -17,5 +20,15 @@ public interface IResource /// Name of this resource instance /// string Name { get; } + + /// + /// The resource's capabilities + /// + ICapabilities Capabilities { get; } + + /// + /// Raised when the capabilities have changed. + /// + event EventHandler CapabilitiesChanged; } } diff --git a/src/Moryx.AbstractionLayer/Resources/IResourceManagement.cs b/src/Moryx.AbstractionLayer/Resources/IResourceManagement.cs index 631a11cad..9e8bf7771 100644 --- a/src/Moryx.AbstractionLayer/Resources/IResourceManagement.cs +++ b/src/Moryx.AbstractionLayer/Resources/IResourceManagement.cs @@ -16,51 +16,51 @@ public interface IResourceManagement /// Get only resources of this type /// TResource GetResource() - where TResource : class, IPublicResource; + where TResource : class, IResource; /// /// Get typed resource by id /// TResource GetResource(long id) - where TResource : class, IPublicResource; + where TResource : class, IResource; /// /// Get typed resource by name /// TResource GetResource(string name) - where TResource : class, IPublicResource; + where TResource : class, IResource; /// /// Get the only resource that provides the required capabilities. /// /// Instance if only one match was found, otherwise null TResource GetResource(ICapabilities requiredCapabilities) - where TResource : class, IPublicResource; + where TResource : class, IResource; /// /// Get the only resource that matches the given predicate /// /// Instance if only one match was found, otherwise null TResource GetResource(Func predicate) - where TResource : class, IPublicResource; + where TResource : class, IResource; /// /// Get all resources of this type /// IEnumerable GetResources() - where TResource : class, IPublicResource; + where TResource : class, IResource; /// /// Get all resources of this type that provide the required capabilities /// IEnumerable GetResources(ICapabilities requiredCapabilities) - where TResource : class, IPublicResource; + where TResource : class, IResource; /// /// Get all resources of this type that match the predicate /// IEnumerable GetResources(Func predicate) - where TResource : class, IPublicResource; + where TResource : class, IResource; /// /// Get all resources inluding the private ones of this type that match the predicate @@ -95,12 +95,12 @@ IEnumerable GetAllResources(Func predicat /// /// Event raised when a resource was added at runtime /// - event EventHandler ResourceAdded; + event EventHandler ResourceAdded; /// /// Event raised when a resource was removed at runtime /// - event EventHandler ResourceRemoved; + event EventHandler ResourceRemoved; /// /// Raised when the capabilities have changed. diff --git a/src/Moryx.AbstractionLayer/Resources/PublicResource.cs b/src/Moryx.AbstractionLayer/Resources/PublicResource.cs deleted file mode 100644 index b098c5b02..000000000 --- a/src/Moryx.AbstractionLayer/Resources/PublicResource.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; -using Moryx.AbstractionLayer.Capabilities; - -namespace Moryx.AbstractionLayer.Resources -{ - /// - /// Base class for all public resources - /// - public abstract class PublicResource : Resource, IPublicResource - { - /// - /// Current capabilities of this resource - /// - private ICapabilities _capabilities = NullCapabilities.Instance; - - /// - public ICapabilities Capabilities - { - get - { - return _capabilities; - } - protected set - { - _capabilities = value; - CapabilitiesChanged?.Invoke(this, _capabilities); - } - } - - /// - /// - /// - public event EventHandler CapabilitiesChanged; - } -} diff --git a/src/Moryx.AbstractionLayer/Resources/Resource.cs b/src/Moryx.AbstractionLayer/Resources/Resource.cs index edb9430bf..c2d520d2a 100644 --- a/src/Moryx.AbstractionLayer/Resources/Resource.cs +++ b/src/Moryx.AbstractionLayer/Resources/Resource.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.Serialization; using Microsoft.Extensions.Logging; +using Moryx.AbstractionLayer.Capabilities; using Moryx.Logging; using Moryx.Modules; using Moryx.Serialization; @@ -144,6 +145,31 @@ public override string ToString() return $"{Id}:{Name} ({GetType().Name})"; } + + /// + /// Current capabilities of this resource + /// + private ICapabilities _capabilities = NullCapabilities.Instance; + + /// + public ICapabilities Capabilities + { + get + { + return _capabilities; + } + protected set + { + _capabilities = value; + CapabilitiesChanged?.Invoke(this, _capabilities); + } + } + + /// + /// + /// + public event EventHandler CapabilitiesChanged; + /// /// Event raised when the resource was modified and the changes should be /// written to the data storage diff --git a/src/Moryx.Asp.Extensions/Moryx.Asp.Extensions.csproj b/src/Moryx.Asp.Extensions/Moryx.Asp.Extensions.csproj index ea47f4474..27255d156 100644 --- a/src/Moryx.Asp.Extensions/Moryx.Asp.Extensions.csproj +++ b/src/Moryx.Asp.Extensions/Moryx.Asp.Extensions.csproj @@ -1,9 +1,8 @@ - net6.0 + net8.0 Extensions for the Integration of MORYX in ASP.NET Core - true MORYX;ASP diff --git a/src/Moryx.CommandCenter.Web/Moryx.CommandCenter.Web.csproj b/src/Moryx.CommandCenter.Web/Moryx.CommandCenter.Web.csproj index 14400baae..9c00b3ba0 100644 --- a/src/Moryx.CommandCenter.Web/Moryx.CommandCenter.Web.csproj +++ b/src/Moryx.CommandCenter.Web/Moryx.CommandCenter.Web.csproj @@ -8,9 +8,8 @@ - net6.0 + net8.0 true - true diff --git a/src/Moryx.CommandCenter.Web/package.json b/src/Moryx.CommandCenter.Web/package.json index e5441ec98..19dba0c84 100644 --- a/src/Moryx.CommandCenter.Web/package.json +++ b/src/Moryx.CommandCenter.Web/package.json @@ -16,7 +16,7 @@ "@emotion/styled": "^11.11.5", "@mdi/js": "^7.4.47", "@mdi/react": "^1.6.1", - "@mui/material": "^5.15.15", + "@mui/material": "^6.1.1", "@types/react": "^18.2.55", "@types/react-dom": "^18.2.19", "@types/react-redux": "^7.1.33", @@ -24,8 +24,8 @@ "moment": "^2.30.1", "path-scurry": "^1.10.2", "query-string": "^9.0.0", - "react": "18.2.0", - "react-dom": "18.2.0", + "react": "18.3.1", + "react-dom": "18.3.1", "react-redux": "^9.1.0", "react-router": "^6.22.0", "react-router-dom": "^6.22.0", @@ -41,11 +41,11 @@ "@types/react-router-redux": "^5.0.27", "css-loader": "^6.10.0", "html-webpack-plugin": "^5.6.0", - "rimraf": "5.0.5", + "rimraf": "5.0.7", "sass": "^1.72.0", "sass-loader": "^14.1.0", "source-map-loader": "^5.0.0", - "style-loader": "^3.3.4", + "style-loader": "^4.0.0", "tslint": "^6.1.3", "tslint-loader": "^3.5.4", "tslint-react": "^5.0.0", diff --git a/src/Moryx.Communication.Serial/Moryx.Communication.Serial.csproj b/src/Moryx.Communication.Serial/Moryx.Communication.Serial.csproj index 41dda1c2d..353b1adb0 100644 --- a/src/Moryx.Communication.Serial/Moryx.Communication.Serial.csproj +++ b/src/Moryx.Communication.Serial/Moryx.Communication.Serial.csproj @@ -1,10 +1,9 @@  - netstandard2.0;net6.0 + netstandard2.0;net8.0 true MORYX binary connection for serial communication - true MORYX;Communication;Serial;Ports diff --git a/src/Moryx.Container/CastleContainer.cs b/src/Moryx.Container/CastleContainer.cs index b1a12edd6..411a51257 100644 --- a/src/Moryx.Container/CastleContainer.cs +++ b/src/Moryx.Container/CastleContainer.cs @@ -18,107 +18,58 @@ namespace Moryx.Container /// public class CastleContainer : IContainer { - /// - /// Internal windsor container doing the real DI - /// - protected IWindsorContainer Container { get; private set; } - - /// - /// Registrator used to evaluate attributes - /// - protected IComponentRegistrator Registrator { get; } #region Constructors + private readonly IWindsorContainer _container; + + private readonly IDictionary _strategies; + /// - /// Create new container instance with default registrator + /// Create instance without strategies /// public CastleContainer() - : this(new ComponentRegistrator()) + : this(new Dictionary()) { } - /// - /// Constructor to modify the applied registrator + /// Create container with strategies /// - /// Registrator replacement - internal CastleContainer(ComponentRegistrator registrator) + /// + public CastleContainer(IDictionary strategies) { - // Boot up the container and give it to the registrator - Container = registrator.Container = new WindsorContainer(); - Registrator = registrator; + _strategies = strategies; + + // Boot up the container + _container = new WindsorContainer(); - Container.AddFacility(); - Container.AddFacility(); + _container.AddFacility(); + _container.AddFacility(mf => mf.AddStrategies(strategies)); // Self registration for framework functionality - SetInstance(this); + RegisterInstance(new[] { typeof(IContainer) }, this, null); } #endregion - /// - public virtual void Destroy() - { - Container.Dispose(); - Container = null; - } - - /// - /// Execute the installer for this assembly - /// - /// - public IContainer ExecuteInstaller(IContainerInstaller installer) - { - installer.Install(Registrator); - - return this; - } - - /// - /// Resolve an instance of the given service - /// - /// Type to resolve - /// Instance of type - public virtual T Resolve() - { - return Container.Kernel.HasComponent(typeof(T)) ? Container.Resolve() : default(T); - } - - /// - /// Resolve this dependency - /// - public virtual object Resolve(Type service) - { - return Container.Kernel.HasComponent(service) ? Container.Resolve(service) : null; - } - - /// - /// Resolve a named instance of the given service - /// - /// Type to resolve - /// Instance of type - public T Resolve(string name) - { - return Container.Kernel.HasComponent(name) ? Container.Resolve(name) : default(T); - } - /// /// Resolve this named dependency /// public object Resolve(Type service, string name) { - return Container.Kernel.HasComponent(name) ? Container.Resolve(name, service) : null; - } + if(name == null && _strategies.ContainsKey(service)) + name = _strategies[service]; + + // Resolve by name if given or determined + if (name != null && _container.Kernel.HasComponent(name)) + return _container.Resolve(name, service); - /// - /// Resolve all implementations of this contract - /// - /// Type to resolve - /// - public T[] ResolveAll() - { - return Container.ResolveAll(); + // Resolve by type if found + if (_container.Kernel.HasComponent(service)) + return _container.Resolve(service); + + // Otherwise return null + return null; } /// @@ -126,153 +77,98 @@ public T[] ResolveAll() /// public Array ResolveAll(Type service) { - return Container.ResolveAll(service); + return _container.ResolveAll(service); } /// /// Get all implementations for a given component interface /// /// - public IEnumerable GetRegisteredImplementations(Type componentInterface) + public IEnumerable GetRegisteredImplementations(Type service) { - return Container.Kernel.GetHandlers(componentInterface).Select(handler => handler.ComponentModel.Implementation); + return _container.Kernel.GetHandlers(service).Select(handler => handler.ComponentModel.Implementation); } - #region LoadComponents - private static Type[] _knownTypes; + #region Register methods /// - /// Load all implementations of type from currently known types - /// KnownTypes: Types in default framework folders and deeper. + /// Register a component in the container /// - public void LoadComponents() where T : class + public void Register(Type type, Type[] services, string name, LifeCycle lifeCycle) { - LoadComponents(null); - } + // Make sure component is not registered yet + var componentName = name ?? type.FullName; + if (_container.Kernel.HasComponent(componentName)) + return; - /// - /// Loads all implementations of type from the currently known types - /// KnownTypes: Types in default framework folders and deeper. - /// - public virtual void LoadComponents(Predicate condition) where T : class - { - if (_knownTypes == null) + var registration = Component.For(services).ImplementedBy(type); + + // Register name + if (!string.IsNullOrEmpty(name)) { - _knownTypes = ReflectionTool.GetAssemblies() - .Where(a => a.GetCustomAttribute() == null) - .SelectMany(a => - { - // TODO: Replace with exported types in MORYX 8 - try - { - // This should only return exported types - return a.GetTypes(); - } - catch - { - // Fall back to exported types in case of exception - try - { - return a.GetExportedTypes(); - } - catch - { - // Give up - return new Type[0]; - } - } - }) - .Where(t => t.GetCustomAttribute(true) != null).ToArray(); + registration.Named(name); } - foreach (var type in _knownTypes.Where(type => typeof(T).IsAssignableFrom(type))) + // Register life style + switch (lifeCycle) { - if(Registrator.ShallInstall(type) && (condition?.Invoke(type) ?? true)) - Registrator.Register(type); + case LifeCycle.Transient: + registration.LifestyleTransient(); + break; + case LifeCycle.Singleton: + registration.LifestyleSingleton(); + break; } - } - #endregion - - #region Register methods - - /// - public IContainer Register() - where TService : class - where TComp : TService - { - Registrator.Register(typeof(TComp), new[] { typeof(TService) }); - return this; - } - - /// - public IContainer Register(string name, LifeCycle lifeCycle) - where TService : class - where TComp : TService - { - Registrator.Register(typeof(TComp), new[] { typeof(TService) }, name, lifeCycle); - return this; + _container.Register(registration); } - /// - public IContainer Register() where TFactory : class - { - Registrator.RegisterFactory(typeof(TFactory)); - return this; - } - - /// - public IContainer Register(string name) where TFactory : class - { - var factoryType = typeof(TFactory); - var att = typeof(TFactory).GetCustomAttribute(); - Registrator.RegisterFactory(factoryType, name, att?.Selector); - return this; - } - - #endregion - - #region SetInstances - /// - /// Set instance of service + /// Register factory interface /// - /// Type of service - /// Instance implementing the service - public IContainer SetInstance(T instance) where T : class + public void RegisterFactory(Type factoryInterface, string name, Type selector) { - if (instance != null) + var registration = Component.For(factoryInterface); + + if (!string.IsNullOrEmpty(name)) { - Container.Register(Component.For().Instance(instance)); + registration.Named(name); } - return this; - } - /// - /// Set globally imported instance with name - /// - /// Type of service - /// Instance to register - /// Name of instance - public IContainer SetInstance(T instance, string name) where T : class - { - if (instance != null) + if (selector == null) + { + registration.AsFactory(); + } + else { - Container.Register(Component.For().Instance(instance).Named(name)); + // Make sure selector is registered in the container + // TODO: Super dirty hack to use interfaces in component selectors + var selectorName = selector.IsClass ? selector.FullName : $"{selector.Namespace}.{selector.Name.Substring(1)}"; + registration.AsFactory(config => config.SelectedWith(selectorName)); } - return this; + + _container.Register(registration); } - public void Extend() where TExtension : new() + /// + /// Register instance in the container + /// + public void RegisterInstance(Type[] services, object instance, string name) { - var facilityType = typeof(IFacility); - if (!facilityType.IsAssignableFrom(typeof(TExtension))) - throw new InvalidOperationException("The underlying container only supports " + facilityType.FullName + "!"); + var registration = Component.For(services).Instance(instance); + + if (!string.IsNullOrEmpty(name)) + registration.Named(name); - var facility = (IFacility)new TExtension(); - Container.AddFacility(facility); + _container.Register(registration); } #endregion + + /// + public virtual void Destroy() + { + _container.Dispose(); + } } } diff --git a/src/Moryx.Container/ChildContainerSubResolver.cs b/src/Moryx.Container/ChildContainerSubResolver.cs index 6e6275d24..d39dd5148 100644 --- a/src/Moryx.Container/ChildContainerSubResolver.cs +++ b/src/Moryx.Container/ChildContainerSubResolver.cs @@ -46,7 +46,7 @@ private static bool IsContainerChild(Type candidate) return candidate.IsGenericType && candidate.GetGenericTypeDefinition() == typeof(IContainerChild<>); } - private UseChildAttribute GetAttribute(Type targetType, DependencyModel dependency) + private static UseChildAttribute GetAttribute(Type targetType, DependencyModel dependency) { UseChildAttribute att = null; if (dependency.IsOptional) diff --git a/src/Moryx.Container/Installer/AutoInstaller.cs b/src/Moryx.Container/Installer/AutoInstaller.cs deleted file mode 100644 index ef772eed2..000000000 --- a/src/Moryx.Container/Installer/AutoInstaller.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; -using System.Reflection; - -namespace Moryx.Container -{ - /// - /// Installer for automatic registration - /// - public class AutoInstaller : IContainerInstaller - { - private readonly Assembly _targetAssembly; - - /// - /// Create a new instance of the for this assembly - /// - public AutoInstaller(Assembly targetAssembly) - { - _targetAssembly = targetAssembly ?? GetType().Assembly; - } - - - /// - /// Install components to the container - /// - /// Registrator to register new types - public virtual void Install(IComponentRegistrator registrator) - { - // Install all components - foreach (var type in _targetAssembly.GetTypes()) - { - // Register all we want - if (ShallInstall(registrator, type)) - registrator.Register(type); - } - } - - /// - /// Method to determine if this component shall be installed - /// - protected internal virtual bool ShallInstall(IComponentRegistrator registrator, Type foundType) - { - return registrator.ShallInstall(foundType); - } - } -} diff --git a/src/Moryx.Container/Installer/ComponentRegistrator.cs b/src/Moryx.Container/Installer/ComponentRegistrator.cs deleted file mode 100644 index fc05ca508..000000000 --- a/src/Moryx.Container/Installer/ComponentRegistrator.cs +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; -using System.Linq; -using System.Reflection; -using Castle.Facilities.TypedFactory; -using Castle.MicroKernel.Registration; -using Castle.Windsor; - -namespace Moryx.Container -{ - internal class ComponentRegistrator : IComponentRegistrator - { - /// - /// Internal windsor container for registration - /// - protected internal IWindsorContainer Container { get; set; } - - /// - /// Method to determine if this component shall be installed - /// - public virtual bool ShallInstall(Type foundType) - { - var regAtt = foundType.GetCustomAttribute(); - var facAtt = foundType.GetCustomAttribute(); - - return (regAtt != null || facAtt != null) && NotRegisteredYet(foundType, regAtt); - } - - /// - /// Check if the type was not registered yet - /// - /// Type that must be checked for suitability to register - /// - /// True if the component was not registered before - protected bool NotRegisteredYet(Type foundType, RegistrationAttribute regAtt) - { - var name = string.IsNullOrEmpty(regAtt?.Name) ? foundType.FullName : regAtt.Name; - return !Container.Kernel.HasComponent(name); - } - - public void Register(Type type) - { - if (type.IsInterface) - { - RegisterFactory(type); - } - else - { - Register(type, GetComponentServices(type)); - } - } - - /// - /// Get all services of this component - /// - public static Type[] GetComponentServices(Type type) - { - var att = type.GetCustomAttribute(); - if (att != null) - return att.Services.Any() ? att.Services : new[] { type }; - - var interfaces = type.GetInterfaces(); - return interfaces.Any() ? interfaces : new[] { type }; - } - - public void Register(Type type, Type[] services) - { - var regAtt = type.GetCustomAttribute(); - Register(type, services, regAtt?.Name, regAtt?.LifeStyle ?? LifeCycle.Singleton); - } - - - public void Register(Type type, Type[] services, string name) - { - Register(type, services, name, LifeCycle.Singleton); - } - - - public void Register(Type type, Type[] services, string name, LifeCycle lifeCycle) - { - var registration = BuildRegistration(type, services, name, lifeCycle); - - Container.Register(registration); - } - - /// - /// Build registration from arguments - /// - protected virtual ComponentRegistration BuildRegistration(Type type, Type[] services, string name, LifeCycle lifeCycle) - { - var registration = Component.For(services).ImplementedBy(type); - - // Register name - if (!string.IsNullOrEmpty(name)) - { - registration.Named(name); - } - - // Register life style - switch (lifeCycle) - { - case LifeCycle.Transient: - registration.LifestyleTransient(); - break; - case LifeCycle.Singleton: - registration.LifestyleSingleton(); - break; - } - - // Optionally override property injection - foreach (var property in registration.Implementation.GetProperties()) - { - // Check if this property has an override - var dependency = OverrideDependency(property.Name, property.PropertyType, property); - - // Override property injection for this property if found - if (dependency != null) - registration.DependsOn(dependency); - } - - // Override Constructor injection as well - foreach (var constructorParameter in registration.Implementation.GetConstructors().SelectMany(constructor => constructor.GetParameters())) - { - // Check if this paramter has an override - var dependency = OverrideDependency(constructorParameter.Name, constructorParameter.ParameterType, constructorParameter); - - // Override constructor injection for this property if found - if (dependency != null) - registration.DependsOn(dependency); - } - - return registration; - } - - /// - /// Determine a possible override for this member. Base implementatin checks for named attribute - /// - protected virtual ServiceOverride OverrideDependency(string dependencyName, Type dependencyType, ICustomAttributeProvider attributeProvider) - { - var atts = attributeProvider.GetCustomAttributes(typeof(NamedAttribute), false); - return atts.Any() ? Dependency.OnComponent(dependencyName, ((NamedAttribute)atts[0]).ComponentName) : null; - } - - - public void RegisterFactory(Type factoryInterface) - { - var facAtt = factoryInterface.GetCustomAttribute(); - RegisterFactory(factoryInterface, facAtt?.Name, facAtt?.Selector); - } - - - public void RegisterFactory(Type factoryInterface, string name) - { - RegisterFactory(factoryInterface, name, null); - } - - public virtual void RegisterFactory(Type factoryInterface, string name, Type selector) - { - var registration = Component.For(factoryInterface); - - if (!string.IsNullOrEmpty(name)) - { - registration.Named(name); - } - - if (selector == null) - { - registration.AsFactory(); - } - else - { - // Make sure selector is registered in the container - // TODO: Super dirty hack to use interfaces in component selectors - var selectorName = selector.IsClass ? selector.FullName : $"{selector.Namespace}.{selector.Name.Substring(1)}"; - registration.AsFactory(config => config.SelectedWith(selectorName)); - } - - Container.Register(registration); - } - } -} diff --git a/src/Moryx.Container/Installer/DependencyAutoInstaller.cs b/src/Moryx.Container/Installer/DependencyAutoInstaller.cs deleted file mode 100644 index 46315d1fc..000000000 --- a/src/Moryx.Container/Installer/DependencyAutoInstaller.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; -using System.Linq; -using System.Reflection; - -namespace Moryx.Container -{ - /// - /// Creates automatically a new instance of the given assembly. - /// - public class DependencyAutoInstaller : AutoInstaller - { - private readonly DependencyRegistrationAttribute _depReg; - - /// - /// Create new instance for the given assembly - /// - /// Assembly to execute installer for - /// Dependency registration attribute - public DependencyAutoInstaller(Assembly targetAssembly, DependencyRegistrationAttribute depReg) : base(targetAssembly) - { - _depReg = depReg; - } - - /// - /// Method to determine if this component shall be installed - /// - protected internal override bool ShallInstall(IComponentRegistrator registrator, Type foundType) - { - if (base.ShallInstall(registrator, foundType)) - { - return _depReg.InstallerMode == InstallerMode.All || TypeRequired(foundType); - } - return false; - } - - private bool TypeRequired(Type foundType) - { - // Check if interface was specified as required - if(foundType.IsInterface && _depReg.RequiredTypes.Contains(foundType)) - return true; - - // Check if class exports required type - if(foundType.IsClass && _depReg.RequiredTypes.Intersect(ComponentRegistrator.GetComponentServices(foundType)).Any()) - return true; - - return false; - } - } -} diff --git a/src/Moryx.Container/Installer/DoubleRegistrationCheck.cs b/src/Moryx.Container/Installer/DoubleRegistrationCheck.cs deleted file mode 100644 index 8028180c7..000000000 --- a/src/Moryx.Container/Installer/DoubleRegistrationCheck.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Castle.MicroKernel; - -namespace Moryx.Container.Installer -{ - /// - /// Class used to check the kernel for an exisiting component registration of this type - /// - public static class DoubleRegistrationCheck - { - /// - /// Look for an existing component in the kernel - /// - public static bool AllreadyRegistered(IKernel kernel, Type foundComponent, RegistrationAttribute regAtt) - { - var name = regAtt == null || string.IsNullOrEmpty(regAtt.Name) ? foundComponent.FullName : regAtt.Name; - return kernel.HasComponent(name); - } - } -} diff --git a/src/Moryx.Container/Installer/IConfiguredInstaller.cs b/src/Moryx.Container/Installer/IConfiguredInstaller.cs deleted file mode 100644 index 9ff7795bf..000000000 --- a/src/Moryx.Container/Installer/IConfiguredInstaller.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -namespace Moryx.Container -{ - internal interface IConfiguredInstaller - { - /// - /// Set config on installer - /// - void SetRegistrator(ComponentRegistrator config); - } -} diff --git a/src/Moryx.Container/LocalContainer/LocalContainer.cs b/src/Moryx.Container/LocalContainer/LocalContainer.cs deleted file mode 100644 index 1b85033f1..000000000 --- a/src/Moryx.Container/LocalContainer/LocalContainer.cs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Castle.MicroKernel.Registration; - -namespace Moryx.Container -{ - /// - /// Module internal castle container - /// - public class LocalContainer : CastleContainer - { - private readonly IDictionary _strategies; - - /// - /// Default constructor without strategies - /// - public LocalContainer() : this(new Dictionary()) - { - } - - /// - /// Constructor for the local castle container. - /// - /// Configuration for the container. - public LocalContainer(IDictionary strategies) - : base(new LocalRegistrator(strategies)) - { - _strategies = strategies; - } - - /// - public override T Resolve() - { - var service = typeof(T); - return _strategies.ContainsKey(service) ? Resolve(_strategies[service]) : base.Resolve(); - } - - /// - public override object Resolve(Type service) - { - return _strategies.ContainsKey(service) ? Resolve(service, _strategies[service]) : base.Resolve(service); - } - - /// - public override void LoadComponents(Predicate condition) - { - // Save all current handlers - var handlers = Container.Kernel.GetHandlers(typeof(T)).Select(handler => handler.ComponentModel.Implementation); - - // Invoke registration - base.LoadComponents(condition); - - // Check registered types for additional registrations - RegisterAdditionalDependencies(Container.Kernel.GetHandlers(typeof(T)) - .Select(handler => handler.ComponentModel.Implementation) - .Except(handlers)); - } - - private void RegisterAdditionalDependencies(IEnumerable modulePlugins) - { - foreach (var implementation in modulePlugins) - { - var att = implementation.GetCustomAttribute(); - if (att == null) - continue; - - var installer = att.InstallerMode == InstallerMode.All ? new AutoInstaller(implementation.Assembly) - : new DependencyAutoInstaller(implementation.Assembly, att); - ExecuteInstaller(installer); - if (att.Initializer == null) - continue; - - if (!typeof(ISubInitializer).IsAssignableFrom(att.Initializer)) - throw new InvalidCastException($"SubInitializer {att.Initializer.Name} of component {implementation.Name} does not implement interface ISubInitializer"); - - // If someone registered this sub initializer before just skip - if (!Container.Kernel.HasComponent(att.Initializer)) - Container.Register(Component.For(typeof(ISubInitializer), att.Initializer).ImplementedBy(att.Initializer)); - } - } - } -} diff --git a/src/Moryx.Container/LocalContainer/LocalRegistrator.cs b/src/Moryx.Container/LocalContainer/LocalRegistrator.cs deleted file mode 100644 index 7acc38bc6..000000000 --- a/src/Moryx.Container/LocalContainer/LocalRegistrator.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; -using System.Collections.Generic; -using System.Reflection; -using Castle.MicroKernel.Registration; - -namespace Moryx.Container -{ - internal class LocalRegistrator : ComponentRegistrator - { - private readonly IDictionary _strategies; - - public LocalRegistrator(IDictionary strategies) - { - _strategies = strategies; - } - - /// - /// Method to determine if this component shall be installed - /// - public override bool ShallInstall(Type foundType) - { - var regAtt = foundType.GetCustomAttribute(); - var facAtt = foundType.GetCustomAttribute(); - - return (regAtt != null || facAtt != null) && NotRegisteredYet(foundType, regAtt); - } - - /// - /// Determine a possible override for this member. Base implementatin checks for named attribute - /// - protected override ServiceOverride OverrideDependency(string dependencyName, Type dependencyType, ICustomAttributeProvider attributeProvider) - { - var dependency = base.OverrideDependency(dependencyName, dependencyType, attributeProvider); - - if (dependency == null && _strategies.ContainsKey(dependencyType)) - dependency = Dependency.OnComponent(dependencyName, _strategies[dependencyType]); - - return dependency; - } - } -} diff --git a/src/Moryx.Container/Moryx.Container.csproj b/src/Moryx.Container/Moryx.Container.csproj index d4aaf59c8..dec10b0f8 100644 --- a/src/Moryx.Container/Moryx.Container.csproj +++ b/src/Moryx.Container/Moryx.Container.csproj @@ -1,10 +1,9 @@  - netstandard2.0;net6.0 + netstandard2.0;net8.0 true MORYX container functionality based on Castle.Windsor. - true MORYX;Container;IoC diff --git a/src/Moryx.Container/MoryxFacility.cs b/src/Moryx.Container/MoryxFacility.cs index 71abcae0d..65f123410 100644 --- a/src/Moryx.Container/MoryxFacility.cs +++ b/src/Moryx.Container/MoryxFacility.cs @@ -5,16 +5,27 @@ using Castle.MicroKernel; using Castle.MicroKernel.Registration; using Castle.MicroKernel.Resolvers.SpecializedResolvers; +using System; +using System.Collections.Generic; namespace Moryx.Container { internal class MoryxFacility : IFacility { + private IDictionary _strategies; + + public void AddStrategies(IDictionary strategies) + { + _strategies = strategies; + } + public void Init(IKernel kernel, IConfiguration facilityConfig) { kernel.Register(Component.For().ImplementedBy().LifestyleTransient()); kernel.Register(Component.For().ImplementedBy().LifestyleTransient()); kernel.Resolver.AddSubResolver(new CollectionResolver(kernel, true)); + kernel.Resolver.AddSubResolver(new NamedDependencyResolver(kernel)); + kernel.Resolver.AddSubResolver(new StrategySubResolver(kernel, _strategies)); kernel.Resolver.AddSubResolver(new ChildContainerSubResolver(kernel)); } diff --git a/src/Moryx.Container/NamedDependencyResolver.cs b/src/Moryx.Container/NamedDependencyResolver.cs new file mode 100644 index 000000000..2bf02c69b --- /dev/null +++ b/src/Moryx.Container/NamedDependencyResolver.cs @@ -0,0 +1,54 @@ +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +using Castle.Core; +using Castle.MicroKernel.Context; +using Castle.MicroKernel; +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using System.Reflection; + +namespace Moryx.Container +{ + internal class NamedDependencyResolver : ISubDependencyResolver + { + private readonly IKernel _kernel; + + public NamedDependencyResolver(IKernel kernel) + { + _kernel = kernel; + } + + public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency) + { + return dependency.TargetType != null && GetAttribute(model.Implementation, dependency) != null; + } + + public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency) + { + // The dependency is declared with a name + var att = GetAttribute(model.Implementation, dependency); + // The dependency is a registered strategy, resolve by strategy name instead + return _kernel.Resolve(att.ComponentName, dependency.TargetType); + } + + private static NamedAttribute GetAttribute(Type targetType, DependencyModel dependency) + { + NamedAttribute att = null; + if (dependency.IsOptional) + { + // Find property and look for attribute + var property = targetType.GetProperty(dependency.DependencyKey); + att = property.GetCustomAttribute(); + } + else if (dependency is ConstructorDependencyModel constDep) + { + var parameter = constDep.Constructor.Constructor.GetParameters().FirstOrDefault(param => param.Name == dependency.DependencyKey); + att = parameter.GetCustomAttribute(); + } + return att; + } + } +} diff --git a/src/Moryx.Container/StrategySubResolver.cs b/src/Moryx.Container/StrategySubResolver.cs new file mode 100644 index 000000000..441f5f8f2 --- /dev/null +++ b/src/Moryx.Container/StrategySubResolver.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +using Castle.Core; +using Castle.MicroKernel.Context; +using Castle.MicroKernel; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Moryx.Container +{ + internal class StrategySubResolver : ISubDependencyResolver + { + private readonly IKernel _kernel; + private readonly IDictionary _strategies; + + public StrategySubResolver(IKernel kernel, IDictionary strategies) + { + _kernel = kernel; + _strategies = strategies; + } + + public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency) + { + return dependency.TargetType != null && _strategies.ContainsKey(dependency.TargetType); + } + + public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency) + { + // The dependency is a registered strategy, resolve by strategy name instead + return _kernel.Resolve(_strategies[dependency.TargetType], dependency.TargetType); + } + } +} diff --git a/src/Moryx.DependentTestModule/ModuleController/ModuleController.cs b/src/Moryx.DependentTestModule/ModuleController/ModuleController.cs index 940f3415b..40400f4bb 100644 --- a/src/Moryx.DependentTestModule/ModuleController/ModuleController.cs +++ b/src/Moryx.DependentTestModule/ModuleController/ModuleController.cs @@ -12,7 +12,7 @@ namespace Moryx.DependentTestModule { [Description("Test module for System tests")] - public class ModuleController : ServerModuleFacadeControllerBase, IFacadeContainer + public class ModuleController : ServerModuleBase, IFacadeContainer { /// /// Name of this module diff --git a/src/Moryx.DependentTestModule/Moryx.DependentTestModule.csproj b/src/Moryx.DependentTestModule/Moryx.DependentTestModule.csproj index ccd3319d9..bd0b9ea42 100644 --- a/src/Moryx.DependentTestModule/Moryx.DependentTestModule.csproj +++ b/src/Moryx.DependentTestModule/Moryx.DependentTestModule.csproj @@ -2,14 +2,11 @@ - net6.0 + net8.0 Moryx Runtime Module: DependentTestModule + false - - - - diff --git a/src/Moryx.Model.InMemory/Moryx.Model.InMemory.csproj b/src/Moryx.Model.InMemory/Moryx.Model.InMemory.csproj index 7331a134a..f6de585e6 100644 --- a/src/Moryx.Model.InMemory/Moryx.Model.InMemory.csproj +++ b/src/Moryx.Model.InMemory/Moryx.Model.InMemory.csproj @@ -1,10 +1,9 @@  - net6.0 + net8.0 true InMemory extension for unit tests referencing Moryx.Model - true MORYX;Entity;Framework;EntityFramework;DataModel;Model;Database;InMemory;Effort diff --git a/src/Moryx.Model.PostgreSQL/Moryx.Model.PostgreSQL.csproj b/src/Moryx.Model.PostgreSQL/Moryx.Model.PostgreSQL.csproj index 19320c878..e45126e44 100644 --- a/src/Moryx.Model.PostgreSQL/Moryx.Model.PostgreSQL.csproj +++ b/src/Moryx.Model.PostgreSQL/Moryx.Model.PostgreSQL.csproj @@ -1,10 +1,9 @@  - net6.0 + net8.0 true Adapter for Moryx.Model on PostgreSQL - true MORYX;Entity;Framework;EntityFramework;DataModel;Model;Database;Npgsql;PostgreSQL;Postgres diff --git a/src/Moryx.Model.PostgreSQL/NpgsqlDatabaseConfig.cs b/src/Moryx.Model.PostgreSQL/NpgsqlDatabaseConfig.cs index 00624d587..e2fb6b4dd 100644 --- a/src/Moryx.Model.PostgreSQL/NpgsqlDatabaseConfig.cs +++ b/src/Moryx.Model.PostgreSQL/NpgsqlDatabaseConfig.cs @@ -1,7 +1,6 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 -using Moryx.Tools; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; diff --git a/src/Moryx.Model.Sqlite/Moryx.Model.Sqlite.csproj b/src/Moryx.Model.Sqlite/Moryx.Model.Sqlite.csproj index 416751019..f34714cc7 100644 --- a/src/Moryx.Model.Sqlite/Moryx.Model.Sqlite.csproj +++ b/src/Moryx.Model.Sqlite/Moryx.Model.Sqlite.csproj @@ -1,10 +1,9 @@  - net6.0 + net8.0 true Adapter for Moryx.Model on Sqlite - true MORYX;Entity;Framework;EntityFramework;DataModel;Model;Database;Sqlite diff --git a/src/Moryx.Model/Configuration/ModelConfiguratorBase.cs b/src/Moryx.Model/Configuration/ModelConfiguratorBase.cs index 0df40c9c1..b3a91b333 100644 --- a/src/Moryx.Model/Configuration/ModelConfiguratorBase.cs +++ b/src/Moryx.Model/Configuration/ModelConfiguratorBase.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.Logging; using Moryx.Configuration; using Moryx.Tools; diff --git a/src/Moryx.Model/Configuration/NullModelConfigurator.cs b/src/Moryx.Model/Configuration/NullModelConfigurator.cs index b6843d262..480e57aaf 100644 --- a/src/Moryx.Model/Configuration/NullModelConfigurator.cs +++ b/src/Moryx.Model/Configuration/NullModelConfigurator.cs @@ -89,6 +89,7 @@ public Task RestoreDatabase(IDatabaseConfig config, string filePath) throw new NotSupportedException("Not supported by " + nameof(NullModelConfigurator)); } + /// public DbContext CreateContext(Type contextType, DbContextOptions dbContextOptions) { throw new NotImplementedException(); diff --git a/src/Moryx.Model/DatabaseConfig.cs b/src/Moryx.Model/DatabaseConfig.cs index 41b2fbf6c..b3346b4a2 100644 --- a/src/Moryx.Model/DatabaseConfig.cs +++ b/src/Moryx.Model/DatabaseConfig.cs @@ -3,9 +3,7 @@ using System.Runtime.Serialization; using Moryx.Configuration; -using Moryx.Model.Attributes; using Moryx.Model.Configuration; -using Moryx.Serialization; namespace Moryx.Model { diff --git a/src/Moryx.Model/DatabaseConnectionSettings.cs b/src/Moryx.Model/DatabaseConnectionSettings.cs index 88d6decbd..34c94607d 100644 --- a/src/Moryx.Model/DatabaseConnectionSettings.cs +++ b/src/Moryx.Model/DatabaseConnectionSettings.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0 using System.Collections.Generic; -using System.ComponentModel; -using System.Reflection; using System.Runtime.Serialization; namespace Moryx.Model diff --git a/src/Moryx.Model/DbContextContainerExtension.cs b/src/Moryx.Model/DbContextContainerExtension.cs index 38886a986..2b14f9453 100644 --- a/src/Moryx.Model/DbContextContainerExtension.cs +++ b/src/Moryx.Model/DbContextContainerExtension.cs @@ -17,18 +17,11 @@ public static class DbContextContainerExtension public static IContainer ActivateDbContexts(this IContainer container, IDbContextManager contextManager) { container.SetInstance(contextManager); - container.ExecuteInstaller(new ContextFactoryInstaller()); - return container; - } + container.Register(typeof(ContextFactory<>), new[] { typeof(IContextFactory<>) }, "GenericContextFactory", LifeCycle.Singleton); + container.Register(typeof(UnitOfWorkFactory<>), new[] { typeof(IUnitOfWorkFactory<>) }, "UnitOfWorkFactory", LifeCycle.Singleton); - private class ContextFactoryInstaller : IContainerInstaller - { - public void Install(IComponentRegistrator registrator) - { - registrator.Register(typeof(ContextFactory<>), new []{ typeof(IContextFactory<>) }, "GenericContextFactory", LifeCycle.Singleton); - registrator.Register(typeof(UnitOfWorkFactory<>), new[] { typeof(IUnitOfWorkFactory<>) }, "UnitOfWorkFactory", LifeCycle.Singleton); - } + return container; } } } \ No newline at end of file diff --git a/src/Moryx.Model/DbContextManager.cs b/src/Moryx.Model/DbContextManager.cs index 1f508049a..1d2c88e88 100644 --- a/src/Moryx.Model/DbContextManager.cs +++ b/src/Moryx.Model/DbContextManager.cs @@ -18,7 +18,6 @@ namespace Moryx.Model /// /// Kernel component handling data models and their runtime configurators /// - [InitializableKernelComponent(typeof(IDbContextManager))] public class DbContextManager : IDbContextManager { private ModelWrapper[] _knownModels; diff --git a/src/Moryx.Model/EntityBase.cs b/src/Moryx.Model/EntityBase.cs index b09494f42..277d2fef5 100644 --- a/src/Moryx.Model/EntityBase.cs +++ b/src/Moryx.Model/EntityBase.cs @@ -1,7 +1,6 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 -using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; diff --git a/src/Moryx.Model/Moryx.Model.csproj b/src/Moryx.Model/Moryx.Model.csproj index 9b3e63695..31addd467 100644 --- a/src/Moryx.Model/Moryx.Model.csproj +++ b/src/Moryx.Model/Moryx.Model.csproj @@ -1,10 +1,9 @@  - net6.0 + net8.0 true Datamodel integration for MORYX applications based on Entity Framework - true MORYX;Entity;Framework;EntityFramework;DataModel;Model;Database diff --git a/src/Moryx.Notifications/Moryx.Notifications.csproj b/src/Moryx.Notifications/Moryx.Notifications.csproj index 8a7719414..c4842c763 100644 --- a/src/Moryx.Notifications/Moryx.Notifications.csproj +++ b/src/Moryx.Notifications/Moryx.Notifications.csproj @@ -1,10 +1,9 @@  - netstandard2.0;net6.0 + netstandard2.0;net8.0 true Types and interfaces for notifications within MORYX applications - true MORYX;IIoT;IoT;Notifications diff --git a/src/Moryx.Products.Management/Implementation/Storage/AutoConfigurator.cs b/src/Moryx.Products.Management/Implementation/Storage/AutoConfigurator.cs index 4e9975ff2..db0245800 100644 --- a/src/Moryx.Products.Management/Implementation/Storage/AutoConfigurator.cs +++ b/src/Moryx.Products.Management/Implementation/Storage/AutoConfigurator.cs @@ -176,7 +176,7 @@ private TConfig StrategyConfig(Type targetType) var config = tuple.Item2; config.TargetType = targetType.FullName; - config.PluginName = tuple.Item1.GetCustomAttribute().Name; + config.PluginName = tuple.Item1.GetCustomAttribute().Name; ValueProviderExecutor.Execute(config, new ValueProviderExecutorSettings().AddDefaultValueProvider()); @@ -208,7 +208,7 @@ private TConfig StrategyConfig(Type targetType) var strategy = propertyTuple.Item1; var propertyConfig = propertyTuple.Item2; propertyConfig.PropertyName = property.Name; - propertyConfig.PluginName = strategy.GetCustomAttribute().Name; + propertyConfig.PluginName = strategy.GetCustomAttribute().Name; var columnType = strategy.GetCustomAttribute()?.ColumnType ?? typeof(string); var column = remainingColumns.FirstOrDefault(rc => rc.PropertyType == columnType); diff --git a/src/Moryx.Products.Management/Implementation/Storage/FloatStrategyConfigurationAttribute.cs b/src/Moryx.Products.Management/Implementation/Storage/FloatStrategyConfigurationAttribute.cs index 0c1dcc3ae..1ef2633b8 100644 --- a/src/Moryx.Products.Management/Implementation/Storage/FloatStrategyConfigurationAttribute.cs +++ b/src/Moryx.Products.Management/Implementation/Storage/FloatStrategyConfigurationAttribute.cs @@ -3,8 +3,10 @@ namespace Moryx.Products.Management { + /// public class FloatStrategyConfigurationAttribute : PropertyStrategyConfigurationAttribute { + /// public FloatStrategyConfigurationAttribute() { ColumnType = typeof(double); diff --git a/src/Moryx.Products.Management/Implementation/Storage/IntegerStrategyConfigurationAttribute.cs b/src/Moryx.Products.Management/Implementation/Storage/IntegerStrategyConfigurationAttribute.cs index ec0bdc065..a477ee462 100644 --- a/src/Moryx.Products.Management/Implementation/Storage/IntegerStrategyConfigurationAttribute.cs +++ b/src/Moryx.Products.Management/Implementation/Storage/IntegerStrategyConfigurationAttribute.cs @@ -5,9 +5,11 @@ namespace Moryx.Products.Management { + /// [AttributeUsage(AttributeTargets.Class)] public class IntegerStrategyConfigurationAttribute : PropertyStrategyConfigurationAttribute { + /// public IntegerStrategyConfigurationAttribute() { ColumnType = typeof(long); diff --git a/src/Moryx.Products.Management/ModuleController/ModuleConsole.cs b/src/Moryx.Products.Management/ModuleController/ModuleConsole.cs index f6fd4e8a0..40a220883 100644 --- a/src/Moryx.Products.Management/ModuleController/ModuleConsole.cs +++ b/src/Moryx.Products.Management/ModuleController/ModuleConsole.cs @@ -1,9 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 -using System; using System.ComponentModel; -using System.Linq; using Moryx.AbstractionLayer.Products; using Moryx.AbstractionLayer.Recipes; using Moryx.Configuration; diff --git a/src/Moryx.Products.Management/ModuleController/ModuleController.cs b/src/Moryx.Products.Management/ModuleController/ModuleController.cs index 83f5d8ab9..db0e8c1ab 100644 --- a/src/Moryx.Products.Management/ModuleController/ModuleController.cs +++ b/src/Moryx.Products.Management/ModuleController/ModuleController.cs @@ -14,7 +14,7 @@ namespace Moryx.Products.Management /// /// The main controller of all product modules. /// - public class ModuleController : ServerModuleFacadeControllerBase, + public class ModuleController : ServerModuleBase, IFacadeContainer, IFacadeContainer { diff --git a/src/Moryx.Products.Management/Moryx.Products.Management.csproj b/src/Moryx.Products.Management/Moryx.Products.Management.csproj index 9507af634..30ae80781 100644 --- a/src/Moryx.Products.Management/Moryx.Products.Management.csproj +++ b/src/Moryx.Products.Management/Moryx.Products.Management.csproj @@ -1,10 +1,9 @@  - net6.0 + net8.0 true ProductManagement module hosting product types and instances, as well as recipes and workplans. - true MORYX;IIoT;IoT;Product;Manufacturing;Management;API diff --git a/src/Moryx.Products.Management/Plugins/GenericStrategies/AvailableColumnsAttribute.cs b/src/Moryx.Products.Management/Plugins/GenericStrategies/AvailableColumnsAttribute.cs index aecc62281..4c48a0638 100644 --- a/src/Moryx.Products.Management/Plugins/GenericStrategies/AvailableColumnsAttribute.cs +++ b/src/Moryx.Products.Management/Plugins/GenericStrategies/AvailableColumnsAttribute.cs @@ -34,9 +34,12 @@ public AvailableColumnsAttribute(Type columnType) _columnType = columnType; } + /// public override bool OverridesConversion => false; + /// public override bool UpdateFromPredecessor => false; + /// public override IEnumerable GetValues(IContainer container) { return typeof(IGenericColumns).GetProperties() diff --git a/src/Moryx.Products.Management/Plugins/GenericStrategies/PropertyMapper.cs b/src/Moryx.Products.Management/Plugins/GenericStrategies/PropertyMapper.cs index 84e647d4e..e289c9450 100644 --- a/src/Moryx.Products.Management/Plugins/GenericStrategies/PropertyMapper.cs +++ b/src/Moryx.Products.Management/Plugins/GenericStrategies/PropertyMapper.cs @@ -103,6 +103,7 @@ protected virtual object ToExpressionValue(object value) return Convert.ChangeType(value, Column.PropertyType); } + /// public bool HasChanged(IGenericColumns current, object updated) { var objectValue = ObjectAccessor.ReadProperty(updated); @@ -114,12 +115,14 @@ public bool HasChanged(IGenericColumns current, object updated) return !columnValue.Equals(objectValue); } + /// public void ReadValue(IGenericColumns source, object target) { var value = ColumnAccessor.ReadProperty(source); ObjectAccessor.WriteProperty(target, value); } + /// public void WriteValue(object source, IGenericColumns target) { var value = ObjectAccessor.ReadProperty(source); diff --git a/src/Moryx.Products.Model/Entities/PartLinkEntity.cs b/src/Moryx.Products.Model/Entities/PartLinkEntity.cs index ed04e9f25..28df78e67 100644 --- a/src/Moryx.Products.Model/Entities/PartLinkEntity.cs +++ b/src/Moryx.Products.Model/Entities/PartLinkEntity.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using Moryx.Model; namespace Moryx.Products.Model diff --git a/src/Moryx.Products.Model/Entities/ProductInstanceEntity.cs b/src/Moryx.Products.Model/Entities/ProductInstanceEntity.cs index 181a38487..6ddaa092c 100644 --- a/src/Moryx.Products.Model/Entities/ProductInstanceEntity.cs +++ b/src/Moryx.Products.Model/Entities/ProductInstanceEntity.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using Moryx.Model; using System.Collections.Generic; diff --git a/src/Moryx.Products.Model/Entities/ProductRecipeEntity.cs b/src/Moryx.Products.Model/Entities/ProductRecipeEntity.cs index eb3e24a08..a630ac279 100644 --- a/src/Moryx.Products.Model/Entities/ProductRecipeEntity.cs +++ b/src/Moryx.Products.Model/Entities/ProductRecipeEntity.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using Moryx.Model; namespace Moryx.Products.Model diff --git a/src/Moryx.Products.Model/Entities/ProductTypeEntity.cs b/src/Moryx.Products.Model/Entities/ProductTypeEntity.cs index 0062c778a..09871f9a2 100644 --- a/src/Moryx.Products.Model/Entities/ProductTypeEntity.cs +++ b/src/Moryx.Products.Model/Entities/ProductTypeEntity.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using Moryx.Model; using System.Collections.Generic; diff --git a/src/Moryx.Products.Model/Entities/ProductTypePropertiesEntity.cs b/src/Moryx.Products.Model/Entities/ProductTypePropertiesEntity.cs index c5c60bc5d..32c8032d9 100644 --- a/src/Moryx.Products.Model/Entities/ProductTypePropertiesEntity.cs +++ b/src/Moryx.Products.Model/Entities/ProductTypePropertiesEntity.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using Moryx.Model; namespace Moryx.Products.Model diff --git a/src/Moryx.Products.Model/Entities/WorkplanEntity.cs b/src/Moryx.Products.Model/Entities/WorkplanEntity.cs index 51813f8e9..746028a56 100644 --- a/src/Moryx.Products.Model/Entities/WorkplanEntity.cs +++ b/src/Moryx.Products.Model/Entities/WorkplanEntity.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using Moryx.Model; using System.Collections.Generic; diff --git a/src/Moryx.Products.Model/Entities/WorkplanOutputDescriptionEntity.cs b/src/Moryx.Products.Model/Entities/WorkplanOutputDescriptionEntity.cs index 452b8cf6a..1801ce673 100644 --- a/src/Moryx.Products.Model/Entities/WorkplanOutputDescriptionEntity.cs +++ b/src/Moryx.Products.Model/Entities/WorkplanOutputDescriptionEntity.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using Moryx.Model; namespace Moryx.Products.Model diff --git a/src/Moryx.Products.Model/Entities/WorkplanReferenceEntity.cs b/src/Moryx.Products.Model/Entities/WorkplanReferenceEntity.cs index a465c525d..d6816e897 100644 --- a/src/Moryx.Products.Model/Entities/WorkplanReferenceEntity.cs +++ b/src/Moryx.Products.Model/Entities/WorkplanReferenceEntity.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using Moryx.Model; namespace Moryx.Products.Model diff --git a/src/Moryx.Products.Model/Entities/WorkplanStepEntity.cs b/src/Moryx.Products.Model/Entities/WorkplanStepEntity.cs index f81653556..01e7166ee 100644 --- a/src/Moryx.Products.Model/Entities/WorkplanStepEntity.cs +++ b/src/Moryx.Products.Model/Entities/WorkplanStepEntity.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using Moryx.Model; using System.Collections.Generic; diff --git a/src/Moryx.Products.Model/Migrations/Npgsql/20220906133824_InitialCreate.Designer.cs b/src/Moryx.Products.Model/Migrations/Npgsql/20220906133824_InitialCreate.Designer.cs index c16706b8f..394079c2d 100644 --- a/src/Moryx.Products.Model/Migrations/Npgsql/20220906133824_InitialCreate.Designer.cs +++ b/src/Moryx.Products.Model/Migrations/Npgsql/20220906133824_InitialCreate.Designer.cs @@ -1,10 +1,12 @@ -// +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +// using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Moryx.Products.Model; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace Moryx.Products.Model.Migrations.Npgsql diff --git a/src/Moryx.Products.Model/Migrations/Npgsql/20220906133824_InitialCreate.cs b/src/Moryx.Products.Model/Migrations/Npgsql/20220906133824_InitialCreate.cs index d906a2559..b974f6fc9 100644 --- a/src/Moryx.Products.Model/Migrations/Npgsql/20220906133824_InitialCreate.cs +++ b/src/Moryx.Products.Model/Migrations/Npgsql/20220906133824_InitialCreate.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +using System; using Microsoft.EntityFrameworkCore.Migrations; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; diff --git a/src/Moryx.Products.Model/Migrations/Sqlite/20230214165158_InitialCreate.Designer.cs b/src/Moryx.Products.Model/Migrations/Sqlite/20230214165158_InitialCreate.Designer.cs index e84034331..d837c1f43 100644 --- a/src/Moryx.Products.Model/Migrations/Sqlite/20230214165158_InitialCreate.Designer.cs +++ b/src/Moryx.Products.Model/Migrations/Sqlite/20230214165158_InitialCreate.Designer.cs @@ -1,10 +1,12 @@ -// +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +// using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Moryx.Products.Model; #nullable disable diff --git a/src/Moryx.Products.Model/Migrations/Sqlite/20230214165158_InitialCreate.cs b/src/Moryx.Products.Model/Migrations/Sqlite/20230214165158_InitialCreate.cs index 1a3aeb4ce..e999daffb 100644 --- a/src/Moryx.Products.Model/Migrations/Sqlite/20230214165158_InitialCreate.cs +++ b/src/Moryx.Products.Model/Migrations/Sqlite/20230214165158_InitialCreate.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +using System; using Microsoft.EntityFrameworkCore.Migrations; #nullable disable diff --git a/src/Moryx.Products.Model/Moryx.Products.Model.csproj b/src/Moryx.Products.Model/Moryx.Products.Model.csproj index 25b61d2de..5291b228b 100644 --- a/src/Moryx.Products.Model/Moryx.Products.Model.csproj +++ b/src/Moryx.Products.Model/Moryx.Products.Model.csproj @@ -1,10 +1,9 @@  - net6.0 + net8.0 true Database model for the ProductManagement module - true MORYX;IIoT;IoT;Product;Manufacturing;Management diff --git a/src/Moryx.Products.Samples/Moryx.Products.Samples.csproj b/src/Moryx.Products.Samples/Moryx.Products.Samples.csproj index 3a434c7ef..2a9435d73 100644 --- a/src/Moryx.Products.Samples/Moryx.Products.Samples.csproj +++ b/src/Moryx.Products.Samples/Moryx.Products.Samples.csproj @@ -1,8 +1,9 @@  - net6.0 + net8.0 false + false diff --git a/src/Moryx.Resources.Management/Extensions/ResourceExtensions.cs b/src/Moryx.Resources.Management/Extensions/ResourceExtensions.cs index bbfb81242..122e596a7 100644 --- a/src/Moryx.Resources.Management/Extensions/ResourceExtensions.cs +++ b/src/Moryx.Resources.Management/Extensions/ResourceExtensions.cs @@ -8,7 +8,7 @@ namespace Moryx.Resources.Management internal static class ResourceExtensions { public static TResource Proxify(this TResource source, IResourceTypeController typeController) - where TResource : class, IPublicResource + where TResource : class, IResource { if (ResourceTypeController.IsGenericResourceInterface(typeof(TResource))) throw new NotSupportedException("Generic resource interfaces are not supported through the facade!"); @@ -17,7 +17,7 @@ public static TResource Proxify(this TResource source, IResourceTypeC } public static IEnumerable Proxify(this IEnumerable source, IResourceTypeController typeController) - where TResource : class, IPublicResource + where TResource : class, IResource { return source.Select(r => r.Proxify(typeController)); } diff --git a/src/Moryx.Resources.Management/Facades/ResourceManagementFacade.cs b/src/Moryx.Resources.Management/Facades/ResourceManagementFacade.cs index 177ab9f06..baa5f7a23 100644 --- a/src/Moryx.Resources.Management/Facades/ResourceManagementFacade.cs +++ b/src/Moryx.Resources.Management/Facades/ResourceManagementFacade.cs @@ -43,70 +43,70 @@ public void Deactivate() private void OnCapabilitiesChanged(object sender, ICapabilities args) { - CapabilitiesChanged?.Invoke(((IPublicResource)sender).Proxify(TypeController), args); + CapabilitiesChanged?.Invoke(((IResource)sender).Proxify(TypeController), args); } - private void OnResourceAdded(object sender, IPublicResource publicResource) + private void OnResourceAdded(object sender, IResource publicResource) { ResourceAdded?.Invoke(this, publicResource.Proxify(TypeController)); } - private void OnResourceRemoved(object sender, IPublicResource publicResource) + private void OnResourceRemoved(object sender, IResource publicResource) { ResourceRemoved?.Invoke(this, publicResource.Proxify(TypeController)); } #endregion #region IResourceManagement - public TResource GetResource() where TResource : class, IPublicResource + public TResource GetResource() where TResource : class, IResource { ValidateHealthState(); return ResourceGraph.GetResource().Proxify(TypeController); } public TResource GetResource(long id) - where TResource : class, IPublicResource + where TResource : class, IResource { ValidateHealthState(); return ResourceGraph.GetResource(id).Proxify(TypeController); } public TResource GetResource(string name) - where TResource : class, IPublicResource + where TResource : class, IResource { ValidateHealthState(); return ResourceGraph.GetResource(name).Proxify(TypeController); } public TResource GetResource(ICapabilities requiredCapabilities) - where TResource : class, IPublicResource + where TResource : class, IResource { ValidateHealthState(); return ResourceGraph.GetResource(r => requiredCapabilities.ProvidedBy(r.Capabilities)).Proxify(TypeController); } public TResource GetResource(Func predicate) - where TResource : class, IPublicResource + where TResource : class, IResource { ValidateHealthState(); return ResourceGraph.GetResource(predicate).Proxify(TypeController); } - public IEnumerable GetResources() where TResource : class, IPublicResource + public IEnumerable GetResources() where TResource : class, IResource { ValidateHealthState(); return ResourceGraph.GetResources().Proxify(TypeController); } public IEnumerable GetResources(ICapabilities requiredCapabilities) - where TResource : class, IPublicResource + where TResource : class, IResource { ValidateHealthState(); return ResourceGraph.GetResources(r => requiredCapabilities.ProvidedBy(r.Capabilities)).Proxify(TypeController); } public IEnumerable GetResources(Func predicate) - where TResource : class, IPublicResource + where TResource : class, IResource { ValidateHealthState(); return ResourceGraph.GetResources(predicate).Proxify(TypeController); @@ -177,10 +177,10 @@ public IEnumerable GetAllResources(Func p /// - public event EventHandler ResourceAdded; + public event EventHandler ResourceAdded; /// - public event EventHandler ResourceRemoved; + public event EventHandler ResourceRemoved; /// public event EventHandler CapabilitiesChanged; diff --git a/src/Moryx.Resources.Management/Model/Entities/ResourceEntity.cs b/src/Moryx.Resources.Management/Model/Entities/ResourceEntity.cs index 7cc5ba790..5ffc57ff2 100644 --- a/src/Moryx.Resources.Management/Model/Entities/ResourceEntity.cs +++ b/src/Moryx.Resources.Management/Model/Entities/ResourceEntity.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using Moryx.Model; using System.Collections.Generic; diff --git a/src/Moryx.Resources.Management/Model/Entities/ResourceRelationEntity.cs b/src/Moryx.Resources.Management/Model/Entities/ResourceRelationEntity.cs index 67eeeaf5e..2f9565f4b 100644 --- a/src/Moryx.Resources.Management/Model/Entities/ResourceRelationEntity.cs +++ b/src/Moryx.Resources.Management/Model/Entities/ResourceRelationEntity.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using Moryx.Model; // ReSharper disable once CheckNamespace diff --git a/src/Moryx.Resources.Management/Model/Migrations/Npgsql/20211104134830_InitialCreate.Designer.cs b/src/Moryx.Resources.Management/Model/Migrations/Npgsql/20211104134830_InitialCreate.Designer.cs index 83c994137..794c47f54 100644 --- a/src/Moryx.Resources.Management/Model/Migrations/Npgsql/20211104134830_InitialCreate.Designer.cs +++ b/src/Moryx.Resources.Management/Model/Migrations/Npgsql/20211104134830_InitialCreate.Designer.cs @@ -1,4 +1,8 @@ -// +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +// using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; diff --git a/src/Moryx.Resources.Management/Model/Migrations/Npgsql/20211104134830_InitialCreate.cs b/src/Moryx.Resources.Management/Model/Migrations/Npgsql/20211104134830_InitialCreate.cs index 28677526f..8a5135124 100644 --- a/src/Moryx.Resources.Management/Model/Migrations/Npgsql/20211104134830_InitialCreate.cs +++ b/src/Moryx.Resources.Management/Model/Migrations/Npgsql/20211104134830_InitialCreate.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +using System; using Microsoft.EntityFrameworkCore.Migrations; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; diff --git a/src/Moryx.Resources.Management/Model/Migrations/Sqlite/20230215071938_InitialCreate.Designer.cs b/src/Moryx.Resources.Management/Model/Migrations/Sqlite/20230215071938_InitialCreate.Designer.cs index 823f19fc4..f471e12b1 100644 --- a/src/Moryx.Resources.Management/Model/Migrations/Sqlite/20230215071938_InitialCreate.Designer.cs +++ b/src/Moryx.Resources.Management/Model/Migrations/Sqlite/20230215071938_InitialCreate.Designer.cs @@ -1,9 +1,12 @@ -// +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +// using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Moryx.Resources.Model; #nullable disable diff --git a/src/Moryx.Resources.Management/Model/Migrations/Sqlite/20230215071938_InitialCreate.cs b/src/Moryx.Resources.Management/Model/Migrations/Sqlite/20230215071938_InitialCreate.cs index 20a95ce26..41aaa8b06 100644 --- a/src/Moryx.Resources.Management/Model/Migrations/Sqlite/20230215071938_InitialCreate.cs +++ b/src/Moryx.Resources.Management/Model/Migrations/Sqlite/20230215071938_InitialCreate.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +using System; using Microsoft.EntityFrameworkCore.Migrations; #nullable disable diff --git a/src/Moryx.Resources.Management/Model/ResourcesContext.cs b/src/Moryx.Resources.Management/Model/ResourcesContext.cs index ad7904e9f..3065d705d 100644 --- a/src/Moryx.Resources.Management/Model/ResourcesContext.cs +++ b/src/Moryx.Resources.Management/Model/ResourcesContext.cs @@ -1,12 +1,8 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 -using System.IO; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; using Moryx.Model; -using Moryx.Model.Attributes; -using Moryx.Model.PostgreSQL; // ReSharper disable once CheckNamespace namespace Moryx.Resources.Model diff --git a/src/Moryx.Resources.Management/ModuleController/ModuleConsole.cs b/src/Moryx.Resources.Management/ModuleController/ModuleConsole.cs index a031e37b3..c7f62a1ad 100644 --- a/src/Moryx.Resources.Management/ModuleController/ModuleConsole.cs +++ b/src/Moryx.Resources.Management/ModuleController/ModuleConsole.cs @@ -31,12 +31,6 @@ internal class ModuleConsole : IServerModuleConsole #endregion - #region Fields - - private IResourceInitializer[] _initializers; - - #endregion - [EntrySerialize, DisplayName("Initialize Resource"), Description("Calls the configured resource initializer")] public string CallResourceInitializer([PluginConfigs(typeof(IResourceInitializer), true)] ResourceInitializerConfig[] configs) { diff --git a/src/Moryx.Resources.Management/ModuleController/ModuleController.cs b/src/Moryx.Resources.Management/ModuleController/ModuleController.cs index 7f33b4777..06cf7ae04 100644 --- a/src/Moryx.Resources.Management/ModuleController/ModuleController.cs +++ b/src/Moryx.Resources.Management/ModuleController/ModuleController.cs @@ -16,7 +16,7 @@ namespace Moryx.Resources.Management /// /// The main controller of all resource modules. /// - public class ModuleController : ServerModuleFacadeControllerBase, + public class ModuleController : ServerModuleBase, IFacadeContainer, IFacadeContainer, IFacadeContainer @@ -33,6 +33,7 @@ public class ModuleController : ServerModuleFacadeControllerBase, /// public IDbContextManager DbContextManager { get; } + /// public ModuleController(IModuleContainerFactory containerFactory, IConfigManager configManager, ILoggerFactory loggerFactory, IDbContextManager contextManager) : base(containerFactory, configManager, loggerFactory) { diff --git a/src/Moryx.Resources.Management/Moryx.Resources.Management.csproj b/src/Moryx.Resources.Management/Moryx.Resources.Management.csproj index fb46a416c..272b56aec 100644 --- a/src/Moryx.Resources.Management/Moryx.Resources.Management.csproj +++ b/src/Moryx.Resources.Management/Moryx.Resources.Management.csproj @@ -1,11 +1,10 @@  - net6.0 + net8.0 true true ResourceManagement module composing and maintaining the resource graph as the habitat for digital twins of manufacturing assets. - true MORYX;IIoT;IoT;Manufacturing;API;Resource diff --git a/src/Moryx.Resources.Management/Resources/DataMemberAttributeValueProviderFilter.cs b/src/Moryx.Resources.Management/Resources/DataMemberAttributeValueProviderFilter.cs index 4bfa68f6a..777c35110 100644 --- a/src/Moryx.Resources.Management/Resources/DataMemberAttributeValueProviderFilter.cs +++ b/src/Moryx.Resources.Management/Resources/DataMemberAttributeValueProviderFilter.cs @@ -18,6 +18,7 @@ public DataMemberAttributeValueProviderFilter(bool filterDataMembers) _filterDataMembers = filterDataMembers; } + /// public bool CheckProperty(PropertyInfo propertyInfo) { if(_filterDataMembers) diff --git a/src/Moryx.Resources.Management/Resources/IManagedResourceGraph.cs b/src/Moryx.Resources.Management/Resources/IManagedResourceGraph.cs index b6c25a21a..e041f2ed4 100644 --- a/src/Moryx.Resources.Management/Resources/IManagedResourceGraph.cs +++ b/src/Moryx.Resources.Management/Resources/IManagedResourceGraph.cs @@ -15,7 +15,7 @@ internal interface IManagedResourceGraph : IResourceGraph /// /// Add a resource to the graph /// - ResourceWrapper Add(Resource instance); + Resource Add(Resource instance); /// /// Remove an instance from the graph @@ -23,14 +23,14 @@ internal interface IManagedResourceGraph : IResourceGraph bool Remove(Resource instance); /// - /// Return the wrapper of a resource instance + /// Return the resource instance /// - ResourceWrapper GetWrapper(long id); + Resource GetResource(long id); /// /// Access the full graph /// - ICollection GetAll(); + ICollection GetAll(); /// /// TODO: Find a better way diff --git a/src/Moryx.Resources.Management/Resources/IResourceManager.cs b/src/Moryx.Resources.Management/Resources/IResourceManager.cs index c086a8168..dc2009cc0 100644 --- a/src/Moryx.Resources.Management/Resources/IResourceManager.cs +++ b/src/Moryx.Resources.Management/Resources/IResourceManager.cs @@ -20,12 +20,12 @@ internal interface IResourceManager : IInitializablePlugin /// /// Event raised when a resource was added at runtime /// - event EventHandler ResourceAdded; + event EventHandler ResourceAdded; /// /// Event raised when a resource was removed at runtime /// - event EventHandler ResourceRemoved; + event EventHandler ResourceRemoved; /// /// Raised when the capabilities have changed. diff --git a/src/Moryx.Resources.Management/Resources/ResourceEntityAccessor.cs b/src/Moryx.Resources.Management/Resources/ResourceEntityAccessor.cs index 3bd569b90..9e3ddbaa7 100644 --- a/src/Moryx.Resources.Management/Resources/ResourceEntityAccessor.cs +++ b/src/Moryx.Resources.Management/Resources/ResourceEntityAccessor.cs @@ -1,7 +1,6 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 -using System; using System.Collections.Generic; using System.Linq; using Moryx.AbstractionLayer.Resources; diff --git a/src/Moryx.Resources.Management/Resources/ResourceGraph.cs b/src/Moryx.Resources.Management/Resources/ResourceGraph.cs index f0f08c041..300b5ccf9 100644 --- a/src/Moryx.Resources.Management/Resources/ResourceGraph.cs +++ b/src/Moryx.Resources.Management/Resources/ResourceGraph.cs @@ -29,24 +29,16 @@ internal class ResourceGraph : IManagedResourceGraph /// /// All resources of the graph /// - private readonly IDictionary _graph = new Dictionary(); - - /// - /// Quick access to all public resources - /// - private readonly IList _publicResources = new List(); + private readonly IDictionary _graph = new Dictionary(); public Action SaveDelegate { get; set; } public Func DestroyDelegate { get; set; } - public ResourceWrapper Add(Resource instance) + public Resource Add(Resource instance) { _graphLock.EnterWriteLock(); - var wrapper = _graph[instance.Id] = new ResourceWrapper(instance); - - if (instance is IPublicResource publicResource) - _publicResources.Add(publicResource); + var wrapper = _graph[instance.Id] = instance; _graphLock.ExitWriteLock(); return wrapper; @@ -56,8 +48,6 @@ public bool Remove(Resource instance) { _graphLock.EnterWriteLock(); var found = _graph.Remove(instance.Id); - if (found) - _publicResources.Remove(instance as IPublicResource); _graphLock.ExitWriteLock(); return found; @@ -65,10 +55,10 @@ public bool Remove(Resource instance) public Resource Get(long id) { - return GetWrapper(id)?.Target; + return GetResource(id); } - public ResourceWrapper GetWrapper(long id) + public Resource GetResource(long id) { _graphLock.EnterReadLock(); var match = _graph.ContainsKey(id) ? _graph[id] : null; @@ -77,7 +67,7 @@ public ResourceWrapper GetWrapper(long id) return match; } - public ICollection GetAll() + public ICollection GetAll() { _graphLock.EnterReadLock(); var values = _graph.Values; @@ -120,16 +110,8 @@ public IEnumerable GetResources(Func pred { IEnumerable matches; _graphLock.EnterReadLock(); - // Use short cut if a public resource is requested - if (typeof(IPublicResource).IsAssignableFrom(typeof(TResource))) - { - matches = _publicResources.Where(p => _graph[p.Id].State.IsAvailable).OfType().Where(predicate); - } - else - { - matches = from wrapper in _graph.Values let target = wrapper.Target as TResource + matches = from resource in _graph.Values let target = resource as TResource where target != null && predicate(target) select target; - } _graphLock.ExitReadLock(); return matches; diff --git a/src/Moryx.Resources.Management/Resources/ResourceManager.cs b/src/Moryx.Resources.Management/Resources/ResourceManager.cs index 5acf6d009..73ec82220 100644 --- a/src/Moryx.Resources.Management/Resources/ResourceManager.cs +++ b/src/Moryx.Resources.Management/Resources/ResourceManager.cs @@ -1,10 +1,6 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Moryx.AbstractionLayer.Capabilities; using Moryx.AbstractionLayer.Resources; @@ -14,6 +10,11 @@ using Moryx.Modules; using Moryx.Resources.Model; using Moryx.Tools; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using IResource = Moryx.AbstractionLayer.Resources.IResource; namespace Moryx.Resources.Management { @@ -97,6 +98,11 @@ private enum ResourceStartupPhase /// private readonly object _fallbackLock = new(); + /// + /// Look-up of resources that failed during init or start and are excluded from certain calls + /// + private List _failedResources = new List(); + #endregion #region LifeCycle @@ -113,45 +119,80 @@ public void Initialize() // Create all objects var allResources = ResourceEntityAccessor.FetchResourceTemplates(uow); if (allResources.Count > 0) - { LoadResources(allResources); - } } _startup = ResourceStartupPhase.Initializing; - // Boot resources - Parallel.ForEach(Graph.GetAll(), resourceWrapper => - { - try - { - resourceWrapper.Initialize(); - } - catch (Exception e) - { - resourceWrapper.ErrorOccured(); - Logger.Log(LogLevel.Warning, e, "Failed to initialize resource {0}-{1}", resourceWrapper.Target.Id, resourceWrapper.Target.Name); - } - }); + // initialize resources + Parallel.ForEach(Graph.GetAll(), InitializeResource); _startup = ResourceStartupPhase.Initialized; } + /// + /// Handles the initialization of the resource + /// + /// + private void InitializeResource(Resource resource) + { + try + { + ((IInitializable)resource).Initialize(); + } + catch (Exception e) + { + Logger.Log(LogLevel.Warning, e, "Failed to initialize resource {0}-{1}", resource.Id, resource.Name); + // Track resources as failed to exclude from future calls + lock (_failedResources) + _failedResources.Add(resource); + } + } + + /// + /// Starts a resource and handles in case of failure. + /// + /// + private void StartResource(Resource resource) + { + try + { + ((IPlugin)resource).Start(); + } + catch (Exception e) + { + Logger.Log(LogLevel.Warning, e, "Failed to start resource {0}-{1}", resource.Id, resource.Name); + } + } + /// /// Load and link all resources from the database /// private void LoadResources(ICollection allResources) { // Create resource objects on multiple threads - var query = from template in allResources.AsParallel() - select template.Instantiate(TypeController, Graph); - foreach (var resource in query) - AddResource(resource, false); + Parallel.ForEach(allResources, InstantiateResource); // Link them to each other Parallel.ForEach(allResources, LinkReferences); // Register events after all links were set - foreach (var resourceWrapper in Graph.GetAll()) - RegisterEvents(resourceWrapper.Target); + foreach (var resource in Graph.GetAll()) + RegisterEvents(resource); + } + + /// + /// Instantiate object from entity based template + /// + private void InstantiateResource(ResourceEntityAccessor template) + { + try + { + var resource = template.Instantiate(TypeController, Graph); + AddResource(resource, false); + } + catch (Exception e) + { + Logger.Log(LogLevel.Warning, e, "Failed to instantiate resource {0}-{1}", template.Id, template.Name); + } } /// @@ -160,7 +201,7 @@ private void LoadResources(ICollection allResources) private void AddResource(Resource instance, bool registerEvents) { // Add instance to the graph - var wrapped = Graph.Add(instance); + var resource = Graph.Add(instance); // Register to events if (registerEvents) @@ -174,12 +215,12 @@ private void AddResource(Resource instance, bool registerEvents) case ResourceStartupPhase.Initializing: case ResourceStartupPhase.Initialized: // Resources those are created during the initialize of a resource are automatically initialized also. - wrapped.Initialize(); + InitializeResource(resource); break; case ResourceStartupPhase.Starting: case ResourceStartupPhase.Started: // Resources those are created during the start of a resource are automatically initialized and started also. - InitializeAndStart(wrapped); + InitializeAndStart(resource); break; case ResourceStartupPhase.Stopping: case ResourceStartupPhase.Stopped: @@ -189,22 +230,17 @@ private void AddResource(Resource instance, bool registerEvents) throw new ArgumentOutOfRangeException(); } - // Inform listeners about the new resource - if (instance is IPublicResource publicResource) - RaiseResourceAdded(publicResource); + RaiseResourceAdded(resource); } - private void InitializeAndStart(ResourceWrapper wrappedResource) + /// + /// Initialize and start the current resource + /// + /// Current resource + private void InitializeAndStart(Resource resource) { - wrappedResource.Initialize(); - try - { - wrappedResource.Start(); - } - catch (Exception ex) - { - Logger.Log(LogLevel.Warning, ex, "Could not start resource {0}-{1}!", wrappedResource.Target.Id, wrappedResource.Target.Name); - } + InitializeResource(resource); + StartResource(resource); } /// @@ -213,9 +249,7 @@ private void InitializeAndStart(ResourceWrapper wrappedResource) private void RegisterEvents(Resource instance) { instance.Changed += OnResourceChanged; - - if (instance is IPublicResource asPublic) - asPublic.CapabilitiesChanged += RaiseCapabilitiesChanged; + instance.CapabilitiesChanged += RaiseCapabilitiesChanged; foreach (var autoSaveCollection in ResourceReferenceTools.GetAutoSaveCollections(instance)) autoSaveCollection.CollectionChanged += OnAutoSaveCollectionChanged; @@ -227,9 +261,7 @@ private void RegisterEvents(Resource instance) private void UnregisterEvents(Resource instance) { instance.Changed -= OnResourceChanged; - - if (instance is IPublicResource asPublic) - asPublic.CapabilitiesChanged -= RaiseCapabilitiesChanged; + instance.CapabilitiesChanged -= RaiseCapabilitiesChanged; foreach (var autoSaveCollection in ResourceReferenceTools.GetAutoSaveCollections(instance)) autoSaveCollection.CollectionChanged -= OnAutoSaveCollectionChanged; @@ -254,19 +286,9 @@ private void LinkReferences(ResourceEntityAccessor entityAccessor) public void Start() { + // start resources _startup = ResourceStartupPhase.Starting; - Parallel.ForEach(Graph.GetAll(), resourceWrapper => - { - try - { - resourceWrapper.Start(); - } - catch (Exception e) - { - resourceWrapper.ErrorOccured(); - Logger.Log(LogLevel.Warning, e, "Failed to start resource {0}-{1}", resourceWrapper.Target.Id, resourceWrapper.Target.Name); - } - }); + Parallel.ForEach(Graph.GetAll().Except(_failedResources), StartResource); _startup = ResourceStartupPhase.Started; } @@ -274,16 +296,16 @@ public void Stop() { _startup = ResourceStartupPhase.Stopping; - Parallel.ForEach(Graph.GetAll(), resourceWrapper => + Parallel.ForEach(Graph.GetAll(), resource => { try { - resourceWrapper.Stop(); - UnregisterEvents(resourceWrapper.Target); + ((IPlugin)resource).Stop(); + UnregisterEvents(resource); } catch (Exception e) { - Logger.Log(LogLevel.Warning, e, "Failed to stop resource {0}-{1}", resourceWrapper.Target.Id, resourceWrapper.Target.Name); + Logger.Log(LogLevel.Warning, e, "Failed to stop resource {0}-{1}", resource.Id, resource.Name); } }); @@ -294,7 +316,7 @@ public void Stop() public void Save(Resource resource) { - lock (Graph.GetWrapper(resource.Id) ?? _fallbackLock) + lock (Graph.GetResource(resource.Id) ?? _fallbackLock) { using var uow = UowFactory.Create(); var newResources = new HashSet(); @@ -339,7 +361,7 @@ private void OnAutoSaveCollectionChanged(object sender, ReferenceCollectionChang var instance = args.Parent; var property = args.CollectionProperty; - lock (Graph.GetWrapper(instance.Id)) // Unlike Save AutoSave collections are ALWAYS part of the Graph + lock (Graph.GetResource(instance.Id)) // Unlike Save AutoSave collections are ALWAYS part of the Graph { using var uow = UowFactory.Create(); var newResources = ResourceLinker.SaveSingleCollection(uow, instance, property); @@ -410,8 +432,8 @@ public bool Destroy(IResource resource, bool permanent) var removed = Graph.Remove(instance); // Notify listeners about the removal of the resource - if (removed && instance is IPublicResource publicResource) - RaiseResourceRemoved(publicResource); + if (removed) + RaiseResourceRemoved(instance); // Destroy the object TypeController.Destroy(instance); @@ -424,25 +446,24 @@ public bool Destroy(IResource resource, bool permanent) #region IResourceManagement - private void RaiseResourceAdded(IPublicResource newResource) + private void RaiseResourceAdded(IResource newResource) { ResourceAdded?.Invoke(this, newResource); } - public event EventHandler ResourceAdded; + public event EventHandler ResourceAdded; - private void RaiseResourceRemoved(IPublicResource newResource) + private void RaiseResourceRemoved(IResource newResource) { ResourceRemoved?.Invoke(this, newResource); } - public event EventHandler ResourceRemoved; + public event EventHandler ResourceRemoved; /// public event EventHandler CapabilitiesChanged; private void RaiseCapabilitiesChanged(object originalSender, ICapabilities capabilities) { - // Only forward events for available resources - if (Graph.GetWrapper(((IResource)originalSender).Id).State.IsAvailable) + if (Graph.GetAll().Any(x => x.Id == ((IResource)originalSender).Id)) CapabilitiesChanged?.Invoke(originalSender, capabilities); } diff --git a/src/Moryx.Resources.Management/Resources/ResourceProxy.cs b/src/Moryx.Resources.Management/Resources/ResourceProxy.cs index 1489df644..238cd29db 100644 --- a/src/Moryx.Resources.Management/Resources/ResourceProxy.cs +++ b/src/Moryx.Resources.Management/Resources/ResourceProxy.cs @@ -1,8 +1,10 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +using System; using System.Collections.Generic; using System.Linq; +using Moryx.AbstractionLayer.Capabilities; using Moryx.AbstractionLayer.Resources; namespace Moryx.Resources.Management @@ -17,6 +19,8 @@ internal abstract class ResourceProxy : IResource /// private IResourceTypeController _typeController; + public event EventHandler CapabilitiesChanged; + /// /// Target resource of the proxy /// @@ -29,14 +33,18 @@ protected ResourceProxy(IResource target, IResourceTypeController typeController { Target = target; _typeController = typeController; + Target.CapabilitiesChanged += OnCapabilitiesChanged; } + /// long IResource.Id => Target.Id; /// string IResource.Name => Target.Name; + public ICapabilities Capabilities => Target.Capabilities; + public virtual void Attach() { } @@ -52,6 +60,10 @@ public override string ToString() return Target.ToString(); } + private void OnCapabilitiesChanged(object sender, ICapabilities e) + { + CapabilitiesChanged?.Invoke(this, e); + } /// /// Convert a referenced instance to a proxy /// diff --git a/src/Moryx.Resources.Management/Resources/ResourceProxyBuilder.cs b/src/Moryx.Resources.Management/Resources/ResourceProxyBuilder.cs index c09508ce4..a6a04f884 100644 --- a/src/Moryx.Resources.Management/Resources/ResourceProxyBuilder.cs +++ b/src/Moryx.Resources.Management/Resources/ResourceProxyBuilder.cs @@ -87,7 +87,7 @@ public Type Build(Type resourceType, IReadOnlyList interfaces) } // Target field for property and method forwarding - const string propertyName = nameof(ResourceProxy.Target); + const string propertyName = nameof(ResourceProxy.Target); var targetProperty = baseType.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); var bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public; diff --git a/src/Moryx.Resources.Management/Resources/ResourceWrapper.cs b/src/Moryx.Resources.Management/Resources/ResourceWrapper.cs deleted file mode 100644 index f319ffaf7..000000000 --- a/src/Moryx.Resources.Management/Resources/ResourceWrapper.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using Moryx.AbstractionLayer.Resources; -using Moryx.Modules; -using Moryx.StateMachines; - -namespace Moryx.Resources.Management -{ - internal sealed class ResourceWrapper : IStateContext - { - internal Resource Target { get; } - - internal ResourceStateBase State { get; private set; } - - void IStateContext.SetState(IState state) - { - State = (ResourceStateBase)state; - } - - internal ResourceWrapper(Resource target) - { - Target = target; - StateMachine.Initialize(this).With(); - } - - internal void Initialize() - { - State.Initialize(); - } - - internal void HandleInitialize() - { - ((IInitializable)Target).Initialize(); - } - - internal void Start() - { - State.Start(); - } - - internal void HandleStart() - { - ((IPlugin)Target).Start(); - } - - internal void ErrorOccured() - { - State.ErrorOccured(); - } - - internal void Stop() - { - State.Stop(); - } - - internal void HandleStop() - { - ((IPlugin)Target).Stop(); - } - } -} diff --git a/src/Moryx.Resources.Management/States/CreatedState.cs b/src/Moryx.Resources.Management/States/CreatedState.cs deleted file mode 100644 index ee7587076..000000000 --- a/src/Moryx.Resources.Management/States/CreatedState.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -namespace Moryx.Resources.Management -{ - /// - /// State of a newly created - /// - internal class CreatedState : ResourceStateBase - { - /// - /// constructor - /// - public CreatedState(ResourceWrapper context, StateMap stateMap) : base(context, stateMap) - { - } - - /// - public override void Initialize() - { - Context.HandleInitialize(); - NextState(StateInitialized); - } - } -} diff --git a/src/Moryx.Resources.Management/States/ErrorState.cs b/src/Moryx.Resources.Management/States/ErrorState.cs deleted file mode 100644 index 5d050c697..000000000 --- a/src/Moryx.Resources.Management/States/ErrorState.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -namespace Moryx.Resources.Management -{ - /// - /// State of a when an error occurred while acting on wrapped resource - /// - internal class ErrorState : ResourceStateBase - { - /// - /// constructor - /// - public ErrorState(ResourceWrapper context, StateMap stateMap) : base(context, stateMap) - { - } - - /// - public override void Initialize() - { - // Do nothing - } - - /// - public override void Start() - { - // Do nothing - } - } -} diff --git a/src/Moryx.Resources.Management/States/InitializedState.cs b/src/Moryx.Resources.Management/States/InitializedState.cs deleted file mode 100644 index 6ae605352..000000000 --- a/src/Moryx.Resources.Management/States/InitializedState.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -namespace Moryx.Resources.Management -{ - /// - /// State of the when the wrappd resource was initialized - /// - internal class InitializedState : ResourceStateBase - { - /// - /// constructor - /// - public InitializedState(ResourceWrapper context, StateMap stateMap) : base(context, stateMap) - { - } - - /// - public override void Start() - { - Context.HandleStart(); - NextState(StateStarted); - } - } -} diff --git a/src/Moryx.Resources.Management/States/ResourceStateBase.cs b/src/Moryx.Resources.Management/States/ResourceStateBase.cs deleted file mode 100644 index 608c5eb56..000000000 --- a/src/Moryx.Resources.Management/States/ResourceStateBase.cs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using Moryx.StateMachines; - -namespace Moryx.Resources.Management -{ - /// - /// Base class for states of the - /// - internal abstract class ResourceStateBase : StateBase - { - /// - /// constructor - /// - protected ResourceStateBase(ResourceWrapper context, StateMap stateMap) : base(context, stateMap) - { - } - - /// - /// Flag if the resource is avaiable for external interaction - /// - public virtual bool IsAvailable => false; - - /// - /// Initialize the wrapped resource - /// - public virtual void Initialize() - { - InvalidState(); - } - - /// - /// Start the wrapped resource - /// - public virtual void Start() - { - InvalidState(); - } - /// - /// Handle an error and set the wrapped resource to the error state - /// - public virtual void ErrorOccured() - { - NextState(StateError); - } - - /// - /// Stop the wrapped resource - /// - public virtual void Stop() - { - Context.HandleStop(); - NextState(StateStopped); - } - - /// - /// The wrapped resource was created - /// - [StateDefinition(typeof(CreatedState), IsInitial = true)] - protected const int StateCreated = 0; - - /// - /// The wrapped resource was initialized - /// - [StateDefinition(typeof(InitializedState))] - protected const int StateInitialized = 10; - - /// - /// The wrapped resource was started - /// - [StateDefinition(typeof(StartedState))] - protected const int StateStarted = 20; - - /// - /// The wrapped resource was stopped - /// - [StateDefinition(typeof(StoppedState))] - protected const int StateStopped = 30; - - /// - /// An error occurred while performing an action on the wrapped resource. - /// - [StateDefinition(typeof(ErrorState))] - protected const int StateError = 40; - } -} diff --git a/src/Moryx.Resources.Management/States/StartedState.cs b/src/Moryx.Resources.Management/States/StartedState.cs deleted file mode 100644 index a0acf4d34..000000000 --- a/src/Moryx.Resources.Management/States/StartedState.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -namespace Moryx.Resources.Management -{ - /// - /// State of the when the wrappd resource was started - /// - internal class StartedState : ResourceStateBase - { - /// - /// constructor - /// - public StartedState(ResourceWrapper context, StateMap stateMap) : base(context, stateMap) - { - } - - /// - /// Indicate that resource is available for interaction - /// - public override bool IsAvailable => true; - } -} diff --git a/src/Moryx.Resources.Management/States/StoppedState.cs b/src/Moryx.Resources.Management/States/StoppedState.cs deleted file mode 100644 index 0f99273d0..000000000 --- a/src/Moryx.Resources.Management/States/StoppedState.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -namespace Moryx.Resources.Management -{ - /// - /// State of the when the wrappd resource was stopped - /// - internal class StoppedState : ResourceStateBase - { - /// - /// constructor - /// - public StoppedState(ResourceWrapper context, StateMap stateMap) : base(context, stateMap) - { - } - - /// - public override void Initialize() - { - NextState(StateInitialized); - } - } -} diff --git a/src/Moryx.Resources.Samples/AssembleResource.cs b/src/Moryx.Resources.Samples/AssembleResource.cs index 3640f2587..24302c711 100644 --- a/src/Moryx.Resources.Samples/AssembleResource.cs +++ b/src/Moryx.Resources.Samples/AssembleResource.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using System.ComponentModel; using System.Runtime.Serialization; using Moryx.AbstractionLayer.Resources; diff --git a/src/Moryx.Resources.Samples/BufferResource.cs b/src/Moryx.Resources.Samples/BufferResource.cs index 7202cdf96..e76dcc2d5 100644 --- a/src/Moryx.Resources.Samples/BufferResource.cs +++ b/src/Moryx.Resources.Samples/BufferResource.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using System.ComponentModel; using System.Linq; using System.Runtime.Serialization; @@ -10,7 +11,7 @@ namespace Moryx.Resources.Samples { [ResourceRegistration] - public class BufferResource : PublicResource + public class BufferResource : Resource { [ReferenceOverride(nameof(Children), AutoSave = true)] public IReferences Values { get; set; } diff --git a/src/Moryx.Resources.Samples/Cell.cs b/src/Moryx.Resources.Samples/Cell.cs index ad4faeaf9..4d833e6a0 100644 --- a/src/Moryx.Resources.Samples/Cell.cs +++ b/src/Moryx.Resources.Samples/Cell.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using System.ComponentModel; using System.Runtime.Serialization; using Moryx.AbstractionLayer.Resources; @@ -9,7 +10,7 @@ namespace Moryx.Resources.Samples { - public abstract class Cell : PublicResource + public abstract class Cell : Resource { #region Config diff --git a/src/Moryx.Resources.Samples/IVisualInstructor.cs b/src/Moryx.Resources.Samples/IVisualInstructor.cs index 0a097c251..40eff2bef 100644 --- a/src/Moryx.Resources.Samples/IVisualInstructor.cs +++ b/src/Moryx.Resources.Samples/IVisualInstructor.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using System.ComponentModel; using System.Runtime.Serialization; using Moryx.AbstractionLayer.Resources; diff --git a/src/Moryx.Resources.Samples/Moryx.Resources.Samples.csproj b/src/Moryx.Resources.Samples/Moryx.Resources.Samples.csproj index 18561d82d..8c94687ef 100644 --- a/src/Moryx.Resources.Samples/Moryx.Resources.Samples.csproj +++ b/src/Moryx.Resources.Samples/Moryx.Resources.Samples.csproj @@ -1,8 +1,9 @@  - netstandard2.0;net6.0 + netstandard2.0;net8.0 true + false diff --git a/src/Moryx.Resources.Samples/RoutingResource.cs b/src/Moryx.Resources.Samples/RoutingResource.cs index 9cd50a005..8dd22c915 100644 --- a/src/Moryx.Resources.Samples/RoutingResource.cs +++ b/src/Moryx.Resources.Samples/RoutingResource.cs @@ -7,7 +7,7 @@ namespace Moryx.Resources.Samples { - public class RoutingResource : PublicResource + public class RoutingResource : Resource { [EntrySerialize, ResourceTypes(typeof(IWpc))] [Description("Type of wpc for Autocreate")] diff --git a/src/Moryx.Resources.Samples/SolderingCell.cs b/src/Moryx.Resources.Samples/SolderingCell.cs index 710104d75..509f23d3a 100644 --- a/src/Moryx.Resources.Samples/SolderingCell.cs +++ b/src/Moryx.Resources.Samples/SolderingCell.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using Moryx.AbstractionLayer; using Moryx.AbstractionLayer.Resources; diff --git a/src/Moryx.Resources.Samples/StrategyUsingResource.cs b/src/Moryx.Resources.Samples/StrategyUsingResource.cs index 410d1886d..0870ebf47 100644 --- a/src/Moryx.Resources.Samples/StrategyUsingResource.cs +++ b/src/Moryx.Resources.Samples/StrategyUsingResource.cs @@ -1,13 +1,6 @@ -using Moryx.AbstractionLayer.Drivers.Rfid; -using Moryx.AbstractionLayer.Drivers; -using Moryx.AbstractionLayer.Resources; +using Moryx.AbstractionLayer.Resources; using Moryx.Container; -using System; -using System.Collections.Generic; -using System.ComponentModel; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Moryx.Serialization; using System.Runtime.Serialization; using System.Text.RegularExpressions; diff --git a/src/Moryx.Runtime.Endpoints/Databases/Endpoint/Exceptions/Exceptions.cs b/src/Moryx.Runtime.Endpoints/Databases/Endpoint/Exceptions/Exceptions.cs index 70db0546d..fbf8cadd3 100644 --- a/src/Moryx.Runtime.Endpoints/Databases/Endpoint/Exceptions/Exceptions.cs +++ b/src/Moryx.Runtime.Endpoints/Databases/Endpoint/Exceptions/Exceptions.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Moryx.Runtime.Endpoints.Databases.Endpoint.Exceptions { diff --git a/src/Moryx.Runtime.Endpoints/Databases/Endpoint/Models/DataModel.cs b/src/Moryx.Runtime.Endpoints/Databases/Endpoint/Models/DataModel.cs index ac433d6de..44b4b25ff 100644 --- a/src/Moryx.Runtime.Endpoints/Databases/Endpoint/Models/DataModel.cs +++ b/src/Moryx.Runtime.Endpoints/Databases/Endpoint/Models/DataModel.cs @@ -1,9 +1,6 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 -using Moryx.Model.Configuration; -using Moryx.Serialization; - namespace Moryx.Runtime.Endpoints.Databases.Endpoint.Models { /// diff --git a/src/Moryx.Runtime.Endpoints/Databases/Endpoint/Services/DatabaseConfigUpdateService.cs b/src/Moryx.Runtime.Endpoints/Databases/Endpoint/Services/DatabaseConfigUpdateService.cs index 8a0541fe5..7f51a46f9 100644 --- a/src/Moryx.Runtime.Endpoints/Databases/Endpoint/Services/DatabaseConfigUpdateService.cs +++ b/src/Moryx.Runtime.Endpoints/Databases/Endpoint/Services/DatabaseConfigUpdateService.cs @@ -5,8 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Moryx.Runtime.Endpoints.Databases.Endpoint.Services { diff --git a/src/Moryx.Runtime.Endpoints/Modules/Endpoint/ModulesController.cs b/src/Moryx.Runtime.Endpoints/Modules/Endpoint/ModulesController.cs index dbf2455f4..73d68e1c3 100644 --- a/src/Moryx.Runtime.Endpoints/Modules/Endpoint/ModulesController.cs +++ b/src/Moryx.Runtime.Endpoints/Modules/Endpoint/ModulesController.cs @@ -8,7 +8,6 @@ using System.Threading; using Moryx.Configuration; using Moryx.Modules; -using Moryx.Runtime.Container; using Moryx.Runtime.Modules; using Moryx.Serialization; using Microsoft.AspNetCore.Mvc; @@ -16,6 +15,7 @@ using Moryx.Runtime.Endpoints.Modules.Endpoint.Request; using Moryx.Runtime.Endpoints.Modules.Serialization; using Moryx.Threading; +using Microsoft.AspNetCore.Authorization; namespace Moryx.Runtime.Endpoints.Modules.Endpoint { @@ -42,6 +42,7 @@ public ActionResult GetDependencyEvaluation() [HttpGet] + [Authorize(Policy = RuntimePermissions.ModulesCanView)] public ActionResult> GetAll() { var models = new List(_moduleManager.AllModules.Count()); @@ -74,6 +75,7 @@ public ActionResult> GetAll() } [HttpGet("{moduleName}/healthstate")] + [Authorize(Policy = RuntimePermissions.ModulesCanView)] public ActionResult HealthState([FromRoute] string moduleName) { var module = _moduleManager.AllModules.FirstOrDefault(m => m.Name == moduleName); @@ -84,6 +86,7 @@ public ActionResult HealthState([FromRoute] string moduleName } [HttpGet("{moduleName}/notifications")] + [Authorize(Policy = RuntimePermissions.ModulesCanView)] public ActionResult> Notifications([FromRoute] string moduleName) { var module = _moduleManager.AllModules.FirstOrDefault(m => m.Name == moduleName); @@ -94,6 +97,7 @@ public ActionResult> Notifications([FromRou } [HttpPost("{moduleName}/start")] + [Authorize(Policy = RuntimePermissions.ModulesCanControl)] public ActionResult Start([FromRoute] string moduleName) { var module = GetModuleFromManager(moduleName); @@ -105,6 +109,7 @@ public ActionResult Start([FromRoute] string moduleName) } [HttpPost("{moduleName}/stop")] + [Authorize(Policy = RuntimePermissions.ModulesCanControl)] public ActionResult Stop([FromRoute] string moduleName) { var module = GetModuleFromManager(moduleName); @@ -116,6 +121,7 @@ public ActionResult Stop([FromRoute] string moduleName) } [HttpPost("{moduleName}/reincarnate")] + [Authorize(Policy = RuntimePermissions.ModulesCanControl)] public ActionResult Reincarnate([FromRoute] string moduleName) { var module = GetModuleFromManager(moduleName); @@ -127,6 +133,7 @@ public ActionResult Reincarnate([FromRoute] string moduleName) } [HttpPost("{moduleName}")] + [Authorize(Policy = RuntimePermissions.ModulesCanConfigure)] public ActionResult Update([FromRoute] string moduleName, [FromBody] ServerModuleModel module) { if (module == null) @@ -148,6 +155,7 @@ public ActionResult Update([FromRoute] string moduleName, [FromBody] ServerModul } [HttpPost("{moduleName}/confirm")] + [Authorize(Policy = RuntimePermissions.ModulesCanConfirmNotifications)] public ActionResult ConfirmWarning([FromRoute] string moduleName) { var module = GetModuleFromManager(moduleName); @@ -163,6 +171,7 @@ public ActionResult ConfirmWarning([FromRoute] string moduleName) } [HttpGet("{moduleName}/config")] + [Authorize(Policy = RuntimePermissions.ModulesCanViewConfiguration)] public ActionResult GetConfig([FromRoute] string moduleName) { try @@ -187,6 +196,7 @@ public ActionResult GetConfig([FromRoute] string moduleName) } [HttpPost("{moduleName}/config")] + [Authorize(Policy = RuntimePermissions.ModulesCanConfigure)] public ActionResult SetConfig([FromRoute] string moduleName, [FromBody] SaveConfigRequest request) { if (request.Config == null) @@ -215,6 +225,7 @@ public ActionResult SetConfig([FromRoute] string moduleName, [FromBody] SaveConf } [HttpGet("{moduleName}/console")] + [Authorize(Policy = RuntimePermissions.ModulesCanViewMethods)] public ActionResult> GetMethods([FromRoute] string moduleName) { var methods = Enumerable.Empty(); @@ -229,6 +240,7 @@ public ActionResult> GetMethods([FromRoute] string modu } [HttpPost("{moduleName}/console")] + [Authorize(Policy = RuntimePermissions.ModulesCanInvoke)] public ActionResult InvokeMethod([FromRoute] string moduleName, [FromBody] MethodEntry method) { if (method == null) @@ -252,11 +264,9 @@ public ActionResult InvokeMethod([FromRoute] string moduleName, [FromBody /// /// Create serialization for this module /// - private ICustomSerialization CreateSerialization(IModule module) + private ICustomSerialization CreateSerialization(IServerModule module) { - var host = (IContainerHost)module; - // TODO: This is dangerous - return new PossibleValuesSerialization(host.Container, _serviceProvider, (IEmptyPropertyProvider)_configManager) + return new PossibleValuesSerialization(module.Container, _serviceProvider, (IEmptyPropertyProvider)_configManager) { FormatProvider = Thread.CurrentThread.CurrentUICulture }; @@ -265,11 +275,9 @@ private ICustomSerialization CreateSerialization(IModule module) /// /// Create serialization for this module /// - private ICustomSerialization CreateEditorSerializeSerialization(IModule module) + private ICustomSerialization CreateEditorSerializeSerialization(IServerModule module) { - var host = (IContainerHost)module; - // TODO: This is dangerous - return new AdvancedEntrySerializeSerialization(host.Container, (IEmptyPropertyProvider)_configManager) + return new AdvancedEntrySerializeSerialization(module.Container, (IEmptyPropertyProvider)_configManager) { FormatProvider = Thread.CurrentThread.CurrentUICulture }; diff --git a/src/Moryx.Runtime.Endpoints/Moryx.Runtime.Endpoints.csproj b/src/Moryx.Runtime.Endpoints/Moryx.Runtime.Endpoints.csproj index bb98cf126..ceda8ed4d 100644 --- a/src/Moryx.Runtime.Endpoints/Moryx.Runtime.Endpoints.csproj +++ b/src/Moryx.Runtime.Endpoints/Moryx.Runtime.Endpoints.csproj @@ -1,8 +1,7 @@ - net6.0 - true + net8.0 diff --git a/src/Moryx.Runtime.Endpoints/RuntimePermissions.cs b/src/Moryx.Runtime.Endpoints/RuntimePermissions.cs index e8e80447b..d021fef4d 100644 --- a/src/Moryx.Runtime.Endpoints/RuntimePermissions.cs +++ b/src/Moryx.Runtime.Endpoints/RuntimePermissions.cs @@ -5,6 +5,7 @@ public static class RuntimePermissions private const string _prefix = "Moryx.Runtime."; private const string _databasePrefix = _prefix + "Database."; private const string _commonPrefix = _prefix + "Common."; + private const string _modulesPrefix = _prefix + "Modules."; public const string DatabaseCanView = _databasePrefix + "CanView"; public const string DatabaseCanSetAndTestConfig = _databasePrefix + "CanSetAndTestConfig"; public const string DatabaseCanCreate = _databasePrefix + "CanCreate"; @@ -13,5 +14,13 @@ public static class RuntimePermissions public const string DatabaseCanMigrateModel = _databasePrefix + "CanMigrateModel"; public const string DatabaseCanSetup = _databasePrefix + "CanSetup"; public const string CanGetGeneralInformation = _commonPrefix + "CanGetGeneralInformation"; + + public const string ModulesCanView = _modulesPrefix + "CanView"; + public const string ModulesCanViewConfiguration = _modulesPrefix + "CanViewConfiguration"; + public const string ModulesCanViewMethods = _modulesPrefix + "CanViewMethods"; + public const string ModulesCanControl = _modulesPrefix + "CanControl"; + public const string ModulesCanConfigure = _modulesPrefix + "CanConfigure"; + public const string ModulesCanConfirmNotifications = _modulesPrefix + "CanConfirmNotifications"; + public const string ModulesCanInvoke = _modulesPrefix + "CanInvoke"; } } diff --git a/src/Moryx.Runtime.Kernel/Configuration/ConfigManager.cs b/src/Moryx.Runtime.Kernel/Configuration/ConfigManager.cs index c851a6de4..4ea6f6095 100644 --- a/src/Moryx.Runtime.Kernel/Configuration/ConfigManager.cs +++ b/src/Moryx.Runtime.Kernel/Configuration/ConfigManager.cs @@ -14,7 +14,6 @@ namespace Moryx.Runtime.Kernel /// /// Manages the configs of the runtime and its modules. /// - [KernelComponent(typeof(IConfigManager))] public class ConfigManager : IConfigManager, IEmptyPropertyProvider { private readonly ConfigLiveUpdater _liveUpdater = new ConfigLiveUpdater(); diff --git a/src/Moryx.Runtime.Kernel/Container/ModuleContainerFactory.cs b/src/Moryx.Runtime.Kernel/Container/ModuleContainerFactory.cs index ed959591d..adef0095e 100644 --- a/src/Moryx.Runtime.Kernel/Container/ModuleContainerFactory.cs +++ b/src/Moryx.Runtime.Kernel/Container/ModuleContainerFactory.cs @@ -12,14 +12,13 @@ namespace Moryx.Runtime.Kernel /// /// Factory to create local containers of /// - [KernelComponent(typeof(IModuleContainerFactory))] public class ModuleContainerFactory : IModuleContainerFactory { /// public IContainer Create(IDictionary strategies, Assembly moduleAssembly) { - var container = new LocalContainer(strategies) - .ExecuteInstaller(new AutoInstaller(moduleAssembly)); + var container = new CastleContainer(strategies); + container.LoadFromAssembly(moduleAssembly); return container; } } diff --git a/src/Moryx.Runtime.Kernel/Modules/Components/MissingFacadeException.cs b/src/Moryx.Runtime.Kernel/Modules/Components/MissingFacadeException.cs index 0381ef61c..53e1ca509 100644 --- a/src/Moryx.Runtime.Kernel/Modules/Components/MissingFacadeException.cs +++ b/src/Moryx.Runtime.Kernel/Modules/Components/MissingFacadeException.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0 using System; -using System.Runtime.Serialization; namespace Moryx.Runtime.Kernel { @@ -19,19 +18,6 @@ public MissingFacadeException() { } - /// - /// Initializes a new instance with serialized data. - /// - /// The SerializationInfo that holds the serialized object data about the exception being thrown. - /// The StreamingContext that contains contextual information about the source or destination. - public MissingFacadeException(SerializationInfo si, StreamingContext context) - : base(si, context) - { - ModuleName = (string)si.GetValue("ModuleName", typeof(string)); - PropName = (string)si.GetValue("PropName", typeof(string)); - FacadeType = (Type)si.GetValue("FacadeType", typeof(Type)); - } - public MissingFacadeException(string moduleName, string propName, Type facadeType) : base($"Found no module hosting a facade of type {facadeType.Name} which was expected by {moduleName}.{propName}") { @@ -39,23 +25,5 @@ public MissingFacadeException(string moduleName, string propName, Type facadeTyp PropName = propName; FacadeType = facadeType; } - - /// - /// When overridden in a derived class, sets the System.Runtime.Serialization.SerializationInfo - /// with information about the exception. - /// - /// The System.Runtime.Serialization.SerializationInfo that holds the serialized - /// object data about the exception being thrown. - /// The System.Runtime.Serialization.StreamingContext that contains contextual - /// information about the source or destination. - /// The info parameter is a null reference - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - - info.AddValue("ModuleName", ModuleName); - info.AddValue("PropName", PropName); - info.AddValue("FacadeType", FacadeType); - } } } diff --git a/src/Moryx.Runtime.Kernel/Modules/MissingServerModule.cs b/src/Moryx.Runtime.Kernel/Modules/MissingServerModule.cs index 2149f337b..c033137b0 100644 --- a/src/Moryx.Runtime.Kernel/Modules/MissingServerModule.cs +++ b/src/Moryx.Runtime.Kernel/Modules/MissingServerModule.cs @@ -1,4 +1,5 @@ -using Moryx.Modules; +using Moryx.Container; +using Moryx.Modules; using Moryx.Runtime.Modules; using System; using System.Collections.Generic; @@ -59,6 +60,9 @@ public void Stop() } public Type RepresentedService { get; private set; } + + public IContainer Container => throw new NotImplementedException(); + public bool Optional { get; } } } diff --git a/src/Moryx.Runtime.Kernel/Modules/ModuleManager.cs b/src/Moryx.Runtime.Kernel/Modules/ModuleManager.cs index dcaca872c..620916251 100644 --- a/src/Moryx.Runtime.Kernel/Modules/ModuleManager.cs +++ b/src/Moryx.Runtime.Kernel/Modules/ModuleManager.cs @@ -14,7 +14,6 @@ namespace Moryx.Runtime.Kernel /// /// Manages all the modules on the server side. /// - [InitializableKernelComponent(typeof(IModuleManager))] public class ModuleManager : IModuleManager { #region Fields and Properties diff --git a/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj b/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj index fdc0e91d4..054c7834f 100644 --- a/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj +++ b/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj @@ -1,18 +1,12 @@  - netstandard2.0;net6.0 + netstandard2.0;net8.0 true Kernel components that comprise the MORYX server side runtime environment - true MORYX;Kernel;Runtime;Server - - - - - diff --git a/src/Moryx.Runtime/Container/IContainerHost.cs b/src/Moryx.Runtime/Container/IContainerHost.cs deleted file mode 100644 index 61e774fc8..000000000 --- a/src/Moryx.Runtime/Container/IContainerHost.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; -using System.Collections.Generic; -using Moryx.Container; - -namespace Moryx.Runtime.Container -{ - /// - /// Base contract for all components hosting their own container - /// - public interface IContainerHost - { - /// - /// Strategy configuration of this host - /// - IDictionary Strategies { get; } - - /// - /// Container hosted by this component - /// - IContainer Container { get; } - } -} diff --git a/src/Moryx.Runtime/Modules/IServerModule.cs b/src/Moryx.Runtime/Modules/IServerModule.cs index 056e951d8..c11bd784d 100644 --- a/src/Moryx.Runtime/Modules/IServerModule.cs +++ b/src/Moryx.Runtime/Modules/IServerModule.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0 using System; +using System.Collections.Generic; +using Moryx.Container; using Moryx.Modules; namespace Moryx.Runtime.Modules @@ -17,6 +19,11 @@ namespace Moryx.Runtime.Modules /// public interface IServerModule : IModule { + /// + /// Internal service provider of the module + /// + IContainer Container { get; } + /// /// Console to interact with the module /// diff --git a/src/Moryx.Runtime/Modules/Management/HealthStateException.cs b/src/Moryx.Runtime/Modules/Management/HealthStateException.cs index 4446ffdb2..a341004dc 100644 --- a/src/Moryx.Runtime/Modules/Management/HealthStateException.cs +++ b/src/Moryx.Runtime/Modules/Management/HealthStateException.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0 using System; -using System.Runtime.Serialization; namespace Moryx.Runtime.Modules { @@ -18,17 +17,6 @@ public HealthStateException() { } - /// - /// Initializes a new instance with serialized data. - /// - /// The SerializationInfo that holds the serialized object data about the exception being thrown. - /// The StreamingContext that contains contextual information about the source or destination. - public HealthStateException(SerializationInfo si, StreamingContext context) - : base(si, context) - { - Current = (ServerModuleState)si.GetValue("Current", typeof(ServerModuleState)); - } - /// /// Create a new instance of the to notify a facade user of an /// invalid operation @@ -48,20 +36,5 @@ public HealthStateException(ServerModuleState current) /// Gets a message that describes the current exception. /// public override string Message => $"Current HealthState {Current} of service does not allow requested operation."; - - /// - /// When overridden in a derived class, sets the System.Runtime.Serialization.SerializationInfo - /// with information about the exception. - /// - /// The System.Runtime.Serialization.SerializationInfo that holds the serialized - /// object data about the exception being thrown. - /// The System.Runtime.Serialization.StreamingContext that contains contextual - /// information about the source or destination. - /// The info parameter is a null reference - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("Current", Current); - } } } diff --git a/src/Moryx.Runtime/Modules/ServerModuleBase.cs b/src/Moryx.Runtime/Modules/ServerModuleBase.cs index 4af32cad3..5a8a693e4 100644 --- a/src/Moryx.Runtime/Modules/ServerModuleBase.cs +++ b/src/Moryx.Runtime/Modules/ServerModuleBase.cs @@ -4,13 +4,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; +using System.Reflection; using System.Threading; using Microsoft.Extensions.Logging; using Moryx.Configuration; using Moryx.Container; using Moryx.Logging; using Moryx.Modules; -using Moryx.Runtime.Container; using Moryx.StateMachines; using Moryx.Threading; @@ -21,17 +22,25 @@ namespace Moryx.Runtime.Modules /// /// Configuration type for the server module. [DebuggerDisplay("{" + nameof(Name) + "} - {" + nameof(State) + "}")] - public abstract class ServerModuleBase : IServerModule, IContainerHost, IServerModuleStateContext + public abstract class ServerModuleBase : IServerModule, IServerModuleStateContext where TConf : class, IConfig, new() { /// public abstract string Name { get; } + /// + /// All facades that were activated + /// + private readonly ICollection _activeFacades = new List(); + /// /// Logger of this module. /// public ILogger Logger { get; set; } + /// + /// Shared factory to create logger in this module + /// public ILoggerFactory LoggerFactory { get; set; } /// @@ -127,14 +136,10 @@ void IServerModuleStateContext.Start() void IServerModuleStateContext.Started() { - OnStarted(); - } - - /// - /// Called when module has been started - /// - protected internal virtual void OnStarted() - { + foreach (var facade in _activeFacades.OfType()) + { + facade.Activated(); + } } void IServerModule.Stop() @@ -166,6 +171,69 @@ void IServerModuleStateContext.Destruct() #endregion + #region Facade + + /// + /// Activate our public API facade and link all dependencies into the local container + /// + protected void ActivateFacade(IFacadeControl facade) + { + // First activation + facade.ValidateHealthState = ValidateHealthState; + + FillProperties(facade, FillProperty); + facade.Activate(); + + _activeFacades.Add(facade); + } + + /// + /// Deactivate our public facade and remove all references into the container + /// + protected void DeactivateFacade(IFacadeControl facade) + { + if (!_activeFacades.Remove(facade)) + return; + + facade.Deactivate(); + FillProperties(facade, (a, b) => null); + + var lifeCycleBoundFacade = facade as ILifeCycleBoundFacade; + lifeCycleBoundFacade?.Deactivated(); + } + + + private void FillProperties(object instance, Func fillingFunc) + { + // Fill everything available in the container + foreach (var prop in instance.GetType().GetProperties()) + { + var type = prop.PropertyType; + type = typeof(Array).IsAssignableFrom(type) ? type.GetElementType() : type; + var implementations = Container.GetRegisteredImplementations(type); + if (!implementations.Any()) + continue; + + if (prop.SetMethod == null) + continue; + + prop.SetValue(instance, fillingFunc(Container, prop)); + } + } + + private object FillProperty(IContainer container, PropertyInfo property) + { + var propType = property.PropertyType; + if (typeof(Array).IsAssignableFrom(propType)) + return container.ResolveAll(propType.GetElementType()); + + var strategyName = Strategies.ContainsKey(propType) ? Strategies[propType] : null; + return strategyName == null ? Container.Resolve(propType) + : Container.Resolve(propType, strategyName); + } + + #endregion + #region Container /// diff --git a/src/Moryx.Runtime/Modules/ServerModuleFacadeControllerBase.cs b/src/Moryx.Runtime/Modules/ServerModuleFacadeControllerBase.cs deleted file mode 100644 index 458d28b72..000000000 --- a/src/Moryx.Runtime/Modules/ServerModuleFacadeControllerBase.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Microsoft.Extensions.Logging; -using Moryx.Configuration; -using Moryx.Container; -using Moryx.Runtime.Container; - -namespace Moryx.Runtime.Modules -{ - /// - /// Base class for the facade contoller. - /// - /// Configuration type of the server module. - public abstract class ServerModuleFacadeControllerBase : ServerModuleBase - where TConf : class, IConfig, new() - { - /// - /// All facades that were activated - /// - private readonly ICollection _activeFacades = new List(); - - protected ServerModuleFacadeControllerBase(IModuleContainerFactory containerFactory, IConfigManager configManager, ILoggerFactory loggerFactory) - : base(containerFactory, configManager, loggerFactory) - { - } - - /// - /// Activate our public API facade - /// - protected void ActivateFacade(IFacadeControl facade) - { - // First activation - facade.ValidateHealthState = ValidateHealthState; - - FillProperties(facade, FillProperty); - facade.Activate(); - - _activeFacades.Add(facade); - } - - /// - /// Deactivate our public facade - /// - protected void DeactivateFacade(IFacadeControl facade) - { - if (!_activeFacades.Contains(facade)) - return; - - facade.Deactivate(); - FillProperties(facade, (a, b) => null); - - _activeFacades.Remove(facade); - - var lifeCycleBoundFacade = facade as ILifeCycleBoundFacade; - lifeCycleBoundFacade?.Deactivated(); - } - - - /// - protected internal sealed override void OnStarted() - { - base.OnStarted(); - - foreach (var facade in _activeFacades.OfType()) - { - facade.Activated(); - } - } - - private void FillProperties(object instance, Func fillingFunc) - { - // Fill everythin available in the container - foreach (var prop in instance.GetType().GetProperties()) - { - var type = prop.PropertyType; - type = typeof(Array).IsAssignableFrom(type) ? type.GetElementType() : type; - var implementations = Container.GetRegisteredImplementations(type); - if (!implementations.Any()) - continue; - - if (prop.SetMethod == null) - continue; - - prop.SetValue(instance, fillingFunc(Container, prop)); - } - } - - private object FillProperty(IContainer container, PropertyInfo property) - { - var propType = property.PropertyType; - if (typeof(Array).IsAssignableFrom(propType)) - return container.ResolveAll(propType.GetElementType()); - - var strategyName = StrategyName(propType); - return strategyName == null ? Container.Resolve(propType) - : Container.Resolve(propType, strategyName); - } - - private string StrategyName(Type dependencyType) - { - var config = ((IContainerHost)this).Strategies; - return config.ContainsKey(dependencyType) ? config[dependencyType] : null; - } - } -} diff --git a/src/Moryx.Runtime/Moryx.Runtime.csproj b/src/Moryx.Runtime/Moryx.Runtime.csproj index 80aec6d44..8c4839e1c 100644 --- a/src/Moryx.Runtime/Moryx.Runtime.csproj +++ b/src/Moryx.Runtime/Moryx.Runtime.csproj @@ -1,10 +1,9 @@  - netstandard2.0;net6.0 + netstandard2.0;net8.0 true Server side component types and implementations for MORYX applications - true MORYX;Runtime;Server diff --git a/src/Moryx.TestModule/ModuleController/ModuleConsole.cs b/src/Moryx.TestModule/ModuleController/ModuleConsole.cs index 94ad538a2..b958beafe 100644 --- a/src/Moryx.TestModule/ModuleController/ModuleConsole.cs +++ b/src/Moryx.TestModule/ModuleController/ModuleConsole.cs @@ -5,6 +5,7 @@ using System.ComponentModel; using Moryx.Runtime.Modules; using Moryx.Serialization; +using Moryx.Container; using IContainer = Moryx.Container.IContainer; namespace Moryx.TestModule diff --git a/src/Moryx.TestModule/ModuleController/ModuleController.cs b/src/Moryx.TestModule/ModuleController/ModuleController.cs index ce8ae334b..1077405ba 100644 --- a/src/Moryx.TestModule/ModuleController/ModuleController.cs +++ b/src/Moryx.TestModule/ModuleController/ModuleController.cs @@ -13,7 +13,7 @@ namespace Moryx.TestModule { [Description("Test module for System tests")] - public class ModuleController : ServerModuleFacadeControllerBase, IFacadeContainer + public class ModuleController : ServerModuleBase, IFacadeContainer { /// /// Db context factory for data models diff --git a/src/Moryx.TestModule/Moryx.TestModule.csproj b/src/Moryx.TestModule/Moryx.TestModule.csproj index 5c0ca9a73..3be921835 100644 --- a/src/Moryx.TestModule/Moryx.TestModule.csproj +++ b/src/Moryx.TestModule/Moryx.TestModule.csproj @@ -1,15 +1,12 @@  - net6.0 + net8.0 Moryx Runtime Module: TestModuleKestrel. Library + false - - - - diff --git a/src/Moryx.TestTools.IntegrationTest/Moryx.TestTools.IntegrationTest.csproj b/src/Moryx.TestTools.IntegrationTest/Moryx.TestTools.IntegrationTest.csproj index 82a71b2cd..bf257e324 100644 --- a/src/Moryx.TestTools.IntegrationTest/Moryx.TestTools.IntegrationTest.csproj +++ b/src/Moryx.TestTools.IntegrationTest/Moryx.TestTools.IntegrationTest.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 Library with helper classes for integration tests. true MORYX;Tests;IntegrationTest diff --git a/src/Moryx.TestTools.IntegrationTest/MoryxTestEnvironment.cs b/src/Moryx.TestTools.IntegrationTest/MoryxTestEnvironment.cs index b794b7761..3b83c7c08 100644 --- a/src/Moryx.TestTools.IntegrationTest/MoryxTestEnvironment.cs +++ b/src/Moryx.TestTools.IntegrationTest/MoryxTestEnvironment.cs @@ -5,7 +5,6 @@ using Moryx.Configuration; using Moryx.Model.InMemory; using Moryx.Model; -using Moryx.Runtime.Container; using Moryx.Runtime.Kernel; using Moryx.Runtime.Modules; using Moryx.TestTools.UnitTest; @@ -15,7 +14,7 @@ using Moryx.Tools; using System.Collections.Generic; -namespace Moryx.Shifts.Management.IntegrationTests +namespace Moryx.TestTools.IntegrationTest { /// /// A test environment for MORYX modules to test the module lifecycle as well as its @@ -103,10 +102,11 @@ public IServerModule StartTestModule() var module = (IServerModule)Services.GetService(_moduleType); module.Initialize(); - var containerHost = module as IContainerHost; - containerHost.Container.Register(nameof(NotSoParallelOps), Container.LifeCycle.Singleton); - if (!containerHost.Strategies.Any(s => s.Value == nameof(NotSoParallelOps))) - containerHost.Strategies.Add(typeof(IParallelOperations), nameof(NotSoParallelOps)); + module.Container.Register(typeof(NotSoParallelOps), [typeof(IParallelOperations)], nameof(NotSoParallelOps), Container.LifeCycle.Singleton); + + var strategies = module.GetType().GetProperty(nameof(ServerModuleBase.Strategies)).GetValue(module) as Dictionary; + if (strategies is not null && !strategies.Any(s => s.Value == nameof(NotSoParallelOps))) + strategies.Add(typeof(IParallelOperations), nameof(NotSoParallelOps)); module.Start(); return module; diff --git a/src/Moryx.TestTools.NUnit/Moryx.TestTools.NUnit.csproj b/src/Moryx.TestTools.NUnit/Moryx.TestTools.NUnit.csproj index 06fb36032..7fea020cc 100644 --- a/src/Moryx.TestTools.NUnit/Moryx.TestTools.NUnit.csproj +++ b/src/Moryx.TestTools.NUnit/Moryx.TestTools.NUnit.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 enable enable diff --git a/src/Moryx.TestTools.Test.Model/Moryx.TestTools.Test.Model.csproj b/src/Moryx.TestTools.Test.Model/Moryx.TestTools.Test.Model.csproj index 504e58611..2051f30f4 100644 --- a/src/Moryx.TestTools.Test.Model/Moryx.TestTools.Test.Model.csproj +++ b/src/Moryx.TestTools.Test.Model/Moryx.TestTools.Test.Model.csproj @@ -1,12 +1,11 @@  - net6.0 + net8.0 + false - - diff --git a/src/Moryx.TestTools.UnitTest/BasicInterceptorInstaller.cs b/src/Moryx.TestTools.UnitTest/BasicInterceptorInstaller.cs index a5520a0bc..fa99bec14 100644 --- a/src/Moryx.TestTools.UnitTest/BasicInterceptorInstaller.cs +++ b/src/Moryx.TestTools.UnitTest/BasicInterceptorInstaller.cs @@ -10,13 +10,13 @@ namespace Moryx.TestTools.UnitTest /// /// Installer registering the interceptor /// - public class BasicInterceptorInstaller : IContainerInstaller + public static class BasicInterceptorInstaller { /// - public void Install(IComponentRegistrator registrator) + public static void Install(this IContainer container) { - registrator.Register(typeof(EmptyInterceptor)); - registrator.Register(typeof(NullLoggerFactory), new []{typeof(ILoggerFactory)}); + container.Register(typeof(EmptyInterceptor)); + container.Register(typeof(NullLoggerFactory), new []{typeof(ILoggerFactory)}); } } } diff --git a/src/Moryx.TestTools.UnitTest/Moryx.TestTools.UnitTest.csproj b/src/Moryx.TestTools.UnitTest/Moryx.TestTools.UnitTest.csproj index 7428d8136..872b1a81d 100644 --- a/src/Moryx.TestTools.UnitTest/Moryx.TestTools.UnitTest.csproj +++ b/src/Moryx.TestTools.UnitTest/Moryx.TestTools.UnitTest.csproj @@ -1,10 +1,9 @@  - netstandard2.0;net6.0 + netstandard2.0;net8.0 true Library with helper classes for UnitTests. - true MORYX;Tests;UnitTests diff --git a/src/Moryx/Configuration/IConfigManager.cs b/src/Moryx/Configuration/IConfigManager.cs index 13352c1e0..c60c1e4f1 100644 --- a/src/Moryx/Configuration/IConfigManager.cs +++ b/src/Moryx/Configuration/IConfigManager.cs @@ -24,6 +24,7 @@ public interface IConfigManager /// Save configuration using its type /// /// Configuration object + /// Name of the configuration /// Update currently active config live void SaveConfiguration(IConfig configuration, string name, bool liveUpdate); diff --git a/src/Moryx/Configuration/InvalidConfigException.cs b/src/Moryx/Configuration/InvalidConfigException.cs index bce1816f9..70ab10fe7 100644 --- a/src/Moryx/Configuration/InvalidConfigException.cs +++ b/src/Moryx/Configuration/InvalidConfigException.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0 using System; -using System.Runtime.Serialization; namespace Moryx.Configuration { @@ -18,18 +17,6 @@ public InvalidConfigException() { } - /// - /// Initializes a new instance with serialized data. - /// - /// The SerializationInfo that holds the serialized object data about the exception being thrown. - /// The StreamingContext that contains contextual information about the source or destination. - public InvalidConfigException(SerializationInfo si, StreamingContext context) - : base(si, context) - { - FaultyEntry = si.GetValue("FaultyEntry", typeof(object)); - PropertyFailure = (string)si.GetValue("PropertyFailure", typeof(string)); - } - /// /// Signal an invalid value within the configuration /// @@ -42,23 +29,6 @@ public InvalidConfigException(object faultyEntry, string propertyFailure) PropertyFailure = propertyFailure; } - /// - /// When overridden in a derived class, sets the System.Runtime.Serialization.SerializationInfo - /// with information about the exception. - /// - /// The System.Runtime.Serialization.SerializationInfo that holds the serialized - /// object data about the exception being thrown. - /// The System.Runtime.Serialization.StreamingContext that contains contextual - /// information about the source or destination. - /// The info parameter is a null reference - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - - info.AddValue("FaultyEntry", FaultyEntry); - info.AddValue("PropertyFailure", PropertyFailure); - } - /// /// Optional subentry defining the faulty property /// diff --git a/src/Moryx/Configuration/ValueProvider/ValueProviderExecutorSettings.cs b/src/Moryx/Configuration/ValueProvider/ValueProviderExecutorSettings.cs index 4481c7cc5..703dba290 100644 --- a/src/Moryx/Configuration/ValueProvider/ValueProviderExecutorSettings.cs +++ b/src/Moryx/Configuration/ValueProvider/ValueProviderExecutorSettings.cs @@ -64,7 +64,7 @@ public ValueProviderExecutorSettings AddFilter(IValueProviderFilter valueProvide } /// - /// Adds + /// Adds a /// /// public ValueProviderExecutorSettings AddDefaultValueProvider() diff --git a/src/Moryx/Container/Attributes/ComponentAttribute.cs b/src/Moryx/Container/Attributes/ComponentAttribute.cs index 47af8b205..64cae13f1 100644 --- a/src/Moryx/Container/Attributes/ComponentAttribute.cs +++ b/src/Moryx/Container/Attributes/ComponentAttribute.cs @@ -8,21 +8,48 @@ namespace Moryx.Container /// /// Registration attribute to decorate components of a module. /// - public class ComponentAttribute : RegistrationAttribute + public class ComponentAttribute : Attribute { + /// + /// Life cycle of this component + /// + public LifeCycle LifeStyle { get; } + + /// + /// Implemented service + /// + public Type[] Services { get; } + + /// + /// Optional name of component + /// + public string Name { get; set; } + /// /// Constructor with life cycle /// /// Life style of component /// Implemented service - public ComponentAttribute(LifeCycle lifeStyle, params Type[] services) - : base(lifeStyle, services) - { + public ComponentAttribute(LifeCycle lifeStyle, params Type[] services) + { + LifeStyle = lifeStyle; + Services = services; } + } + + /// + /// Life cycle for this component + /// + public enum LifeCycle + { + /// + /// Create only one instance during container life time + /// + Singleton, /// - /// Flag that this plugin shall not be intercepted + /// Create a new instance for every request /// - public bool DontIntercept { get; set; } + Transient } } diff --git a/src/Moryx/Container/Attributes/DependencyRegistrationAttribute.cs b/src/Moryx/Container/Attributes/DependencyRegistrationAttribute.cs index bcbbbc04c..6fdc9ea9f 100644 --- a/src/Moryx/Container/Attributes/DependencyRegistrationAttribute.cs +++ b/src/Moryx/Container/Attributes/DependencyRegistrationAttribute.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 +using Microsoft.Extensions.DependencyInjection; using System; namespace Moryx.Container @@ -72,6 +73,6 @@ public interface ISubInitializer /// /// Execute further initialization /// - void Initialize(IContainer container); + void Initialize(IContainer services); } } diff --git a/src/Moryx/Container/Attributes/FactoryRegistrationAttribute.cs b/src/Moryx/Container/Attributes/FactoryRegistrationAttribute.cs deleted file mode 100644 index d6fb1cc9e..000000000 --- a/src/Moryx/Container/Attributes/FactoryRegistrationAttribute.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; - -namespace Moryx.Container -{ - /// - /// Installation attribute for factories - /// - [AttributeUsage(AttributeTargets.Interface)] - public class FactoryRegistrationAttribute : Attribute - { - /// - /// Optional component selector - /// - public Type Selector - { - get; - private set; - } - - /// - /// Optional name of factory - /// - public string Name - { - get; - private set; - } - - /// - /// Default constructor - /// - public FactoryRegistrationAttribute() - { - } - - /// - /// Constructor with component selector - /// - /// Selector - public FactoryRegistrationAttribute(Type selectorType) - { - Selector = selectorType; - } - - /// - /// Constructor with name - /// - /// Name of factory - public FactoryRegistrationAttribute(string name) - { - Name = name; - } - - /// - /// Constructor with name and selector - /// - /// Name - /// Selector - public FactoryRegistrationAttribute(string name, Type selectorType) - { - Selector = selectorType; - Name = name; - } - } -} diff --git a/src/Moryx/Container/Attributes/GlobalComponentAttribute.cs b/src/Moryx/Container/Attributes/GlobalComponentAttribute.cs deleted file mode 100644 index 74c1560f2..000000000 --- a/src/Moryx/Container/Attributes/GlobalComponentAttribute.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; - -namespace Moryx.Container -{ - /// - /// Base attribute for all registrations of the global container - /// - [AttributeUsage(AttributeTargets.Class)] - public class GlobalComponentAttribute : RegistrationAttribute - { - /// - /// Constructor with life cycle - /// - /// Life style of componentImplemented service - public GlobalComponentAttribute(LifeCycle lifeStyle, params Type[] services) : base(lifeStyle, services) - { - } - } -} diff --git a/src/Moryx/Container/Attributes/KernelComponentAttribute.cs b/src/Moryx/Container/Attributes/KernelComponentAttribute.cs deleted file mode 100644 index 4bb66b56d..000000000 --- a/src/Moryx/Container/Attributes/KernelComponentAttribute.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; -using System.Linq; -using Moryx.Modules; - -namespace Moryx.Container -{ - /// - /// Register a kernel component - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] - public class KernelComponentAttribute : GlobalComponentAttribute - { - /// - /// Register a kernel component - /// - public KernelComponentAttribute(params Type[] services) - : base(LifeCycle.Singleton, services) - { - } - } - - /// - /// Register a kernel component - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] - public class InitializableKernelComponentAttribute : KernelComponentAttribute - { - /// - /// Register a kernel component - /// - public InitializableKernelComponentAttribute(params Type[] services) - : base(new[] { typeof(IInitializable) }.Union(services).ToArray()) - { - } - } - - /// - /// Register a kernel plugin - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] - public class KernelPluginAttribute : GlobalComponentAttribute - { - /// - /// Register a kernel component - /// - public KernelPluginAttribute(params Type[] services) - : base(LifeCycle.Singleton, services) - { - } - } - -} diff --git a/src/Moryx/Container/Attributes/PluginFactoryAttribute.cs b/src/Moryx/Container/Attributes/PluginFactoryAttribute.cs index c8f0c6988..a2e53e61c 100644 --- a/src/Moryx/Container/Attributes/PluginFactoryAttribute.cs +++ b/src/Moryx/Container/Attributes/PluginFactoryAttribute.cs @@ -9,23 +9,31 @@ namespace Moryx.Container /// Interface for plguin factories within the local container /// [AttributeUsage(AttributeTargets.Interface)] - public class PluginFactoryAttribute : FactoryRegistrationAttribute + public class PluginFactoryAttribute : Attribute { /// - /// + /// Optional component selector /// - public PluginFactoryAttribute() + public Type Selector { - + get; + private set; } /// - /// + /// Default constructor /// - /// - public PluginFactoryAttribute(Type selectorType) : base(selectorType) + public PluginFactoryAttribute() { + } + /// + /// Constructor with component selector + /// + /// Selector + public PluginFactoryAttribute(Type selectorType) + { + Selector = selectorType; } } } diff --git a/src/Moryx/Container/Attributes/RegistrationAttribute.cs b/src/Moryx/Container/Attributes/RegistrationAttribute.cs deleted file mode 100644 index fd23d854d..000000000 --- a/src/Moryx/Container/Attributes/RegistrationAttribute.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; - -namespace Moryx.Container -{ - /// - /// Installation attribute for castle windsor - /// - [AttributeUsage(AttributeTargets.Class)] - public class RegistrationAttribute : Attribute - { - /// - /// Life cycle of this component - /// - public LifeCycle LifeStyle { get; } - - /// - /// Implemented service - /// - public Type[] Services { get; } - - /// - /// Optional name of component - /// - public string Name { get; set; } - - /// - /// Constructor with life cycle - /// - /// Life style of component - /// Implemented service - public RegistrationAttribute(LifeCycle lifeStyle, params Type[] services) - { - LifeStyle = lifeStyle; - Services = services; - } - } - - /// - /// Lifecylce for this component - /// - public enum LifeCycle - { - /// - /// Create only one instance during container life time - /// - Singleton, - - /// - /// Create a new instance for every request - /// - Transient - } -} diff --git a/src/Moryx/Container/ContainerLoadComponentsExtension.cs b/src/Moryx/Container/ContainerLoadComponentsExtension.cs new file mode 100644 index 000000000..50586ecbe --- /dev/null +++ b/src/Moryx/Container/ContainerLoadComponentsExtension.cs @@ -0,0 +1,132 @@ +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +using Moryx.Tools; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Moryx.Container +{ + /// + /// Extension to replace load components on + /// + public static class ContainerLoadComponentsExtension + { + /// + /// Load all types from an assembly + /// + public static void LoadFromAssembly(this IContainer container, Assembly assembly) + { + container.LoadFromAssembly(assembly, t => true); + } + + /// + /// Load types from assembly filtered by dependency attribute + /// + public static void LoadFromAssembly(this IContainer container, Assembly assembly, DependencyRegistrationAttribute att) + { + container.LoadFromAssembly(assembly, type => TypeRequired(att, type)); + } + + /// + /// Load filtered types from assembly + /// + public static void LoadFromAssembly(this IContainer container, Assembly assembly, Predicate predicate) + { + // Install all components + foreach (var type in assembly.GetTypes()) + { + // Register all we want + if (ShallInstall(type) && predicate(type)) + container.Register(type); + } + } + + /// + /// Method to determine if this component shall be installed + /// + private static bool ShallInstall(Type foundType) + { + var regAtt = foundType.GetCustomAttribute(); + var facAtt = foundType.GetCustomAttribute(); + + return (regAtt != null || facAtt != null); + } + + private static bool TypeRequired(DependencyRegistrationAttribute att, Type foundType) + { + if (att.InstallerMode == InstallerMode.All) + return true; + + // Check if interface was specified as required + if (foundType.IsInterface && att.RequiredTypes.Contains(foundType)) + return true; + + // Check if class exports required type + var services = ContainerRegistrationExtensions.GetComponentServices(foundType); + if (foundType.IsClass && att.RequiredTypes.Intersect(services).Any()) + return true; + + return false; + } + + /// + /// Load all implementations of type from currently known types + /// KnownTypes: Types in default framework folders and deeper. + /// + public static void LoadComponents(this IContainer container) where T : class + { + LoadComponents(container, null); + } + + /// + /// Loads all implementations of type from the currently known types + /// KnownTypes: Types in default framework folders and deeper. + /// + public static IContainer LoadComponents(this IContainer container, Predicate condition) where T : class + { + foreach (var type in ReflectionTool.GetPublicClasses(LoadComponentCandidate)) + { + if (condition?.Invoke(type) ?? true) + { + container.Register(type); + + RegisterAdditionalDependencies(container, type); + } + } + + return container; + } + + private static bool LoadComponentCandidate(Type type) + { + if (type.Assembly.GetCustomAttribute() != null) + return false; + + if (type.GetCustomAttribute(true) == null) + return false; + + return true; + } + + private static void RegisterAdditionalDependencies(IContainer container, Type implementation) + { + var att = implementation.GetCustomAttribute(); + if (att == null) + return; + + container.LoadFromAssembly(implementation.Assembly, att); + + if (att.Initializer == null) + return; + + if (!typeof(ISubInitializer).IsAssignableFrom(att.Initializer)) + throw new InvalidCastException($"SubInitializer {att.Initializer.Name} of component {implementation.Name} does not implement interface ISubInitializer"); + + container.Register(att.Initializer, new[] { typeof(ISubInitializer), att.Initializer }, null, LifeCycle.Singleton); + } + } +} diff --git a/src/Moryx/Container/ContainerRegistrationExtensions.cs b/src/Moryx/Container/ContainerRegistrationExtensions.cs new file mode 100644 index 000000000..5534aea18 --- /dev/null +++ b/src/Moryx/Container/ContainerRegistrationExtensions.cs @@ -0,0 +1,171 @@ +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Moryx.Container +{ + /// + /// Extensions on the reduced interface + /// + public static class ContainerRegistrationExtensions + { + /// + /// Register external type in local container + /// + public static IContainer Register(this IContainer container) + where TComp : TService + where TService : class + { + var type = typeof(TComp); + var regAtt = type.GetCustomAttribute(); + container.Register(type, new[] { typeof(TService) }, regAtt?.Name, regAtt?.LifeStyle ?? LifeCycle.Singleton); + + return container; + } + + /// + /// Register external type in local container + /// + public static IContainer Register(this IContainer container, string name, LifeCycle lifeCycle) + where TComp : TService + where TService : class + { + container.Register(typeof(TComp), new[] { typeof(TService) }, name, lifeCycle); + + return container; + } + + /// + /// Register type and determine factory and services automatically + /// + public static IContainer Register(this IContainer container, Type type) + { + if (type.IsInterface) + { + container.RegisterFactory(type); + } + else + { + var services = GetComponentServices(type); + container.Register(type, services); + } + + return container; + } + + /// + /// Get all services of this component + /// + public static Type[] GetComponentServices(Type type) + { + var att = type.GetCustomAttribute(); + if (att != null) + return att.Services.Any() ? att.Services : new[] { type }; + + var interfaces = type.GetInterfaces(); + return interfaces.Any() ? interfaces : new[] { type }; + } + + + /// + /// Register a type for different services + /// + public static IContainer Register(this IContainer container, Type type, Type[] services) + { + var regAtt = type.GetCustomAttribute(); + container.Register(type, services, regAtt?.Name, regAtt?.LifeStyle ?? LifeCycle.Singleton); + + return container; + } + + /// + /// Register named component for the services + /// + public static IContainer Register(this IContainer container, Type type, Type[] services, string name) + { + container.Register(type, services, name, LifeCycle.Singleton); + + return container; + } + + /// + /// Register a factory by generic interface + /// + public static IContainer Register(this IContainer container) where TFactory : class + { + var att = typeof(TFactory).GetCustomAttribute(); + container.RegisterFactory(typeof(TFactory), null, att?.Selector); + return container; + } + + /// + /// Register a named factory + /// + public static IContainer Register(this IContainer container, string name) where TFactory : class + { + var factoryType = typeof(TFactory); + var att = typeof(TFactory).GetCustomAttribute(); + container.RegisterFactory(factoryType, name, att?.Selector); + + return container; + } + + /// + /// Register factory by type + /// + public static IContainer RegisterFactory(this IContainer container, Type factoryInterface) + { + var facAtt = factoryInterface.GetCustomAttribute(); + container.RegisterFactory(factoryInterface, null, facAtt?.Selector); + + return container; + } + + /// + /// Register named factory by type + /// + public static IContainer RegisterFactory(this IContainer container, Type factoryInterface, string name) + { + container.RegisterFactory(factoryInterface, name, null); + + return container; + } + + /// + /// Set instance of service + /// + /// Type of service + /// Container to register in + /// Instance implementing the service + public static IContainer SetInstance(this IContainer container, T instance) where T : class + { + if (instance != null) + { + container.RegisterInstance(new[] {typeof(T)}, instance, null); + } + return container; + } + + /// + /// Set globally imported instance with name + /// + /// Type of service + /// Container to register in + /// Instance to register + /// Name of instance + public static IContainer SetInstance(this IContainer container, T instance, string name) where T : class + { + if (instance != null) + { + container.RegisterInstance(new[] { typeof(T) }, instance, name); + } + return container; + } + } +} diff --git a/src/Moryx/Container/ContainerResolveExtensions.cs b/src/Moryx/Container/ContainerResolveExtensions.cs new file mode 100644 index 000000000..de70d8d44 --- /dev/null +++ b/src/Moryx/Container/ContainerResolveExtensions.cs @@ -0,0 +1,54 @@ +// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG +// Licensed under the Apache License, Version 2.0 + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace Moryx.Container +{ + /// + /// Extensions to replace the overloads of + /// + public static class ContainerResolveExtensions + { + /// + /// Resolve an instance of the given service + /// + /// Type to resolve + /// Instance of type + public static T Resolve(this IContainer container) + { + return (T)container.Resolve(typeof(T), null); + } + + /// + /// Resolve this dependency + /// + public static object Resolve(this IContainer container, Type service) + { + return container.Resolve(service, null); + } + + /// + /// Resolve a named instance of the given service + /// + /// Type to resolve + /// Instance of type + public static T Resolve(this IContainer container, string name) + { + return (T)container.Resolve(typeof(T), name); + } + + /// + /// Resolve all implementations of this contract + /// + /// Type to resolve + /// + public static T[] ResolveAll(this IContainer container) + { + return (T[])container.ResolveAll(typeof(T)); + } + } +} diff --git a/src/Moryx/Container/IComponentRegistrator.cs b/src/Moryx/Container/IComponentRegistrator.cs deleted file mode 100644 index d76bb64c7..000000000 --- a/src/Moryx/Container/IComponentRegistrator.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -using System; - -namespace Moryx.Container -{ - /// - /// Responensible for component registration based on information given in - /// - public interface IComponentRegistrator - { - /// - /// Check if a type shall be registered - /// - /// - /// - bool ShallInstall(Type foundType); - - /// - /// Register a type in the container. Automatically registers interfaces as factory - /// - /// Type to register - void Register(Type type); - - /// - /// Register a type for a couple of services - /// - /// - /// - void Register(Type type, Type[] services); - - /// - /// Register a type for services under a given name - /// - void Register(Type type, Type[] services, string name); - - /// - /// Full registration method - /// - void Register(Type type, Type[] services, string name, LifeCycle lifeCycle); - - /// - /// Register a factory - /// - /// - void RegisterFactory(Type factoryInterface); - - /// - /// Register a factory under a special name - /// - void RegisterFactory(Type factoryInterface, string name); - - /// - /// Register a factory under a special name - /// - void RegisterFactory(Type factoryInterface, string name, Type selector); - } -} diff --git a/src/Moryx/Container/IContainer.cs b/src/Moryx/Container/IContainer.cs index 43d68fbac..150d75552 100644 --- a/src/Moryx/Container/IContainer.cs +++ b/src/Moryx/Container/IContainer.cs @@ -12,138 +12,42 @@ namespace Moryx.Container /// public interface IContainer { - /// - /// Destroy the internal container and all registered objects - /// - void Destroy(); - - #region Resolve - - /// - /// Resolve an instance of the given service - /// - /// Type to resolve - /// Instance of type - T Resolve(); - - /// - /// Resolve this dependency - /// - object Resolve(Type service); - - /// - /// Resolve a named instance of the given service - /// - T Resolve(string name); - /// /// Resolve this named dependency /// object Resolve(Type service, string name); - /// - /// Resolve all implementations of this contract - /// - /// Type to resolve - /// - T[] ResolveAll(); - /// /// Resolve all implementations of this contract /// /// Service to resolve implementation for /// Array ResolveAll(Type service); - #endregion /// /// Get all implementations for a given component interface /// /// - IEnumerable GetRegisteredImplementations(Type componentInterface); - - #region LoadComponents - - /// - /// Load all implementations of type from currently known types - /// KnownTypes: Types in default framework folders and deeper. - /// - void LoadComponents() - where T : class; + IEnumerable GetRegisteredImplementations(Type service); /// - /// Load all implementations of type from currently known types - /// KnownTypes: Types in default framework folders and deeper. + /// Full registration method /// - void LoadComponents(Predicate condition) - where T : class; - - #endregion - - #region Register - - /// - /// Execute the installer - /// - /// - IContainer ExecuteInstaller(IContainerInstaller installer); - - /// - /// Register external type in local container - /// - IContainer Register() - where TComp : TService - where TService : class; - - /// - /// Register external type in local container - /// - IContainer Register(string name, LifeCycle lifeCycle) - where TComp : TService - where TService : class; - - /// - /// Register factory interface - /// - /// - IContainer Register() - where TFactory : class; - - /// - /// Register factory interface - /// - /// - IContainer Register(string name) - where TFactory : class; - - #endregion - - #region Set instance + void Register(Type type, Type[] services, string name, LifeCycle lifeCycle); /// - /// Set instance of service + /// Register a factory interface for automatic implementation /// - /// Type of service - /// Instance implementing the service - IContainer SetInstance(T instance) where T : class; + void RegisterFactory(Type factoryInterface, string name, Type selector); /// - /// Set globally imported instance with name + /// Register instance for given services in the container /// - /// Type of service - /// Instance to register - /// Name of instance - IContainer SetInstance(T instance, string name) where T : class; - - #endregion - - #region Extensions + void RegisterInstance(Type[] services, object instance, string name); /// - /// + /// Destroy the internal container and all registered objects /// - void Extend() where TExtension : new(); - - #endregion + void Destroy(); } } diff --git a/src/Moryx/Container/IContainerInstaller.cs b/src/Moryx/Container/IContainerInstaller.cs deleted file mode 100644 index 3d21ae311..000000000 --- a/src/Moryx/Container/IContainerInstaller.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -namespace Moryx.Container -{ - /// - /// Interface for all installers that extend the - /// - public interface IContainerInstaller - { - /// - /// Install using the given registrator - /// - void Install(IComponentRegistrator registrator); - } -} diff --git a/src/Moryx/Moryx.csproj b/src/Moryx/Moryx.csproj index 76d3188cd..e511c0dc0 100644 --- a/src/Moryx/Moryx.csproj +++ b/src/Moryx/Moryx.csproj @@ -1,15 +1,14 @@  - netstandard2.0;net6.0 + netstandard2.0;net8.0 true true Core package of the MORYX ecosystem. It defines the necessary types for MORYX compatibility as well as commonly required tools. - true MORYX;Serialization;Configuration;Logging;Core;Modules;Workplans - + HAVE_TCP_KEEPALIVE diff --git a/src/Moryx/Serialization/EntryConvert/CollectionStrategy/ArrayIListStrategy.cs b/src/Moryx/Serialization/EntryConvert/CollectionStrategy/ArrayIListStrategy.cs index ab8385a66..fb26e7a3a 100644 --- a/src/Moryx/Serialization/EntryConvert/CollectionStrategy/ArrayIListStrategy.cs +++ b/src/Moryx/Serialization/EntryConvert/CollectionStrategy/ArrayIListStrategy.cs @@ -5,6 +5,7 @@ namespace Moryx.Serialization { + /// public class ArrayIListStrategy : ICollectionStrategy { private readonly IList _list; @@ -14,6 +15,7 @@ public class ArrayIListStrategy : ICollectionStrategy private readonly object _instance; private readonly IList _toAdd = new List(); + /// public ArrayIListStrategy(IList list, ICustomSerialization customSerialization, ICustomAttributeProvider attributeProvider, object instance) { @@ -23,6 +25,7 @@ public ArrayIListStrategy(IList list, ICustomSerialization customSerialization, _instance = instance; } + /// public IEnumerable Serialize() { var entries = new List(); @@ -34,31 +37,37 @@ public IEnumerable Serialize() return entries; } + /// public IEnumerable Keys() { return CollectionStrategyTools.GenerateKeys(_list.Count); } + /// public object ElementAt(string key) { return _list[int.Parse(key)]; } + /// public void Added(Entry entry, object addedValue) { _toAdd.Add(addedValue); } + /// public void Updated(Entry entry, object updatedValue) { _list[int.Parse(entry.Identifier)] = updatedValue; } + /// public void Removed(string key) { _toDelete.Add(_list[int.Parse(key)]); } + /// public void Flush() { diff --git a/src/Moryx/Serialization/PossibleValues/PluginNameSelectorAttribute.cs b/src/Moryx/Serialization/PossibleValues/PluginNameSelectorAttribute.cs index 025280109..fa2a62d6b 100644 --- a/src/Moryx/Serialization/PossibleValues/PluginNameSelectorAttribute.cs +++ b/src/Moryx/Serialization/PossibleValues/PluginNameSelectorAttribute.cs @@ -36,7 +36,7 @@ public override IEnumerable GetValues(IContainer container) private static string GetComponentName(Type component) { - var att = component.GetCustomAttribute(); + var att = component.GetCustomAttribute(); return string.IsNullOrEmpty(att?.Name) ? component.FullName : att.Name; } diff --git a/src/Moryx/Tools/Extensions/CustomAttributeProviderExtensions.cs b/src/Moryx/Tools/Extensions/CustomAttributeProviderExtensions.cs index 47dda4bbe..63a4803b8 100644 --- a/src/Moryx/Tools/Extensions/CustomAttributeProviderExtensions.cs +++ b/src/Moryx/Tools/Extensions/CustomAttributeProviderExtensions.cs @@ -60,7 +60,7 @@ public static TAttribute[] GetCustomAttributes(this ICustomAttribute /// /// Tries to get attributes defining display names on this attribute provider. /// If no attribute was found, null will be the result. - /// The chain follows: , and + /// The chain follows: and /// /// Provider of the attributes /// The value of the display name or null. @@ -77,7 +77,7 @@ public static string GetDisplayName(this ICustomAttributeProvider attributeProvi /// /// Tries to get attributes defining a description on this attribute provider. /// If no attribute was found, null will be the result. - /// The chain follows: , and + /// The chain follows: and /// /// Provider of the attributes /// The value of the description or null. diff --git a/src/Moryx/Tools/ReflectionTool.cs b/src/Moryx/Tools/ReflectionTool.cs index b517c01ec..c5d1854b4 100644 --- a/src/Moryx/Tools/ReflectionTool.cs +++ b/src/Moryx/Tools/ReflectionTool.cs @@ -50,10 +50,23 @@ public static Assembly[] GetAssemblies() /// private static Type[] LoadPublicClasses() { - return (from assembly in RelevantAssemblies.Value - from type in assembly.GetExportedTypes() - where type.IsClass && !type.IsAbstract - select type).ToArray(); + // Assume 30 exports per assembly for initial size + var publicClasses = new List(RelevantAssemblies.Value.Length * 30); + foreach (var assembly in RelevantAssemblies.Value) + { + try + { + var exports = assembly.GetExportedTypes() + .Where(type => type.IsClass && !type.IsAbstract); + publicClasses.AddRange(exports); + } + catch(Exception x) + { + CrashHandler.WriteErrorToFile($"Failed to load types from {assembly.FullName}. Error: {x.Message}"); + } + } + + return publicClasses.ToArray(); } /// diff --git a/src/StartProject.Asp/StartProject.Asp.csproj b/src/StartProject.Asp/StartProject.Asp.csproj index f055536c0..9fd92e5b9 100644 --- a/src/StartProject.Asp/StartProject.Asp.csproj +++ b/src/StartProject.Asp/StartProject.Asp.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 StartProject of the MORYX-Framework. This is for debugging only. diff --git a/src/Tests/Directory.Build.props b/src/Tests/Directory.Build.props new file mode 100644 index 000000000..a2119370e --- /dev/null +++ b/src/Tests/Directory.Build.props @@ -0,0 +1,5 @@ + + + false + + \ No newline at end of file diff --git a/src/Tests/Moryx.AbstractionLayer.Tests/Moryx.AbstractionLayer.Tests.csproj b/src/Tests/Moryx.AbstractionLayer.Tests/Moryx.AbstractionLayer.Tests.csproj index df430c0a8..dfd8f9912 100644 --- a/src/Tests/Moryx.AbstractionLayer.Tests/Moryx.AbstractionLayer.Tests.csproj +++ b/src/Tests/Moryx.AbstractionLayer.Tests/Moryx.AbstractionLayer.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 false full diff --git a/src/Tests/Moryx.Communication.Sockets.IntegrationTests/Moryx.Communication.Sockets.IntegrationTests.csproj b/src/Tests/Moryx.Communication.Sockets.IntegrationTests/Moryx.Communication.Sockets.IntegrationTests.csproj index 6f1956905..8da75c14b 100644 --- a/src/Tests/Moryx.Communication.Sockets.IntegrationTests/Moryx.Communication.Sockets.IntegrationTests.csproj +++ b/src/Tests/Moryx.Communication.Sockets.IntegrationTests/Moryx.Communication.Sockets.IntegrationTests.csproj @@ -2,20 +2,18 @@ Library - net6.0 + net8.0 full - - diff --git a/src/Tests/Moryx.Container.TestPlugin/Moryx.Container.TestPlugin.csproj b/src/Tests/Moryx.Container.TestPlugin/Moryx.Container.TestPlugin.csproj index 3e4347729..7c6fa2a02 100644 --- a/src/Tests/Moryx.Container.TestPlugin/Moryx.Container.TestPlugin.csproj +++ b/src/Tests/Moryx.Container.TestPlugin/Moryx.Container.TestPlugin.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 diff --git a/src/Tests/Moryx.Container.TestRootPlugin/Moryx.Container.TestRootPlugin.csproj b/src/Tests/Moryx.Container.TestRootPlugin/Moryx.Container.TestRootPlugin.csproj index 3e4347729..7c6fa2a02 100644 --- a/src/Tests/Moryx.Container.TestRootPlugin/Moryx.Container.TestRootPlugin.csproj +++ b/src/Tests/Moryx.Container.TestRootPlugin/Moryx.Container.TestRootPlugin.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 diff --git a/src/Tests/Moryx.Container.TestTools/Moryx.Container.TestTools.csproj b/src/Tests/Moryx.Container.TestTools/Moryx.Container.TestTools.csproj index dc57d1125..4c4707fa3 100644 --- a/src/Tests/Moryx.Container.TestTools/Moryx.Container.TestTools.csproj +++ b/src/Tests/Moryx.Container.TestTools/Moryx.Container.TestTools.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 diff --git a/src/Tests/Moryx.Container.Tests/Local/ConfiguredComponent.cs b/src/Tests/Moryx.Container.Tests/Local/ConfiguredComponent.cs index c1b670b98..a721f5c65 100644 --- a/src/Tests/Moryx.Container.Tests/Local/ConfiguredComponent.cs +++ b/src/Tests/Moryx.Container.Tests/Local/ConfiguredComponent.cs @@ -6,7 +6,7 @@ namespace Moryx.Container.Tests { [Plugin(LifeCycle.Singleton, typeof(IRootClass), Name = PluginName)] - internal class RootClass : IRootClass + public class RootClass : IRootClass { internal const string PluginName = "RootClass"; @@ -33,7 +33,7 @@ public void Stop() } [Plugin(LifeCycle.Singleton, typeof(IConfiguredComponent), Name = PluginName)] - internal class ConfiguredComponentA : IConfiguredComponent + public class ConfiguredComponentA : IConfiguredComponent { internal const string PluginName = "ConfiguredA"; @@ -59,7 +59,7 @@ public void Stop() } [Plugin(LifeCycle.Singleton, typeof(IConfiguredComponent), Name = PluginName)] - internal class ConfiguredComponentB : IConfiguredComponent + public class ConfiguredComponentB : IConfiguredComponent { internal const string PluginName = "ConfiguredB"; diff --git a/src/Tests/Moryx.Container.Tests/Local/LocalComponent.cs b/src/Tests/Moryx.Container.Tests/Local/LocalComponent.cs index 3676e0e96..5c66c47ce 100644 --- a/src/Tests/Moryx.Container.Tests/Local/LocalComponent.cs +++ b/src/Tests/Moryx.Container.Tests/Local/LocalComponent.cs @@ -8,7 +8,7 @@ public interface ILocalComponent } [Plugin(LifeCycle.Transient, typeof(ILocalComponent))] - internal class LocalComponent : ILocalComponent + public class LocalComponent : ILocalComponent { } diff --git a/src/Tests/Moryx.Container.Tests/Local/LocalContainerTest.cs b/src/Tests/Moryx.Container.Tests/Local/LocalContainerTest.cs index d7fd56353..82db45d09 100644 --- a/src/Tests/Moryx.Container.Tests/Local/LocalContainerTest.cs +++ b/src/Tests/Moryx.Container.Tests/Local/LocalContainerTest.cs @@ -2,19 +2,21 @@ // Licensed under the Apache License, Version 2.0 using NUnit.Framework; +using System; +using System.Collections.Generic; namespace Moryx.Container.Tests { [TestFixture] public class LocalContainerTest { - private LocalContainer _container; + private CastleContainer _container; [SetUp] public void Init() { - _container = new LocalContainer(); - _container.ExecuteInstaller(new AutoInstaller(GetType().Assembly)); + _container = new CastleContainer(new Dictionary()); + _container.LoadFromAssembly(GetType().Assembly); } [Test] diff --git a/src/Tests/Moryx.Container.Tests/Local/NamedComponents.cs b/src/Tests/Moryx.Container.Tests/Local/NamedComponents.cs index 7456f4d45..e46a5a0cd 100644 --- a/src/Tests/Moryx.Container.Tests/Local/NamedComponents.cs +++ b/src/Tests/Moryx.Container.Tests/Local/NamedComponents.cs @@ -9,7 +9,7 @@ public interface INamedComponent } [Plugin(LifeCycle.Transient, typeof(INamedComponent), Name = ComponentName)] - internal class NamedComponentA : INamedComponent + public class NamedComponentA : INamedComponent { internal const string ComponentName = "CompA"; @@ -20,7 +20,7 @@ public string GetName() } [Plugin(LifeCycle.Transient, typeof(INamedComponent), Name = ComponentName)] - internal class NamedComponentB : INamedComponent + public class NamedComponentB : INamedComponent { internal const string ComponentName = "CompB"; diff --git a/src/Tests/Moryx.Container.Tests/Local/StrategySelectionTest.cs b/src/Tests/Moryx.Container.Tests/Local/StrategySelectionTest.cs index aa80ab7d6..de8250206 100644 --- a/src/Tests/Moryx.Container.Tests/Local/StrategySelectionTest.cs +++ b/src/Tests/Moryx.Container.Tests/Local/StrategySelectionTest.cs @@ -122,7 +122,7 @@ public void OverrideWithFactory(string rootName, string pluginName) private static IContainer CreateContainer(IDictionary strategies) { - var container = new LocalContainer(strategies); + var container = new CastleContainer(strategies); container.LoadComponents(); container.LoadComponents(); diff --git a/src/Tests/Moryx.Container.Tests/Moryx.Container.Tests.csproj b/src/Tests/Moryx.Container.Tests/Moryx.Container.Tests.csproj index ca366b30c..69fe60437 100644 --- a/src/Tests/Moryx.Container.Tests/Moryx.Container.Tests.csproj +++ b/src/Tests/Moryx.Container.Tests/Moryx.Container.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 Library full @@ -15,7 +15,6 @@ - diff --git a/src/Tests/Moryx.Container.Tests/Named/Component.cs b/src/Tests/Moryx.Container.Tests/Named/Component.cs index c79d6c014..3e08800f3 100644 --- a/src/Tests/Moryx.Container.Tests/Named/Component.cs +++ b/src/Tests/Moryx.Container.Tests/Named/Component.cs @@ -3,8 +3,8 @@ namespace Moryx.Container.Tests { - [Registration(LifeCycle.Singleton)] - internal class Component + [Component(LifeCycle.Singleton)] + public class Component { public IDependency Unnamed { get; set; } @@ -15,18 +15,18 @@ internal class Component public IDependency DepB { get; set; } } - internal class Impossible + public class Impossible { [Named("DepC")] public IDependency DepC { get; set; } } - internal interface IDependency + public interface IDependency { string GetName(); } - internal class DependencyA : IDependency + public class DependencyA : IDependency { public string GetName() { @@ -34,7 +34,7 @@ public string GetName() } } - internal class DependencyB : IDependency + public class DependencyB : IDependency { public string GetName() { diff --git a/src/Tests/Moryx.Container.Tests/Registrator/FakeAutoInstaller.cs b/src/Tests/Moryx.Container.Tests/Registrator/FakeAutoInstaller.cs deleted file mode 100644 index 8d68f3e84..000000000 --- a/src/Tests/Moryx.Container.Tests/Registrator/FakeAutoInstaller.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - -namespace Moryx.Container.Tests -{ - internal class FakeAutoInstaller : AutoInstaller - { - /// - /// Create a new instance of the for this assembly - /// - public FakeAutoInstaller() : base(typeof(FakeAutoInstaller).Assembly) - { - } - - public bool SkippedNamed { get; private set; } - public bool SkippedUnnamed { get; private set; } - - /// - /// Install all components - /// - public override void Install(IComponentRegistrator registrator) - { - SkippedNamed = !ShallInstall(registrator, typeof(NamedDummy)); - - SkippedUnnamed = !ShallInstall(registrator, typeof(UnnamedDummy)); - } - } -} diff --git a/src/Tests/Moryx.Container.Tests/Registrator/NamedDummy.cs b/src/Tests/Moryx.Container.Tests/Registrator/NamedDummy.cs index 63438a50a..7f4a2b9d2 100644 --- a/src/Tests/Moryx.Container.Tests/Registrator/NamedDummy.cs +++ b/src/Tests/Moryx.Container.Tests/Registrator/NamedDummy.cs @@ -3,13 +3,13 @@ namespace Moryx.Container.Tests { - [Registration(LifeCycle.Transient, Name = "Dummy")] - internal class NamedDummy + [Component(LifeCycle.Transient, Name = "Dummy")] + public class NamedDummy { } - [Registration(LifeCycle.Transient)] - internal class UnnamedDummy + [Component(LifeCycle.Transient)] + public class UnnamedDummy { } diff --git a/src/Tests/Moryx.Container.Tests/Registrator/RegistratorTest.cs b/src/Tests/Moryx.Container.Tests/Registrator/RegistratorTest.cs index 76811947a..35c32946a 100644 --- a/src/Tests/Moryx.Container.Tests/Registrator/RegistratorTest.cs +++ b/src/Tests/Moryx.Container.Tests/Registrator/RegistratorTest.cs @@ -22,18 +22,14 @@ public void Init() [Test] public void DoubleRegistrationWithRegister() { - Assert.Throws(() => _container.Register()); - Assert.Throws(() => _container.Register()); + Assert.DoesNotThrow(() => _container.Register()); + Assert.DoesNotThrow(() => _container.Register()); } [Test] public void DoubleRegistrationWithAutoInstaller() { - var fakeAutoInstaller = new FakeAutoInstaller(); - _container.ExecuteInstaller(fakeAutoInstaller); - - Assert.True(fakeAutoInstaller.SkippedNamed, "Named was not skipped"); - Assert.True(fakeAutoInstaller.SkippedUnnamed, "Unnamed was not skipped"); + Assert.DoesNotThrow(() => _container.LoadFromAssembly(GetType().Assembly)); } } } diff --git a/src/Tests/Moryx.Model.Tests/Moryx.Model.Tests.csproj b/src/Tests/Moryx.Model.Tests/Moryx.Model.Tests.csproj index f692d2370..7f438b982 100644 --- a/src/Tests/Moryx.Model.Tests/Moryx.Model.Tests.csproj +++ b/src/Tests/Moryx.Model.Tests/Moryx.Model.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 Library full @@ -9,7 +9,6 @@ - @@ -19,7 +18,6 @@ - diff --git a/src/Tests/Moryx.Model.Tests/SqliteTests.cs b/src/Tests/Moryx.Model.Tests/SqliteTests.cs index 66bf4c810..19d8727ce 100644 --- a/src/Tests/Moryx.Model.Tests/SqliteTests.cs +++ b/src/Tests/Moryx.Model.Tests/SqliteTests.cs @@ -1,4 +1,4 @@ -using Moryx.Model.Sqlite; +using Moryx.Model.Sqlite; using Moryx.Products.Model; using Moryx.Runtime.Kernel; using NUnit.Framework; @@ -18,7 +18,7 @@ public class SqliteTests public void Setup() { string databaseName = "TestDatabase"; - datasource = $".\\db\\{databaseName}.db"; + datasource = Path.Combine(".", "db", databaseName+".db"); string connectionString = $@"Data Source={datasource};"; dbConfig = new SqliteDatabaseConfig(); dbConfig.ConnectionSettings = new DatabaseConnectionSettings { ConnectionString = connectionString, Database = databaseName }; @@ -71,6 +71,5 @@ public void Destroy() //remove the database configurator.DeleteDatabase(dbConfig).Wait(); } - } } \ No newline at end of file diff --git a/src/Tests/Moryx.Notifications.Tests/Moryx.Notifications.Tests.csproj b/src/Tests/Moryx.Notifications.Tests/Moryx.Notifications.Tests.csproj index 094742684..1940dd422 100644 --- a/src/Tests/Moryx.Notifications.Tests/Moryx.Notifications.Tests.csproj +++ b/src/Tests/Moryx.Notifications.Tests/Moryx.Notifications.Tests.csproj @@ -2,7 +2,7 @@ Library - net6.0 + net8.0 full diff --git a/src/Tests/Moryx.Products.IntegrationTests/Moryx.Products.IntegrationTests.csproj b/src/Tests/Moryx.Products.IntegrationTests/Moryx.Products.IntegrationTests.csproj index beb45acc9..d28118d39 100644 --- a/src/Tests/Moryx.Products.IntegrationTests/Moryx.Products.IntegrationTests.csproj +++ b/src/Tests/Moryx.Products.IntegrationTests/Moryx.Products.IntegrationTests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 false full diff --git a/src/Tests/Moryx.Products.Management.Tests/Moryx.AbstractionLayer.Products.Endpoints.Tests.csproj b/src/Tests/Moryx.Products.Management.Tests/Moryx.AbstractionLayer.Products.Endpoints.Tests.csproj index 7cb39db8f..e96309139 100644 --- a/src/Tests/Moryx.Products.Management.Tests/Moryx.AbstractionLayer.Products.Endpoints.Tests.csproj +++ b/src/Tests/Moryx.Products.Management.Tests/Moryx.AbstractionLayer.Products.Endpoints.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 false full @@ -15,7 +15,6 @@ - diff --git a/src/Tests/Moryx.Resources.Management.Tests/Mocks/ReferenceResource.cs b/src/Tests/Moryx.Resources.Management.Tests/Mocks/ReferenceResource.cs index cda0e92c4..50e0dc9c8 100644 --- a/src/Tests/Moryx.Resources.Management.Tests/Mocks/ReferenceResource.cs +++ b/src/Tests/Moryx.Resources.Management.Tests/Mocks/ReferenceResource.cs @@ -8,7 +8,7 @@ namespace Moryx.Resources.Management.Tests { - public interface IReferenceResource : IPublicResource + public interface IReferenceResource : IResource { ISimpleResource Reference { get; set; } @@ -48,7 +48,7 @@ public class RequiredReferenceResource : Resource public IReferences References { get; set; } } - public class ReferenceResource : PublicResource, IReferenceResource + public class ReferenceResource : Resource, IReferenceResource { private ISimpleResource _reference; diff --git a/src/Tests/Moryx.Resources.Management.Tests/Mocks/ResourceWithGenericMethod.cs b/src/Tests/Moryx.Resources.Management.Tests/Mocks/ResourceWithGenericMethod.cs index ee751b561..f77311bce 100644 --- a/src/Tests/Moryx.Resources.Management.Tests/Mocks/ResourceWithGenericMethod.cs +++ b/src/Tests/Moryx.Resources.Management.Tests/Mocks/ResourceWithGenericMethod.cs @@ -11,7 +11,7 @@ namespace Moryx.Resources.Management.Tests { - public interface IGenericMethodCall : IPublicResource + public interface IGenericMethodCall : IResource { /// /// Get channel using specialized API diff --git a/src/Tests/Moryx.Resources.Management.Tests/Mocks/ResourceWithImplicitApi.cs b/src/Tests/Moryx.Resources.Management.Tests/Mocks/ResourceWithImplicitApi.cs index 84cec8f28..c1d214438 100644 --- a/src/Tests/Moryx.Resources.Management.Tests/Mocks/ResourceWithImplicitApi.cs +++ b/src/Tests/Moryx.Resources.Management.Tests/Mocks/ResourceWithImplicitApi.cs @@ -10,12 +10,12 @@ public interface IExtension int Add(int value); } - public interface IResourceWithImplicitApi : IPublicResource, IExtension + public interface IResourceWithImplicitApi : IResource, IExtension { } - public class ResourceWithImplicitApi : PublicResource, IResourceWithImplicitApi + public class ResourceWithImplicitApi : Resource, IResourceWithImplicitApi { public int Add(int value) { diff --git a/src/Tests/Moryx.Resources.Management.Tests/Mocks/SimpleResource.cs b/src/Tests/Moryx.Resources.Management.Tests/Mocks/SimpleResource.cs index 832936f36..c398803d9 100644 --- a/src/Tests/Moryx.Resources.Management.Tests/Mocks/SimpleResource.cs +++ b/src/Tests/Moryx.Resources.Management.Tests/Mocks/SimpleResource.cs @@ -2,16 +2,17 @@ // Licensed under the Apache License, Version 2.0 using System; +using Moryx.AbstractionLayer.Capabilities; using Moryx.AbstractionLayer.Resources; namespace Moryx.Resources.Management.Tests { - public interface IDuplicateFoo : IPublicResource + public interface IDuplicateFoo : IResource { int Foo { get; } } - public interface ISimpleResource : IPublicResource + public interface ISimpleResource : IResource { int Foo { get; set; } @@ -34,7 +35,7 @@ public interface INonResourceInterface } [ResourceAvailableAs(typeof(INonResourceInterface))] - public class SimpleResource : PublicResource, ISimpleResource, IDuplicateFoo, INonResourceInterface + public class SimpleResource : Resource, ISimpleResource, IDuplicateFoo, INonResourceInterface { private int _foo; @@ -69,6 +70,10 @@ public void RaiseEvent() SomeEvent?.Invoke(this, EventArgs.Empty); } + public void UpdateCapabilities(ICapabilities capabilities) + { + Capabilities = capabilities; + } public void Validate() { } diff --git a/src/Tests/Moryx.Resources.Management.Tests/Moryx.Resources.Management.Tests.csproj b/src/Tests/Moryx.Resources.Management.Tests/Moryx.Resources.Management.Tests.csproj index 67acc5147..ed77ed38d 100644 --- a/src/Tests/Moryx.Resources.Management.Tests/Moryx.Resources.Management.Tests.csproj +++ b/src/Tests/Moryx.Resources.Management.Tests/Moryx.Resources.Management.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 false full diff --git a/src/Tests/Moryx.Resources.Management.Tests/ResourceLinkerTests.cs b/src/Tests/Moryx.Resources.Management.Tests/ResourceLinkerTests.cs index a6027ef37..2a0e580c7 100644 --- a/src/Tests/Moryx.Resources.Management.Tests/ResourceLinkerTests.cs +++ b/src/Tests/Moryx.Resources.Management.Tests/ResourceLinkerTests.cs @@ -20,13 +20,13 @@ public class ResourceLinkerTests { private ResourceLinker _linker; - private readonly Dictionary _graph = new Dictionary(); + private readonly Dictionary _graph = new Dictionary(); [OneTimeSetUp] public void PrepareLinker() { var mock = new Mock(); - mock.Setup(g => g.Get(It.IsAny())).Returns(id => _graph.ContainsKey(id) ? _graph[id].Target : null); + mock.Setup(g => g.Get(It.IsAny())).Returns(id => _graph.ContainsKey(id) ? _graph[id] : null); _linker = new ResourceLinker { @@ -83,12 +83,12 @@ public void LinkResource() { // Arrange var instance = new ReferenceResource { Id = 1 }; - _graph[1] = new ResourceWrapper(instance); - _graph[2] = new ResourceWrapper(new SimpleResource { Id = 2, Name = "Ref1" }); - _graph[3] = new ResourceWrapper(new SimpleResource { Id = 3, Name = "Pos1" }); - _graph[4] = new ResourceWrapper(new DerivedResource { Id = 4, Name = "Ref2" }); - _graph[5] = new ResourceWrapper(new DerivedResource { Id = 5, Name = "ChildOnly" }); - _graph[6] = new ResourceWrapper(new DerivedResource { Id = 6, Name = "BackRef" }); + _graph[1] = instance; + _graph[2] = new SimpleResource { Id = 2, Name = "Ref1" }; + _graph[3] = new SimpleResource { Id = 3, Name = "Pos1" }; + _graph[4] = new DerivedResource { Id = 4, Name = "Ref2" }; + _graph[5] = new DerivedResource { Id = 5, Name = "ChildOnly" }; + _graph[6] = new DerivedResource { Id = 6, Name = "BackRef" }; var relations = new List { // All Parent-Child relations @@ -199,11 +199,11 @@ public void SaveReferences() var ref5 = new DerivedResource { Id = 6, Name = "BackRef" }; ResourceReferenceTools.InitializeCollections(ref5); // Fill graph - _graph[1] = new ResourceWrapper(instance); - _graph[2] = new ResourceWrapper(ref1); - _graph[3] = new ResourceWrapper(ref2); - _graph[5] = new ResourceWrapper(ref4); - _graph[6] = new ResourceWrapper(ref5); + _graph[1] = instance; + _graph[2] = ref1; + _graph[3] = ref2; + _graph[5] = ref4; + _graph[6] = ref5; // Set single references instance.Parent = ref5; // Parent is set and // ref5.Children.Add(instance); Bidirectional reference synced --> no longer necessary @@ -268,10 +268,10 @@ public void ReferenceInterferenceOnSave() var other = new OtherResource { Id = 3, Name = "Ref2" }; var different = new DifferentResource { Id = 4, Name = "Different" }; // Fill graph - _graph[1] = new ResourceWrapper(instance); - _graph[2] = new ResourceWrapper(derived); - _graph[3] = new ResourceWrapper(other); - _graph[4] = new ResourceWrapper(different); + _graph[1] = instance; + _graph[2] = derived; + _graph[3] = other; + _graph[4] = different; // Set references instance.Derived = derived; instance.Others.Add(other); @@ -324,8 +324,8 @@ public void SetParentWhenAddingChild() ResourceReferenceTools.InitializeCollections(child); var mocks = SetupDbMocks(new List()); // Setup graph mock - _graph[1] = new ResourceWrapper(parent); - _graph[2] = new ResourceWrapper(child); + _graph[1] = parent; + _graph[2] = child; // Act parent.Children.Add(child); @@ -354,8 +354,8 @@ public void ClearParentWhenRemovingChild() }; var mocks = SetupDbMocks(relations); // Setup graph mock - _graph[1] = new ResourceWrapper(parent); - _graph[2] = new ResourceWrapper(child); + _graph[1] = parent; + _graph[2] = child; // Act parent.Children.Remove(child); @@ -386,9 +386,9 @@ public void SyncChildrenOnParentModification() }; var mocks = SetupDbMocks(relations); // Setup graph mock - _graph[1] = new ResourceWrapper(parent1); - _graph[2] = new ResourceWrapper(parent2); - _graph[3] = new ResourceWrapper(child); + _graph[1] = parent1; + _graph[2] = parent2; + _graph[3] = child; // Act child.Parent = parent2; diff --git a/src/Tests/Moryx.Resources.Management.Tests/ResourceManagerTests.cs b/src/Tests/Moryx.Resources.Management.Tests/ResourceManagerTests.cs index df5e432dc..4fa2a6183 100644 --- a/src/Tests/Moryx.Resources.Management.Tests/ResourceManagerTests.cs +++ b/src/Tests/Moryx.Resources.Management.Tests/ResourceManagerTests.cs @@ -306,7 +306,7 @@ public void RaiseChanged() } } - private class PublicResourceMock : ResourceMockBase, IPublicResource, IReferenceResource + private class PublicResourceMock : ResourceMockBase, IResource, IReferenceResource { public ICapabilities Capabilities { get; private set; } diff --git a/src/Tests/Moryx.Resources.Management.Tests/TypeControllerTests.cs b/src/Tests/Moryx.Resources.Management.Tests/TypeControllerTests.cs index 8ef3f51f7..744805217 100644 --- a/src/Tests/Moryx.Resources.Management.Tests/TypeControllerTests.cs +++ b/src/Tests/Moryx.Resources.Management.Tests/TypeControllerTests.cs @@ -8,6 +8,7 @@ using Moryx.Container; using Moq; using NUnit.Framework; +using Moryx.AbstractionLayer.Capabilities; namespace Moryx.Resources.Management.Tests { @@ -162,8 +163,9 @@ public void ForwardEventsFromProxy() var proxy = (ISimpleResource) _typeController.GetProxy(instance); // Act: Register listener and change foo - object eventSender = null, eventSender2 = null; + object eventSender = null, eventSender2 = null, eventSender3 = null; int eventValue = 0; + ICapabilities capabilitiesValue = null; var finallyEven = false; Assert.DoesNotThrow(() => instance.Foo = 10); EventHandler eventHandler = (sender, foo) => @@ -171,18 +173,30 @@ public void ForwardEventsFromProxy() eventSender = sender; eventValue = foo; }; + EventHandler eventHandler2 = (sender, capabilities) => + { + eventSender3 = sender; + capabilitiesValue = capabilities; + }; + proxy.FooChanged += eventHandler; proxy.FooEven += (sender, b) => finallyEven = b; proxy.SomeEvent += (sender, args) => eventSender2 = sender; + proxy.CapabilitiesChanged += eventHandler2; instance.Foo = 100; instance.RaiseEvent(); + instance.UpdateCapabilities(NullCapabilities.Instance); proxy.FooChanged -= eventHandler; + proxy.CapabilitiesChanged -= eventHandler2; // Assert: Check if eventSender is not null and equals the proxy Assert.NotNull(eventSender); Assert.NotNull(eventSender2); + Assert.NotNull(eventSender3); Assert.AreNotEqual(0, eventValue); Assert.AreEqual(proxy, eventSender); + Assert.AreEqual(proxy, eventSender3); + Assert.AreEqual(NullCapabilities.Instance, capabilitiesValue); Assert.AreEqual(100, eventValue); Assert.IsTrue(finallyEven); } diff --git a/src/Tests/Moryx.Runtime.Endpoints.IntegrationTests/Moryx.Runtime.Endpoints.IntegrationTests.csproj b/src/Tests/Moryx.Runtime.Endpoints.IntegrationTests/Moryx.Runtime.Endpoints.IntegrationTests.csproj index a52c61b87..5e5f646f0 100644 --- a/src/Tests/Moryx.Runtime.Endpoints.IntegrationTests/Moryx.Runtime.Endpoints.IntegrationTests.csproj +++ b/src/Tests/Moryx.Runtime.Endpoints.IntegrationTests/Moryx.Runtime.Endpoints.IntegrationTests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 enable false @@ -9,18 +9,14 @@ - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/src/Tests/Moryx.Runtime.Endpoints.Tests/Databases/UpdateConfigSqliteTests.cs b/src/Tests/Moryx.Runtime.Endpoints.Tests/Databases/UpdateConfigSqliteTests.cs index 70ff1c4bb..5e77dc3f2 100644 --- a/src/Tests/Moryx.Runtime.Endpoints.Tests/Databases/UpdateConfigSqliteTests.cs +++ b/src/Tests/Moryx.Runtime.Endpoints.Tests/Databases/UpdateConfigSqliteTests.cs @@ -2,23 +2,14 @@ // Licensed under the Apache License, Version 2.0 using Microsoft.Extensions.Logging; -using Moq; using Moryx.Model; using Moryx.Runtime.Endpoints.Databases.Endpoint.Services; using Moryx.Runtime.Kernel; using Moryx.TestTools.Test.Model; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.ComponentModel; -using System.Xml.Linq; using Moryx.Runtime.Endpoints.Databases.Endpoint.Models; using Moryx.Model.Sqlite; -using System.Runtime.CompilerServices; using NUnit.Framework; -using Moryx.Model.Configuration; using Moryx.Runtime.Endpoints.Databases.Endpoint.Exceptions; namespace Moryx.Runtime.Endpoints.Tests.Databases diff --git a/src/Tests/Moryx.Runtime.Endpoints.Tests/Moryx.Runtime.Endpoints.Tests.csproj b/src/Tests/Moryx.Runtime.Endpoints.Tests/Moryx.Runtime.Endpoints.Tests.csproj index 14b1d6e96..547ca8d9e 100644 --- a/src/Tests/Moryx.Runtime.Endpoints.Tests/Moryx.Runtime.Endpoints.Tests.csproj +++ b/src/Tests/Moryx.Runtime.Endpoints.Tests/Moryx.Runtime.Endpoints.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 false @@ -10,7 +10,6 @@ - diff --git a/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleManagerTests.cs b/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleManagerTests.cs index 64b5c3728..37bf00a67 100644 --- a/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleManagerTests.cs +++ b/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleManagerTests.cs @@ -294,7 +294,6 @@ public void CheckLifeCycleBoundActivatedCountIs1() // Act moduleManager.StartModules(); - var i = 0; WaitForTimeboxed(() => module.State == ServerModuleState.Running); // Assert diff --git a/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleMocks/LifeCycleBoundFacadeTestModule.cs b/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleMocks/LifeCycleBoundFacadeTestModule.cs index 8ee4d51d2..3d7f69fcc 100644 --- a/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleMocks/LifeCycleBoundFacadeTestModule.cs +++ b/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleMocks/LifeCycleBoundFacadeTestModule.cs @@ -10,7 +10,7 @@ namespace Moryx.Runtime.Kernel.Tests.ModuleMocks { - public class LifeCycleBoundFacadeTestModule : ServerModuleFacadeControllerBase + public class LifeCycleBoundFacadeTestModule : ServerModuleBase { public override string Name => "LifeCycleBoundTestModule"; diff --git a/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleMocks/ModuleBase.cs b/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleMocks/ModuleBase.cs index e06b85b3a..fe046cf5f 100644 --- a/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleMocks/ModuleBase.cs +++ b/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleMocks/ModuleBase.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0 using System; +using Moryx.Container; using Moryx.Modules; using Moryx.Runtime.Modules; @@ -20,6 +21,8 @@ internal class ModuleBase : IServerModule /// public IServerModuleConsole Console { get; private set; } + public IContainer Container => throw new NotImplementedException(); + /// /// Initialize this component and prepare it for incoming taks. This must only involve preparation and must not start /// any active functionality and/or periodic execution of logic. diff --git a/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleMocks/ServerModuleA.cs b/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleMocks/ServerModuleA.cs index d887de84c..296aa5a41 100644 --- a/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleMocks/ServerModuleA.cs +++ b/src/Tests/Moryx.Runtime.Kernel.Tests/ModuleMocks/ServerModuleA.cs @@ -10,7 +10,7 @@ namespace Moryx.Runtime.Kernel.Tests.ModuleMocks { - public class ServerModuleA : ServerModuleFacadeControllerBase, IFacadeContainer + public class ServerModuleA : ServerModuleBase, IFacadeContainer { public ServerModuleA(IModuleContainerFactory containerFactory, IConfigManager configManager, ILoggerFactory loggerFactory) : base(containerFactory, configManager, loggerFactory) diff --git a/src/Tests/Moryx.Runtime.Kernel.Tests/Moryx.Runtime.Kernel.Tests.csproj b/src/Tests/Moryx.Runtime.Kernel.Tests/Moryx.Runtime.Kernel.Tests.csproj index 12e208480..e0763d99c 100644 --- a/src/Tests/Moryx.Runtime.Kernel.Tests/Moryx.Runtime.Kernel.Tests.csproj +++ b/src/Tests/Moryx.Runtime.Kernel.Tests/Moryx.Runtime.Kernel.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 Library full @@ -17,7 +17,6 @@ - diff --git a/src/Tests/Moryx.Runtime.Tests/ModuleBaseTest.cs b/src/Tests/Moryx.Runtime.Tests/ModuleBaseTest.cs index fc5c7fb6f..484e6261b 100644 --- a/src/Tests/Moryx.Runtime.Tests/ModuleBaseTest.cs +++ b/src/Tests/Moryx.Runtime.Tests/ModuleBaseTest.cs @@ -1,7 +1,6 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 -using Moryx.Runtime.Container; using Moryx.Runtime.Modules; using Moryx.Runtime.Tests.Mocks; using Moryx.Runtime.Tests.Modules; @@ -36,7 +35,7 @@ public void StrategiesInConfigFound() var casted = (IServerModule) _moduleUnderTest; casted.Initialize(); - var containerConfig = ((IContainerHost) _moduleUnderTest).Strategies; + var containerConfig = _moduleUnderTest.Strategies; Assert.GreaterOrEqual(containerConfig.Count, 1, "No strategy found!"); Assert.IsTrue(containerConfig.ContainsKey(typeof(IStrategy)), "Wrong type!"); diff --git a/src/Tests/Moryx.Runtime.Tests/Moryx.Runtime.Tests.csproj b/src/Tests/Moryx.Runtime.Tests/Moryx.Runtime.Tests.csproj index 12e208480..e0763d99c 100644 --- a/src/Tests/Moryx.Runtime.Tests/Moryx.Runtime.Tests.csproj +++ b/src/Tests/Moryx.Runtime.Tests/Moryx.Runtime.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 Library full @@ -17,7 +17,6 @@ - diff --git a/src/Tests/Moryx.Tests/Moryx.Tests.csproj b/src/Tests/Moryx.Tests/Moryx.Tests.csproj index ce8ad8b6e..39faf789d 100644 --- a/src/Tests/Moryx.Tests/Moryx.Tests.csproj +++ b/src/Tests/Moryx.Tests/Moryx.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 Library full diff --git a/src/Tests/Moryx.Tests/Serialization/EntryConvertInvokeMethodTests.cs b/src/Tests/Moryx.Tests/Serialization/EntryConvertInvokeMethodTests.cs index 7240476d4..6a51ad7b8 100644 --- a/src/Tests/Moryx.Tests/Serialization/EntryConvertInvokeMethodTests.cs +++ b/src/Tests/Moryx.Tests/Serialization/EntryConvertInvokeMethodTests.cs @@ -1,9 +1,6 @@ // Copyright (c) 2023, Phoenix Contact GmbH & Co. KG // Licensed under the Apache License, Version 2.0 -using System.Collections.Generic; -using System.Globalization; -using System.Linq; using Moryx.Serialization; using NUnit.Framework; @@ -16,7 +13,6 @@ namespace Moryx.Tests public class EntryConvertInvokeMethodTests { private readonly EntrySerialize_Methods _sut; - private readonly EntrySerializeSerialization _serialization; public EntryConvertInvokeMethodTests() { _sut = new EntrySerialize_Methods();