From b74260645b38050351f11b3ab04ab015ca2b3189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 20 Sep 2017 18:58:36 +0300 Subject: [PATCH] Handle remote service error response in dynamic HTTP Proxy clients wherever possible. #90. --- .../ExceptionHandling/AbpExceptionFilter.cs | 5 +++- .../Abp/Http/Client/AbpRemoteCallException.cs | 28 +++++++++++++++++++ .../DynamicHttpProxyInterceptor.cs | 23 ++++++++++++--- .../DynamicProxying/IRegularTestController.cs | 2 ++ .../DynamicProxying/RegularTestController.cs | 8 ++++++ .../RegularTestControllerClientProxy_Tests.cs | 8 ++++++ 6 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpRemoteCallException.cs diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs index 7a273e097d..0c6eb45380 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs @@ -1,8 +1,10 @@ -using System.Net; +using System.Collections.Generic; +using System.Net; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Primitives; using Volo.Abp.Authorization; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities; @@ -47,6 +49,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling } context.HttpContext.Response.StatusCode = GetStatusCode(context); + context.HttpContext.Response.Headers.Add(new KeyValuePair("_AbpErrorFormat", "true")); context.Result = new ObjectResult( new RemoteServiceErrorResponse( diff --git a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpRemoteCallException.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpRemoteCallException.cs new file mode 100644 index 0000000000..8093dba1cf --- /dev/null +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpRemoteCallException.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.Serialization; + +namespace Volo.Abp.Http.Client +{ + [Serializable] + public class AbpRemoteCallException : AbpException + { + public RemoteServiceErrorInfo Error { get; set; } + + public AbpRemoteCallException() + { + + } + + public AbpRemoteCallException(SerializationInfo serializationInfo, StreamingContext context) + : base(serializationInfo, context) + { + + } + + public AbpRemoteCallException(RemoteServiceErrorInfo error) + : base(error.Message) + { + Error = error; + } + } +} diff --git a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs index 8cd36ba478..f9ce970f36 100644 --- a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs @@ -94,12 +94,12 @@ namespace Volo.Abp.Http.Client.DynamicProxying }; AddHeaders(invocation, action, requestMessage); - + var response = await client.SendAsync(requestMessage); if (!response.IsSuccessStatusCode) { - throw new AbpException($"Remote service returns error! HttpStatusCode: {response.StatusCode}, ReasonPhrase: {response.ReasonPhrase}"); + await ThrowExceptionForResponseAsync(response); } return await response.Content.ReadAsStringAsync(); @@ -123,9 +123,24 @@ namespace Volo.Abp.Http.Client.DynamicProxying var clientConfig = _clientOptions.HttpClientProxies.GetOrDefault(typeof(TService)) ?? throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {typeof(TService).FullName}."); - return _remoteServiceOptions.RemoteServices.GetOrDefault(clientConfig.RemoteServiceName) - ?? _remoteServiceOptions.RemoteServices.Default + return _remoteServiceOptions.RemoteServices.GetOrDefault(clientConfig.RemoteServiceName) + ?? _remoteServiceOptions.RemoteServices.Default ?? throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {typeof(TService).FullName}."); } + + + private async Task ThrowExceptionForResponseAsync(HttpResponseMessage response) + { + if (response.Headers.Contains("_AbpErrorFormat")) + { + var errorResponse = _jsonSerializer.Deserialize( + await response.Content.ReadAsStringAsync() + ); + + throw new AbpRemoteCallException(errorResponse.Error); + } + + throw new AbpException($"Remote service returns error! HttpStatusCode: {response.StatusCode}, ReasonPhrase: {response.ReasonPhrase}"); + } } } \ No newline at end of file diff --git a/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs b/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs index f7cd96d7c2..7a5b2f95f6 100644 --- a/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs +++ b/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs @@ -7,5 +7,7 @@ namespace Volo.Abp.Http.DynamicProxying int IncrementValue(int value); Task IncrementValueAsync(int value); + + Task GetException1Async(); } } diff --git a/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs b/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs index 477890a5df..282a04e4b6 100644 --- a/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs +++ b/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Volo.Abp.Application.Services; using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Ui; namespace Volo.Abp.Http.DynamicProxying { @@ -23,5 +24,12 @@ namespace Volo.Abp.Http.DynamicProxying { return Task.FromResult(value + 1); } + + [HttpGet] + [Route("get-exception1")] + public Task GetException1Async() + { + throw new UserFriendlyException("This is an error message!"); + } } } \ No newline at end of file diff --git a/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs b/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs index deaa8bf48c..9c4984d00a 100644 --- a/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs +++ b/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; +using Volo.Abp.Http.Client; using Xunit; namespace Volo.Abp.Http.DynamicProxying @@ -27,5 +28,12 @@ namespace Volo.Abp.Http.DynamicProxying { (await _controller.IncrementValueAsync(42)).ShouldBe(43); } + + [Fact] + public async Task GetException1Async() + { + var exception = await Assert.ThrowsAsync(async () => await _controller.GetException1Async()); + exception.Error.Message.ShouldBe("This is an error message!"); + } } } \ No newline at end of file