Add `IObjectToQueryString`.

pull/10220/head
maliming 4 years ago
parent 509564f96d
commit 43c4d80b6d

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Volo.Abp.Http
{
public interface IObjectToQueryString<in TValue>
{
Task<string> ConvertAsync(TValue value);
}
}

@ -134,7 +134,7 @@ namespace Volo.Abp.Reflection
var currentType = objectType;
var objectPath = currentType.FullName;
var absolutePropertyPath = propertyPath;
if (objectPath != null && absolutePropertyPath.StartsWith(objectPath))
if (objectPath != null && absolutePropertyPath.StartsWith(objectPath))
{
absolutePropertyPath = absolutePropertyPath.Replace(objectPath + ".", "");
}
@ -144,7 +144,10 @@ namespace Volo.Abp.Reflection
var property = currentType.GetProperty(propertyName);
if (property != null)
{
value = property.GetValue(value, null);
if (value != null)
{
value = property.GetValue(value, null);
}
currentType = property.PropertyType;
}
else

@ -156,9 +156,9 @@ namespace Volo.Abp.Http.Client.ClientProxying
return new ApiVersionInfo(versionParam?.BindingSourceId, apiVersion);
}
protected virtual Task<string> GetUrlWithParametersAsync(ClientProxyRequestContext requestContext, ApiVersionInfo apiVersion)
protected virtual async Task<string> GetUrlWithParametersAsync(ClientProxyRequestContext requestContext, ApiVersionInfo apiVersion)
{
return Task.FromResult(ClientProxyUrlBuilder.GenerateUrlWithParameters(requestContext.Action, requestContext.Arguments, apiVersion));
return await ClientProxyUrlBuilder.GenerateUrlWithParametersAsync(requestContext.Action, requestContext.Arguments, apiVersion);
}
protected virtual Task<HttpContent> GetHttpContentAsync(ClientProxyRequestContext requestContext, ApiVersionInfo apiVersion)

@ -3,8 +3,11 @@ using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.Proxying;
using Volo.Abp.Http.Modeling;
@ -15,7 +18,23 @@ namespace Volo.Abp.Http.Client.ClientProxying
{
public class ClientProxyUrlBuilder : ITransientDependency
{
public string GenerateUrlWithParameters(ActionApiDescriptionModel action, IReadOnlyDictionary<string, object> methodArguments, ApiVersionInfo apiVersion)
protected static MethodInfo CallObjectToQueryStringAsyncMethod { get; }
static ClientProxyUrlBuilder()
{
CallObjectToQueryStringAsyncMethod = typeof(ClientProxyUrlBuilder)
.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
.First(m => m.Name == nameof(ObjectToQueryStringAsync) && m.IsGenericMethodDefinition);
}
protected IServiceScopeFactory ServiceScopeFactory { get; }
public ClientProxyUrlBuilder(IServiceScopeFactory serviceScopeFactory)
{
ServiceScopeFactory = serviceScopeFactory;
}
public async Task<string> GenerateUrlWithParametersAsync(ActionApiDescriptionModel action, IReadOnlyDictionary<string, object> methodArguments, ApiVersionInfo apiVersion)
{
// The ASP.NET Core route value provider and query string value provider:
// Treat values as invariant culture.
@ -24,14 +43,14 @@ namespace Volo.Abp.Http.Client.ClientProxying
{
var urlBuilder = new StringBuilder(action.Url);
ReplacePathVariables(urlBuilder, action.Parameters, methodArguments, apiVersion);
AddQueryStringParameters(urlBuilder, action.Parameters, methodArguments, apiVersion);
await ReplacePathVariablesAsync(urlBuilder, action.Parameters, methodArguments, apiVersion);
await AddQueryStringParametersAsync(urlBuilder, action.Parameters, methodArguments, apiVersion);
return urlBuilder.ToString();
}
}
protected virtual void ReplacePathVariables(StringBuilder urlBuilder, IList<ParameterApiDescriptionModel> actionParameters, IReadOnlyDictionary<string, object> methodArguments, ApiVersionInfo apiVersion)
protected virtual Task ReplacePathVariablesAsync(StringBuilder urlBuilder, IList<ParameterApiDescriptionModel> actionParameters, IReadOnlyDictionary<string, object> methodArguments, ApiVersionInfo apiVersion)
{
var pathParameters = actionParameters
.Where(p => p.BindingSourceId == ParameterBindingSources.Path)
@ -39,7 +58,7 @@ namespace Volo.Abp.Http.Client.ClientProxying
if (!pathParameters.Any())
{
return;
return Task.CompletedTask;
}
if (pathParameters.Any(p => p.Name == "apiVersion"))
@ -71,9 +90,11 @@ namespace Volo.Abp.Http.Client.ClientProxying
urlBuilder = urlBuilder.Replace($"{{{pathParameter.Name}}}", value.ToString());
}
}
return Task.CompletedTask;
}
protected virtual void AddQueryStringParameters(StringBuilder urlBuilder, IList<ParameterApiDescriptionModel> actionParameters, IReadOnlyDictionary<string, object> methodArguments, ApiVersionInfo apiVersion)
protected virtual async Task AddQueryStringParametersAsync(StringBuilder urlBuilder, IList<ParameterApiDescriptionModel> actionParameters, IReadOnlyDictionary<string, object> methodArguments, ApiVersionInfo apiVersion)
{
var queryStringParameters = actionParameters
.Where(p => p.BindingSourceId.IsIn(ParameterBindingSources.ModelBinding, ParameterBindingSources.Query))
@ -89,7 +110,26 @@ namespace Volo.Abp.Http.Client.ClientProxying
continue;
}
if (AddQueryStringParameter(urlBuilder, isFirstParam, queryStringParameter.Name, value))
using (var scope = ServiceScopeFactory.CreateScope())
{
var objectToQuery = scope.ServiceProvider.GetService(typeof(IObjectToQueryString<>).MakeGenericType(value.GetType()));
if (objectToQuery != null)
{
var queryString = await (Task<string>)CallObjectToQueryStringAsyncMethod
.MakeGenericMethod(value.GetType())
.Invoke(this, new object[] { value });
if (!queryString.IsNullOrWhiteSpace())
{
urlBuilder.Append(isFirstParam ? "?" : "&");
urlBuilder.Append(queryString);
isFirstParam = false;
continue;
}
}
}
if (await AddQueryStringParameterAsync(urlBuilder, isFirstParam, queryStringParameter.Name, value))
{
isFirstParam = false;
}
@ -97,11 +137,24 @@ namespace Volo.Abp.Http.Client.ClientProxying
if (apiVersion.ShouldSendInQueryString())
{
AddQueryStringParameter(urlBuilder, isFirstParam, "api-version", apiVersion.Version); //TODO: Constant!
await AddQueryStringParameterAsync(urlBuilder, isFirstParam, "api-version", apiVersion.Version); //TODO: Constant!
}
}
protected virtual async Task<string> ObjectToQueryStringAsync<T>(T value)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
var objectToQueryString = scope.ServiceProvider.GetService<IObjectToQueryString<T>>();
if (objectToQueryString != null)
{
return await objectToQueryString.ConvertAsync(value);
}
}
return null;
}
protected virtual bool AddQueryStringParameter(
protected virtual async Task<bool> AddQueryStringParameterAsync(
StringBuilder urlBuilder,
bool isFirstParam,
string name,
@ -116,7 +169,7 @@ namespace Volo.Abp.Http.Client.ClientProxying
{
urlBuilder.Append(isFirstParam ? "?" : "&");
}
urlBuilder.Append(name + $"[{index++}]=" + System.Net.WebUtility.UrlEncode(ConvertValueToString(item)) + "&");
urlBuilder.Append(name + $"[{index++}]=" + System.Net.WebUtility.UrlEncode(await ConvertValueToStringAsync(item)) + "&");
}
if (index > 0)
@ -130,18 +183,18 @@ namespace Volo.Abp.Http.Client.ClientProxying
}
urlBuilder.Append(isFirstParam ? "?" : "&");
urlBuilder.Append(name + "=" + System.Net.WebUtility.UrlEncode(ConvertValueToString(value)));
urlBuilder.Append(name + "=" + System.Net.WebUtility.UrlEncode(await ConvertValueToStringAsync(value)));
return true;
}
protected virtual string ConvertValueToString([CanBeNull] object value)
protected virtual Task<string> ConvertValueToStringAsync([CanBeNull] object value)
{
if (value is DateTime dateTimeValue)
{
return dateTimeValue.ToUniversalTime().ToString("O");
return Task.FromResult(dateTimeValue.ToUniversalTime().ToString("O"));
}
return value?.ToString();
return Task.FromResult(value?.ToString());
}
}
}

@ -276,5 +276,32 @@ namespace Volo.Abp.Http.DynamicProxying
});
result.ShouldBe("123.rtf:File1:application/rtf:1-1.rtf123.rtf:File2:application/rtf2:1-2.rtf789.rtf:File3:application/rtf3:i-789.rtf");
}
[Fact]
public async Task GetParamsFromQueryAsync()
{
var result = await _peopleAppService.GetParamsFromQueryAsync(new GetParamsFromQueryInput()
{
NameValues = new List<GetParamsFromQueryInputNameValue>()
{
new GetParamsFromQueryInputNameValue()
{
Name = "name1",
Value = "value1"
},
new GetParamsFromQueryInputNameValue()
{
Name = "name2",
Value = "value2"
}
},
NameValue = new GetParamsFromQueryInputNameValue()
{
Name = "name3",
Value = "value3"
}
});
result.ShouldBe("name1-value1:name2-value2:name3-value3");
}
}
}

@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http;
namespace Volo.Abp.TestApp.Application.Dto
{
public class GetParamsFromQueryInput
{
public List<GetParamsFromQueryInputNameValue> NameValues { get; set; }
public GetParamsFromQueryInputNameValue NameValue { get; set; }
}
public class GetParamsFromQueryInputNameValue
{
public string Name { get; set; }
public string Value { get; set; }
}
[ExposeServices(typeof(IObjectToQueryString<List<GetParamsFromQueryInputNameValue>>))]
public class TestInputToQueryString : IObjectToQueryString<List<GetParamsFromQueryInputNameValue>>, ITransientDependency
{
public Task<string> ConvertAsync(List<GetParamsFromQueryInputNameValue> values)
{
if (values.IsNullOrEmpty())
{
return null;
}
var sb = new StringBuilder();
for (var i = 0; i < values.Count; i++)
{
sb.Append($"NameValues[{i}].Name={values[i].Name}&NameValues[{i}].Value={values[i].Value}&");
}
sb.Remove(sb.Length - 1, 1);
return Task.FromResult(sb.ToString());
}
}
}

@ -32,5 +32,6 @@ namespace Volo.Abp.TestApp.Application
Task<string> CreateMultipleFileAsync(CreateMultipleFileInput input);
Task<string> GetParamsFromQueryAsync(GetParamsFromQueryInput input);
}
}

@ -125,5 +125,13 @@ namespace Volo.Abp.TestApp.Application
return str;
}
public Task<string> GetParamsFromQueryAsync(GetParamsFromQueryInput input)
{
return Task.FromResult(input.NameValues?.FirstOrDefault()?.Name + "-" +
input.NameValues?.FirstOrDefault()?.Value + ":" +
input.NameValues?.LastOrDefault()?.Name + "-" + input.NameValues?.LastOrDefault()?.Value + ":" +
input.NameValue?.Name + "-" + input.NameValue?.Value);
}
}
}

Loading…
Cancel
Save