From f053870733afdee384c097542bb389b7b624ab6d Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Fri, 11 Oct 2019 16:09:46 +0300 Subject: [PATCH] add RemoteServiceExceptionHandler --- .../Abp/Cli/Licensing/AbpIoApiKeyService.cs | 12 ++- .../Volo/Abp/Cli/NuGet/NuGetService.cs | 13 ++- .../ProjectBuilding/AbpIoSourceCodeStore.cs | 33 ++++--- .../Analyticses/CliAnalyticsCollect.cs | 19 +++- .../IRemoteServiceExceptionHandler.cs | 12 +++ .../Cli/ProjectBuilding/ModuleInfoProvider.cs | 15 +-- .../RemoteServiceExceptionHandler.cs | 92 +++++++++++++++++++ .../ProjectNugetPackageAdder.cs | 8 +- .../SolutionModuleAdder.cs | 8 +- 9 files changed, 176 insertions(+), 36 deletions(-) create mode 100644 framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/IRemoteServiceExceptionHandler.cs create mode 100644 framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/RemoteServiceExceptionHandler.cs diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs index 22cd692ec3..c8f221b73c 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Volo.Abp.Cli.Http; +using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.DependencyInjection; using Volo.Abp.Json; @@ -8,13 +9,16 @@ namespace Volo.Abp.Cli.Licensing { public class AbpIoApiKeyService : IApiKeyService, ITransientDependency { - public AbpIoApiKeyService(IJsonSerializer jsonSerializer) + protected IJsonSerializer JsonSerializer { get; } + + protected IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } + + public AbpIoApiKeyService(IJsonSerializer jsonSerializer, IRemoteServiceExceptionHandler remoteServiceExceptionHandler) { JsonSerializer = jsonSerializer; + RemoteServiceExceptionHandler = remoteServiceExceptionHandler; } - protected IJsonSerializer JsonSerializer { get; } - public async Task GetApiKeyOrNullAsync() { using (var client = new CliHttpClient()) @@ -28,6 +32,8 @@ namespace Volo.Abp.Cli.Licensing throw new Exception($"ERROR: Remote server returns '{response.StatusCode}'"); } + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); + var responseContent = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize(responseContent); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs index b0dd6328db..700303006b 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Volo.Abp.Cli.Http; +using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.DependencyInjection; using Volo.Abp.Json; using Volo.Abp.Threading; @@ -17,11 +18,15 @@ namespace Volo.Abp.Cli.NuGet protected ICancellationTokenProvider CancellationTokenProvider { get; } + protected IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } + public NuGetService( IJsonSerializer jsonSerializer, + IRemoteServiceExceptionHandler remoteServiceExceptionHandler, ICancellationTokenProvider cancellationTokenProvider) { JsonSerializer = jsonSerializer; + RemoteServiceExceptionHandler = remoteServiceExceptionHandler; CancellationTokenProvider = cancellationTokenProvider; } @@ -35,10 +40,7 @@ namespace Volo.Abp.Cli.NuGet var responseMessage = await client.GetAsync(url, CancellationTokenProvider.Token); - if (!responseMessage.IsSuccessStatusCode) - { - throw new Exception("Remote server returns error! HTTP status code: " + responseMessage.StatusCode); - } + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage); var result = await responseMessage.Content.ReadAsStringAsync(); @@ -49,7 +51,8 @@ namespace Volo.Abp.Cli.NuGet versions = versions.Where(x => !x.IsPrerelease); } - return versions.Any() ? versions.Max() : null; + var semanticVersions = versions.ToList(); + return semanticVersions.Any() ? semanticVersions.Max() : null; } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs index 6fde8db9e3..ac51be6fac 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs @@ -2,7 +2,9 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; @@ -23,14 +25,18 @@ namespace Volo.Abp.Cli.ProjectBuilding protected IJsonSerializer JsonSerializer { get; } + protected IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } + protected ICancellationTokenProvider CancellationTokenProvider { get; } public AbpIoSourceCodeStore( IOptions options, IJsonSerializer jsonSerializer, + IRemoteServiceExceptionHandler remoteServiceExceptionHandler, ICancellationTokenProvider cancellationTokenProvider) { JsonSerializer = jsonSerializer; + RemoteServiceExceptionHandler = remoteServiceExceptionHandler; CancellationTokenProvider = cancellationTokenProvider; Options = options.Value; @@ -42,6 +48,7 @@ namespace Volo.Abp.Cli.ProjectBuilding string type, string version = null) { + var latestVersion = await GetLatestSourceCodeVersionAsync(name, type); if (version == null) { @@ -74,26 +81,29 @@ namespace Volo.Abp.Cli.ProjectBuilding } return new TemplateFile(fileContent, version, latestVersion); + } private async Task GetLatestSourceCodeVersionAsync(string name, string type) { - var postData = JsonSerializer.Serialize(new GetLatestSourceCodeVersionDto { Name = name }); - using (var client = new CliHttpClient()) { - var responseMessage = await client.PostAsync( + var response = await client.PostAsync( $"{CliUrls.WwwAbpIo}api/download/{type}/get-version/", - new StringContent(postData, Encoding.UTF8, MimeTypes.Application.Json), + new StringContent( + JsonSerializer.Serialize( + new GetLatestSourceCodeVersionDto { Name = name } + ), + Encoding.UTF8, + MimeTypes.Application.Json + ), CancellationTokenProvider.Token ); - if (!responseMessage.IsSuccessStatusCode) - { - throw new Exception("Remote server returns error! HTTP status code: " + responseMessage.StatusCode); - } + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); + + var result = await response.Content.ReadAsStringAsync(); - var result = await responseMessage.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize(result).Version; } } @@ -110,10 +120,7 @@ namespace Volo.Abp.Cli.ProjectBuilding CancellationTokenProvider.Token ); - if (!responseMessage.IsSuccessStatusCode) - { - throw new Exception("Remote server returns error! HTTP status code: " + responseMessage.StatusCode); - } + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage); return await responseMessage.Content.ReadAsByteArrayAsync(); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Analyticses/CliAnalyticsCollect.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Analyticses/CliAnalyticsCollect.cs index 6598c9fb31..fdfbb8b5d3 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Analyticses/CliAnalyticsCollect.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Analyticses/CliAnalyticsCollect.cs @@ -16,12 +16,16 @@ namespace Volo.Abp.Cli.ProjectBuilding.Analyticses private readonly ICancellationTokenProvider _cancellationTokenProvider; private readonly IJsonSerializer _jsonSerializer; private readonly ILogger _logger; + private readonly IRemoteServiceExceptionHandler _remoteServiceExceptionHandler; - public CliAnalyticsCollect(ICancellationTokenProvider cancellationTokenProvider, - IJsonSerializer jsonSerializer) + public CliAnalyticsCollect( + ICancellationTokenProvider cancellationTokenProvider, + IJsonSerializer jsonSerializer, + IRemoteServiceExceptionHandler remoteServiceExceptionHandler) { _cancellationTokenProvider = cancellationTokenProvider; _jsonSerializer = jsonSerializer; + _remoteServiceExceptionHandler = remoteServiceExceptionHandler; _logger = NullLogger.Instance; } @@ -38,8 +42,15 @@ namespace Volo.Abp.Cli.ProjectBuilding.Analyticses if (!responseMessage.IsSuccessStatusCode) { - _logger.LogInformation("Remote server returns error! HTTP status code: " + - responseMessage.StatusCode); + var exceptionMessage = "Remote server returns '" + (int)responseMessage.StatusCode + "-" + responseMessage.ReasonPhrase + "'. "; + var remoteServiceErrorMessage = await _remoteServiceExceptionHandler.GetAbpRemoteServiceErrorAsync(responseMessage); + + if (remoteServiceErrorMessage != null) + { + exceptionMessage += remoteServiceErrorMessage; + } + + _logger.LogInformation(exceptionMessage); } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/IRemoteServiceExceptionHandler.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/IRemoteServiceExceptionHandler.cs new file mode 100644 index 0000000000..b3459f53ed --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/IRemoteServiceExceptionHandler.cs @@ -0,0 +1,12 @@ +using System.Net.Http; +using System.Threading.Tasks; + +namespace Volo.Abp.Cli.ProjectBuilding +{ + public interface IRemoteServiceExceptionHandler + { + Task EnsureSuccessfulHttpResponseAsync(HttpResponseMessage responseMessage); + + Task GetAbpRemoteServiceErrorAsync(HttpResponseMessage responseMessage); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleInfoProvider.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleInfoProvider.cs index e82d4478b7..10b3a07172 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleInfoProvider.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleInfoProvider.cs @@ -10,15 +10,20 @@ using Volo.Abp.Threading; namespace Volo.Abp.Cli.ProjectBuilding { - public class ModuleInfoProvider: IModuleInfoProvider, ITransientDependency + public class ModuleInfoProvider : IModuleInfoProvider, ITransientDependency { public IJsonSerializer JsonSerializer { get; } public ICancellationTokenProvider CancellationTokenProvider { get; } + public IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } - public ModuleInfoProvider(IJsonSerializer jsonSerializer, ICancellationTokenProvider cancellationTokenProvider) + public ModuleInfoProvider( + IJsonSerializer jsonSerializer, + ICancellationTokenProvider cancellationTokenProvider, + IRemoteServiceExceptionHandler remoteServiceExceptionHandler) { JsonSerializer = jsonSerializer; CancellationTokenProvider = cancellationTokenProvider; + RemoteServiceExceptionHandler = remoteServiceExceptionHandler; } public async Task GetAsync(string name) @@ -44,11 +49,7 @@ namespace Volo.Abp.Cli.ProjectBuilding CancellationTokenProvider.Token ); - if (!responseMessage.IsSuccessStatusCode) - { - throw new Exception("Remote server returns error! HTTP status code: " + responseMessage.StatusCode); - } - + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage); var result = await responseMessage.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize>(result); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/RemoteServiceExceptionHandler.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/RemoteServiceExceptionHandler.cs new file mode 100644 index 0000000000..fe41577583 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/RemoteServiceExceptionHandler.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http; +using Volo.Abp.Json; + +namespace Volo.Abp.Cli.ProjectBuilding +{ + public class RemoteServiceExceptionHandler : IRemoteServiceExceptionHandler, ITransientDependency + { + private readonly IJsonSerializer _jsonSerializer; + + public RemoteServiceExceptionHandler(IJsonSerializer jsonSerializer) + { + _jsonSerializer = jsonSerializer; + } + + public async Task EnsureSuccessfulHttpResponseAsync(HttpResponseMessage responseMessage) + { + if (responseMessage == null) + { + return; + } + + if (responseMessage.IsSuccessStatusCode) + { + return; + } + + var exceptionMessage = "Remote server returns '" + (int)responseMessage.StatusCode + "-" + responseMessage.ReasonPhrase + "'. "; + + var remoteServiceErrorMessage = await GetAbpRemoteServiceErrorAsync(responseMessage); + if (remoteServiceErrorMessage != null) + { + exceptionMessage += remoteServiceErrorMessage; + } + + throw new Exception(exceptionMessage); + } + + public async Task GetAbpRemoteServiceErrorAsync(HttpResponseMessage responseMessage) + { + var errorResult = _jsonSerializer.Deserialize + ( + await responseMessage.Content.ReadAsStringAsync() + ); + + if (errorResult?.Error == null) + { + return null; + } + + var sbError = new StringBuilder(); + if (!string.IsNullOrWhiteSpace(errorResult.Error.Code)) + { + sbError.Append("Code: " + errorResult.Error.Code); + } + + if (!string.IsNullOrWhiteSpace(errorResult.Error.Message)) + { + if (sbError.Length > 0) + { + sbError.Append(" - "); + } + + sbError.Append("Message: " + errorResult.Error.Message); + } + + if (errorResult.Error.ValidationErrors != null && errorResult.Error.ValidationErrors.Any()) + { + if (sbError.Length > 0) + { + sbError.Append(" - "); + } + + sbError.AppendLine("Validation Errors: "); + for (var i = 0; i < errorResult.Error.ValidationErrors.Length; i++) + { + var validationError = errorResult.Error.ValidationErrors[i]; + sbError.AppendLine("Validation error #" + i + ": " + validationError.Message + " - Members: " + validationError.Members.JoinAsString(", ") + "."); + } + } + + return sbError.ToString(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs index 2b2941a30d..1bacd7cd61 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Cli.Http; +using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; using Volo.Abp.IO; @@ -22,17 +23,20 @@ namespace Volo.Abp.Cli.ProjectModification protected ProjectNpmPackageAdder NpmPackageAdder { get; } protected DerivedClassFinder ModuleClassFinder { get; } protected ModuleClassDependcyAdder ModuleClassDependcyAdder { get; } + protected IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } public ProjectNugetPackageAdder( IJsonSerializer jsonSerializer, ProjectNpmPackageAdder npmPackageAdder, DerivedClassFinder moduleClassFinder, - ModuleClassDependcyAdder moduleClassDependcyAdder) + ModuleClassDependcyAdder moduleClassDependcyAdder, + IRemoteServiceExceptionHandler remoteServiceExceptionHandler) { JsonSerializer = jsonSerializer; NpmPackageAdder = npmPackageAdder; ModuleClassFinder = moduleClassFinder; ModuleClassDependcyAdder = moduleClassDependcyAdder; + RemoteServiceExceptionHandler = remoteServiceExceptionHandler; Logger = NullLogger.Instance; } @@ -84,7 +88,7 @@ namespace Volo.Abp.Cli.ProjectModification throw new CliUsageException($"'{moduleName}' nuget package could not be found!"); } - throw new Exception($"ERROR: Remote server returns '{response.StatusCode}'"); + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); } var responseContent = await response.Content.ReadAsStringAsync(); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs index 22e063a8ae..5950872419 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Net; using System.Threading.Tasks; using Volo.Abp.Cli.Http; +using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.DependencyInjection; using Volo.Abp.Json; @@ -24,6 +25,7 @@ namespace Volo.Abp.Cli.ProjectModification protected DerivedClassFinder DerivedClassFinder { get; } protected ProjectNpmPackageAdder ProjectNpmPackageAdder { get; } protected NpmGlobalPackagesChecker NpmGlobalPackagesChecker { get; } + protected IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } public SolutionModuleAdder( IJsonSerializer jsonSerializer, @@ -32,7 +34,8 @@ namespace Volo.Abp.Cli.ProjectModification EfCoreMigrationAdder efCoreMigrationAdder, DerivedClassFinder derivedClassFinder, ProjectNpmPackageAdder projectNpmPackageAdder, - NpmGlobalPackagesChecker npmGlobalPackagesChecker) + NpmGlobalPackagesChecker npmGlobalPackagesChecker, + IRemoteServiceExceptionHandler remoteServiceExceptionHandler) { JsonSerializer = jsonSerializer; ProjectNugetPackageAdder = projectNugetPackageAdder; @@ -41,6 +44,7 @@ namespace Volo.Abp.Cli.ProjectModification DerivedClassFinder = derivedClassFinder; ProjectNpmPackageAdder = projectNpmPackageAdder; NpmGlobalPackagesChecker = npmGlobalPackagesChecker; + RemoteServiceExceptionHandler = remoteServiceExceptionHandler; Logger = NullLogger.Instance; } @@ -142,7 +146,7 @@ namespace Volo.Abp.Cli.ProjectModification throw new CliUsageException($"ERROR: '{moduleName}' module could not be found!"); } - throw new Exception($"ERROR: Remote server returns '{response.StatusCode}'"); + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); } var responseContent = await response.Content.ReadAsStringAsync();