From cf231807b40555a14d9c52982a00dcb3d318466b Mon Sep 17 00:00:00 2001 From: Tho Ho Date: Fri, 20 Oct 2023 12:00:14 +0800 Subject: [PATCH] .Net 8.0 (#6) * Consolidate Directory.Build.targets * Support .NET 8.0 and 7.0 * Build branch dev * Fix publish * Update minver-cli@4.3.0 * Fix build warning * Update README * Consolidate dependency * Update docker .NET 8.0 * Windows support .NET 7.0 and .NET 8.0 * Fix Shell SIGTERM with exec * Typo * Update dependency --- .azure/pipelines/azure-pipelines.yml | 17 +- .config/dotnet-tools.json | 8 +- .docker-linux/Dockerfile | 7 +- .docker-windows/Dockerfile | 3 +- .github/workflows/aspnet-core.yml | 71 ++++- Common.props | 34 +++ Directory.Build.targets | 268 +++++++++++++----- EchoServiceApi/EchoServiceApi.csproj | 175 +++++++++++- EchoServiceApi/Program.cs | 3 - EchoServiceApi/Verifiers/BaseVerifier.cs | 4 +- .../Verifiers/CosmosCacheVerifier.cs | 8 +- EchoServiceApi/Verifiers/CosmosVerifier.cs | 12 +- EchoServiceApi/Verifiers/DirVerifier.cs | 2 + EchoServiceApi/Verifiers/HttpVerifier.cs | 2 + .../Verifiers/KeyVaultCertificateVerifier.cs | 7 +- .../Verifiers/KeyVaultKeyVerifier.cs | 4 +- EchoServiceApi/Verifiers/PosgreSqlVerifier.cs | 10 +- .../ProviderConnectionStringExtensions.cs | 4 +- .../Verifiers/ServiceBusVerifier.cs | 12 +- .../Verifiers/TokenCredentialFactory.cs | 7 +- EchoServiceApi/Verifiers/VerifyResult.cs | 6 +- NuGet.Config | 6 + README.md | 14 +- 23 files changed, 556 insertions(+), 128 deletions(-) create mode 100644 Common.props create mode 100644 NuGet.Config diff --git a/.azure/pipelines/azure-pipelines.yml b/.azure/pipelines/azure-pipelines.yml index 680d7ad..0432e83 100644 --- a/.azure/pipelines/azure-pipelines.yml +++ b/.azure/pipelines/azure-pipelines.yml @@ -2,6 +2,7 @@ trigger: branches: include: - main + - dev* tags: include: - "*.*.*" @@ -26,6 +27,17 @@ pool: vmImage: $(imageName) steps: + - task: UseDotNet@2 + displayName: "Use .NET Core sdk 8.x" + inputs: + version: 8.x + includePreviewVersions: true + + - task: UseDotNet@2 + displayName: "Use .NET Core sdk 7.x" + inputs: + version: 7.x + - task: UseDotNet@2 displayName: "Use .NET Core sdk 6.x" inputs: @@ -37,5 +49,8 @@ steps: - script: dotnet build --configuration $(buildConfiguration) displayName: "dotnet build $(buildConfiguration)" - - script: dotnet publish EchoServiceApi -o ./artifacts/echoServiceApi/ --configuration $(buildConfiguration) --no-build + - script: | + dotnet publish EchoServiceApi --configuration $(buildConfiguration) --no-build -f net6.0 --no-build -o artifacts/net6.0/app + dotnet publish EchoServiceApi --configuration $(buildConfiguration) --no-build -f net7.0 --no-build -o artifacts/net7.0/app + dotnet publish EchoServiceApi --configuration $(buildConfiguration) --no-build -f net8.0 --no-build -o artifacts/net8.0/app displayName: "dotnet publish $(buildConfiguration)" diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index bcd6adc..d4e8819 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,10 +3,8 @@ "isRoot": true, "tools": { "minver-cli": { - "version": "4.2.0", - "commands": [ - "minver" - ] + "version": "4.3.0", + "commands": ["minver"] } } -} \ No newline at end of file +} diff --git a/.docker-linux/Dockerfile b/.docker-linux/Dockerfile index e9b5d6d..ee6021f 100644 --- a/.docker-linux/Dockerfile +++ b/.docker-linux/Dockerfile @@ -1,11 +1,8 @@ -#ARG ASPNET_IMAGE_TAG=6.0-alpine -#ARG ASPNET_IMAGE=mcr.microsoft.com/dotnet/aspnet:${ASPNET_IMAGE_TAG} -ARG ASPNET_IMAGE_TAG=latest +ARG ASPNET_IMAGE_TAG=6.0-alpine ARG ASPNET_IMAGE=netlah/aspnet-webssh:${ASPNET_IMAGE_TAG} FROM ${ASPNET_IMAGE} WORKDIR /app EXPOSE 80 RUN apk update && apk add --no-cache ca-certificates COPY app . -ENTRYPOINT ["/opt/startup/init_container.sh"] -CMD ["dotnet", "EchoServiceApi.dll"] +ENTRYPOINT ["/opt/startup/init_container.sh", "exec", "dotnet", "EchoServiceApi.dll"] diff --git a/.docker-windows/Dockerfile b/.docker-windows/Dockerfile index 3ecde7f..dd6ab12 100644 --- a/.docker-windows/Dockerfile +++ b/.docker-windows/Dockerfile @@ -1,4 +1,5 @@ -ARG ASPNET_IMAGE=mcr.microsoft.com/dotnet/aspnet:6.0-nanoserver-1809 +ARG ASPNET_IMAGE_TAG=6.0-nanoserver-1809 +ARG ASPNET_IMAGE=mcr.microsoft.com/dotnet/aspnet:${ASPNET_IMAGE_TAG} FROM ${ASPNET_IMAGE} WORKDIR /app EXPOSE 80 diff --git a/.github/workflows/aspnet-core.yml b/.github/workflows/aspnet-core.yml index e738dff..b3d8a50 100644 --- a/.github/workflows/aspnet-core.yml +++ b/.github/workflows/aspnet-core.yml @@ -1,4 +1,4 @@ -name: ASP.NETCore 6 +name: ASP.NET Core on: push: @@ -20,11 +20,13 @@ jobs: with: fetch-depth: 0 - - name: Setup .NET Core 6.x + - name: Setup .NET Core 8.0.x, 7.0.x, and 6.0.x uses: actions/setup-dotnet@v3 with: dotnet-version: | 6.0.x + 7.0.x + 8.0.x-x - name: dotnet info run: dotnet --info @@ -71,6 +73,50 @@ jobs: type=match,enable=${{ startsWith(github.ref, 'refs/tags/') }},priority=570,prefix=6.0-,pattern=^(\d+\.\d+)(\.\d+)?(-.+)?$,group=1 type=match,enable=${{ startsWith(github.ref, 'refs/tags/') }},priority=560,prefix=6.0-,pattern=^(\d+)\.\d+(\.\d+)?(-.+)?$,group=1 + - name: Docker meta 7.0 + if: ${{ success() && (runner.os == 'Linux' || runner.os == 'Windows') }} + id: meta70 + uses: docker/metadata-action@v4 + with: + images: | + ${{ secrets.DOCKER_HUB_REPOS }} + netlah/echo-service-api,enable=${{ startsWith(github.ref, 'refs/tags/') }} + flavor: | + latest=auto + suffix=${{ env.TAG_SUFFIX }} + prefix=7.0- + tags: | + type=raw,enable=${{ github.event_name != 'pull_request' }},priority=699,value=${{ steps.minver.outputs.version }} + type=ref,event=branch,priority=500 + type=ref,event=pr,priority=500,prefix=7.0-pr- + type=sha,enable=${{ github.event_name != 'pull_request' }},priority=400,prefix=7.0-sha-,format=short + type=match,enable=${{ startsWith(github.ref, 'refs/tags/') }},priority=600,pattern=^(\d+\.\d+(\.\d+)?(-.+)?)$,group=1 + type=match,enable=${{ startsWith(github.ref, 'refs/tags/') }},priority=580,pattern=^(\d+\.\d+(\.\d+)?)(-.+)?$,group=1 + type=match,enable=${{ startsWith(github.ref, 'refs/tags/') }},priority=570,pattern=^(\d+\.\d+)(\.\d+)?(-.+)?$,group=1 + type=match,enable=${{ startsWith(github.ref, 'refs/tags/') }},priority=560,pattern=^(\d+)\.\d+(\.\d+)?(-.+)?$,group=1 + + - name: Docker meta 8.0 + if: ${{ success() && (runner.os == 'Linux' || runner.os == 'Windows') }} + id: meta80 + uses: docker/metadata-action@v4 + with: + images: | + ${{ secrets.DOCKER_HUB_REPOS }} + netlah/echo-service-api,enable=${{ startsWith(github.ref, 'refs/tags/') }} + flavor: | + latest=auto + suffix=${{ env.TAG_SUFFIX }} + prefix=8.0-preview- + tags: | + type=raw,enable=${{ github.event_name != 'pull_request' }},priority=699,value=${{ steps.minver.outputs.version }} + type=ref,event=branch,priority=500 + type=ref,event=pr,priority=500,prefix=8.0-preview-pr- + type=sha,enable=${{ github.event_name != 'pull_request' }},priority=400,prefix=8.0-preview-sha-,format=short + type=match,enable=${{ startsWith(github.ref, 'refs/tags/') }},priority=600,pattern=^(\d+\.\d+(\.\d+)?(-.+)?)$,group=1 + type=match,enable=${{ startsWith(github.ref, 'refs/tags/') }},priority=580,pattern=^(\d+\.\d+(\.\d+)?)(-.+)?$,group=1 + type=match,enable=${{ startsWith(github.ref, 'refs/tags/') }},priority=570,pattern=^(\d+\.\d+)(\.\d+)?(-.+)?$,group=1 + type=match,enable=${{ startsWith(github.ref, 'refs/tags/') }},priority=560,pattern=^(\d+)\.\d+(\.\d+)?(-.+)?$,group=1 + - name: Install dependencies run: dotnet restore @@ -81,13 +127,18 @@ jobs: run: dotnet test -c Release --no-build --verbosity normal - name: Publish - run: dotnet publish EchoServiceApi -c Release --no-build -o artifacts/net6.0/app + run: | + dotnet publish EchoServiceApi -c Release -f net6.0 --no-build -o artifacts/net6.0/app + dotnet publish EchoServiceApi -c Release -f net7.0 --no-build -o artifacts/net7.0/app + dotnet publish EchoServiceApi -c Release -f net8.0 --no-build -o artifacts/net8.0/app - name: Copy Dockerfile if: ${{ success() && (runner.os == 'Linux' || runner.os == 'Windows') }} shell: pwsh run: | Copy-Item -Recurse -Force -Path '.dockerignore',".docker-$( if ($Env:RUNNER_OS -eq 'Linux') { 'linux' } else { 'windows' } )/*" -Destination artifacts/net6.0/ -ErrorAction Stop -Verbose + Copy-Item -Recurse -Force -Path '.dockerignore',".docker-$( if ($Env:RUNNER_OS -eq 'Linux') { 'linux' } else { 'windows' } )/*" -Destination artifacts/net7.0/ -ErrorAction Stop -Verbose + Copy-Item -Recurse -Force -Path '.dockerignore',".docker-$( if ($Env:RUNNER_OS -eq 'Linux') { 'linux' } else { 'windows' } )/*" -Destination artifacts/net8.0/ -ErrorAction Stop -Verbose - name: Enabling Docker Daemon With experimental features if: ${{ success() && runner.os == 'Linux' }} @@ -114,3 +165,17 @@ jobs: if: ${{ success() && (runner.os == 'Linux' || runner.os == 'Windows') }} shell: pwsh run: ./docker-build.ps1 -Context ./artifacts/net6.0 -Squash -Tags "${{ steps.meta60.outputs.tags }}" -Labels "${{ steps.meta60.outputs.labels }}" + + - name: Build and Push 7.0 + if: ${{ success() && (runner.os == 'Linux' || runner.os == 'Windows') }} + shell: pwsh + run: | + $aspnetImageTag70 = if ($Env:RUNNER_OS -eq 'Linux') { '7.0-alpine' } else { '7.0-nanoserver-1809' } + ./docker-build.ps1 -Context ./artifacts/net7.0 -Squash -Tags "${{ steps.meta70.outputs.tags }}" -Labels "${{ steps.meta70.outputs.labels }}" -BuildArgs "ASPNET_IMAGE_TAG=$aspnetImageTag70" + + - name: Build and Push 8.0 + if: ${{ success() && (runner.os == 'Linux' || runner.os == 'Windows') }} + shell: pwsh + run: | + $aspnetImageTag80 = if ($Env:RUNNER_OS -eq 'Linux') { '8.0-alpine' } else { '8.0-nanoserver-1809' } + ./docker-build.ps1 -Context ./artifacts/net8.0 -Squash -Tags "${{ steps.meta80.outputs.tags }}" -Labels "${{ steps.meta80.outputs.labels }}" -BuildArgs "ASPNET_IMAGE_TAG=$aspnetImageTag80" diff --git a/Common.props b/Common.props new file mode 100644 index 0000000..f9433bd --- /dev/null +++ b/Common.props @@ -0,0 +1,34 @@ + + + + 6.0.23;7.0.12;8.0.0-rc.2 + True + + $([MSBuild]::GetTargetFrameworkIdentifier($(TargetFramework))) + $([MSBuild]::GetTargetFrameworkVersion($(TargetFramework))) + + False + False + False + False + False + False + False + False + + True + True + True + True + True + True + True + + False + False + True + True + + + + diff --git a/Directory.Build.targets b/Directory.Build.targets index 5cacde9..5d55e41 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,106 +1,152 @@ + + + + 6.* + 7.* + 8.*-* + + + + 7.* + 8.*-* + + - 6.0.14 - 3.1.* - 5.* - 6.* - 7.* - 5.* - $(FrameworkVersion) - 5.* - 6.* + 5.* + $(FrameworkVersion) + + 5.* + 6.* + + + - - + - - - - - + + + + + - - - + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + - - + + + + + + + + + + + + + + - + + + + + + + + + + + + - + + + + + + + + + + + + - + + @@ -109,6 +155,7 @@ + @@ -116,54 +163,106 @@ + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + - - - - - + + + + + + + + + + + + - + + + + + + + + + @@ -175,8 +274,12 @@ + + + + @@ -186,14 +289,46 @@ + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -203,6 +338,7 @@ + @@ -227,11 +363,13 @@ - - + + + + 0 diff --git a/EchoServiceApi/EchoServiceApi.csproj b/EchoServiceApi/EchoServiceApi.csproj index 620f60b..1d0ef6b 100644 --- a/EchoServiceApi/EchoServiceApi.csproj +++ b/EchoServiceApi/EchoServiceApi.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0;net7.0;net6.0 netlah-echoserviceapi-bf38 Linux @@ -13,46 +13,211 @@ - + + - + + + + + + - + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/EchoServiceApi/Program.cs b/EchoServiceApi/Program.cs index a1d3849..5a26878 100644 --- a/EchoServiceApi/Program.cs +++ b/EchoServiceApi/Program.cs @@ -62,10 +62,7 @@ logger.LogInformation("Environment: {environmentName}; DeveloperMode:{isDevelopment}", app.Environment.EnvironmentName, app.Environment.IsDevelopment()); app.UseHttpOverrides(); - -#pragma warning disable S3923 // All branches in a conditional structure should not have exactly the same implementation if (app.Environment.IsDevelopment()) -#pragma warning restore S3923 // All branches in a conditional structure should not have exactly the same implementation { // app.UseDeveloperExceptionPage() } diff --git a/EchoServiceApi/Verifiers/BaseVerifier.cs b/EchoServiceApi/Verifiers/BaseVerifier.cs index d4d2254..c7ce647 100644 --- a/EchoServiceApi/Verifiers/BaseVerifier.cs +++ b/EchoServiceApi/Verifiers/BaseVerifier.cs @@ -27,12 +27,14 @@ protected BaseVerifier(IServiceProvider serviceProvider) protected ProviderConnectionString GetConnection(string name) { if (string.IsNullOrEmpty(name)) + { throw new ArgumentNullException(nameof(name)); + } IConnectionStringManager connectionStringManager = new ConnectionStringManager(Configuration); var connectionObj = connectionStringManager[name] ?? throw new Exception($"Connection string '{name}' not found"); return connectionObj; } - protected IDisposable LoggerBeginScopeDiagnostic() => Logger.BeginScope(DiagnosticInfo.LoggingScopeState); + protected IDisposable LoggerBeginScopeDiagnostic() => Logger.BeginScope(DiagnosticInfo.LoggingScopeState) ?? throw new Exception("Logger.BeginScope null"); } diff --git a/EchoServiceApi/Verifiers/CosmosCacheVerifier.cs b/EchoServiceApi/Verifiers/CosmosCacheVerifier.cs index ff23ac7..f955c34 100644 --- a/EchoServiceApi/Verifiers/CosmosCacheVerifier.cs +++ b/EchoServiceApi/Verifiers/CosmosCacheVerifier.cs @@ -17,12 +17,12 @@ public CosmosCacheVerifier(IServiceProvider serviceProvider) : base(serviceProvi public async Task VerifyAsync(string name) { var connectionObj = GetConnection(name); - var cosmosCacheInfo = connectionObj.Get(); + var cosmosCacheInfo = connectionObj.Get() ?? throw new Exception("CosmosCacheInfo is required"); var databaseName = cosmosCacheInfo.DatabaseName; var containerName = cosmosCacheInfo.ContainerName; - using var cosmosclient = await CreateClientAsync(connectionObj, cosmosCacheInfo); + using var cosmosClient = await CreateClientAsync(connectionObj, cosmosCacheInfo); using var scope = LoggerBeginScopeDiagnostic(); @@ -31,7 +31,7 @@ public async Task VerifyAsync(string name) var cosmosCacheOptions = new CosmosCacheOptions { - CosmosClient = cosmosclient, + CosmosClient = cosmosClient, ContainerName = containerName, DatabaseName = databaseName, CreateIfNotExists = false, @@ -39,6 +39,6 @@ public async Task VerifyAsync(string name) var cache = new CosmosCache(Options.Create(cosmosCacheOptions)); _ = await cache.GetStringAsync("CosmosCacheVerifier"); - return VerifyResult.Successed("CosmosCache", connectionObj); + return VerifyResult.Succeed("CosmosCache", connectionObj); } } diff --git a/EchoServiceApi/Verifiers/CosmosVerifier.cs b/EchoServiceApi/Verifiers/CosmosVerifier.cs index 14a0a6d..851e562 100644 --- a/EchoServiceApi/Verifiers/CosmosVerifier.cs +++ b/EchoServiceApi/Verifiers/CosmosVerifier.cs @@ -1,7 +1,6 @@ using Microsoft.Azure.Cosmos; using NetLah.Extensions.Configuration; -#pragma warning disable S4457 // Parameter validation in "async"/"await" methods should be wrapped namespace EchoServiceApi.Verifiers; public class CosmosVerifier : BaseCosmosVerifier @@ -11,26 +10,27 @@ public CosmosVerifier(IServiceProvider serviceProvider) : base(serviceProvider) public async Task VerifyAsync(string name, string key) { if (string.IsNullOrEmpty(key)) + { throw new ArgumentNullException(nameof(key)); + } var connectionObj = GetConnection(name); - var cosmosInfo = connectionObj.Get(); + var cosmosInfo = connectionObj.Get() ?? throw new Exception("CosmosContainerInfo is required"); var containerName = cosmosInfo.ContainerName; var databaseName = cosmosInfo.DatabaseName; - using var cosmosclient = await CreateClientAsync(connectionObj, cosmosInfo); + using var cosmosClient = (await CreateClientAsync(connectionObj, cosmosInfo)) ?? throw new Exception("CosmosContainerInfo is required"); using var scope = LoggerBeginScopeDiagnostic(); Logger.LogInformation("CosmosVerifier db:{databaseName} container:{containerName} name={query_name} key={query_key}", databaseName, containerName, name, key); - var container = cosmosclient.GetContainer(databaseName, containerName); + var container = cosmosClient.GetContainer(databaseName, containerName); _ = await container.ReadContainerAsync().ConfigureAwait(false); var itemResponse = await container.ReadItemAsync>(key, new PartitionKey(key)); return VerifyResult.SuccessObject("Cosmos", connectionObj, itemResponse.Resource); } -} -#pragma warning restore S4457 // Parameter validation in "async"/"await" methods should be wrapped +} \ No newline at end of file diff --git a/EchoServiceApi/Verifiers/DirVerifier.cs b/EchoServiceApi/Verifiers/DirVerifier.cs index 5f33747..89d03df 100644 --- a/EchoServiceApi/Verifiers/DirVerifier.cs +++ b/EchoServiceApi/Verifiers/DirVerifier.cs @@ -7,7 +7,9 @@ public DirVerifier(IServiceProvider serviceProvider) : base(serviceProvider) { } public Task VerifyAsync(string path) { if (string.IsNullOrEmpty(path)) + { throw new ArgumentException("Path is required"); + } var isDir = false; var isFile = File.Exists(path); diff --git a/EchoServiceApi/Verifiers/HttpVerifier.cs b/EchoServiceApi/Verifiers/HttpVerifier.cs index dea8dd8..46c845e 100644 --- a/EchoServiceApi/Verifiers/HttpVerifier.cs +++ b/EchoServiceApi/Verifiers/HttpVerifier.cs @@ -13,7 +13,9 @@ public HttpVerifier(HttpClient httpClient, IServiceProvider serviceProvider) public async Task VerifyAsync(Uri url, string? host) { if (url == null) + { throw new ArgumentException("Url is required"); + } if (!string.IsNullOrEmpty(host)) { diff --git a/EchoServiceApi/Verifiers/KeyVaultCertificateVerifier.cs b/EchoServiceApi/Verifiers/KeyVaultCertificateVerifier.cs index 45d15ea..c1c0891 100644 --- a/EchoServiceApi/Verifiers/KeyVaultCertificateVerifier.cs +++ b/EchoServiceApi/Verifiers/KeyVaultCertificateVerifier.cs @@ -33,8 +33,11 @@ public async Task VerifyAsync(string name, bool privateKey, bool a var certificateName = locationParts[2]; var versions = new List(); var version = locationParts.Length >= 4 ? locationParts[3] : null; - if (string.IsNullOrEmpty(version)) version = null; - + if (string.IsNullOrEmpty(version)) + { + version = null; + } + versions.Add(version); if (privateKey) diff --git a/EchoServiceApi/Verifiers/KeyVaultKeyVerifier.cs b/EchoServiceApi/Verifiers/KeyVaultKeyVerifier.cs index a4ca887..a468232 100644 --- a/EchoServiceApi/Verifiers/KeyVaultKeyVerifier.cs +++ b/EchoServiceApi/Verifiers/KeyVaultKeyVerifier.cs @@ -28,7 +28,9 @@ public async Task VerifyAsync(string name) var keyName = locationParts[2]; var version = locationParts.Length >= 4 ? locationParts[3] : null; if (string.IsNullOrEmpty(version)) + { version = null; + } var keyClient = new KeyClient(keyIdentifier, tokenCredential); var response = await keyClient.GetKeyAsync(keyName, version); @@ -51,7 +53,7 @@ public async Task VerifyAsync(string name) var detail = $"KeyType={keyVaultKey.KeyType}; Text={text}; Signature={signed}; Ciphertext={ciphertext}; Plaintext={decryptText}; ValidSignature={validSignature}"; - return VerifyResult.Successed("KeyVaultKey", connectionObj, detail: detail); + return VerifyResult.Succeed("KeyVaultKey", connectionObj, detail: detail); } return new VerifyResult diff --git a/EchoServiceApi/Verifiers/PosgreSqlVerifier.cs b/EchoServiceApi/Verifiers/PosgreSqlVerifier.cs index 0051bb9..f8a40eb 100644 --- a/EchoServiceApi/Verifiers/PosgreSqlVerifier.cs +++ b/EchoServiceApi/Verifiers/PosgreSqlVerifier.cs @@ -1,5 +1,4 @@ -#pragma warning disable S4457 // Parameter validation in "async"/"await" methods should be wrapped -namespace EchoServiceApi.Verifiers; +namespace EchoServiceApi.Verifiers; public class PosgreSqlVerifier : BaseVerifier { @@ -8,7 +7,9 @@ public PosgreSqlVerifier(IServiceProvider serviceProvider) : base(serviceProvide public async Task VerifyAsync(string name, string tableName) { if (string.IsNullOrEmpty(tableName)) + { throw new ArgumentNullException(nameof(tableName)); + } var connectionObj = GetConnection(name); var connectionString = connectionObj.Value; @@ -22,7 +23,6 @@ public async Task VerifyAsync(string name, string tableName) command.CommandType = System.Data.CommandType.Text; command.ExecuteNonQuery(); - return VerifyResult.Successed("PosgreSql", connectionObj, detail: query); + return VerifyResult.Succeed("PosgreSql", connectionObj, detail: query); } -} -#pragma warning restore S4457 // Parameter validation in "async"/"await" methods should be wrapped +} \ No newline at end of file diff --git a/EchoServiceApi/Verifiers/ProviderConnectionStringExtensions.cs b/EchoServiceApi/Verifiers/ProviderConnectionStringExtensions.cs index cbd0740..621392f 100644 --- a/EchoServiceApi/Verifiers/ProviderConnectionStringExtensions.cs +++ b/EchoServiceApi/Verifiers/ProviderConnectionStringExtensions.cs @@ -37,12 +37,12 @@ public static TConnectionCredentialInfo TryGet(this P return new TConnectionCredentialInfo { Value = connectionString.Value }; } - return connectionString.Get(); + return connectionString.Get() ?? throw new Exception("ConnectionCredentialValue is required"); } public static ConnectionCredentialBag Load(this ProviderConnectionString connectionString) { - var result = connectionString.Get>(); + var result = connectionString.Get>() ?? throw new Exception("ConnectionCredentialBag is required"); result.Value = connectionString.Get(); return result; } diff --git a/EchoServiceApi/Verifiers/ServiceBusVerifier.cs b/EchoServiceApi/Verifiers/ServiceBusVerifier.cs index affbd05..21222ba 100644 --- a/EchoServiceApi/Verifiers/ServiceBusVerifier.cs +++ b/EchoServiceApi/Verifiers/ServiceBusVerifier.cs @@ -25,7 +25,7 @@ public async Task VerifyAsync(string name, bool send, bool receive { if (string.IsNullOrEmpty(queueName)) { - queueName = connectionObj.Get().QueueName ?? throw new Exception("QueueName is required"); + queueName = connectionObj.Get()?.QueueName ?? throw new Exception("QueueName is required"); } client = new ServiceBusClient(connectionString: connectionObj.Value); } @@ -57,7 +57,7 @@ public async Task VerifyAsync(string name, bool send, bool receive await receiver.CompleteMessageAsync(message); } var detail1 = $"Received={isExist}; queueName={queueName}; fqns={receiver.FullyQualifiedNamespace}; messageId={message?.MessageId}; messageBody={message?.Body.ToString()}"; - return VerifyResult.Successed("ServiceBus", connectionObj, detail1); + return VerifyResult.Succeed("ServiceBus", connectionObj, detail1); } else if (send) { @@ -65,21 +65,25 @@ public async Task VerifyAsync(string name, bool send, bool receive await sender.SendMessageAsync(new ServiceBusMessage($"{queueName}-{DateTimeOffset.Now}")); var detail1 = $"Status=Sent; queueName={queueName}; fqns={sender.FullyQualifiedNamespace};"; - return VerifyResult.Successed("ServiceBus", connectionObj, detail1); + return VerifyResult.Succeed("ServiceBus", connectionObj, detail1); } sender = client.CreateSender(queueName); receiver = client.CreateReceiver(queueName); var detail = $"queueName={queueName}; fqns={sender.FullyQualifiedNamespace};"; - return VerifyResult.Successed("ServiceBus", connectionObj, detail); + return VerifyResult.Succeed("ServiceBus", connectionObj, detail); } finally { if (receiver != null) + { await receiver.DisposeAsync(); + } if (sender != null) + { await sender.DisposeAsync(); + } await client.DisposeAsync(); diff --git a/EchoServiceApi/Verifiers/TokenCredentialFactory.cs b/EchoServiceApi/Verifiers/TokenCredentialFactory.cs index 7aef825..d78501d 100644 --- a/EchoServiceApi/Verifiers/TokenCredentialFactory.cs +++ b/EchoServiceApi/Verifiers/TokenCredentialFactory.cs @@ -38,15 +38,12 @@ private async Task GetDefaultTokenCredentialAsync() return result; } - public async Task GetTokenCredentialAsync(AzureCredentialInfo? options) => -#pragma warning disable S3358 // Ternary operators should not be nested - options != null && options.ClientId is { } clientId - ? options.TenantId is { } tenantId + public async Task GetTokenCredentialAsync(AzureCredentialInfo? options) => options != null && options.ClientId is { } clientId + ? options.TenantId is { } tenantId && options.ClientSecret is { } clientSecret ? await GetClientSecretCredentialAsync(tenantId, clientId, clientSecret) : await GetManagedIdentityClientIdAsync(clientId) : null; -#pragma warning restore S3358 // Ternary operators should not be nested public string? Redact(string? secret) { diff --git a/EchoServiceApi/Verifiers/VerifyResult.cs b/EchoServiceApi/Verifiers/VerifyResult.cs index 34e8273..29c8d1b 100644 --- a/EchoServiceApi/Verifiers/VerifyResult.cs +++ b/EchoServiceApi/Verifiers/VerifyResult.cs @@ -18,7 +18,7 @@ public static VerifyResult Failed(Exception ex) { Success = false, Error = $"{ex.GetType().FullName}: {cosmosException.Message}", - Disagnostics = cosmosException.Diagnostics?.ToString(), + Diagnostics = cosmosException.Diagnostics?.ToString(), StackTrace = cosmosException.StackTrace, DetailError = cosmosException.ToString(), } @@ -31,7 +31,7 @@ public static VerifyResult Failed(Exception ex) }; } - public static VerifyResult Successed(string serviceName, ProviderConnectionString connectionObj, string? detail = null) + public static VerifyResult Succeed(string serviceName, ProviderConnectionString connectionObj, string? detail = null) { return new VerifySuccessMessage { @@ -57,7 +57,7 @@ public class VerifyFailed : VerifyResult public string? Error { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public object? Disagnostics { get; set; } + public object? Diagnostics { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? StackTrace { get; internal set; } diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000..daa5700 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index e94b1fd..f3eca18 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# ASPNET.Core 6 Echo Service WebApi +# ASP.NET Core Echo Service WebApi -ASPNET.Core 6 WebApi provide Echo Service Api for troubleshooting and diagnosing during deployment and integration. This is useful tool on detecting deployment (setup environment) and development issue OAuth and OIDC with deployment environment. +ASP.NET Core WebApi provide Echo Service Api for troubleshooting and diagnosing during deployment and integration. This is useful tool on detecting deployment (setup environment) and development issue OAuth and OIDC with deployment environment. ## Build Status @@ -14,7 +14,7 @@ ASPNET.Core 6 WebApi provide Echo Service Api for troubleshooting and diagnosing - Support Linux and Windows Server 2019 with nanoserver 1809 base. -- This docker respository not support tag `latest` and multi arch yet, there is 2 tags `linux` and `nanoserver-1809` +- This docker repository not support tag `latest` and multi arch yet, there is 2 tags `linux` and `nanoserver-1809` ``` docker pull netlah/echo-service-api:linux @@ -23,9 +23,9 @@ docker logs -f echoapi docker rm -f echoapi ``` -### Run ASP.NETCore Echo Service API from command line using dotnet +### Run ASP.NET Core Echo Service API from command line using dotnet -- Checkout source code from Github +- Checkout source code from GitHub - Run the ASP.NET Core WebApi application using command line @@ -69,11 +69,11 @@ https:///e/ ### Test with hosting and Reverse Proxy -- This Echo Service Api support both IIS In process, IIS out process, IIS ARR Urlrewite or NGINX. +- This Echo Service Api support both IIS In process, IIS out process, IIS ARR URL Rewrite or NGINX. - For forwarded headers issue when behind Reverse Proxy, can check this article for further understanding: https://devblogs.microsoft.com/aspnet/forwarded-headers-middleware-updates-in-net-core-3-0-preview-6/ -- To add support Forwarded Headers when use with Reverse Proxy, make sure add this environment setting (environment setings, it is not support appsettings.json). +- To add support Forwarded Headers when use with Reverse Proxy, make sure add this environment setting (environment settings, it is not support appsettings.json). ``` ASPNETCORE_FORWARDEDHEADERS_ENABLED=true