diff --git a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs index a96797ce40..eeddb2e9be 100644 --- a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs +++ b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs @@ -59,7 +59,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling exception = TryToGetActualException(exception); - if (exception is AbpRemoteCallException remoteCallException) + if (exception is AbpRemoteCallException remoteCallException && remoteCallException.Error != null) { return remoteCallException.Error; } @@ -76,7 +76,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling var errorInfo = new RemoteServiceErrorInfo(); - if (exception is IUserFriendlyException) + if (exception is IUserFriendlyException || exception is AbpRemoteCallException) { errorInfo.Message = exception.Message; errorInfo.Details = (exception as IHasErrorDetails)?.Details; @@ -175,7 +175,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling return new RemoteServiceErrorInfo(exception.Message); } - + protected virtual Exception TryToGetActualException(Exception exception) { if (exception is AggregateException && exception.InnerException != null) diff --git a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/Http/Client/AbpRemoteCallException.cs b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/Http/Client/AbpRemoteCallException.cs index f9a6436715..f561c4cab7 100644 --- a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/Http/Client/AbpRemoteCallException.cs +++ b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/Http/Client/AbpRemoteCallException.cs @@ -20,14 +20,20 @@ namespace Volo.Abp.Http.Client } + public AbpRemoteCallException(string message, Exception innerException = null) + : base(message, innerException) + { + + } + public AbpRemoteCallException(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) { } - public AbpRemoteCallException(RemoteServiceErrorInfo error) - : base(error.Message) + public AbpRemoteCallException(RemoteServiceErrorInfo error, Exception innerException = null) + : base(error.Message, innerException) { Error = error; diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs index 73e51080c6..66dbe4f3cd 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs @@ -132,11 +132,19 @@ namespace Volo.Abp.Http.Client.ClientProxying ); } - var response = await client.SendAsync( - requestMessage, - HttpCompletionOption.ResponseHeadersRead /*this will buffer only the headers, the content will be used as a stream*/, - GetCancellationToken(requestContext.Arguments) - ); + HttpResponseMessage response; + try + { + response = await client.SendAsync( + requestMessage, + HttpCompletionOption.ResponseHeadersRead /*this will buffer only the headers, the content will be used as a stream*/, + GetCancellationToken(requestContext.Arguments) + ); + } + catch (Exception ex) + { + throw new AbpRemoteCallException($"An error occurred during the ABP remote HTTP request. ({ex.Message}) See the inner exception for details.", ex); + } if (!response.IsSuccessStatusCode) { @@ -197,26 +205,46 @@ namespace Volo.Abp.Http.Client.ClientProxying { if (response.Headers.Contains(AbpHttpConsts.AbpErrorFormat)) { - var errorResponse = JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ); + RemoteServiceErrorResponse errorResponse; + try + { + errorResponse = JsonSerializer.Deserialize( + await response.Content.ReadAsStringAsync() + ); + } + catch (Exception ex) + { + throw new AbpRemoteCallException( + new RemoteServiceErrorInfo + { + Message = response.ReasonPhrase, + Code = response.StatusCode.ToString() + }, + ex + ) + { + HttpStatusCode = (int)response.StatusCode + }; + } throw new AbpRemoteCallException(errorResponse.Error) { HttpStatusCode = (int) response.StatusCode }; } - - throw new AbpRemoteCallException( - new RemoteServiceErrorInfo - { - Message = response.ReasonPhrase, - Code = response.StatusCode.ToString() - } - ) + else { - HttpStatusCode = (int) response.StatusCode - }; + throw new AbpRemoteCallException( + new RemoteServiceErrorInfo + { + Message = response.ReasonPhrase, + Code = response.StatusCode.ToString() + } + ) + { + HttpStatusCode = (int) response.StatusCode + }; + } } protected virtual void AddHeaders( diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_AbpRemoteCallException_Tests.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_AbpRemoteCallException_Tests.cs new file mode 100644 index 0000000000..77f126cf5e --- /dev/null +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_AbpRemoteCallException_Tests.cs @@ -0,0 +1,61 @@ +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Shouldly; +using Volo.Abp.AspNetCore.TestBase; +using Volo.Abp.Http.Client; +using Volo.Abp.Http.Client.Proxying; +using Xunit; + +namespace Volo.Abp.Http.DynamicProxying +{ + public class RegularTestControllerClientProxy_AbpRemoteCallException_Tests : AbpHttpClientTestBase + { + private readonly IRegularTestController _controller; + + public RegularTestControllerClientProxy_AbpRemoteCallException_Tests() + { + _controller = ServiceProvider.GetRequiredService(); + } + + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + services.Replace(ServiceDescriptor.Singleton()); + } + + [Fact] + public async Task AbpRemoteCallException_On_SendAsync_Test() + { + var exception = await Assert.ThrowsAsync(async () => await _controller.AbortRequestAsync(default)); + exception.Message.ShouldContain("An error occurred during the ABP remote HTTP request."); + } + + class TestProxyHttpClientFactory : IProxyHttpClientFactory + { + private readonly ITestServerAccessor _testServerAccessor; + + private int _count; + + public TestProxyHttpClientFactory(ITestServerAccessor testServerAccessor) + { + _testServerAccessor = testServerAccessor; + } + + public HttpClient Create(string name) => Create(); + + public HttpClient Create() + { + if (_count++ > 0) + { + //Will get an error on the SendAsync method. + return new HttpClient(); + } + + // for DynamicHttpProxyInterceptor.GetActionApiDescriptionModel + return _testServerAccessor.Server.CreateClient(); + } + } + } +} diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs index 8df3e94b3c..c1c46b298f 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs @@ -168,8 +168,8 @@ namespace Volo.Abp.Http.DynamicProxying var result = await _controller.AbortRequestAsync(default); result.ShouldBe("AbortRequestAsync"); - var exception = await Assert.ThrowsAsync(async () => await _controller.AbortRequestAsync(cts.Token)); - exception.InnerException.InnerException.Message.ShouldBe("The client aborted the request."); + var exception = await Assert.ThrowsAsync(async () => await _controller.AbortRequestAsync(cts.Token)); + exception.InnerException.InnerException.InnerException.Message.ShouldBe("The client aborted the request."); } } }