Browse Source

Merge pull request #11081 from abpframework/IObjectToPath

Add `IObjectToPath`.
pull/11087/head
liangshiwei 4 years ago
committed by GitHub
parent
commit
89c4598fc6
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/AbpHttpClientProxyingOptions.cs
  2. 6
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyRequestPayloadBuilder.cs
  3. 59
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyUrlBuilder.cs
  4. 3
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToFormData.cs
  5. 10
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToPath.cs
  6. 3
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToQueryString.cs
  7. 1
      framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestModule.cs
  8. 4
      framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs
  9. 16
      framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs
  10. 17
      framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs
  11. 3
      framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToFormData.cs
  12. 23
      framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToPath.cs
  13. 3
      framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/TestObjectToQueryString.cs

3
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<Type, Type> FormDataConverts { get; set; } public Dictionary<Type, Type> FormDataConverts { get; set; }
public Dictionary<Type, Type> PathConverts { get; set; }
public AbpHttpClientProxyingOptions() public AbpHttpClientProxyingOptions()
{ {
QueryStringConverts = new Dictionary<Type, Type>(); QueryStringConverts = new Dictionary<Type, Type>();
FormDataConverts = new Dictionary<Type, Type>(); FormDataConverts = new Dictionary<Type, Type>();
PathConverts = new Dictionary<Type, Type>();
} }
} }
} }

6
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[] .Invoke(this, new object[]
{ {
scope.ServiceProvider.GetRequiredService(HttpClientProxyingOptions.FormDataConverts[value.GetType()]), scope.ServiceProvider.GetRequiredService(HttpClientProxyingOptions.FormDataConverts[value.GetType()]),
action,
parameter,
value value
}); });
@ -168,9 +170,9 @@ namespace Volo.Abp.Http.Client.ClientProxying
return formData; return formData;
} }
protected virtual async Task<List<KeyValuePair<string, HttpContent>>> ObjectToFormDataAsync<T>(IObjectToFormData<T> converter, T value) protected virtual async Task<List<KeyValuePair<string, HttpContent>>> ObjectToFormDataAsync<T>(IObjectToFormData<T> converter, ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, T value)
{ {
return await converter.ConvertAsync(value); return await converter.ConvertAsync(actionApiDescription, parameterApiDescription, value);
} }
} }
} }

59
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 CallObjectToQueryStringAsyncMethod { get; }
protected static MethodInfo CallObjectToPathAsyncMethod { get; }
static ClientProxyUrlBuilder() static ClientProxyUrlBuilder()
{ {
CallObjectToQueryStringAsyncMethod = typeof(ClientProxyUrlBuilder) CallObjectToQueryStringAsyncMethod = typeof(ClientProxyUrlBuilder)
.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
.First(m => m.Name == nameof(ObjectToQueryStringAsync) && m.IsGenericMethodDefinition); .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; } protected IServiceScopeFactory ServiceScopeFactory { get; }
@ -46,22 +52,22 @@ namespace Volo.Abp.Http.Client.ClientProxying
{ {
var urlBuilder = new StringBuilder(action.Url); var urlBuilder = new StringBuilder(action.Url);
await ReplacePathVariablesAsync(urlBuilder, action.Parameters, methodArguments, apiVersion); await ReplacePathVariablesAsync(urlBuilder, action, methodArguments, apiVersion);
await AddQueryStringParametersAsync(urlBuilder, action.Parameters, methodArguments, apiVersion); await AddQueryStringParametersAsync(urlBuilder, action, methodArguments, apiVersion);
return urlBuilder.ToString(); return urlBuilder.ToString();
} }
} }
protected virtual Task ReplacePathVariablesAsync(StringBuilder urlBuilder, IList<ParameterApiDescriptionModel> actionParameters, IReadOnlyDictionary<string, object> methodArguments, ApiVersionInfo apiVersion) protected virtual async Task ReplacePathVariablesAsync(StringBuilder urlBuilder, ActionApiDescriptionModel action, IReadOnlyDictionary<string, object> methodArguments, ApiVersionInfo apiVersion)
{ {
var pathParameters = actionParameters var pathParameters = action.Parameters
.Where(p => p.BindingSourceId == ParameterBindingSources.Path) .Where(p => p.BindingSourceId == ParameterBindingSources.Path)
.ToArray(); .ToArray();
if (!pathParameters.Any()) if (!pathParameters.Any())
{ {
return Task.CompletedTask; return;
} }
if (pathParameters.Any(p => p.Name == "apiVersion")) if (pathParameters.Any(p => p.Name == "apiVersion"))
@ -81,7 +87,7 @@ namespace Volo.Abp.Http.Client.ClientProxying
} }
else if (pathParameter.DefaultValue != null) else if (pathParameter.DefaultValue != null)
{ {
urlBuilder = urlBuilder.Replace($"{{{pathParameter.Name}}}", pathParameter.DefaultValue.ToString()); urlBuilder = urlBuilder.Replace($"{{{pathParameter.Name}}}", await ConvertValueToStringAsync(pathParameter.DefaultValue));
} }
else else
{ {
@ -90,16 +96,36 @@ namespace Volo.Abp.Http.Client.ClientProxying
} }
else else
{ {
urlBuilder = urlBuilder.Replace($"{{{pathParameter.Name}}}", value.ToString()); if (HttpClientProxyingOptions.PathConverts.ContainsKey(value.GetType()))
{
using (var scope = ServiceScopeFactory.CreateScope())
{
var path = await (Task<string>)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<ParameterApiDescriptionModel> actionParameters, IReadOnlyDictionary<string, object> methodArguments, ApiVersionInfo apiVersion) protected virtual async Task AddQueryStringParametersAsync(StringBuilder urlBuilder, ActionApiDescriptionModel action, IReadOnlyDictionary<string, object> methodArguments, ApiVersionInfo apiVersion)
{ {
var queryStringParameters = actionParameters var queryStringParameters = action.Parameters
.Where(p => p.BindingSourceId.IsIn(ParameterBindingSources.ModelBinding, ParameterBindingSources.Query)) .Where(p => p.BindingSourceId.IsIn(ParameterBindingSources.ModelBinding, ParameterBindingSources.Query))
.ToArray(); .ToArray();
@ -122,6 +148,8 @@ namespace Volo.Abp.Http.Client.ClientProxying
.Invoke(this, new object[] .Invoke(this, new object[]
{ {
scope.ServiceProvider.GetRequiredService(HttpClientProxyingOptions.QueryStringConverts[value.GetType()]), scope.ServiceProvider.GetRequiredService(HttpClientProxyingOptions.QueryStringConverts[value.GetType()]),
action,
queryStringParameter,
value value
}); });
@ -147,9 +175,14 @@ namespace Volo.Abp.Http.Client.ClientProxying
} }
} }
protected virtual async Task<string> ObjectToQueryStringAsync<T>(IObjectToQueryString<T> converter, T value) protected virtual async Task<string> ObjectToQueryStringAsync<T>(IObjectToQueryString<T> converter, ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, T value)
{
return await converter.ConvertAsync(actionApiDescription, parameterApiDescription, value);
}
protected virtual async Task<string> ObjectToPathAsync<T>(IObjectToPath<T> converter, ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, T value)
{ {
return await converter.ConvertAsync(value); return await converter.ConvertAsync(actionApiDescription, parameterApiDescription, value);
} }
protected virtual async Task<bool> AddQueryStringParameterAsync( protected virtual async Task<bool> AddQueryStringParameterAsync(

3
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToFormData.cs

@ -1,11 +1,12 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Http.Modeling;
namespace Volo.Abp.Http.Client.ClientProxying namespace Volo.Abp.Http.Client.ClientProxying
{ {
public interface IObjectToFormData<in TValue> public interface IObjectToFormData<in TValue>
{ {
Task<List<KeyValuePair<string, HttpContent>>> ConvertAsync(TValue value); Task<List<KeyValuePair<string, HttpContent>>> ConvertAsync(ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, TValue value);
} }
} }

10
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<in TValue>
{
Task<string> ConvertAsync(ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, TValue value);
}
}

3
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IObjectToQueryString.cs

@ -1,9 +1,10 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Http.Modeling;
namespace Volo.Abp.Http.Client.ClientProxying namespace Volo.Abp.Http.Client.ClientProxying
{ {
public interface IObjectToQueryString<in TValue> public interface IObjectToQueryString<in TValue>
{ {
Task<string> ConvertAsync(TValue value); Task<string> ConvertAsync(ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, TValue value);
} }
} }

1
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<GetParamsNameValue>), typeof(TestObjectToQueryString)); options.QueryStringConverts.Add(typeof(List<GetParamsNameValue>), typeof(TestObjectToQueryString));
options.FormDataConverts.Add(typeof(List<GetParamsNameValue>), typeof(TestObjectToFormData)); options.FormDataConverts.Add(typeof(List<GetParamsNameValue>), typeof(TestObjectToFormData));
options.PathConverts.Add(typeof(int), typeof(TestObjectToPath));
}); });
} }
} }

4
framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs

@ -26,6 +26,10 @@ namespace Volo.Abp.Http.DynamicProxying
Task<Car> GetObjectandIdAsync(int id, Car bodyValue); Task<Car> GetObjectandIdAsync(int id, Car bodyValue);
Task<Car> GetObjectandFirstReleaseDateAsync(DateTime time, Car bodyValue);
Task<Car> GetObjectandCountAsync(int count, Car bodyValue);
Task<Car> GetObjectAndIdWithQueryAsync(int id, Car bodyValue); Task<Car> GetObjectAndIdWithQueryAsync(int id, Car bodyValue);
Task<string> PutValueWithBodyAsync(string bodyValue); Task<string> PutValueWithBodyAsync(string bodyValue);

16
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); return Task.FromResult(bodyValue);
} }
[HttpGet]
[Route("post-object-and-first-release-date-with-url/{time:datetime}")]
public Task<Car> GetObjectandFirstReleaseDateAsync(DateTime time, Car bodyValue)
{
bodyValue.FirstReleaseDate = time;
return Task.FromResult(bodyValue);
}
[HttpGet]
[Route("post-object-and-count-with-url/{count}")]
public Task<Car> GetObjectandCountAsync(int count, Car bodyValue)
{
bodyValue.Year = count;
return Task.FromResult(bodyValue);
}
[HttpGet] [HttpGet]
[Route("post-object-and-id-with-url-and-query/{id}")] [Route("post-object-and-id-with-url-and-query/{id}")]
public Task<Car> GetObjectAndIdWithQueryAsync(int id, Car bodyValue) public Task<Car> GetObjectAndIdWithQueryAsync(int id, Car bodyValue)

17
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"); 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] [Fact]
public async Task GetObjectAndIdWithQueryAsync() public async Task GetObjectAndIdWithQueryAsync()
{ {

3
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 System.Threading.Tasks;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying; using Volo.Abp.Http.Client.ClientProxying;
using Volo.Abp.Http.Modeling;
using Volo.Abp.TestApp.Application.Dto; using Volo.Abp.TestApp.Application.Dto;
namespace Volo.Abp.Http.DynamicProxying namespace Volo.Abp.Http.DynamicProxying
{ {
public class TestObjectToFormData : IObjectToFormData<List<GetParamsNameValue>>, ITransientDependency public class TestObjectToFormData : IObjectToFormData<List<GetParamsNameValue>>, ITransientDependency
{ {
public Task<List<KeyValuePair<string, HttpContent>>> ConvertAsync(List<GetParamsNameValue> values) public Task<List<KeyValuePair<string, HttpContent>>> ConvertAsync(ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, List<GetParamsNameValue> values)
{ {
if (values.IsNullOrEmpty()) if (values.IsNullOrEmpty())
{ {

23
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<int>, ITransientDependency
{
public Task<string> 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<string>(null);
}
}

3
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 System.Threading.Tasks;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying; using Volo.Abp.Http.Client.ClientProxying;
using Volo.Abp.Http.Modeling;
using Volo.Abp.TestApp.Application.Dto; using Volo.Abp.TestApp.Application.Dto;
namespace Volo.Abp.Http.DynamicProxying namespace Volo.Abp.Http.DynamicProxying
{ {
public class TestObjectToQueryString : IObjectToQueryString<List<GetParamsNameValue>>, ITransientDependency public class TestObjectToQueryString : IObjectToQueryString<List<GetParamsNameValue>>, ITransientDependency
{ {
public Task<string> ConvertAsync(List<GetParamsNameValue> values) public Task<string> ConvertAsync(ActionApiDescriptionModel actionApiDescription, ParameterApiDescriptionModel parameterApiDescription, List<GetParamsNameValue> values)
{ {
if (values.IsNullOrEmpty()) if (values.IsNullOrEmpty())
{ {

Loading…
Cancel
Save