From 91503616d351df05119d951f9318a55e6623f57d Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 27 Dec 2021 21:06:03 +0800 Subject: [PATCH] Add `IObjectToPath`. --- .../AbpHttpClientProxyingOptions.cs | 3 + .../ClientProxyRequestPayloadBuilder.cs | 6 +- .../ClientProxying/ClientProxyUrlBuilder.cs | 59 +++++++++++++++---- .../ClientProxying/IObjectToFormData.cs | 3 +- .../Client/ClientProxying/IObjectToPath.cs | 10 ++++ .../ClientProxying/IObjectToQueryString.cs | 3 +- .../Volo/Abp/Http/AbpHttpClientTestModule.cs | 1 + .../DynamicProxying/IRegularTestController.cs | 4 ++ .../DynamicProxying/RegularTestController.cs | 16 +++++ .../RegularTestControllerClientProxy_Tests.cs | 17 ++++++ .../DynamicProxying/TestObjectToFormData.cs | 3 +- .../Http/DynamicProxying/TestObjectToPath.cs | 23 ++++++++ .../TestObjectToQueryString.cs | 3 +- 13 files changed, 132 insertions(+), 19 deletions(-) create mode 100644 framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToPath.cs create mode 100644 framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToPath.cs diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/AbpHttpClientProxyingOptions.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/AbpHttpClientProxyingOptions.cs index 87ee7de37c..ecf9199c1a 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/AbpHttpClientProxyingOptions.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/AbpHttpClientProxyingOptions.cs @@ -9,10 +9,13 @@ namespace Volo.Abp.Http.Client.ClientProxying public Dictionary FormDataConverts { get; set; } + public Dictionary PathConverts { get; set; } + public AbpHttpClientProxyingOptions() { QueryStringConverts = new Dictionary(); FormDataConverts = new Dictionary(); + PathConverts = new Dictionary(); } } } diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyRequestPayloadBuilder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyRequestPayloadBuilder.cs index 69066199f9..db0c73379c 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyRequestPayloadBuilder.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyRequestPayloadBuilder.cs @@ -113,6 +113,8 @@ namespace Volo.Abp.Http.Client.ClientProxying .Invoke(this, new object[] { scope.ServiceProvider.GetRequiredService(HttpClientProxyingOptions.FormDataConverts[value.GetType()]), + action, + parameter, value }); @@ -168,9 +170,9 @@ namespace Volo.Abp.Http.Client.ClientProxying return formData; } - protected virtual async Task>> ObjectToFormDataAsync(IObjectToFormData converter, T value) + protected virtual async Task>> ObjectToFormDataAsync(IObjectToFormData converter, ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, T value) { - return await converter.ConvertAsync(value); + return await converter.ConvertAsync(actionApiDescription, parameterApiDescription, value); } } } diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyUrlBuilder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyUrlBuilder.cs index 12f7bc1ac8..7934cdbf8d 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyUrlBuilder.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyUrlBuilder.cs @@ -21,11 +21,17 @@ namespace Volo.Abp.Http.Client.ClientProxying { protected static MethodInfo CallObjectToQueryStringAsyncMethod { get; } + protected static MethodInfo CallObjectToPathAsyncMethod { get; } + static ClientProxyUrlBuilder() { CallObjectToQueryStringAsyncMethod = typeof(ClientProxyUrlBuilder) .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) .First(m => m.Name == nameof(ObjectToQueryStringAsync) && m.IsGenericMethodDefinition); + + CallObjectToPathAsyncMethod = typeof(ClientProxyUrlBuilder) + .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) + .First(m => m.Name == nameof(ObjectToPathAsync) && m.IsGenericMethodDefinition); } protected IServiceScopeFactory ServiceScopeFactory { get; } @@ -46,22 +52,22 @@ namespace Volo.Abp.Http.Client.ClientProxying { var urlBuilder = new StringBuilder(action.Url); - await ReplacePathVariablesAsync(urlBuilder, action.Parameters, methodArguments, apiVersion); - await AddQueryStringParametersAsync(urlBuilder, action.Parameters, methodArguments, apiVersion); + await ReplacePathVariablesAsync(urlBuilder, action, methodArguments, apiVersion); + await AddQueryStringParametersAsync(urlBuilder, action, methodArguments, apiVersion); return urlBuilder.ToString(); } } - protected virtual Task ReplacePathVariablesAsync(StringBuilder urlBuilder, IList actionParameters, IReadOnlyDictionary methodArguments, ApiVersionInfo apiVersion) + protected virtual async Task ReplacePathVariablesAsync(StringBuilder urlBuilder, ActionApiDescriptionModel action, IReadOnlyDictionary methodArguments, ApiVersionInfo apiVersion) { - var pathParameters = actionParameters + var pathParameters = action.Parameters .Where(p => p.BindingSourceId == ParameterBindingSources.Path) .ToArray(); if (!pathParameters.Any()) { - return Task.CompletedTask; + return; } if (pathParameters.Any(p => p.Name == "apiVersion")) @@ -81,7 +87,7 @@ namespace Volo.Abp.Http.Client.ClientProxying } else if (pathParameter.DefaultValue != null) { - urlBuilder = urlBuilder.Replace($"{{{pathParameter.Name}}}", pathParameter.DefaultValue.ToString()); + urlBuilder = urlBuilder.Replace($"{{{pathParameter.Name}}}", await ConvertValueToStringAsync(pathParameter.DefaultValue)); } else { @@ -90,16 +96,36 @@ namespace Volo.Abp.Http.Client.ClientProxying } else { - urlBuilder = urlBuilder.Replace($"{{{pathParameter.Name}}}", value.ToString()); + if (HttpClientProxyingOptions.PathConverts.ContainsKey(value.GetType())) + { + using (var scope = ServiceScopeFactory.CreateScope()) + { + var path = await (Task)CallObjectToPathAsyncMethod + .MakeGenericMethod(value.GetType()) + .Invoke(this, new object[] + { + scope.ServiceProvider.GetRequiredService(HttpClientProxyingOptions.PathConverts[value.GetType()]), + action, + pathParameter, + value + }); + + if (path != null) + { + urlBuilder = urlBuilder.Replace($"{{{pathParameter.Name}}}", path); + continue; + } + } + } + + urlBuilder = urlBuilder.Replace($"{{{pathParameter.Name}}}", await ConvertValueToStringAsync(value)); } } - - return Task.CompletedTask; } - protected virtual async Task AddQueryStringParametersAsync(StringBuilder urlBuilder, IList actionParameters, IReadOnlyDictionary methodArguments, ApiVersionInfo apiVersion) + protected virtual async Task AddQueryStringParametersAsync(StringBuilder urlBuilder, ActionApiDescriptionModel action, IReadOnlyDictionary methodArguments, ApiVersionInfo apiVersion) { - var queryStringParameters = actionParameters + var queryStringParameters = action.Parameters .Where(p => p.BindingSourceId.IsIn(ParameterBindingSources.ModelBinding, ParameterBindingSources.Query)) .ToArray(); @@ -122,6 +148,8 @@ namespace Volo.Abp.Http.Client.ClientProxying .Invoke(this, new object[] { scope.ServiceProvider.GetRequiredService(HttpClientProxyingOptions.QueryStringConverts[value.GetType()]), + action, + queryStringParameter, value }); @@ -147,9 +175,14 @@ namespace Volo.Abp.Http.Client.ClientProxying } } - protected virtual async Task ObjectToQueryStringAsync(IObjectToQueryString converter, T value) + protected virtual async Task ObjectToQueryStringAsync(IObjectToQueryString converter, ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, T value) + { + return await converter.ConvertAsync(actionApiDescription, parameterApiDescription, value); + } + + protected virtual async Task ObjectToPathAsync(IObjectToPath converter, ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, T value) { - return await converter.ConvertAsync(value); + return await converter.ConvertAsync(actionApiDescription, parameterApiDescription, value); } protected virtual async Task AddQueryStringParameterAsync( diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToFormData.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToFormData.cs index 5aec4252e3..23a0972937 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToFormData.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToFormData.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; +using Volo.Abp.Http.Modeling; namespace Volo.Abp.Http.Client.ClientProxying { public interface IObjectToFormData { - Task>> ConvertAsync(TValue value); + Task>> ConvertAsync(ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, TValue value); } } diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToPath.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToPath.cs new file mode 100644 index 0000000000..2da0a3b90e --- /dev/null +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToPath.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using Volo.Abp.Http.Modeling; + +namespace Volo.Abp.Http.Client.ClientProxying +{ + public interface IObjectToPath + { + Task ConvertAsync(ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, TValue value); + } +} diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToQueryString.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToQueryString.cs index ef223a903d..08b7b05dcb 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToQueryString.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToQueryString.cs @@ -1,9 +1,10 @@ using System.Threading.Tasks; +using Volo.Abp.Http.Modeling; namespace Volo.Abp.Http.Client.ClientProxying { public interface IObjectToQueryString { - Task ConvertAsync(TValue value); + Task ConvertAsync(ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, TValue value); } } diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestModule.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestModule.cs index d90ef50006..5d3eec6542 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestModule.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestModule.cs @@ -59,6 +59,7 @@ namespace Volo.Abp.Http { options.QueryStringConverts.Add(typeof(List), typeof(TestObjectToQueryString)); options.FormDataConverts.Add(typeof(List), typeof(TestObjectToFormData)); + options.PathConverts.Add(typeof(int), typeof(TestObjectToPath)); }); } } diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs index d1c1275db7..65ad05b16b 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs @@ -26,6 +26,10 @@ namespace Volo.Abp.Http.DynamicProxying Task GetObjectandIdAsync(int id, Car bodyValue); + Task GetObjectandFirstReleaseDateAsync(DateTime time, Car bodyValue); + + Task GetObjectandCountAsync(int count, Car bodyValue); + Task GetObjectAndIdWithQueryAsync(int id, Car bodyValue); Task PutValueWithBodyAsync(string bodyValue); diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs index 782b839626..8101fb143e 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs @@ -86,6 +86,22 @@ namespace Volo.Abp.Http.DynamicProxying return Task.FromResult(bodyValue); } + [HttpGet] + [Route("post-object-and-first-release-date-with-url/{time:datetime}")] + public Task GetObjectandFirstReleaseDateAsync(DateTime time, Car bodyValue) + { + bodyValue.FirstReleaseDate = time; + return Task.FromResult(bodyValue); + } + + [HttpGet] + [Route("post-object-and-count-with-url/{count}")] + public Task GetObjectandCountAsync(int count, Car bodyValue) + { + bodyValue.Year = count; + return Task.FromResult(bodyValue); + } + [HttpGet] [Route("post-object-and-id-with-url-and-query/{id}")] public Task GetObjectAndIdWithQueryAsync(int id, Car bodyValue) 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 c1c46b298f..5c60410bb4 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 @@ -124,6 +124,23 @@ namespace Volo.Abp.Http.DynamicProxying result.Model.ShouldBe("Ford"); } + [Fact] + public async Task GetObjectandFirstReleaseDateAsync() + { + var time = DateTime.Now; + var result = await _controller.GetObjectandFirstReleaseDateAsync(time, new Car { Year = 1976, Model = "Ford", FirstReleaseDate = new DateTime(1976, 02, 22, 15, 0, 6, 22) }); + result.FirstReleaseDate.ToUniversalTime().ShouldBe(time.ToUniversalTime()); + result.Model.ShouldBe("Ford"); + } + + [Fact] + public async Task GetObjectandCountAsync() + { + var result = await _controller.GetObjectandCountAsync(-1, new Car { Year = 1976, Model = "Ford", FirstReleaseDate = new DateTime(1976, 02, 22, 15, 0, 6, 22) }); + result.Year.ShouldBe(888); + result.Model.ShouldBe("Ford"); + } + [Fact] public async Task GetObjectAndIdWithQueryAsync() { diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToFormData.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToFormData.cs index 65b65fc54b..face0c7ac0 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToFormData.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToFormData.cs @@ -4,13 +4,14 @@ using System.Text; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client.ClientProxying; +using Volo.Abp.Http.Modeling; using Volo.Abp.TestApp.Application.Dto; namespace Volo.Abp.Http.DynamicProxying { public class TestObjectToFormData : IObjectToFormData>, ITransientDependency { - public Task>> ConvertAsync(List values) + public Task>> ConvertAsync(ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, List values) { if (values.IsNullOrEmpty()) { diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToPath.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToPath.cs new file mode 100644 index 0000000000..a9b7936578 --- /dev/null +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToPath.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.Client.ClientProxying; +using Volo.Abp.Http.Modeling; + +namespace Volo.Abp.Http.DynamicProxying; + +public class TestObjectToPath : IObjectToPath, ITransientDependency +{ + public Task ConvertAsync(ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, int value) + { + if (actionApiDescription.Name == nameof(IRegularTestController.GetObjectandCountAsync)) + { + if (value <= 0) + { + value = 888; + } + return Task.FromResult(value.ToString()); + } + + return Task.FromResult(null); + } +} diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToQueryString.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToQueryString.cs index ae11a7bf2f..73bd570bb9 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToQueryString.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToQueryString.cs @@ -3,13 +3,14 @@ using System.Text; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client.ClientProxying; +using Volo.Abp.Http.Modeling; using Volo.Abp.TestApp.Application.Dto; namespace Volo.Abp.Http.DynamicProxying { public class TestObjectToQueryString : IObjectToQueryString>, ITransientDependency { - public Task ConvertAsync(List values) + public Task ConvertAsync(ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, List values) { if (values.IsNullOrEmpty()) {