Added ReflectionHelper.GetValueByPath and used in HynamicHttpProxyInterceptor.

pull/112/head
Halil İbrahim Kalkan 8 years ago
parent 8f9d41817e
commit 994d43bbfd

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using Castle.DynamicProxy;
@ -11,6 +12,9 @@ namespace Volo.Abp.Castle.DynamicProxy
{
public object[] Arguments => Invocation.Arguments;
public IReadOnlyDictionary<string, object> ArgumentsDictionary => _lazyArgumentsDictionary.Value;
private readonly Lazy<IReadOnlyDictionary<string, object>> _lazyArgumentsDictionary;
public Type[] GenericArguments => Invocation.GenericArguments;
public object TargetObject => Invocation.InvocationTarget;
@ -23,32 +27,47 @@ namespace Volo.Abp.Castle.DynamicProxy
set => Invocation.ReturnValue = value;
}
private object _actualReturnValue;
private object _actualReturnValue;
protected IInvocation Invocation { get; }
public CastleAbpMethodInvocationAdapter(IInvocation invocation)
{
Invocation = invocation;
_lazyArgumentsDictionary = new Lazy<IReadOnlyDictionary<string, object>>(GetArgumentsDictionary);
}
public void Proceed()
{
Invocation.Proceed();
if (Invocation.Method.IsAsync())
{
AsyncHelper.RunSync(() => (Task) Invocation.ReturnValue);
}
}
public Task ProceedAsync()
{
Invocation.Proceed();
_actualReturnValue = Invocation.ReturnValue;
return Invocation.Method.IsAsync()
? (Task)_actualReturnValue
: Task.FromResult(_actualReturnValue);
}
}
public void Proceed()
{
Invocation.Proceed();
if (Invocation.Method.IsAsync())
{
AsyncHelper.RunSync(() => (Task)Invocation.ReturnValue);
}
}
public Task ProceedAsync()
{
Invocation.Proceed();
_actualReturnValue = Invocation.ReturnValue;
return Invocation.Method.IsAsync()
? (Task)_actualReturnValue
: Task.FromResult(_actualReturnValue);
}
private IReadOnlyDictionary<string, object> GetArgumentsDictionary()
{
var dict = new Dictionary<string, object>();
var methodParameters = Method.GetParameters();
for (int i = 0; i < methodParameters.Length; i++)
{
dict[methodParameters[i].Name] = Invocation.Arguments[i];
}
return dict;
}
}
}

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
@ -9,6 +10,7 @@ using Newtonsoft.Json.Serialization;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Reflection;
using Volo.Abp.Threading;
namespace Volo.Abp.Http.Client.DynamicProxying
@ -91,7 +93,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
{
//TODO: Can be optimized using StringBuilder?
var url = ReplacePathVariables(action.Url, action.Parameters, invocation);
//url = AddQueryStringParameters(url, action.Parameters);
url = AddQueryStringParameters(url, action.Parameters, invocation);
return url;
}
@ -108,42 +110,58 @@ namespace Volo.Abp.Http.Client.DynamicProxying
foreach (var pathParameter in pathParameters)
{
url = url.Replace($"{{{pathParameter.Name}}}", FindParameterValue(invocation.Method, invocation.Arguments, pathParameter.Name));
url = url.Replace($"{{{pathParameter.Name}}}", FindParameterValue(invocation, pathParameter));
}
return url;
}
//private static string AddQueryStringParameters(string url, IList<ParameterApiDescriptionModel> actionParameters)
//{
// var queryStringParameters = actionParameters
// .Where(p => p.BindingSourceId.IsIn("ModelBinding", "Query"))
// .ToArray();
private static string AddQueryStringParameters(string url, IList<ParameterApiDescriptionModel> actionParameters, IAbpMethodInvocation invocation)
{
var queryStringParameters = actionParameters
.Where(p => p.BindingSourceId.IsIn("ModelBinding", "Query"))
.ToArray();
// if (!queryStringParameters.Any())
// {
// return url;
// }
if (!queryStringParameters.Any())
{
return url;
}
// var qsBuilderParams = queryStringParameters
// .Select(p => $"{{ name: '{p.Name.ToCamelCase()}', value: {ProxyScriptingJsFuncHelper.GetParamNameInJsFunc(p)} }}")
// .JoinAsString(", ");
var qsBuilder = new StringBuilder();
// return url + $"' + abp.utils.buildQueryString([{qsBuilderParams}]) + '";
//}
foreach (var queryStringParameter in queryStringParameters)
{
var value = FindParameterValue(invocation, queryStringParameter);
if (value == null)
{
continue;
}
private static string FindParameterValue(MethodInfo method, object[] arguments, string parameterName)
qsBuilder.Append(qsBuilder.Length == 0 ? "?" : "&");
qsBuilder.Append(queryStringParameter.Name + "=" + value); //TODO: URL Encode!
}
return url + qsBuilder;
}
private static string FindParameterValue(IAbpMethodInvocation invocation, ParameterApiDescriptionModel parameter)
{
var methodParameters = method.GetParameters();
for (int i = 0; i < methodParameters.Length; i++)
//TODO: Handle null values
if (parameter.Name == parameter.NameOnMethod)
{
if (methodParameters[i].Name == parameterName)
return invocation.ArgumentsDictionary[parameter.Name]?.ToString();
}
else
{
var obj = invocation.ArgumentsDictionary[parameter.NameOnMethod];
if (obj == null)
{
return arguments[i].ToString();
return null;
}
}
throw new AbpException("Could not find parameter in the invocation: " + parameterName);
return ReflectionHelper.GetValueByPath(obj, obj.GetType(), parameter.Name)?.ToString();
}
}
}
}

@ -9,8 +9,6 @@ namespace Volo.Abp.Http.Modeling
public string Name { get; set; }
public Type Type { get; set; }
public string TypeAsString { get; set; }
public bool IsOptional { get; set; }
@ -32,7 +30,6 @@ namespace Volo.Abp.Http.Modeling
{
Name = name,
NameOnMethod = nameOnMethod,
Type = type,
TypeAsString = type.FullName,
IsOptional = isOptional,
DefaultValue = defaultValue,

@ -12,6 +12,7 @@ using System.Runtime.InteropServices;
[assembly: InternalsVisibleTo("Volo.Abp.Tests")]
[assembly: InternalsVisibleTo("Volo.Abp.AspNetCore.Mvc")]
[assembly: InternalsVisibleTo("Volo.Abp.Http.Client")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
@ -8,6 +9,8 @@ namespace Volo.Abp.DynamicProxy
{
object[] Arguments { get; }
IReadOnlyDictionary<string, object> ArgumentsDictionary { get; }
Type[] GenericArguments { get; }
object TargetObject { get; }

@ -91,5 +91,63 @@ namespace Volo.Abp.Reflection
return defaultValue;
}
/// <summary>
/// Gets value of a property by it's full path from given object
/// </summary>
internal static object GetValueByPath(object obj, Type objectType, string propertyPath)
{
var value = obj;
var currentType = objectType;
var objectPath = currentType.FullName;
var absolutePropertyPath = propertyPath;
if (absolutePropertyPath.StartsWith(objectPath))
{
absolutePropertyPath = absolutePropertyPath.Replace(objectPath + ".", "");
}
foreach (var propertyName in absolutePropertyPath.Split('.'))
{
var property = currentType.GetProperty(propertyName);
value = property.GetValue(value, null);
currentType = property.PropertyType;
}
return value;
}
/// <summary>
/// Sets value of a property by it's full path on given object
/// </summary>
internal static void SetValueByPath(object obj, Type objectType, string propertyPath, object value)
{
var currentType = objectType;
PropertyInfo property;
var objectPath = currentType.FullName;
var absolutePropertyPath = propertyPath;
if (absolutePropertyPath.StartsWith(objectPath))
{
absolutePropertyPath = absolutePropertyPath.Replace(objectPath + ".", "");
}
var properties = absolutePropertyPath.Split('.');
if (properties.Length == 1)
{
property = objectType.GetProperty(properties.First());
property.SetValue(obj, value);
return;
}
for (int i = 0; i < properties.Length - 1; i++)
{
property = currentType.GetProperty(properties[i]);
obj = property.GetValue(obj, null);
currentType = property.PropertyType;
}
property = currentType.GetProperty(properties.Last());
property.SetValue(obj, value);
}
}
}

@ -39,5 +39,28 @@ namespace Volo.Abp.Http.DynamicProxying
person.Id.ShouldBe(firstPerson.Id);
person.Name.ShouldBe(firstPerson.Name);
}
[Fact]
public async Task GetWithComplexType()
{
var result = await _peopleAppService.GetWithComplexType(
new GetWithComplexTypeInput
{
Value1 = "value one",
Inner1 = new GetWithComplexTypeInner
{
Value2 = "value two",
Inner2 = new GetWithComplexTypeInnerInner
{
Value3 = "value three"
}
}
}
);
result.Value1.ShouldBe("value one");
result.Inner1.Value2.ShouldBe("value two");
result.Inner1.Inner2.Value3.ShouldBe("value three");
}
}
}

@ -12,5 +12,25 @@ namespace Volo.Abp.TestApp.Application
Task<PhoneDto> AddPhone(Guid id, PhoneDto phoneDto);
Task RemovePhone(Guid id, long phoneId);
Task<GetWithComplexTypeInput> GetWithComplexType(GetWithComplexTypeInput input);
}
public class GetWithComplexTypeInput
{
public string Value1 { get; set; }
public GetWithComplexTypeInner Inner1 { get; set; }
}
public class GetWithComplexTypeInner
{
public string Value2 { get; set; }
public GetWithComplexTypeInnerInner Inner2 { get; set; }
}
public class GetWithComplexTypeInnerInner
{
public string Value3 { get; set; }
}
}

@ -43,5 +43,10 @@ namespace Volo.Abp.TestApp.Application
var person = await GetEntityByIdAsync(id);
person.Phones.RemoveAll(p => p.Id == phoneId);
}
public Task<GetWithComplexTypeInput> GetWithComplexType(GetWithComplexTypeInput input)
{
return Task.FromResult(input);
}
}
}

Loading…
Cancel
Save