Browse Source

Improvements on DynamicHttpProxyInterceptor

pull/113/head
Halil İbrahim Kalkan 9 years ago
parent
commit
115b4c0c26
  1. 4
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs
  2. 2
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DefaultUrlActionNameNormalizer.cs
  3. 89
      src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs
  4. 82
      src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs
  5. 28
      src/Volo.Abp.Http/Volo/Abp/Http/HttpMethodHelper.cs
  6. 6
      src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs
  7. 0
      src/Volo.Abp.Http/Volo/Abp/Http/RemoteServiceAttribute.cs
  8. 4
      src/Volo.Abp/Volo.Abp.csproj

4
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs

@ -227,8 +227,8 @@ namespace Volo.Abp.AspNetCore.Mvc
protected virtual string SelectHttpMethod(ActionModel action, AbpControllerAssemblySetting configuration) protected virtual string SelectHttpMethod(ActionModel action, AbpControllerAssemblySetting configuration)
{ {
return configuration?.UseConventionalHttpVerbs == true return configuration?.UseConventionalHttpVerbs == true
? HttpMethodConventionHelper.GetConventionalVerbForMethodName(action.ActionName) ? HttpMethodHelper.GetConventionalVerbForMethodName(action.ActionName)
: HttpMethodConventionHelper.DefaultHttpVerb; : HttpMethodHelper.DefaultHttpVerb;
} }
protected virtual void NormalizeSelectorRoutes(string moduleName, string controllerName, ActionModel action) protected virtual void NormalizeSelectorRoutes(string moduleName, string controllerName, ActionModel action)

2
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DefaultUrlActionNameNormalizer.cs

@ -12,7 +12,7 @@ namespace Volo.Abp.AspNetCore.Mvc
return; return;
} }
context.ActionNameInUrl = HttpMethodConventionHelper.RemoveHttpMethodPrefix(context.ActionNameInUrl, context.HttpMethod); context.ActionNameInUrl = HttpMethodHelper.RemoveHttpMethodPrefix(context.ActionNameInUrl, context.HttpMethod);
} }
} }
} }

89
src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs

@ -1,16 +1,13 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy; using Volo.Abp.DynamicProxy;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Reflection;
using Volo.Abp.Threading; using Volo.Abp.Threading;
namespace Volo.Abp.Http.Client.DynamicProxying namespace Volo.Abp.Http.Client.DynamicProxying
@ -56,14 +53,17 @@ namespace Volo.Abp.Http.Client.DynamicProxying
private async Task<T> InterceptAsync<T>(IAbpMethodInvocation invocation) private async Task<T> InterceptAsync<T>(IAbpMethodInvocation invocation)
{ {
//TODO: Somehow capture cancellationtoken and pass to other methods...?
var proxyConfig = GetProxyConfig(); var proxyConfig = GetProxyConfig();
var actionApiDescription = await _apiDescriptionFinder.FindActionAsync(proxyConfig, invocation.Method); var actionApiDescription = await _apiDescriptionFinder.FindActionAsync(proxyConfig, invocation.Method);
using (var client = _httpClientFactory.Create()) using (var client = _httpClientFactory.Create())
{ {
var url = GenerateUrlWithParameters(actionApiDescription, invocation); var url = proxyConfig.BaseUrl + UrlBuilder.GenerateUrlWithParameters(actionApiDescription, invocation.ArgumentsDictionary);
var response = await client.GetAsync(proxyConfig.BaseUrl + url); var requestMessage = new HttpRequestMessage(actionApiDescription.GetHttpMethod(), url);
var response = await client.SendAsync(requestMessage);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
throw new AbpException("Remote service returns error!"); throw new AbpException("Remote service returns error!");
@ -88,80 +88,5 @@ namespace Volo.Abp.Http.Client.DynamicProxying
return _options.HttpClientProxies.GetOrDefault(typeof(TService)) return _options.HttpClientProxies.GetOrDefault(typeof(TService))
?? throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {typeof(TService).FullName}."); ?? throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {typeof(TService).FullName}.");
} }
public static string GenerateUrlWithParameters(ActionApiDescriptionModel action, IAbpMethodInvocation invocation)
{
//TODO: Can be optimized using StringBuilder?
var url = ReplacePathVariables(action.Url, action.Parameters, invocation);
url = AddQueryStringParameters(url, action.Parameters, invocation);
return url;
}
private static string ReplacePathVariables(string url, IList<ParameterApiDescriptionModel> actionParameters, IAbpMethodInvocation invocation)
{
var pathParameters = actionParameters
.Where(p => p.BindingSourceId == "Path")
.ToArray();
if (!pathParameters.Any())
{
return url;
}
foreach (var pathParameter in pathParameters)
{
url = url.Replace($"{{{pathParameter.Name}}}", FindParameterValue(invocation, pathParameter));
}
return url;
}
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;
}
var qsBuilder = new StringBuilder();
foreach (var queryStringParameter in queryStringParameters)
{
var value = FindParameterValue(invocation, queryStringParameter);
if (value == null)
{
continue;
}
qsBuilder.Append(qsBuilder.Length == 0 ? "?" : "&");
qsBuilder.Append(queryStringParameter.Name + "=" + value); //TODO: URL Encode!
}
return url + qsBuilder;
}
private static string FindParameterValue(IAbpMethodInvocation invocation, ParameterApiDescriptionModel parameter)
{
//TODO: Handle null values
if (parameter.Name == parameter.NameOnMethod)
{
return invocation.ArgumentsDictionary[parameter.Name]?.ToString();
}
else
{
var obj = invocation.ArgumentsDictionary[parameter.NameOnMethod];
if (obj == null)
{
return null;
}
return ReflectionHelper.GetValueByPath(obj, obj.GetType(), parameter.Name)?.ToString();
}
}
} }
} }

82
src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Reflection;
namespace Volo.Abp.Http.Client.DynamicProxying
{
internal static class UrlBuilder
{
public static string GenerateUrlWithParameters(ActionApiDescriptionModel action, IReadOnlyDictionary<string, object> methodArguments)
{
var urlBuilder = new StringBuilder(action.Url);
ReplacePathVariables(urlBuilder, action.Parameters, methodArguments);
AddQueryStringParameters(urlBuilder, action.Parameters, methodArguments);
return urlBuilder.ToString();
}
private static void ReplacePathVariables(StringBuilder urlBuilder, IList<ParameterApiDescriptionModel> actionParameters, IReadOnlyDictionary<string, object> methodArguments)
{
var pathParameters = actionParameters
.Where(p => p.BindingSourceId == "Path")
.ToArray();
if (!pathParameters.Any())
{
return;
}
foreach (var pathParameter in pathParameters)
{
urlBuilder = urlBuilder.Replace($"{{{pathParameter.Name}}}", FindParameterValue(methodArguments, pathParameter));
}
}
private static void AddQueryStringParameters(StringBuilder urlBuilder, IList<ParameterApiDescriptionModel> actionParameters, IReadOnlyDictionary<string, object> methodArguments)
{
var queryStringParameters = actionParameters
.Where(p => p.BindingSourceId.IsIn("ModelBinding", "Query"))
.ToArray();
if (!queryStringParameters.Any())
{
return;
}
var isFirstParam = true;
foreach (var queryStringParameter in queryStringParameters)
{
var value = FindParameterValue(methodArguments, queryStringParameter);
if (value == null)
{
continue;
}
urlBuilder.Append(isFirstParam ? "?" : "&");
urlBuilder.Append(queryStringParameter.Name + "=" + System.Net.WebUtility.UrlEncode(value));
isFirstParam = false;
}
}
private static string FindParameterValue(IReadOnlyDictionary<string, object> methodArguments, ParameterApiDescriptionModel apiParameter)
{
var value = methodArguments[apiParameter.NameOnMethod];
if (value == null)
{
return null;
}
if (apiParameter.Name == apiParameter.NameOnMethod)
{
return value.ToString();
}
return ReflectionHelper.GetValueByPath(value, value.GetType(), apiParameter.Name)?.ToString();
}
}
}

28
src/Volo.Abp/Volo/Abp/Http/HttpMethodConventionHelper.cs → src/Volo.Abp.Http/Volo/Abp/Http/HttpMethodHelper.cs

@ -1,11 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace Volo.Abp.Http namespace Volo.Abp.Http
{ {
public static class HttpMethodConventionHelper public static class HttpMethodHelper
{ {
public const string DefaultHttpVerb = "POST"; public const string DefaultHttpVerb = "POST";
@ -44,5 +45,30 @@ namespace Volo.Abp.Http
return methodName.RemovePreFix(prefixes); return methodName.RemovePreFix(prefixes);
} }
public static HttpMethod ConvertToHttpMethod(string httpMethod)
{
switch (httpMethod.ToUpperInvariant())
{
case "GET":
return HttpMethod.Get;
case "POST":
return HttpMethod.Post;
case "PUT":
return HttpMethod.Put;
case "DELETE":
return HttpMethod.Delete;
case "OPTIONS":
return HttpMethod.Options;
case "TRACE":
return HttpMethod.Trace;
case "HEAD":
return HttpMethod.Head;
case "PATCH":
return new HttpMethod("PATCH");
default:
throw new AbpException("Unknown HTTP METHOD: " + httpMethod);
}
}
} }
} }

6
src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http;
using System.Reflection; using System.Reflection;
namespace Volo.Abp.Http.Modeling namespace Volo.Abp.Http.Modeling
@ -49,5 +50,10 @@ namespace Volo.Abp.Http.Modeling
Parameters.Add(parameter); Parameters.Add(parameter);
return parameter; return parameter;
} }
public HttpMethod GetHttpMethod()
{
return HttpMethodHelper.ConvertToHttpMethod(HttpMethod);
}
} }
} }

0
src/Volo.Abp/Volo/Abp/Http/RemoteServiceAttribute.cs → src/Volo.Abp.Http/Volo/Abp/Http/RemoteServiceAttribute.cs

4
src/Volo.Abp/Volo.Abp.csproj

@ -27,4 +27,8 @@
<PackageReference Include="Nito.AsyncEx.Context" Version="1.1.0" /> <PackageReference Include="Nito.AsyncEx.Context" Version="1.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Volo\Abp\Http\" />
</ItemGroup>
</Project> </Project>

Loading…
Cancel
Save